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);
        });
      },
  • 相关阅读:
    [kuangbin带你飞]专题十六 KMP & 扩展KMP & ManacherK
    [kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher J
    [kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher I
    pat 1065 A+B and C (64bit)(20 分)(大数, Java)
    pat 1069 The Black Hole of Numbers(20 分)
    pat 1077 Kuchiguse(20 分) (字典树)
    pat 1084 Broken Keyboard(20 分)
    pat 1092 To Buy or Not to Buy(20 分)
    pat 1046 Shortest Distance(20 分) (线段树)
    pat 1042 Shuffling Machine(20 分)
  • 原文地址:https://www.cnblogs.com/love-life-insist/p/10130975.html
Copyright © 2011-2022 走看看