Last active
May 23, 2018 05:34
-
-
Save thinkgarden/14d332b86296d85c57d65a3459203fdd to your computer and use it in GitHub Desktop.
[mvvm] A simple code for mvvm framework #js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>forvue</title> | |
</head> | |
<body> | |
<div id="app"> | |
<input type="text" v-model="text"> <br> | |
{{ text }} <br> | |
{{ text }} | |
</div> | |
<script> | |
function observe(obj, vm) { | |
Object.keys(obj).forEach(function (key) { | |
defineReactive(vm, key, obj[key]); | |
}); | |
} | |
function defineReactive(obj, key, val) { | |
var dep = new Dep(); | |
// 响应式的数据绑定 | |
Object.defineProperty(obj, key, { | |
get: function () { | |
// 添加订阅者watcher到主题对象Dep | |
if (Dep.target) { | |
dep.addSub(Dep.target); | |
} | |
return val; | |
}, | |
set: function (newVal) { | |
if (newVal === val) { | |
return; | |
} else { | |
val = newVal; | |
// 作为发布者发出通知 | |
dep.notify() | |
} | |
} | |
}); | |
} | |
function nodeToFragment(node, vm) { | |
var flag = document.createDocumentFragment(); | |
var child; | |
while (child = node.firstChild) { | |
compile(child, vm); | |
flag.appendChild(child); // 将子节点劫持到文档片段中 | |
} | |
return flag; | |
} | |
function compile(node, vm) { | |
var reg = /\{\{(.*)\}\}/; | |
// 节点类型为元素 | |
if (node.nodeType === 1) { | |
var attr = node.attributes; | |
// 解析属性 | |
for (var i = 0; i < attr.length; i++) { | |
if (attr[i].nodeName == 'v-model') { | |
var name = attr[i].nodeValue; // 获取v-model绑定的属性名 | |
node.addEventListener('input', function (e) { | |
// 给相应的data属性赋值,进而触发属性的set方法 | |
vm[name] = e.target.value; | |
}) | |
node.value = vm[name]; // 将data的值赋值给该node | |
node.removeAttribute('v-model'); | |
} | |
} | |
} | |
// 节点类型为text | |
if (node.nodeType === 3) { | |
if (reg.test(node.nodeValue)) { | |
var name = RegExp.$1; // 获取匹配到的字符串 | |
name = name.trim(); | |
// node.nodeValue = vm[name]; // 将data的值赋值给该node | |
new Watcher(vm, node, name); | |
} | |
} | |
} | |
function Watcher(vm, node, name) { | |
Dep.target = this; | |
this.name = name; | |
this.node = node; | |
this.vm = vm; | |
this.update(); | |
Dep.target = null; | |
} | |
Watcher.prototype = { | |
update: function () { | |
this.get(); | |
this.node.nodeValue = this.value; | |
}, | |
// 获取data中的属性值 | |
get: function () { | |
this.value = this.vm[this.name]; // 触发相应属性的get | |
} | |
} | |
function Dep () { | |
this.subs = []; | |
} | |
Dep.prototype = { | |
addSub: function (sub) { | |
this.subs.push(sub); | |
}, | |
notify: function () { | |
this.subs.forEach(function (sub) { | |
sub.update(); | |
}); | |
} | |
} | |
function Vue(options) { | |
this.data = options.data; | |
var data = this.data; | |
observe(data, this); | |
var id = options.el; | |
var dom = nodeToFragment(document.getElementById(id), this); | |
// 编译完成后,将dom返回到app中。 | |
document.getElementById(id).appendChild(dom); | |
} | |
var vm = new Vue({ | |
el: 'app', | |
data: { | |
text: 'hello world' | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment