一,什么是双向绑定
双向:数据 - > 视图、视图 - > 数据; 绑定:v-model、v-bind . . .
从数据到视图。当数据变化时,视图也跟着变化。
从视图到数据。当input框中的内容变化时,数据也跟着变化。
二,实现原理:(个人理解)
利用数据劫持结合订阅者发布者模式,通过objeck.defineproperty中的set和get方法(作用:拦截器),在数据变动时发布消息给订阅者(v-model、v-bind绑定的那个属性),触发相应的监听回调。set方法设置数据时触发,get是访问时触发监听。对比数据变动前后的虚拟DOM,计算出那些地方需要更新,只更新需要更新的地方。
三,实现基本构造器
-
写出构造器的基本架子,完成参数传递与获取。这里的参数只有两个:el,data
-
实现数据拦截:
-
在代码外部,让MVVM实例可以操作data选项中的属性。
-
在代码内部,能通过this.属性名 的方式去操作data选项中的属性。
-
<script type="text/javascript">
var data = {
salary:15000
}
// 1. 完成参数传递与获取
// 2. 实现数据拦截
// (1) 在代码外部,让实例能够操作data选项中的数据
// (2) 在代码内部,通过this.XXX来访问data选项中的属性值
function MVVM (options) {
// 用解构赋值,取出配置项中内容
let {el, data} = options
console.log(data)
// 对data中所有的可枚举属性进行循环
for(let key in data) {
console.log(key)
// 在构造器内部,this就会指向当前实例对象
Object.defineProperty(this, key, {
get () {
console.log('get', key)
return data[key]
},
set ( val ) {
if (val != data[key]) {
data[key] = val
}
}
})
}
console.log(this.salary)
}
var vm = new MVVM({
el:"#app",
data
})
// console.log( vm.salary )
</script>
模板编译并初始显示内容:
function MVVM (options) {
// 用解构赋值,取出配置项中内容
let {el, data} = options
console.log(data)
// 对data中所有的可枚举属性进行循环
for(let key in data) {
console.log(key)
// 在构造器内部,this就会指向当前实例对象
Object.defineProperty(this, key, {
get () {
console.log('get', key)
return data[key]
},
set ( val ) {
if (val != data[key]) {
data[key] = val
}
}
})
}
// 循环el下的所有的子节点
// 如果某个节点上有v-html, v-model则需要特殊处理
// 1. 取出所有的子节点
let rootDom =document.querySelector(el)
// console.dir(Array.isArray(rootDom.children))
// console.dir(rootDom.children)
// rootDom.children 表示所有的子结点,它是一个伪数组,要用循环,还要转一下。
Array.from(rootDom.children).forEach(node => {
// console.log(node)
// 对每一个节点,分析是否有 v-html, v-model属性?
console.log( node.hasAttribute('v-html'))
if (node.hasAttribute('v-html')) {
// 处理v-html指令: 把数据显示出来
//以: <h2 v-html="salary"></h2> 为例
// (1) 把属性值取出来。把salary取出来
let attrVal = node.getAttribute('v-html')
console.log(attrVal) // attrVal : salary
// (2) 找出对应的data中的salary的属性值15000
console.log(this[attrVal])
// (3) 15000 放入当前的node中
node.innerHTML = this[attrVal]
}
})
}
// MVVM中的m: 数据项
var data = {
salary:15000
}
// MVVM中的 vm
// 目标:自已写代码,实现类似Vue的功能
var vm = new MVVM({
"el":"#app",
"data": data
})
-
Array.from :把一个伪数组转成数组
-
hasAttribute判断一个dom是否有指定的属性
-
getAttribute是用来获取dom的指定属性的值
-
this[attrVal]
-
获取对象的属性值。由于attrVal是一个变量,不能通过this.attrVal的方式来获取
-
this是当前的实例对象,在上一步 构造器 的过程,已经把数据的属性全挂在实例对象上了。所以,这里可以直接访问。
-
效果:图1,图2