站长资讯网
最全最丰富的资讯网站

浅析vue中complie数据双向绑定原理(代码详解)

之前的文章《一文了解vue中watcher数据双向绑定原理(附代码)》中,给大家介绍了解了vue中complie数据双向绑定原理。下面本篇文章给大家了解vue中complie数据双向绑定原理,伙伴们过来看看吧。

浅析vue中complie数据双向绑定原理(代码详解)

vue数据双向绑定原理,和简单的实现,本文将实现mvvm的模板指令解析器

浅析vue中complie数据双向绑定原理(代码详解)

1)vue数据双向绑定原理-observer

2)vue数据双向绑定原理-wather

3)vue数据双向绑定原理-解析器 Complie

vue数据双向绑定原理,和简单的实现,本文将实现mvvm的模板指令解析器

上一步实现了简单数据绑定,最后实现解析器,来解析v-model,v-on:click等指令,和{{}}模板数据。解析器Compile实现步骤:

  • 解析模板指令,并替换模板数据,初始化视图

  • 将模板指令对应的节点绑定对应的更新函数,初始化相应的订阅器

为了解析模板,首先需要获取到dom元素,然后对含有dom元素上含有指令的节点进行处理,因此这个环节需要对dom操作比较频繁,所有可以先建一个fragment片段,将需要解析的dom节点存入fragment片段里再进行处理:

function node2Fragment(el) {   var fragment = document.createDocumentFragment(),     child;   // 将原生节点拷贝到fragment   while ((child = el.firstChild)) {     fragment.appendChild(child);   }    return fragment; }

接下来渲染'{{}}'模板

//Compile function Compile(el, vm) {   this.$vm = vm;   this.$el = this.isElementNode(el) ? el : document.querySelector(el);   if (this.$el) {     this.$fragment = this.node2Fragment(this.$el);     this.init();     this.$el.appendChild(this.$fragment);   } }  Compile.prototype = {   init: function () {     this.compileElement(this.$fragment);   },    node2Fragment: function (el) {     //...   },    //编译模板   compileElement: function (el) {     var childNodes = el.childNodes,       self = this;     [].slice.call(childNodes).forEach(function (node) {       var text = node.textContent;       var reg = /{{(.*)}}/; //表达式文本       //按元素节点方式编译       if (self.isElementNode(node)) {         self.compile(node);       } else if (self.isTextNode(node) && reg.test(text)) {         self.compileText(node, RegExp.$1);       }       //遍历编译子节点       if (node.childNodes && node.childNodes.length) {         self.compileElement(node);       }     });   },    isElementNode: function (node) {     return node.nodeType == 1;   },    isTextNode: function (node) {     return node.nodeType == 3;   },    compileText: function (node, exp) {     var self = this;     var initText = this.$vm[exp];     this.updateText(node, initText);     new Watcher(this.$vm, exp, function (value) {       self.updateText(node, value);     });   },    updateText: function (node, value) {     node.textContent = typeof value == "undefined" ? "" : value;   }, };

处理解析指令对相关指令进行函数绑定。

Compile.prototype = {    ......   isDirective: function(attr) {     return attr.indexOf('v-') == 0;   },    isEventDirective: function(dir) {     return dir.indexOf('on:') === 0;   },    //处理v-指令   compile: function(node) {      var nodeAttrs = node.attributes,       self = this;     [].slice.call(nodeAttrs).forEach(function(attr) {       // 规定:指令以 v-xxx 命名       // 如 <span v-text="content"></span> 中指令为 v-text       var attrName = attr.name; // v-text       if (self.isDirective(attrName)) {         var exp = attr.value; // content         var dir = attrName.substring(2); // text         if (self.isEventDirective(dir)) {           // 事件指令, 如 v-on:click           self.compileEvent(node, self.$vm, exp, dir);         } else {           // 普通指令如:v-model, v-html, 当前只处理v-model           self.compileModel(node, self.$vm, exp, dir);         }         //处理完毕要干掉 v-on:, v-model 等元素属性         node.removeAttribute(attrName)       }     });    },    compileEvent: function(node, vm, exp, dir) {      var eventType = dir.split(':')[1];     var cb = vm.$options.methods && vm.$options.methods[exp];     if (eventType && cb) {       node.addEventListener(eventType, cb.bind(vm), false);     }    },    compileModel: function(node, vm, exp, dir) {      var self = this;     var val = this.$vm[exp];     this.updaterModel(node, val);     new Watcher(this.$vm, exp, function(value) {       self.updaterModel(node, value);     });     node.addEventListener('input', function(e) {       var newValue = e.target.value;       if (val === newValue) {         return;       }       self.$vm[exp] = newValue;       val = newValue;     });    },    updaterModel: function(node, value, oldValue) {     node.value = typeof value == 'undefined' ? '' : value;   },  }

最后再关联起来

function Vue(options) {   .....   observe(this.data, this);   this.$compile = new Compile(options.el || document.body, this)   return this;  }

来尝试下效果

<!--html--> <div id="app">   <h2>{{name}}</h2>   <input v-model="name" />   <h1>{{name}}</h1>   <button v-on:click="test">click here!</button> </div> <script>   new Vue({     el: "#app",     data: {       name: "chuchur",       age: 29,     },     methods: {       test() {         this.name = "My name is chuchur";       },     },   }); </script>

OK. 基本完善了

推荐学习:JavaScript视频教程

赞(0)
分享到: 更多 (0)
网站地图   沪ICP备18035694号-2    沪公网安备31011702889846号