模板引擎的使用

模板引擎

模板的诞生是为了将显示与数据分离,模板技术多种多样,但其本质是将模板文件和数据通过模板引擎生成最终的HTML代码。如图如下:

在这里插入图片描述

模板引擎就是利用正则表达式识别模板标识,并利用数据替换其中的标识符。比如:
Hello, <%= name%>

数据是{name: ‘木的树’},那么通过模板引擎解析后,我们希望得到Hello, 木的树。模板的前半部分是普通字符串,后半部分是模板标识,我们需要将其中的标识符替换为表达式。模板的渲染过程如下:

在这里插入图片描述
代码如下:

function tmpl(str, obj) {
    if (typeof str === 'string') {
        return str.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
            var key = arguments[1];
            return obj[key];
        });
    }
}

var str = "Hello, <%= name%>";
var obj = {name: "Lzz"};

引擎核心
上面我们演示是简单的字符串替换,但对于模板引擎来说,要做的事情更复杂些。通常需要以下几个步骤:

利用正则表达式分解出普通字符串和模板标识符,<%=%>的正则表达式为/<%=\s*([^%>]+)\s*%>/g.
将模板标识符转换成普通的语言表达式
生成待执行语句
将数据填入执行,生成最终的字符串

Demo代码如下:

function tmpl(str, obj) {
    if (typeof str === 'string') {
        var tm = str.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
            var key = arguments[1];
            return "' + obj." + key; // 在函数字符串中利用'包裹正常字符串
        });

        tm = "return '" + tm; //"'Hello' + obj.name"
        var compile = new Function('obj', tm);
        return compile(obj);
    }
}

var str = "Hello, <%= name%>";
var obj = {name: "Lzz"}; // Hello, Lzz

模板逻辑
功能稍微强大的模板引擎,都允许在模板中添加一部分逻辑来控制页面的最终渲染。如:
var str = “<%for(var i = 0; i < 3; i++){%>name is <%= name%> <%}%>”;

这里我们用<%%>代表逻辑代码<%=%>代表模板中需要替换的标识符。我们的模板代码变成了如下所示:

//模板逻辑
var tmpl = (function(){
    var cache = {};
    var strip = function(html) {
        return String(html)
        .replace(/&/g, '&amp;')//&
        .replace(/</g, '&lt;')//左尖号
        .replace(/>/g, '&gt;')//右尖号
        .replace(/"/g, '&quot;')//双引号"
        .replace(/'/g, '&#039;');//IE下不支持&apos;'
    }
    return function(str, obj){debugger;
        if (!typeof str === 'string') {
            return;
        }
        var compile = cache[str];
        if (!cache[str]) {
            //var tm = str.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
            //    var key = arguments[1];
            //    return "' + strip(" + key + ")";
            //});
            var tm = str.replace(/<%\s*([^=][^%>]*)\s*%>/g, function() {
                var key = arguments[1];
                return "';" + key + " tmp+='"; // 逻辑代码需要一块块的拼接起来,为的是拼接成一段合理的函数字符串传递给new Function
            }).replace(/<%=\s*([^%>]+)\s*%>/g, function() {
                var code = arguments[1];
                return "' + strip(" + code + ") +'"; //利用escape包裹code ,加入模板逻辑时要注意,保证拼接成正确的函数字符串
            }).replace(/<%=\s*([^%>]+)\s*%>/g, function() {
                var key = arguments[1];
                return "' + " + key + "+ '";//加入模板逻辑时要注意,保证拼接成正确的函数字符串
            });debugger;
            tm = "var tmp = \"\"; with(obj){ tmp = '" + tm + "'; } return tmp;"; //"'Hello' + obj.name"
            compile = new Function('obj', 'strip', tm);
            cache[str] = compile;
        }
        return compile(obj, strip); //预编译情况下应该返回compile函数
    }
}());

var str = "<%for(var i = 0; i < 3; i++){%>name is <%= name%> <%}%>";
var obj = {name: "<script>alert(\"XSS\")</script>"};
tmpl(str, obj);

第一步,我们将模板中的逻辑表达式找出来,用的正则表达式是
/<%\s*([=][%>])\s%>/g

str.replace(/<%\s*([^=][^%>]*)\s*%>/g, function() {
                var key = arguments[1];
                return "';" + key + " tmp+='"; // 逻辑代码需要一块块的拼接起来,为的是拼接成一段合理的函数字符串传递给new Function
            })

注意在拼接时,为了防止函数字符串中的字符串没有闭合对表达式造成影响,我们在key前后都加了’来保证其中的字符串闭合。
第二步, 对可能存在的HTML标签进行转义

.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
                var code = arguments[1];
                return "' + strip(" + code + ") +'"; //利用escape包裹code ,加入模板逻辑时要注意,保证拼接成正确的函数字符串
            })

同样需要注意前后的字符串闭合
第三步,像先前一样处理模板标识符,仍然要注意其中的字符串闭合问题。

.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
                var key = arguments[1];
                return "' + " + key + "+ '";//加入模板逻辑时要注意,保证拼接成正确的函数字符串
            })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值