微信Vue框架构建Part5——渲染对象数据

299 阅读1分钟

概述

  • 本节内容是在上一篇的基础上,实现对象类型的数据渲染,渲染到真实页面中
  • 难点有:
    1. 如何知道单个vnode中有那些模板语法
    2. 如何实现知道模板语法对应的值
    3. 如何实现数据的替换,实现页面渲染
  • 流程概览图示 image.png

找到模板语法

  • 在上文中我们实现了模板和vnode之间的相互映射,且用Map对象保存,所以可通过Map的内置方法实现
  • 代码实现
    /**
     * 渲染虚拟DOM
     * @param {*} vm
     * @param {*} vnode
     */
    function renderVNode(vm, vnode) {
      if (vnode.nodeType === NODE_TYPE_TEXT) {
        const templateArr = VNodeToTemplate.get(vnode);
        if (templateArr && templateArr.length) {
          for (let i = 0; i < templateArr.length; i++) {
              // 1.遍历vnode下所有的模板语法
              // 2. 知道每个模板语法对应的值
              // 3. 操作真实DOM,替换模板语法,实现数据渲染
      
          }
        }
      } else {
        for (let i = 0; i < vnode.children.length; i++) {
          renderVNode(vm, vnode.children[i]);
        }
      }
    }

找到模板语法在data中的值

  • vue中的data属性值是一个变量,所以我们将定义一个方法来实现这个功能
  • 模板的数据可能有两个,一个是data中定义的,一个可能是类型v-for循环这样的局部变量
  • 代码实现
    /**
     * 返回模板语法对应的数据
     * @param {*} dataArr 数据源
     * @param {*} template 模板语法
     */
    export function getTemplateValue(dataArr, template) {
      let templateValue;
      if (dataArr instanceof Array) {
        for (let i = 0; i < dataArr.length; i++) {
          templateValue = getObectValue(dataArr[i], template);
          if (templateValue) break;
        }
      }
      return templateValue;
    }

    function getObectValue(obj, template) {
      let tempalteValue;

      const keyArr = template.split(".");

      for (let i = 0; i < keyArr.length; i++) {
        const key = keyArr[i].trim();
        const value = obj[key];
       if (value instanceof Object) {
          // 数据是对象的情况
          return (tempalteValue = getObectValue(value, template));
        } else {
          tempalteValue = obj[key];
        }
      }

      if (!tempalteValue) {
        throw new Error(`${template} is not undefined`);
      }
      return tempalteValue || "undefined";
    }

拿到模板语法的值后,渲染数据

  • 之前我们定义的vnode中有真实DOM,所以可以直接操作
  • 通过正则实现模板语法的替换
  • 代码实现
   function renderVNode(vm, vnode) {
      if (vnode.nodeType === NODE_TYPE_TEXT) {
        const templateArr = VNodeToTemplate.get(vnode);
        if (templateArr && templateArr.length) {
          for (let i = 0; i < templateArr.length; i++) {
              // 获取模板语法的值
            const templateValue = getTemplateValue(
              [vm._data, vnode.env],
              templateArr[i]
            );
            let nodeValue;
            console.log("templateValue", templateValue);
             
             // 如果模板语法有对应的值,就替换模板语法
            if (templateValue) {
              nodeValue = vnode.text.replace(
                new RegExp(`{{[\s|${templateArr[i]}|\s]+}}`, "g"),
                templateValue
              );
            }
            // 操作真实DOM,实现数据渲染
            vnode.elm.nodeValue = nodeValue;
          }
        }
      } else {
        for (let i = 0; i < vnode.children.length; i++) {
          renderVNode(vm, vnode.children[i]);
        }
      }
    }