1-1 【数据驱动】:解决 1.0 版本的 多层级属性, 例如{{info.phone}}, 及代码整合

134 阅读1分钟

一、代码整合及多层级属性

如下, 上一文章代码从上而下,没有进行整合,太乱,且只考虑了单属性,如下多层级属性也是必要的

<div id="root">
    <p>{{info.phone}}</p>
</div>

二、更正如下

<body>
  <div id="root">
    <div>
      <div>
        <div>
          <p>{{message}}-{{name}}</p>
        </div>
      </div>
    </div>
    <p>{{name}}</p>
    <p>{{info.phone}}</p>
  </div>
    
  <script>
    let rKuohao = /{\{(.+?)\}\}/g;
    // 多层次数据返回属性值
    function getValueByPath(obj, path) {
      let paths = path.split('.');
      let res = obj;
      let prop;
      while (prop = paths.shift()) {
        res = res[prop];
      };
      return res;
    }
    // 4. 将数据与模板结合,生成 dom 渲染到页面中。
    function compiler(template, data) {
      // 获取到该模板的所有子元素,通过对子元素进行遍历,
      // 文本节点通过正则来匹配{{}},对{{}}进行 data 赋值
      // 元素节点通过递归来对它的子元素再次遍历
      let childNodes = template.childNodes;
      for (var i = 0; i < childNodes.length; i++) {
        let nodeType = childNodes[i].nodeType;
        if (nodeType === 3) {
          let txt = childNodes[i].nodeValue;
          /*
          * replace 使用正则匹配一次, 函数就会被调用一次
          * 函数的 第 0 个参数,表示 匹配到的内容
          * 函数的 第 n 个参数,表示 正则中的第 n 组
          */
          txt = txt.replace(rKuohao, (_, path) => {
            // path 表示 data 里 key的路径,例如:info.phone
            let value = getValueByPath(data, path);
            return value;
          })
          childNodes[i].nodeValue = txt;

        } else if (nodeType == 1) {
          compiler(childNodes[i], data)
        }
      }
    }

    function JGVue(options) {
      // 内部数据用 _ 下划线开头,内部属性用 $ 开头。
      this._data = options.data;
      this.el = options.el;
      // 拿到当前元素。
      this.$el = this._tmpNode = document.querySelector(this.el);
      // 获取当前元素的父节点
      this.$parentNode = this._tmpNode.parentNode;
      this.render();
    }
    // 将模板与数据进行结合,得到 html 加到页面中去
    JGVue.prototype.render = function () {
      this.compiler();
    }
    // 编译,将模板与数据结合,得到真正的 DOM 元素
    JGVue.prototype.compiler = function () {
      let realDom = this._tmpNode.cloneNode(true);
      compiler(realDom, this._data);
      this.update(realDom);
    }
    // 将 DOM 元素放到页面中
    JGVue.prototype.update = function (realDom) {
      this.$parentNode.replaceChild(realDom, this.$el)
    }
    let app = new JGVue({
      el: '#root',
      data: {
        name: '姓名',
        message: '消息',
        info: {
          phone: '12345678901'
        }
      }
    })
  </script>
</body>

三、以上问题

  • 没有转化成虚拟 DOM