文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php教程>浅析vue中complie数据双向绑定原理(代码详解)

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

时间:2021-09-02  来源:互联网

今天PHP爱好者给大家带来vue中complie数据双向绑定原理介绍,之前的文章《一文了解vue中watcher数据双向绑定原理(附代码)》中,给大家介绍了解了vue中complie数据双向绑定原理。下面本篇文章给大家了解vue中complie数据双向绑定原理,伙伴们过来看看吧。希望对大家有所帮助。

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

微信截图_20210823095546.jpg

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

OK. 基本完善了

以上就是浅析vue中complie数据双向绑定原理(代码详解)的详细内容,更多请关注php爱好者其它相关文章!

相关阅读更多 +
最近更新
排行榜 更多 +
元梦之星最新版手游

元梦之星最新版手游

棋牌卡牌 下载
我自为道安卓版

我自为道安卓版

角色扮演 下载
一剑斩仙

一剑斩仙

角色扮演 下载