手撕Vue-编译模板数据

经上一篇编译指令数据后,我们已经可以将指令数据编译成具体需要展示的数据了,上一篇只是编译了指令数据,还没有编译模板数据,这一篇我们就来编译模板数据。

也就是 {{}} 这种模板的形式我们该如何编译,其实和指令数据编译的思路是一样的,废话不多说,直接上代码。

改造一下 buildText 方法,让它支持编译模板数据,调用 CompilerUtil content 方法,传入模板数据,返回编译后的数据,然后再将编译后的数据替换到文本节点中。

CompilerUtil['content'](node, content, this.vm);

在 CompilerUtil 中添加 content 方法,该方法和指令数据编译的思路是一样的,只是编译的数据不一样,指令数据是 v-text 这种,而模板数据是 {{}} 这种。

/**
 * 处理模板字符串
 * @param node 当前元素
 * @param value 指令的值
 * @param vm Nue 的实例对象
 */
content: function (node, value, vm) {
    // console.log(value); // {{ name }} -> name -> $data[name]
    node.textContent = this.getContent(vm, value);
}

getContent 方法我单独拿出来,我先贴代码,然后再解释。

/**
 * 获取指定模板字符串的内容
 * @param vm Nue 的实例对象
 * @param value 指令的值
 */
getContent(vm, value) {
    const reg = /\{\{(.+?)\}\}/gi;
    return value.replace(reg, (...args) => {
        // 第一次执行 args[1] = name
        // 第二次执行 args[1] = age
        return this.getValue(vm, args[1]);
    });
},

getContent 方法中,我们先定义了一个正则表达式,用来匹配模板字符串,/\{\{(.+?)\}\}/gi 这个正则表达式的意思是匹配 {{}} 里面的内容,g 表示全局匹配,i 表示忽略大小写,(.+?) 表示匹配任意字符,+ 表示匹配一次或多次,? 表示非贪婪模式,也就是匹配到第一个 }} 就结束匹配。() 表示分组,args[1] 就是分组匹配到的内容。

在方法当中,我们调用了 getValue 方法,该方法的作用是获取模板字符串的值,在运行测试代码的时候,我发现, {{ name }} 这种模板编译出来是 undefined 所以我们需要在 getValue [obj][key] 的时候,去一下空格:

return data[currentKey.trim()];

这样就可以了,我们再来看一下测试代码:

<p>{{ name }}</p>
<p>{{age}}</p>
<p>{{time.h}}</p>
<p>{{name}}-{{age}}</p>

发现 {{name}}-{{age}} 这种也可以编译了,那么可以我们来看看我们 getContent 源码的执行效果,如果是 {{name}}-{{age}}, value 等于 {{name}}-{{age}} 进入 replace 循环,第一次执行 args[1] 等于 name,第二次执行 args[1] 等于 age,第一次循环已经将我们的 {{name}}-{{age}} 替换为了 BNTang-{{age}},第二次循环将 {{age}} 替换为了 age,所以最终的结果就是 BNTang-33

posted @ 2023-10-15 18:14  BNTang  阅读(42)  评论(0编辑  收藏  举报