RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:8:30-17:00
你可能遇到了下面的问题
关闭右侧工具栏

新闻中心

这里有您想知道的互联网营销解决方案
    function Compile(node, vm) {    if(node) {     this.$frag = this.nodeToFragment(node, vm);     return this.$frag;    }   }   Compile.prototype = {    nodeToFragment: function(node, vm) {     var self = this;     var frag = document.createDocumentFragment();     var child;     while(child = node.firstChild) {      self.compileElement(child, vm);      frag.append(child); // 将所有子节点添加到fragment中     }     return frag;    },    compileElement: function(node, vm) {     var reg = /\{\{(.*)\}\}/;     //节点类型为元素     if(node.nodeType === 1) {      var attr = node.attributes;      // 解析属性      for(var i = 0; i < attr.length; i++ ) {       if(attr[i].nodeName == 'v-model') {        var name = attr[i].nodeValue; // 获取v-model绑定的属性名        node.addEventListener('input', function(e) {         // 给相应的data属性赋值,进而触发该属性的set方法          vm[name]= e.target.value;        });        // node.value = vm[name]; // 将data的值赋给该node        new Watcher(vm, node, name, 'value');       }      };     }     //节点类型为text     if(node.nodeType === 3) {      if(reg.test(node.nodeValue)) {       var name = RegExp.$1; // 获取匹配到的字符串       name = name.trim();       // node.nodeValue = vm[name]; // 将data的值赋给该node       new Watcher(vm, node, name, 'nodeValue');      }     }    },   }   function Dep() {    this.subs = [];   }   Dep.prototype = {    addSub: function(sub) {     this.subs.push(sub);    },    notify: function() {     this.subs.forEach(function(sub) {      sub.update();     })    }   }   function Watcher(vm, node, name, type) {    Dep.target = this;    this.name = name;    this.node = node;    this.vm = vm;    this.type = type;    this.update();    Dep.target = null;   }   Watcher.prototype = {    update: function() {     this.get();     this.node[this.type] = this.value; // 订阅者执行相应操作    },    // 获取data的属性值    get: function() {     this.value = this.vm[this.name]; //触发相应属性的get    }   }   function defineReactive (obj, key, val) {    var dep = new Dep();    Object.defineProperty(obj, key, {     get: function() {       //添加订阅者watcher到主题对象Dep      if(Dep.target) {       // JS的浏览器单线程特性,保证这个全局变量在同一时间内,只会有同一个监听器使用       dep.addSub(Dep.target);      }      return val;     },     set: function (newVal) {      if(newVal === val) return;      val = newVal;      console.log(val);      // 作为发布者发出通知      dep.notify();     }    })   }   function observe(obj, vm) {    Object.keys(obj).forEach(function(key) {     defineReactive(vm, key, obj[key]);    })   }    function Vue(options) {    this.data = options.data;    var data = this.data;    observe(data, this);    var id = options.el;    var dom =new Compile(document.getElementById(id),this);    // 编译完成后,将dom返回到app中    document.getElementById(id).appendChild(dom);   }   var vm = new Vue({    el: 'app',    data: {     text: 'hello world'    }   });    

七、总结

关于双向绑定的实现,看了网上很多资料,开始看到是对Vue源码的解析,看的过程似懂非懂。后来找到参考资料1,然后自己跟着实现一遍,才理解许多。感谢这篇文章的作者,写的由浅入深,比较好理解。为了加深自己的理解,于是自己顺着这个思路写下这个笔记。本文主要了解了几种双向绑定的做法,然后先用原生JS,dom操作实现一个最简单双向绑定,在这个基础上进行改装,为减少dom操作,实现简单的Compile(编译HTML);接着为了实现数据监听,实现observe;最后为了实现数据的双向绑定实现订阅发布模式。

虽然实现的比较简单,有很多功能没有考虑,不过这个过程还是可以理解到Vue实现双向绑定的原理。过程中,有思考:

1. Vue的源代码中,用了文档碎片fragment作为真实节点的存储吗?

之前有听说用VDOM,在Vue源代码中,也找过是否有创建文档碎片,结果没找到。看了参考资料4中,VDOM的介绍,好像是把节点用JS对象模拟。类似:

模板


 Item 1
 Item 2
 Item 3

js对象

var element = {
 tagName: 'ul', // 节点标签名
 props: { // DOM的属性,用一个对象存储键值对
  id: 'list'
 },
 children: [ // 该节点的子节点
  {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
  {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
  {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
 ]
}

以上就是“Vue2.0如何实现双向绑定”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注创新互联行业资讯频道。


新闻名称:Vue2.0如何实现双向绑定
当前URL:http://scpingwu.com/article/pcisic.html
Top