坚持造轮子第一天 - 模板引擎

简介: 坚持造轮子第一天 - 模板引擎

看点


  • 针对大厂笔试、面试必考手写题目


  • TDD方式开发


  • 配合视频讲解


造轮子计划


(计划赶不上变化 随时迭代 欢迎留言 随时摸鱼)


  • 框架基础







  • 洋葱圈Compose


  • Flux模式


  • Promise


  • Thunk


  • HTML编译器


  • Pipe管道


  • 原生Ajax


  • JS基础


  • Promise.all/race


  • 路由


  • new


  • call/apply/bind


  • Object.create


  • 深拷贝、浅拷贝


  • 算法、设计模式


  • 二分查找


  • 快排


  • 二分查找


  • 冒泡排序


  • 选择排序


  • 订阅发布


  • 斐波那契算法


  • 去重


模板引擎


为了实现视图与业务逻辑的分离,无论MVP、MVVM、MVC那个V都会使用模板引擎。线面我们说说模板引擎的要求。


需求


{{ }} 表达式


其实就是 将{{ }}中的值根据替换为表达式的结果。


模板 结果
<b>{{ name }}</b> <b>tom</b>
<b>{{ name.toUpperCase() }}</b> <b>TOM</b>
<b>{{ '[' + name + ']' }}</b> <b>[tom]</b>


用测试用例表示就是这样


it("{{}} 表达式", () => {
    const output = compile("<b>{{ name }}</b>")({ name: "tom" });
    expect(output).toBe(`<b>tom</b>`);
  });
  it("{{}} toUpperCase 表达式", () => {
    const output = compile("<b>{{ name.toUpperCase() }}</b>")({ name: "tom" });
    expect(output).toBe(`<b>TOM</b>`);
  });
  it("{{}} +连接", () => {
    const output = compile("<b>{{ '[' + name + ']' }}</b>")({ name: "tom" });
    expect(output).toBe(`<b>[tom]</b>`);
  });


forEach遍历


{%arr.forEach(item => {%}
    <li>{{item}}</li>
{%})%}


生成结果


<li>aaa</li>
    <li>bbb</li>


if判断


{% if(isShow) { %} <b>{{ name }}</b> {% } %}


生成结果


<b>tom</b>


功能实现


模板渲染的功能大概可以归纳为两步:


  1. 编译模板为Generate函数


  1. 执行渲染函数


比如最简单的模板


<b>{{ name }}</b>


生成后的渲染函数


generate(obj){
  let str = '';
  with(obj){
  str+=`<b>${name}</b>`}
  return str;
}


执行generate结果


const ret = generate({name : 'tom'})
// 运行结果: <b>tom</b>


编译过程


我们把编译过程其实就是通过正则表达式的匹配


第一步 将{{ xxx }}表达式 转化为ES6模板字符串 ${ xxx }


// 全局正则表达式替换
  template = template.replace(/\{\{([^}]+)\}\}/g, function () {
    let key = arguments[1].trim();
    return "${" + key + "}";
  });


第二步 将{% %}表达式 转化为JS语句这样的就可以在模板中使用if、foreach了

比如if判断:


{% if(isShow) { %} <b>{{ name }}</b> {% } %}
// 转化的函数
let str = '';
   with(obj){
   str+=``
   if(isShow) {
    str+=`<b>${name}</b> `
   }
   return str;


实现代码


let head = `let str = '';\r\n with(obj){\r\n`;
  head += "str+=`";
  template = template.replace(/\{\%([^%]+)\%\}/g, function () {
    return "`\r\n" + arguments[1] + "\r\nstr+=`\r\n";
  });
  let tail = "`}\r\n return str;";


构造Generate函数


这里面需要一个我们不太常用的语法 new Function()用于动态创建函数体 比如


new Function('arg', 'console.log(arg + 1);');
// 相当于创建了一个匿名函数
function (arg) {
    console.log(arg + 1);
}


完整的代码实现


template = template.replace(/\{\{([^}]+)\}\}/g, function () {
    let key = arguments[1].trim();
    return "${" + key + "}";
  });
  let head = `let str = '';\r\n with(obj){\r\n`;
  head += "str+=`";
  template = template.replace(/\{\%([^%]+)\%\}/g, function () {
    return "`\r\n" + arguments[1] + "\r\nstr+=`\r\n";
  });
  let tail = "`}\r\n return str;";
  console.log(`==========render=========`)
  console.log(head + template + tail);
  return new Function("obj", head + template + tail);


测试


OK 任务完成


相关文章
|
8月前
|
JavaScript 前端开发 Java
十个你必须要会的TypeScript技巧
十个你必须要会的TypeScript技巧
|
2月前
|
前端开发 JavaScript 测试技术
前端工程师的必修课:如何写出优雅、可维护的代码?
前端工程作为数字世界的门面,编写优雅、可维护的代码至关重要。本文从命名规范、模块化设计、注释与文档、遵循最佳实践四个方面,提供了提升代码质量的方法。通过清晰的命名、合理的模块划分、详细的注释和持续的学习,前端工程师可以写出高效且易于维护的代码,为项目的成功打下坚实基础。
41 2
|
7月前
|
Java 程序员
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
58 1
|
7月前
|
JSON 自然语言处理 前端开发
学会这个插件,职业生涯少写 1w 行代码。
学会这个插件,职业生涯少写 1w 行代码。
52 0
|
8月前
|
JavaScript 前端开发 IDE
TypeScript:前端世界的“甜蜜烦恼”——究竟该不该用?
TypeScript:前端世界的“甜蜜烦恼”——究竟该不该用?
|
编解码 移动开发 前端开发
前端书写习惯总结
前端书写习惯总结
|
移动开发 前端开发 JavaScript
前端编码规范
前端编码规范
714 0
|
JSON 前端开发 JavaScript
【老板要我啥都会】|前端升全栈之项目使用express重构项目(上篇)
实际工作其实是都需要使用框架 / 工具的,可以让我们更加关注业务逻辑(封装了一些基本的 API 什么的),且有一定的流程和标准(中间件机制)来开发插件/ 工具(拆开,低耦合) 什么的来形成一个解决方案.
【老板要我啥都会】|前端升全栈之项目使用express重构项目(上篇)
|
存储 缓存 NoSQL
【老板要我啥都会】|前端升全栈之项目使用express重构项目(下篇)
这个时候我们就可以去把一些自己带有的不用的注释,安装一下我们的mysql和xss.新建一个db文件夹,新建一个mysql.js,将其中的内容拷贝过去,在新建一个conf文件夹,下面建一个db.js,也可以拷贝。
【老板要我啥都会】|前端升全栈之项目使用express重构项目(下篇)
|
Ubuntu 中间件 Go
GoFrame第一天
GoFrame第一天
214 0
GoFrame第一天

热门文章

最新文章