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

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

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

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

微信截图_20210823095546.jpg

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

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

立即学习“前端免费学习笔记(深入)”;

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

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 命名      // 如  中指令为 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;}

登录后复制

来尝试下效果

  

{{name}}

    

{{name}}

  
new Vue({ el: "#app", data: { name: "chuchur", age: 29, }, methods: { test() { this.name = "My name is chuchur"; }, }, });

登录后复制

OK. 基本完善了

推荐学习:vue数据双向绑定原理-observer

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/3020026.html

(0)
上一篇 2025年3月13日 05:33:22
下一篇 2025年3月13日 05:33:41

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Uniapp自定义vue导航菜单组件完成菜单动态高亮

            前几日使用uniapp框架写项目, 需要自定义vue导航菜单组件,并且完成菜单动态高亮,简而言之,tab组件内完成点哪哪个发生高亮。【相关推荐:《vue.js教程》】         这里需要使用uniapp scroll-…

    2025年3月13日
    200
  • 深入了解vue中mixins的用法和注意事项

    本篇文章带大家了解一下vue中mixins(混入)特性,介绍一下mixins的使用方法和注意点,希望对大家有所帮助! mixins基础概况 vue中的解释是这样的,如果觉得语言枯燥的可以自行跳过嘿~ 混入 (mixins): 是一种分发 V…

    2025年3月13日 编程技术
    200
  • vue的八大生命周期状态分别是什么

    vue的八大生命周期状态:1、beforeCreate;2、created;3、beforeMount;4、mounted;5、beforeUpdate;6、updated;7、beforeDestroy;8、destroyed。 本教程操…

    2025年3月13日
    200
  • vuejs是什么时候出来的

    vuejs是2013年受到Angular的启发,开发出来的一款轻量框架,最初命名为Seed;2013年12月更名为vue,图标颜色是代表勃勃生机的绿色,版本号是“0.6.0”。2014年1月24日,vue正式对外发布,版本号是“0.8.0”…

    2025年3月13日
    200
  • vue怎么读取文件内容

    vue读取文件内容的方法:1、创建一个test.properties测试内容;2、通过“readTestFile(){const file = this.loadFile(‘test.properties’)&#82…

    2025年3月13日
    200
  • 怎么离线安装vue环境

    离线安装vue环境的方法:1、cmd运行命令“npm config get cache”;2、内网电脑安装nodejs;3、内网全局安装目录;4、内网命令安装离线依赖包;5、把vue项目复制到内网;6、查看全局命令是否正常即可。 本文操作环…

    2025年3月13日 编程技术
    200
  • vue脚手架安装步骤

    vue脚手架安装步骤:1、安装node环境;2、通过“npm install -g vue-cli”安装vue-cli脚手架;3、根据提示选择安装插件;4、安装项目依赖;5、运行“npm run dev”即可。 本文操作环境:windows…

    2025年3月13日 编程技术
    200
  • vue传值方式有哪些

    vue传值方式有:1、prop向下传递,事件向上传递;2、子组件通过$emit触发父组件的自定义事件;3、通过定义公共实例文件来进行非父子组件之间的传值。 本文操作环境:windows7系统、vue2.5.17版,DELL G3电脑。 vu…

    2025年3月13日
    200
  • vue有哪三种传值方式

    vue三种传值方式:1、“父传子”;父组件通过prop给子组件下发数据(传值)。2、“子传父”;子组件通过“事件”给父组件发送消息。3、“非父子传值”;非父子组件之间需要定义个公共的公共实例文件“bus.js”,作为中间仓库来传值。 本教程…

    2025年3月13日
    200
  • vue的router和route区别是什么

    区别:router是通过“Vue.use(VueRouter)”和VueRouter构造函数得到一个实例对象,它是一个全局的对象。而route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象。 本教程操作环境:wi…

    2025年3月13日
    200

发表回复

登录后才能评论