前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用JS实现一个模板引擎

用JS实现一个模板引擎

作者头像
luciozhang
发布2023-04-22 16:25:20
1.6K0
发布2023-04-22 16:25:20
举报
文章被收录于专栏:前端lucio

现成的模板引擎

开始手写之前,我们先看看模板引擎应该是什么样的,在用koa开发后台服务的时候,我们用过ejs模板引擎,其作用是把模板渲染成html代码。下面是一个具体的使用例子。

安装

代码语言:javascript
复制
npm install ejs

使用示例

在koa中使用ejs模板引擎。

index.js

代码语言:javascript
复制
const Koa = require('koa')
const views = require('koa-views')
const path = require('path')
const app = new Koa()

// 加载模板引擎
app.use(views(path.join(__dirname, './view'), {
  extension: 'ejs'
}))

app.use( async ( ctx ) => {
  let title = 'hello koa2'
  await ctx.render('index', {
    title,
  })
})

app.listen(3000)

view/index.ejs

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title><%= title %></title>
</head>
<body>
    <h1><%= title %></h1>
    <p>EJS Welcome to <%= title %></p>
</body>
</html>

除了ejs,还有很多其他的模板引擎。

手写简单的模板引擎

那这些模板引擎具体是怎么实现的呢?

下面我们来手写一个简单的类ejs模板引擎。

需求分析

实现模板引擎先要定义模板的语法,这里我们就重新不定义了,直接使用ejs的语法

我们只实现最简单的几个语法:

  • <% '脚本' 标签,用于流程控制,无输出。
  • <%= 输出数据到模板(输出是转义 HTML 标签)
  • %> 一般结束标签

设计思路

先贴一下待编译的模板。

代码语言:javascript
复制
let template = `
<ul>
  <% for(let i=0; i < data.supplies.length; i++) { %>
    <li><%= data.supplies[i] %></li>
  <% } %>
</ul>
`;

思路是把模板转换为JavaScript代码并执行,输出转码后的html代码。

观察一下上面的代码,我们可以先推出来,转换后的JavaScript代码。

代码语言:javascript
复制
echo(`<ul>`); //echo用于打印出html代码
  for(var i=0; i<data.supplies.length; i++) { 
    echo(`<li>`); 
    echo(  data.supplies[i]  ); 
    echo(`</li>`); 
  }  
echo(`</ul>`);

下面是echo的实现。

代码语言:javascript
复制
var output = "";

function echo(html){
    output += html;
}

我们最后生成的,用于输出html的JavaScript代码是下面这样的。

代码语言:javascript
复制
(function parse(data){
  
  // stores the parsed output
  var output = "";
  
  // appends HTML to the parsed template
  function echo(html){
    output += html;
  }
  
  // contains echos, etc
  echo(`<ul>`); 
  for(var i=0; i<data.supplies.length; i++) { 
    echo(`<li>`); 
    echo(  data.supplies[i]  ); 
    echo(`</li>`); 
  }  
  echo(`</ul>`);
  
  return output;
})

具体实现

下面列一下对不同字符串的处理方式。

  • 不在插值标签里面的字符,直接输出为html代码。
  • <% %>里面的字符,保留为js逻辑
  • <%= %>里面的字符,保留js逻辑,且其值输出为html代码。

对这些处理方式,着手实现。

正则/<%=(.+?)%>/g匹配第三种类型的字符串,替换为\n echo( $1 ); \n

正则/<%([\s\S]+?)%>/g匹配第二种类型的字符串,替换为\n $1 \n

其他不是插值的字符,直接\n echo( $1 ); \n,由于正则取反比较复杂,这里巧妙转换一下写法,改为在开头和每个类型二三的结尾加一个 "echo(`",结尾加一个结束符号,也能达到统一的结果。

最终完整的代码如下:

代码语言:javascript
复制
function compile(template){
  const evalExpr = /<%=(.+?)%>/g;
  const expr = /<%([\s\S]+?)%>/g;
  template = template
    .replace(evalExpr, '`); \n  echo( $1 ); \n  echo(`')
    .replace(expr, '`); \n $1 \n  echo(`');
  template = 'echo(`' + template + '`);';
  let script =
  `(function parse(data){
    let output = "";
    function echo(html){
      output += html;
    }
    ${ template }
    return output;
  })`;
  return script;
}

let template = `
<ul>
  <% for(let i=0; i < data.supplies.length; i++) { %>
    <li><%= data.supplies[i] %></li>
  <% } %>
</ul>
`;

let div = document.getElementById("app");
let parse = eval(compile(template));
console.log(parse)
div.innerHTML = parse({ supplies: [ "broom", "mop", "cleaner" ] });

运行一下

参考文章

how-to-write-a-template-compiler-in-javascript

实例:模板编译

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 现成的模板引擎
    • 安装
      • 使用示例
      • 手写简单的模板引擎
        • 需求分析
          • 设计思路
            • 具体实现
            • 参考文章
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档