您的位置 首页 技术

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

之前的文章《一文了解vue中watcher数据双向绑定原理(附代码)》中,给大家介绍了解了vue中complie数据双向绑定原理。下面本篇文章给大家了解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;}

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

//Compilefunction 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. 基本完善了

推荐学习:vue.js教程

以上就是浅析vue中complie数据双向绑定原理(代码详解)的详细内容,更多请关注24课堂在线网其它相关文章!

本文来自网络,不代表24小时课堂在线立场,转载请注明出处:https://www.24ketang.cn/95475.html

为您推荐

返回顶部