vue双方向バインド原理(データ応答式原理)
3615 ワード
Document
/*
1. VUE ,Watcher
2. MVVM M V,
3.(1) V-M, ,
(2)
*/
//
class Vue {
constructor(options) {
this.options = options
this.$data = options.data //
this.$el = document.querySelector(options.el)
this._directive = {} // ,
this.Observer(this.$data)
this.Compile(this.$el)
}
//
Observer (data) {
for (let key in data) {
this._directive[key] = []
let Val = data[key]
let watch = this._directive[key]
// this.$data ,
Object.defineProperty(this.$data, key, {
get: function () {
return Val
},
set: function(newVal) {
if (newVal !== Val) { // ,
Val = newVal
watch.forEach(item => {
item.update()
})
}
}
})
}
}
//
Compile (el) {
let nodes = el.children
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].children.length) {
//
this.Compile(nodes[i])
}
// v-text
if (nodes[i].hasAttribute('v-text')) {
let attrVal = nodes[i].getAttribute('v-text')
this._directive[attrVal].push(new Watcher(nodes[i], this, attrVal, "innerHTML"))
}
// v-model
if (nodes[i].hasAttribute('v-model')) {
let attrVal = nodes[i].getAttribute('v-model')
this._directive[attrVal].push(new Watcher(nodes[i], this, attrVal, "value"))
// input
nodes[i].addEventListener('input',()=>{
this.$data[attrVal] = nodes[i].value
})
}
}
}
}
//
class Watcher {
constructor(el, vm, exp, attr) {
this.el = el
this.vm = vm
this.exp = exp
this.attr = attr
this.update() //
}
update () {
this.el[this.attr] = this.vm.$data[this.exp]
}
}
const app = new Vue({
el: "#app",
data: {
myText: ' , ',
myBox: ' '
}
})