Vue中的双向绑定,让开发者能够更加集中精力于业务逻辑而不是操作dom。
实现数据响应式的原理主要有Object.defineProperty为对象设置存取器属性,以及ES6的proxy对象代理。
这里我通过proxy实现了简单的数据响应式。
数据渲染
<div id="app">
<div>
{
{msg1}}
</div>
{
{msg1}} ~~ {
{msg2}}
<form>
<input type="text" v-model="msg1">
</form>
</div>
<script>
var data = {
msg1: 'hello world',
msg2: 'bye world'
}
var vm = new MyVue ({
el: '#app',
data
})
vm.data.msg2 = 'ok'
</script>
我们想通过将data中的数据渲染到页面上,即将html中的标签模版替换为对应的数据,这部分通过正则表达式即可实现。
具体来说,对div#app遍历子节点,文本节点即替换,元素节点就递归遍历子节点。
同时对元素节点,判断v-model属性是否存在,若存在,则设置其value为对应的数据。
数据单向绑定
单向绑定就是,如果在代码中改变了数据的值,那么页面立即重新渲染对应的元素。如上面代码中页面渲染后,执行代码vm.data.msg2 = 'ok'
,那么会自动更新页面内容。
简单说就是 data -> DOM 的绑定。
如何实现呢?可以分为两步:
- 监听到数据的变化
- 数据变化后,相应节点的重新渲染
监听数据变化可以通过Object.defineProperty,但这里采用了proxy的方式数据对象创建代理。
observe (data) {
return new Proxy (data, {
set: (target, prop, newValue) => {
console.log('数据正在被修改:', prop, newValue)
return Reflect.set(target, prop, newValue)
}
})
}
监听到数据变化后如何让相应的元素立即重新渲染呢?我是这样考虑的:
在第一次数据渲染的同时,为每个node注册自定义事件’dataChanged’,可以通过事件对象e.detail.newValue获取到新设定的值。对于文本节点,则用正则替换内容,元素节点则根据v-model属性中的值设定其value。
// 文本节点 注册自定义事件
node.addEventListener('dataChanged', (e) => {
node.textContent = templateText.replace(reg,