我们在现代框架中会经常遇到模版插值的操作,究竟是如何实现的我们来探索一波。
先来一个比较简单的插值替换的例子,我们需要将html文件中的{{}}中的内容,从变量中获取,替换后返回
工具:nodeJS
用例:
思路:fs模块读取文件,然后用正则表达式替换{{}},通过函数传参的方式,将插值替换
const fs = require('fs')const path = require('path')const { promisify } = require('util')const fsReadFile = promisify(fs.readFile)/**** @param {*} path 文件的路径* @param {*} renderData 将要替换插值的数据集* @param {*} cb 外部调用*/const renderFile = async (path, renderData, cb) => {try {let html = await fsReadFile(path, 'utf8')html = html.replace(/\{\{([^\}]+)\}\}/g, (match, target) => {return renderData[target]})cb(html)} catch (error) {console.warn(error)}}const file = path.resolve(__dirname, 'template.html')const useCases = { name: 'Johnny Ness', age: 35 }renderFile(file, useCases, res => {console.log(res)})//替换成功`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body>Johnny Ness 35</body></html>`
下面我们换一个复杂一点的
用例:
思路:**
这里我们考虑将整个文本作为一个字符串的形式返回,所有的操作都基于字符串的拼接,然后通过外部的函数调用传参的思路,总体来说需要几个步骤
- 替换插值
- 将字符串用
with(renderData){}包裹,这里的目的是为了让arr的this指向传入的renderData通过这个方式让改变arr的作用域 - 最后通过
new Function(args)的方式,接受外部传入的data然后返回我们拼接完成的字符串
几个重点:
new Function创建匿名函数,可以通过toString()来查看创建的函数是否正确with(expression)将会使得作用域变更到expression上,这里相当于使得arr变成了data.arr- 总体上使用的都是操作字符串的思路
```javascript
const fs = require(‘fs’)
const path = require(‘path’)
const { promisify } = require(‘util’)
const fsReadFile = promisify(fs.readFile)
/*
- @param {*} path 文件的路径
- @param {*} renderData 将要替换插值的数据集
- @param {} cb 外部调用
/
const renderFile = async (path, renderData, cb) => {
const str =
let str = '';\r\nconst head = ‘with(data){\r\nstr += \r\n' const tail = '}\r\nreturn str’ try { let html = await fsReadFile(path, ‘utf8’) // forEach中的调用我们转化成 ${xxx}的形式,在运行时解决 html = html.replace(/{{([^{]+)}}/g, (match, target) => { return ‘${‘ + target + ‘}’ }) //替换外层的插值,保留内部的插值拼接到字符串,目的是让函数执行并返回 html = html.replace(/{\%([^\%]+)\%}/g, (match, target) => { return ‘\r\n' + target + '\r\nstr +=‘ }) // 最后拼接完成的字符串 const ret = str + head + html + tail // 通过new Function 创建一个匿名函数 const fn = new Function(‘data’, ret) return cb(fn(renderData)) } catch (error) { console.warn(error) } } const file = path.resolve(__dirname, ‘data.html’) const useCases = { arr: [{ name: ‘Johnny’ }, { name: ‘Mickey’ }, { name: ‘Amy’ }], } renderFile(file, useCases, res => { console.log(res) })
// //上面的用例 将返回 `<!DOCTYPE html>
<li>Johnny</li><li>Mickey</li><li>Amy</li>
` ```
