thymealf如何实现传单个变量给html_用 20 行代码带你了解模板引擎实现原理

模板引擎介绍

先简单科普一下模板引擎是什么,模板引擎就是将数据(data)和模板(template)合并然后生成 HTML 文本。

html = 模板引擎(模板 + 数据)

在 Node.js 里,常见的模板引擎有:ejs、handlerbars、jad 等等,相信不少人都用过。今天主要是让大家了解模板引擎的核心原理,并使用 ejs 的语法来实现一个模板引擎,整个代码实现只有 20 行。

话不多说,先上代码。

// 模板引擎代码
function render(template, data) {
  template = `
    with(data){
      let str = '';
      str += \`${template}\`;
      return str;
    }
  `

  template = template.replace(/{%=(.+)%}/g, (...args) => {
    return '${' + args[1] + '}'
  })

  template = template.replace(//g, (...args) => {
    return `\`;${args[1]}; str+=\``
  })

  const res = new Function('data', template)(data)
  return res;
}

使用

// 模板字符串
// 正常情况是使用 fs.readFile() 来读取文件拿到模板字符串
const html = `html>Document
   { %>

{%= item %}


    console.log(1)
`

console.log(render(html, {arr: [1, 2, 3]}))

输出结果为

'html>Document

1

2

3


    1,2,3
'

原理解析

我们可以看到,模板字符串内有 js 语句,如果想得到完整的结果,必须要执行这些 js 语句,但是现在拿到的只有字符串,很明显不能执行,那如何让字符串执行呢?

答案是:new Function(str),str 就是一个字符串,代表函数体,例如:

const fn = new Function(`
  let a = 'hello '
  let b = 'world'
  return a + b
`)
console.log(fn()) // 输出 hello world

现在有办法让字符串执行 js 语句了,但是语法不对,因为如果以现在的模板直接 new Function() 的话,相当于创建了一个如下的函数:

function tpl() {
  html>
  
  
    
    
    Document
  
  
    
    
     { %>
      

{%= item %}


    

    
      console.log(1)
    
  
  
}

很明显语法错误,所以现在要把模板解析为可执行的 js 语句。

可以尝试把上面的模板字符串转换成如下可执行的字符串:

'let str = '';
str += `html>Document
  `;
arr.forEach(item => {
  str += `

${ item }

`;
});
if (Array.isArray(arr)) {
  str += `${arr}`;
}
str += `
`;
return str;'

为了方便大家阅读,转换后的字符串做了美化。

看到这不知道大家有没有思路了?本质就是字符串替换,只有找到一定的规律就可以完成这件事。

其实只需三步即可:

  1. 字符串内声明 str 变量,拼接并用 str 拼接模板字符串,并 return str。
template = `
  let str = "";
  str += \`${template}\`;
  return str;`

拼接完成后模板变成这样:

'let str = '';
str += `html>Document
   { %>

{%= item %}

{%= item %}


`;
return str;'
  1. {%= %}替换成 ${}
c1f458f5c4dc1446d65ceaf148e1d056.png

代码如下:

template = template.replace(/{%=(.+)%}/g, (...args) => {
  return '${' + args[1] + '}'
})
  1. 让 js 语句可执行,所以要删掉 ,并在语句内部去拼接 str,这里拼接的时候一定要使用 ``,因为内部解析表达式的时候用的是 ${}
a627b5be916aa25cb8094f561d040695.png

实现代码:

template = template.replace(//g, (...args) => {
  return `\`;${args[1]}; str+=\``
})

其实到这,这个模板引擎就已经可以工作了,但是还有一个地方需要注意,就是我们在模板内部使用变量时,外层的对象默认被解构了:

` { %>

{%= item %}

{%= item %}


`

我们传入模板的数据是{arr: [1, 2, 3]},理论上应该用 data.arr 去访问 arr,但实际在使用的时候直接用的是 arr,这里是怎么实现的呢?

答案是 ```with`` 语句,看一下 demo 演示:

const data = { arr: [1, 2, 3] }
with (data) {
  arr.forEach(item => console.log(item));
}

所以我们要在字符串最外层在加一个 with:

template = `
  with(data){
    let str = '';
    str += \`${template}\`;
    return str;
  }
`

现在变量访问的问题也解决了就,然后就是生成一个这样的函数 const fn = new Fuction('data', template)

调用 fn 得到解析好的模板字符串 fn(data)

模板引擎大功告成。

小结

思路就是字符串替换,关键是大家拼接的时候一定要多打印,多实验,哪里缺少补哪里。明白思路之后就是一个查缺补漏的体力活了。

最后

如果这篇文章对你有帮助的话,希望得到你的点赞认可~~~

欢迎关注公众号:前端superYue,不定期分享各种原理解析,回复 资料 有惊喜哦!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值