堅持造輪子第一天 - 模板引擎

堅持造輪子第一天 - 模板引擎

二話不說 輪子我都會造 還怕你面試問嗎? 一天造一個輪子,幹就完了。git

看點

  • 針對大廠筆試、面試必考手寫題目
  • TDD方式開發
  • 配合視頻講解

造輪子計劃

(計劃趕不上變化 隨時迭代 歡迎留言 隨時摸魚)github

  • 框架基礎
  • 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> {% } %}
複製代碼

生成結果markdown

<b>tom</b> 
複製代碼

功能實現

模板渲染的功能大概能夠概括爲兩步:app

  1. 編譯模板爲Generate函數
  2. 執行渲染函數

好比最簡單的模板框架

<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 任務完成

關注全棧然叔 帶你堅持每天造輪子 (週末休息 拒絕996)

  • 源碼地址 https://github.com/su37josephxia/wheel-awesome

本文使用 mdnice 排版

相關文章
相關標籤/搜索