zoukankan      html  css  js  c++  java
  • MVVM(二)模板编译(指令编译,大括号表达式编译)

    1:模板编译(html中能够识别指令和大括号表达式)实现指定的功能

    目的:编译大括号表达式和v-on等等的一些指令

    <div id="test">

      <p >{{name}}</p>

    </div>

    实现思路:找的指定的#test需要编译的模板,将#test取出#test中所有子节点, 封装在一个framgment对象中。例如:<div id="test">  <p >{{name}}</p></div> text节点,p元素节点,text节点,然后编译framgment的所有子节点(递归更找出子节点的子节点 p元素中有一个text节点里面有大括号表达式。

    //framgment
    compileElement: function (el) {
        // 得到所有子节点
        var childNodes = el.childNodes,
          // 保存compile对象
          me = this;
        // 遍历所有子节点
        [].slice.call(childNodes).forEach(function (node) {
          // 得到节点的文本内容
          var text = node.textContent;
          // 正则对象(匹配大括号表达式)
          var reg = /{{(.*)}}/;  // {{name}}
          // 如果是元素节点
          if (me.isElementNode(node)) {
            // 编译元素节点的指令属性
            me.compile(node);
            // 如果是一个大括号表达式格式的文本节点
          } else if (me.isTextNode(node) && reg.test(text)) {
            // 编译大括号表达式格式的文本节点
            me.compileText(node, RegExp.$1); // RegExp.$1: 表达式   name
          }
          // 如果子节点还有子节点
          if (node.childNodes && node.childNodes.length) {
            // 递归调用实现所有层次节点的编译
            me.compileElement(node);
          }
        });
      },

    me.compileText(node, RegExp.$1); // RegExp.$1: 表达式   name

    {{name}}实例就是找到了这个text节点,然后通过对象代理 vm.name//获取属性{{name}}就被解析出来了。

     me.compile(node);编译元素节点判断里面是否具有v-开头的属性本质上是通过正则表达式匹配v-,根据attributeNode来寻找属性在匹配

    2:指令解析<button v-on:click="test">测试</button>

    来举例:同样首先通过上面类似的步骤找到<button v-on:click="test">测试</button>这个元素节点

    if (me.isElementNode(node)) {

            // 编译元素节点的指令属性

            me.compile(node); //buuton元素进入此判断

            // 如果是一个大括号表达式格式的文本节点

          }

    //button节点进入编译 node=button

     compile: function (node) {
        // 得到所有标签属性节点
        var nodeAttrs = node.attributes,  //v-on:click="test"被获取
          me = this;
        // 遍历所有属性
        [].slice.call(nodeAttrs).forEach(function (attr) {
          // 得到属性名: v-on:click
          var attrName = attr.name; // 
          // 判断是否是指令属性
          if (me.isDirective(attrName)) {
    //isDirective: function (attr) {
        return attr.indexOf('v-') == 0; 这个函数是通过v-判断是否是指令属性
      }//
            // 得到表达式(属性值): test
            var exp = attr.value;
            // 得到指令名: on:click
            var dir = attrName.substring(2);
            // 事件指令
            if (me.isEventDirective(dir)) {
              // 解析事件指令
              compileUtil.eventHandler(node, me.$vm, exp, dir);
            // 普通指令
            } else {
              // 解析普通指令
              compileUtil[dir] && compileUtil[dir](node, me.$vm, exp);
            }
    
            // 移除指令属性
            node.removeAttribute(attrName);
          }
        });
      },
    //添加事件监听(监听元素节点 button,vm对象,事件回调函数名 "test","on:click")
      compileUtil.eventHandler(node, me.$vm, exp, dir);
    // 事件处理
      eventHandler: function (node, vm, exp, dir) {
        // 得到事件名/类型: click
        var eventType = dir.split(':')[1],
          // 根据表达式得到事件处理函数(从methods中): test(){}
          fn = vm.$options.methods && vm.$options.methods[exp];
        // 如果都存在
        if (eventType && fn) {
          // 绑定指定事件名和回调函数的DOM事件监听, 将回调函数中的this强制绑定为vm
          node.addEventListener(eventType, fn.bind(vm), false);
        }
      },
    // 解析: v-model
      model: function (node, vm, exp) {
        this.bind(node, vm, exp, 'model');
         
        var me = this,
          val = this._getVMVal(vm, exp);
        node.addEventListener('input', function (e) {
          var newValue = e.target.value;
          if (val === newValue) {
            return;
          }
    
          me._setVMVal(vm, exp, newValue);
          val = newValue;
        });
      },
    // 真正用于解析指令的方法
      bind: function (node, vm, exp, dir) {
        /*实现初始化显示*/
        // 根据指令名(text)得到对应的更新节点函数
        var updaterFn = updater[dir + 'Updater'];
        // 如果存在调用来更新节点
        updaterFn && updaterFn(node, this._getVMVal(vm, exp));
    
        // 创建表达式对应的watcher对象
        new Watcher(vm, exp, function (value, oldValue) {/*更新界面*/
          // 当对应的属性值发生了变化时, 自动调用, 更新对应的节点
          updaterFn && updaterFn(node, value, oldValue);
        });
      },
  • 相关阅读:
    爬虫笔记:使用python生成词云(八)
    31丨2内核剖析
    六飞翔篇(4讲)30 丨 2特性概览
    29 丨 我应该迁移到HTTPS吗?
    28 丨 连接太慢该怎么办:HTTPS的优化
    27丨更好更快的握手:TLS1.3特性解析
    26丨信任始于握手:TLS1.2连接过程解析
    Python全栈工程师 (exercises)
    Python全栈工程师(每周总结:2)
    Python全栈工程师(函数嵌套、变量作用域)
  • 原文地址:https://www.cnblogs.com/love-life-insist/p/10130975.html
Copyright © 2011-2022 走看看