目标将如下js语句:
'<ul class="{{ =$data.myclass }}">'+
'{{for(let i = 0;i < 3;i++){}}'+
'<li>{{ =i }}</li>'+
'{{}}}'+
'</ul>';
转换为字符串:
<ul class="active">
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
书写语法为:
{{ =变量值 }} 说明:值是获取值必须在左右两个双大括号中添加=
{{ 写js表达式 }} 说明:表达式两边必须添加双大括号
实现步骤一【去掉所有的换行】:
const temp2 = temp.replace(/[\r\n]/g, '');
结果为:<ul class="{{ =$data.myclass }}">{{for(let i = 0;i < 3;i++){}}<li>{{ =i }}</li>{{}}}</ul>
实现步骤二【将双大括号左右两侧的单引号或双引号添加斜线】:
const temp3 = temp2.replace(/^(.+?)\{\{|\}\}(.+?)\{\{|\}\}(.+?)$/g, function (a) {
return a.replace(/(['"])/g, '\\\$1');
})
第一个正则表达式为匹配双大括号左右两侧的内容
第二个正则表达式为将单引号或双引号添加斜线进行转义
结果为:<ul class=\"{{ =$data.myclass }}\">{{for(let i = 0;i < 3;i++){}}<li>{{ =i }}</li>{{}}}</ul>
实现步骤三【替换{{ = }}中的内容】:
var temp4 = temp3.replace(/\{\{\s*=\s*(.+?)\}\}/g, "';$out+=$1;$out+='");
结果为:<ul class=\"';$out+=$data.myclass ;$out+='\">{{for(let i = 0;i < 3;i++){}}<li>';$out+=i ;$out+='</li>{{}}}</ul>
这句话的作用是将一个完整的语句根据括号的位置拆分成两句,举个例子:
'我是{{ =变量 }}人'拆分为:'我是';$out +=变量;$out +=‘人'
假设变量的值为:中国。并且我们在拆分后的语句前添加var $out=则组合成的完整语句为:var $out='我是';$out +=变量;$out +=‘人'
实现步骤四【替换{{ }}中的内容】:
var temp5 = temp4.replace(/\{\{(.+?)\}\}/g, "';$1$out+='");
结果为:ul class=\"';$out+=$data.myclass ;$out+='\">';for(let i = 0;i < 3;i++){$out+='<li>';$out+=i ;$out+='</li>';}$out+='</ul>
这句话的作用是双大括号中的js表达式提取出来不要让其在字符串的引号中,这样在最后直接执行。
实现步骤五【在字符串前后分别添加拼接字符串】:
var temp6 = "var $out='" + temp5 + "';return new String($out);";
结果为:var $out='<ul class=\"';$out+=$data.myclass ;$out+='\">';for(let i = 0;i < 3;i++){$out+='<li>';$out+=i ;$out+='</li>';}$out+='</ul>';return new String($out);
作用是构建一个可执行的js语句
实现步骤五【构建可执行函数传递参数返回结果】:
参数param为:const param = {myclass:'active'}
//这一步的作用是将字符串转换为函数,其中第一个参数为函数的参数名
var Render = new Function('$data', temp6);
//执行函数返回结果
var result = new Render(param).toString();
抽取公共方法:
//第一个参数为模版语句,第二个参数为模版语句中的变量
function template(source, data) {
var code = "var $out='" + source.replace(/[\r\n]/g, '').replace(/^(.+?)\{\{|\}\}(.+?)\{\{|\}\}(.+?)$/g, function (a) {
return a.replace(/(['"])/g, '\\\$1');
}).replace(/\{\{\s*=\s*(.+?)\}\}/g, "';$out+=$1;$out+='").replace(/\{\{(.+?)\}\}/g, "';$1$out+='") + "';return new String($out);";
var Render = new Function('$data', code);
return new Render(data).toString();
}
总结:利用正则表达式将特定的语句进行替换,从而实现模版引擎。
参考:https://gitee.com/qinshenxue/datepicker项目中的源码部分。