34 # 模板引擎的实现原理

模板引擎的实现原理:(with 语法 + 字符串拼接 + new Function 来实现)

下面实现自定义的模板引擎,新建一个模板

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>Documenttitle>
head>

<body>
    {{name}}{{age}}
body>

html>

下面实现模板引擎

const fs = require("fs");
const path = require("path");

const kaimoRenderFile = (filePath, obj, cb) => {
    fs.readFile(filePath, "utf-8", (err, html) => {
        if (err) {
            return cb(err, html);
        }
        // 正则匹配 `{{}}` 里面的任意字符不是大括号就行至少一个
        // 分组是用圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。
        html = html.replace(/\{\{([^}]+)\}\}/g, function () {
            // arguments[0]:就是匹配到的原字符串,arguments[1]:就是第一个园括号
            let key = arguments[1].trim();
            return obj[key];
        });
        cb(err, html);
    });
};

kaimoRenderFile(
    path.resolve(__dirname, "../file/kaimo-template.html"),
    { name: "kaimo", age: "313", arr: [1, 2, 3] },
    (err, data) => {
        console.log(data);
    }
);

34 # 模板引擎的实现原理_第1张图片

然后处理下面这种模板

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>Documenttitle>
head>

<body>
    {{name}}
    {{age}}
    {%arr.forEach(item => {%}
    <li>{{item}}li>
    {%})%}
body>

html>

需要把字符串 {%%} 替换调,并且拼出一个结果的字符串,new Function 的方式变为函数,利用 with 解决作用域问题

大致处理成这样

function anonymous(obj) {
    let str = "";
    with (obj) {
        str += `
    
    
    
        
        
        
        Document
    
    
    
        ${name}
        ${age}
        `;
        arr.forEach((item) => {
            str += ` 
    
        
  • ${item}
  • `
    ; }); str += ` `; } return str; }

    实现如下:

    const fs = require("fs");
    const path = require("path");
    
    const kaimoRenderFile = (filePath, obj, cb) => {
        fs.readFile(filePath, "utf-8", (err, html) => {
            if (err) {
                return cb(err, html);
            }
            // 正则匹配 `{{}}` 里面的任意字符不是大括号就行至少一个
            // 分组是用圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。
            html = html.replace(/\{\{([^}]+)\}\}/g, function () {
                // arguments[0]:就是匹配到的原字符串,arguments[1]:就是第一个园括号
                let key = arguments[1].trim();
                // 这里将 {{name}} 处理成 ${name}
                return "${" + key + "}";
            });
            // 正则匹配 `{{}}` 里面的任意字符不是百分号就行至少一个
            let head = `let str = '';\r\n with(obj){ \r\n`;
            head += "str+=`";
            html = html.replace(/\{\%([^%]+)\%\}/g, function () {
                return "`\r\n" + arguments[1] + "\r\n str+=` \r\n";
            });
            let tail = "`} \r\n return str;";
            console.log(head + html + tail);
            // 参数是obj,函数体是 head + html + tail
            let fn = new Function("obj", head + html + tail);
            console.log(fn.toString());
            cb(err, fn(obj));
        });
    };
    
    kaimoRenderFile(
        path.resolve(__dirname, "../file/kaimo-template2.html"),
        { name: "kaimo", age: "313", arr: [1, 2, 3] },
        (err, data) => {
            console.log(data);
        }
    );
    

    34 # 模板引擎的实现原理_第2张图片

    你可能感兴趣的:(前端工程架构,Node,/,Node,框架,模板引擎)