<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text" /> {{ text }}
</div>
<script>
function Vue(obj) {
this.id = obj.el,
this.data = obj.data
listenData(this.data, this)
var flag = nodeToFragment(document.getElementById(this.id), this)
document.getElementById(this.id).appendChild(flag)
}
function listenData(data, vue) {
Object.keys(data).forEach(function (key) {
var dep = new Dep()
Object.defineProperty(vue, key, {
set(value) {
if (!(vue.data[key] == value)) {
vue.data[key] = value
console.log(vue.data[key])
dep.notify()
}
},
get() {
if (Dep.newSubScribers) dep.addSubScribers(Dep.newSubScribers)
return vue.data[key]
}
})
})
}
function Dep() {
this.subScribers = []
}
Dep.prototype = {
addSubScribers(sub) {
this.subScribers.push(sub)
},
notify() {
this.subScribers.forEach(function (sub) {
sub.updata()
})
}
}
function nodeToFragment(node, vue) {
var flag = document.createDocumentFragment()
while (node.firstChild) {
compile(node.firstChild, vue)
flag.appendChild(node.firstChild)
}
return flag
}
function compile(node, vue) {
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
node.addEventListener('input', function (e) {
vue[name] = e.target.value
})
node.removeAttribute('v-model')
new Watcher(node, name, vue)
}
}
}
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1
name = name.trim()
node.nodeValue = vue[name]
new Watcher(node, name, vue)
}
}
}
function Watcher(node, name, vue) {
Dep.newSubScribers = this
this.node = node
this.name = name
this.vue = vue
this.value = vue[name]
Dep.newSubScribers = null
}
Watcher.prototype = {
updata() {
if (this.node.nodeType === 1) {
this.node.value = this.vue[this.name]
}
if (this.node.nodeType === 3) {
this.node.nodeValue = this.vue[this.name]
}
}
}
var vue = new Vue({
el: 'app',
data: {
text: 'hello world'
}
})
</script>
</body>
</html>
<!-- http://transcoder.baiducontent.com/from=1012852y/bd_page_type=1/ssid=0/uid=0/pu=usm%401%2Csz%40320_1004%2Cta%40iphone_2_6.0_11_9.1/baiduid=7FFB1B3B6229E8E723991DE796900A1B/w=0_10_/t=iphone/l=3/tc?ref=www_iphone&lid=13311096275631538808&order=1&fm=alop&h5ad=1&srd=1&dict=32&tj=www_normal_1_0_10_title&vit=osres&m=8&cltj=cloud_title&asres=1&nt=wnor&title=Vue.js%E5%8F%8C%E5%90%91%E7%BB%91%E5%AE%9A%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86-kidney-%E5%8D%9A%E5%AE%A2%E5%9B%AD&w_qd=IlPT2AEptyoA_yijCULhngvYOjMmtXdTo6lb&sec=23604&di=004609dd99d90bdd&bdenc=1&tch=124.0.67.295.0.0&nsrc=IlPT2AEptyoA_yixCFOxXnANedT62v3IEQGG_ytK1DK6mlrte4viZQRAWTbrLnq4ZpPPtCPQpxcFxXKi0GEskNYWgLdnpS-bll_aurmqs1CLHaB_s255J2DUVzMr64rFiO2ewAoy0Adf&eqid=b8ba8389980b00001000000659a6a966&wd=&clk_info=%7B%22srcid%22%3A%221599%22%2C%22tplname%22%3A%22www_normal%22%2C%22t%22%3A1504094568858%2C%22sig%22%3A%222004%22%2C%22xpath%22%3A%22div-div-div-a-div-img%22%7D
//Object.keys() 方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,
//数组中属性名的排列顺序和使用for-in循环遍历该对象时返回的顺序一致
//(两者的主要区别是 for-in 还会遍历出一个对象从其原型链上继承到的可枚举属性)。
var flag = document.createDocumentFragment()
// DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点
// 当我们将它插入到 DOM 中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。
flag.appendChild(child) //child在dom树消失 变为DocumentFragment内部节点
document.getElementById(id).appendChild(flag) //把DocumentFragment加进dom树,此时DocumentFragment容器为空,即内部节点移动到dom树,此为DocumentFragment特性
-->
思路是别人的,代码是自己打的,大家可以去看原文,原文有详细解释