vue.js 最核心的功能有两个,一个是响应式数据绑定,二是组件系统。
今天讲讲双向数据绑定的实现
vue.js和avalon.js是通过Object.defineProperty实现双向数据绑定的
1、简单用法如下
var a= {}
Object.defineProperty(a,"b",{
value:123
})
console.log(a.b);//123
2、具体参数看下面代码、其中有比较关键的set和get
var obj = {}; // Creates a new object 创造对象
Object.defineProperty(obj, "hello", {
get: function () {return sth},
set: function (val) {/* do sth */}
})
obj.hello // 可以像普通属性一样读取访问器属性
访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。
obj.hello // 读取属性,就是调用get函数并返回get函数的返回值
obj.hello = "abc" // 为属性赋值,就是调用set函数,赋值其实是传参
好了现在简单讲下如何实现数据视图绑定
极简双向绑定的实现一
<input type="text" id="test">
<p id="test2"></p>
<script type="text/javascript">
var obj = {};
Object.defineProperty(obj, "test", {
set: function (newVal){
document.getElementById("test2").innerHTML = newVal;
}
})
document.addEventListener('keyup', function(e) {
obj.test = e.target.value; // input输入的值作为obj的“动态属性值”,赋值给p
})
</script>
此例实现的效果是:随文本框输入文字的变化,span 中会同步显示相同的文字内容;在js或控制台显式的修改 obj.hello 的值,视图会相应更新。这样就实现了 model => view 以及 view => model 的双向绑定。
![vue实现双向绑定的原理]554AJ.png](http://upload-images.jianshu.io/upload_images/1627906-f6bd2f7554a1e143.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
极简双向绑定的实现二
HTML
<div>
<p>你好,<span id='nickName'></span></p>
<div id="introduce"></div>
</div>
<button id="btn">点击</button>
JS
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
get: function(){
return document.getElementById('nickName').innerHTML;
},
set: function(nick){
document.getElementById('nickName').innerHTML = nick;
}
});
Object.defineProperty(userInfo, "introduce", {
get: function(){
return document.getElementById('introduce').innerHTML;
},
set: function(introduce){
document.getElementById('introduce').innerHTML = introduce;
}
})
document.getElementById('btn').onclick = function(){
userInfo.nickName = "xxx";
userInfo.introduce = "我是xxx,我来自杭州,..."
}
三、分解任务
上述示例仅仅是为了说明原理。我们最终要实现的是:
首先将该任务分成几个子任务:
1、输入框以及文本节点与 data 中的数据绑定
2、输入框内容变化时,data 中的数据同步变化。即 view => model 的变化。
3、data 中的数据变化时,文本节点的内容同步变化。即 model => view 的变化。
要实现任务一,需要对 DOM 进行编译,这里有一个知识点:DocumentFragment
DocumentFragment
DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点,当我们将它插入到 DOM 中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。使用 DocumentFragment 处理节点,速度和性能远远优于直接操作 DOM。Vue 进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持,通过 append 方法,DOM 中的节点会被自动删除)到 DocumentFragment 中,经过一番处理后,再将 DocumentFragment 整体返回插入挂载目标。