主题
Vue双向绑定原理解析。😃
javascript
<script>
//双向绑定的原理
let doc = document
let log = console.info.bind(console)
function node2Fragment(node, vm) {
let temp = doc.createDocumentFragment()
let child
while (child = node.firstChild) {
complie(child, vm)
temp.appendChild(child)
}
return temp
}
function complie(node, vm) {
let reg = /\{\{(.*)\}\}/
let type = node.nodeType
switch(type) {
case 1:
let attr = node.attributes;
for ( let i = 0; i < attr.length; i++ ) {
if (attr[i].nodeName == 'v-model') {
let name = attr[i].nodeValue
node.addEventListener('input', function(e) {
vm[name] = e.target.value
})
node.value = vm[name]
node.removeAttribute('v-model')
}
}
break
case 3:
if (reg.test(node.nodeValue)) {
let name = RegExp.$1
name = name.trim()
node.nodeValue = vm[name]
new Watcher(vm, node, name)
}
break
}
}
function observe(obj, vm) {
Object.keys(obj).forEach(function(key) {
defineReactive(vm, key, obj[key])
})
}
function defineReactive(obj, key, val) {
let dep = new Dep()
Object.defineProperty(obj, key, {
get: function() {
if (Dep.target) dep.addSub(Dep.target)
return val
},
set: function(newVal) {
if (val === newVal) return
val = newVal
dep.notify()
}
})
}
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
},
get: function() {
this.value = this.vm[this.name]
}
}
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
let data = this.data
observe(data, this)
let id = options.el
let dom = node2Fragment(doc.getElementById(id), this)
doc.getElementById(id).appendChild(dom)
}
</script>
<body>
<div id="app">
<input type="text" v-model="text" />
{{text}}
</div>
</body>
<script>
var vm=new Vue({
el:'app',
data:{
text:'hello world!'
}
})
</script>