响应数据绑定
4.1创建监听器,进行数据劫持和监听
3.4.1 接3.4 对当前节点进行事件的监听
4.2当数据改变时,改变vm一级下的数据,进行赋值,因为劫持的数据在vm的一级根下,这时触发监听器
4.3监听器,数据改变,触发set方法,给vm.data相对应数据赋值
/** * vue 的监听器 * @param {Object} obj vm.data * @param {Object} vm */ function observe(obj, vm) { console.log(obj,vm); Object.keys(obj).forEach(key => { //对 vm.data 进行遍历 Object.defineProperty(vm, key, { enumerable: true, // 当 enumerable 为 true 时,该属性才能出现在对象的枚举属性中 configurable: true, // 当 configurable 为 true 时,该属性描述符才能够被改变 get() { return obj[key]; }, set(newVal) { if (obj[key] === newVal) return; obj[key] = newVal; } }) }) } /** * 使用documentfragment处理节点速度和性能要高于直接操作dom。vue编译的时候,就是将挂载目标的所有子节点劫持到documentfragment中,经过处理后再将documentfragment整体返回到挂载目标中。 */ // DocumentFragment(文档片段,节点容器) 劫持vue挂载的所有节点 function nodeToFragment(node, vm) { let fragment = document.createDocumentFragment(); //创建代码片段 let child while (child = node.firstChild) { compile(child, vm) //appendChild 会删掉所有原来的节点 fragment.appendChild(child) //改变原节点 } return fragment } //解析指令和赋值 //做用对框架的指令进行双向绑定(数据响应,和视图更新渲染) function compile(node, vm) { //这里讲解一下,nodeType等于1说明节点是标签,所有解析标签所有的属性; nodeType等于3说明节点是文本,可以操作文本的文本名和值(node.nodeName,node.nodeValue) if (node.nodeType === 1) { let attr = node.attributes // 获取所有属性 // 解析属性 for (var i in attr) { if (attr.hasOwnProperty(i)) { if (attr[i].nodeName === 'v-model') { var name = attr[i].nodeValue node.addEventListener('input', function (event) { // 给相应的data属性赋值,进而触发该属性的set方法 //注意这里是给vm一级下的数据赋值,因为劫持的数据在vm的一级根下 //这里会促发监听器,从而改变 data 中的数据 vm[name] = event.target.value console.log(event.target.value, vm.data) }) node.value = vm.data[name] node.removeAttribute('v-model') } } } } let regex = /\{\{(.*?)\}\}/ if (node.nodeType === 3) { //文本节点没有 attributes if (regex.test(node.nodeValue)) { const name = RegExp.$1.trim(); //text node.nodeValue = vm.data[name]; } } }
//定义一个Vue class Vue { constructor(opt) { this.el = document.querySelector(opt.el) this.data = opt.data observe(this.data, this) // 启动监听所有的 data 数据 this.el.appendChild(nodeToFragment(this.el, this)) } }
2. 在observe方法中,遍历vue实例中data的属性,逐一调vue实例中的data的属性重新定义为访问器属性,并在set方法中将新的值更新到这个属性上,把他们定义为访问器属性
3. 在compile方法中,如果是input这样的标签,给它添加事件(也可以是keyup,change),监听input值变化,并给vue实例中相应的访问器属性赋值
4. 在Vue类方法中,调用observer方法,传入当前实例对象和对象的data属性,将data属性中的子元素重新定义为当前对象的访问器属性
set方法被触发之后,vue实例的text属性跟着变化,但是<span>的内容并没有变化,下面的内容将会介绍“订阅/发布模式”来解决这个问题。
人生很漫长,或许我只是你人生中微不足道的一小段,只是你人生中的惊鸿一瞥。
浙公网安备 33010602011771号