一个简单的模板引(han)擎(shu)
自制一个简单的模板引(han)擎(shu)
原理
说大了 实际上是模板函数 原理呢就是简单的字符串替换
第一版
var data = {
username: 'Muhha'
}
str = '<%=username%>';
var compile = function(str){
var tpl = str.replace(/<%=([\s\S]+?)%>/,function(match, p1){
return 'obj.' + p1;
}); // 得到 obj.username
tpl = 'return ' + tpl; // return obj.username
return new Function('obj',tpl); //function(obj){return obj.username}
}
var compiled = compile(str);
var rs = compiled(data); // Muhha
缺点很明显 只能对<%=obj.xxx%>这样的部分作替换, 若模板变成<p><%=username%></p> 这样就不能通过
第二版
上面有缺陷的原因就在于替换的之后只考虑了呗替换的部分, 那些没有被替换的部分 比如 <p> 没有考虑
var data = {
username: 'Muhha'
}
str = '<p><%=username%></p>';
var compile = function(str){
var tpl = str.replace(/<%=([\s\S]+?)%>/gi,function(match, p1){
return '\'+' + 'obj.' + p1 + '+\'';
}); // 得到 <p>' + obj.username + '</p>
tpl = 'return ' + '\'' +tpl + '\''; //return '<p>' + obj.username + '</p>'
return new Function('obj',tpl); //function(obj){return '<p>' + obj.username + '</p>'}
}
var compiled = compile(str);
var rs = compiled(data); // <p>Muhha</p>
多加一个属性
var data = {
username: 'Muhha',
age: 12
}
str = '<p><%=username%></p><p><%=age%></p>';
var compile = function(str){
var tpl = str.replace(/<%=([\s\S]+?)%>/gi,function(match, p1){
return '\'+' + 'obj.' + p1 + '+\'';
}); // 得到 <p>' + obj.username + '</p><p> '+ obj.age + '</p>
tpl = 'return ' + '\'' +tpl + '\''; //return '<p>' + obj.username + '</p><p>'+ obj.age + '</p>'
return new Function('obj',tpl); //return '<p>' + obj.username + '</p><p>'+ obj.age + '</p>'}
}
var compiled = compile(str);
var rs = compiled(data); // <p>Muhha</p><p>12</p>
不过这仍然是有缺陷的, 比如不能使用语句
当模板写成str = 'if(gender>1){<p><%=username%></p>}<p><%=age%></p>'; 这样时
得到的结果是if(gender>1){<p>Muhha</p>}<p>12</p>
显然这对逻辑没有解析, 原因就在于return太早了
把整个模板当成了一个结果return了
我们期待的模板函数是这样的
var tpl = '';
if(gender ==1){
tpl +='<p>'+ obj.gender +'</p>';
}
tpl += '<p>' + obj.age +'</p>';
return tpl;
第三版
var data = {
username: 'Muhha',
age: 12,
gender: 1
}
str = [
'<p><%=obj.username%></p>',
'<%if(obj.gender==1){%>',
'<p><%=obj.gender%></p>',
'<%}%>',
'<p><%=obj.age%></p>'].join('\n');
var compile = function(str){
tpl = str.replace(/\n/g, '')
//替换变量
.replace(/<%=([\s\S]+?)%>/gi,function(match, p1){
return [
'\'+',
p1,
'+\''
].join(''); // <%=obj.username%> 变成 ' + obj.username + '
})
//替换执行语句
.replace(/<%([\s\S]+?)%>/g, function(match, p1){
return [
'\';',
'\n',
p1,
'\n',
'tpl+=\''
].join(''); // if(a){ 变成 ';\n if(a){ tpl+= '
})
tpl = '\'' +tpl + '\'';
//此时tpl
// '<p>'+obj.username+'</p>';
// if(obj.gender==1){
// tpl+='<p>'+obj.gender+'</p>';
// }
// tpl+='<p>'+obj.age+'</p>'
tpl = 'var tpl="";\ntpl+=' + tpl;
tpl = tpl + ';\nreturn tpl;';
return new Function('obj',tpl);
}
var compiled = compile(str);
var rs = compiled(data); // <p>Muhha</p><p>1</p><p>12</p>
这样还是有缺陷的, 比如某个字段的值为<script>...</script> 这样的话就会向页面中插入了可执行的标签
第四版
<script type="text/template" id="temp">
<p><%=obj.username%></p>
<%if(obj.gender==1){%>
<p><%=obj.gender%></p>
<%}%>
<p><%=obj.age%></p>
</script>
这一版还将模板放在了script标签中
var data = {
username: '\<script\>Muhha\<\/script\>',
age: 12,
gender: 1
}
var escape = function(str){
str = '' + str;
str= str.replace(/&(?!\w+)/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); // ''' 就是单引号 ' 这样写是因为IE不支持 '
return str;
}
var compile = function(str){
tpl = str
.replace(/\n/g, '')
.replace(/\s/g, '')
//替换变量
.replace(/<%=([\s\S]+?)%>/gi,function(match, p1){
return [
'\'+',
'escape(' + p1 + ')',
'+\''
].join(''); // <%=obj.username%> 变成 ' + obj.username + '
})
//替换执行语句
.replace(/<%([\s\S]+?)%>/g, function(match, p1){
return [
'\';',
'\n',
p1,
'\n',
'tpl+=\''
].join(''); // if(a){ 变成 ';\n if(a){ tpl+= '
})
tpl = '\'' +tpl + '\'';
//此时tpl
// '<p>'+obj.username+'</p>';
// if(obj.gender==1){
// tpl+='<p>'+obj.gender+'</p>';
// }
// tpl+='<p>'+obj.age+'</p>'
tpl = 'var tpl="";\ntpl+=' + tpl;
tpl = tpl + ';\nreturn tpl;';
return new Function('obj, escape',tpl);
//得到
//(function(obj, escape
// /**/) {
// var tpl="";
// tpl+='<p>'+escape(obj.username)+'</p>';
// if(obj.gender==1){
// tpl+='<p>'+escape(obj.gender)+'</p>';
// }
// tpl+='<p>'+escape(obj.age)+'</p>';
// return tpl;
// })
}
var compiled = compile(document.querySelector('#temp').text); //script标签有text属性 但是其他标签只能用textContent innerText
var rs = compiled(data, escape); // <p><script>Muhha</script></p><p>1</p><p>12</p>
一个简单的模板引(han)擎(shu)的更多相关文章
- [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, cl ...
- 1、编写一个简单Makefile模板
一.Makefile简介 一个工程中的源文件不计其数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译, ...
- Java实现的一个简单的模板渲染
代码 package com.hdwang; import java.util.HashMap; import java.util.Map; /** * Created by hdwang on 20 ...
- 一个简单的模板了解css+div网页布局
直接附上最终效果图: index.html内容: <html> <!--20170730 soulsjie--> <head> <meta http-equi ...
- OpenCms JSP 模板开发——创建一个简单的JSP模板
OpenCms中的JSP模板就是一个普通的JSP页面,在特定的位置使用标签来包含内容,在这个的例子中,我们将要开发一个简单JSP模板,这个模板只是在内容(如<html>.<body& ...
- 如何设计Java框架----一个简单的例子【翻译】
原文:http://www.programcreek.com/2011/09/how-to-design-a-java-framework/ 原文和翻译都只是参考,如有不对,欢迎指正. 你可能会好奇框 ...
- 用EF DataBase First做一个简单的MVC3报名页面
使用EF DataBase First做一个简单的MVC3报名网站 ORM(Object Relational Mapping)是面向对象语言中的一种数据访问技术,在ASP.NET中,可以通过ADO. ...
- 创建一个简单的terraform module
terraform module可以实现代码的复用,同时方便分享,下面创建一个简单的基于localfile && template provider 的module module ...
- 手把手教你从零写一个简单的 VUE--模板篇
教程目录1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 Hello,我又回来了,上一次的文章教会了大家如何书写一个简单 VUE,里面实现了VUE 的数据驱动视图 ...
随机推荐
- Mac浏览器全屏设置
在 mac 升级之后,以往点击放大的按钮,现在显示的效果是全屏:
- C#:读取配置文件
以下代码演示如何读取配置文件---------------------Factory.cs----------------------------using System;using System.C ...
- js——cookie
cookie:存储数据,当用户访问了某个网站(网页)的时候,我们就可以通过cookie来向访问者电脑上存储数据 1.不同的浏览器存放的cookie位置不一样,也是不能通用的 2. cookie的存储是 ...
- & 和 && 区别
java中&和&&的区别,&和&&虽然都是逻辑运算符,都是判断两边为真,则语句成立,但是在运行的时候,还是有差别的,下面举例来说明. java中& ...
- git本地仓库与github远程仓库链接协议问题
前提条件:有github账号,本地安装了git,能上网. 环境:ubuntu14.0.4LTS 首先在你得在github上创建一个仓库new repository,然后再本地创建一个文件夹mkdir ...
- 为何遍历Ldr会得到空项?
转自:http://www.0xaa55.com/thread-1385-1-1.html 之前做过ldr遍历的操作,发现第一项竟然是空,也就是大部分元素都是0,下面来揭示一下原理: 经过研究,其实L ...
- Python核心编程读笔 10:函数和函数式编程
第11章 函数和函数式编程 一 调用函数 1 关键字参数 def foo(x): foo_suite # presumably does some processing with 'x' 标准调用 ...
- poj 2771 最大独立集
这道题又无耻的抄袭了别人的代码. 刚开始以为是最大匹配,把条件不相符的人连一起,然后求最大匹配,感觉麻烦,然后看了别人的解题报告,是把相符的人连一起,然后减去,其实就是最大独立集. 最大独立集=|G| ...
- Java 工厂模式学习
工厂模式分三种:简单工厂.工厂方法.抽象工厂.其中抽象工厂是用于多个产品族的情况.所谓产品族就是不同产品组成的有机整体,各不同产品之间相互依赖.打个比方,一台电脑有CPU.主板.内存和硬盘等,这些不同 ...
- 浅谈C中的指针和数组(五)
前面写了一些C指针和数组的一些知识,但是还有一些很重要的知识没有交代,这里做一个补充. 首先看一下,普通变量(指针也是变量)和数组名查看地址的方式是不同的. 查看数组变量的地址,不需要使用 & ...