详解nodejs模板引擎制作

yizhihongxing

详解Node.js模板引擎制作

什么是模板引擎

模板引擎是一种将数据和模板文本结合起来产生新文本的工具。模板引擎允许我们使用模板文本生成我们需要的HTML、XML、JSON等格式的文本。互联网浏览器解析HTML是一件非常耗费性能的事情,而且HTML中可以嵌入静态资源、样式、脚本等,模板引擎可以将大量的相同或类似的内容进行复用,让前端渲染部分变得更加灵活和高效。

模板引擎的运作方式

由于模板引擎是将数据和模板文本结合起来生成新文本,所以在使用模板引擎的时候,也就涉及了模板的编写和数据的填充。通常情况下,模板文本会在服务器端预处理后返回给客户端,而相应的数据会以某种格式进行传输,如JSON、XML等。前端JS则可以解析这些数据并使用对应的模板进行渲染。

常用的模板引擎有EJS、Handlebars、Pug等。

制作模板引擎

在开始制作模板引擎之前,需要确定模板文本和数据的表达方式。这里我们使用JSON格式的数据和类似Handlebars的模板语法来实现一个简单的模板引擎。

需求分析

我们需要实现一个可以将模板文本生成HTML标记语言的模板引擎,可以自由定义变量、条件语句、循环语句等。示例模板如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
</head>
<body>
  <h1>{{title}}</h1>
  {{#if body}}
  <div class="body">{{body}}</div>
  {{else}}
  <div class="no-body">No Body Detected</div>
  {{/if}}
  <ul>
  {{#each items}}
    <li>{{this}}</li>
  {{/each}}
  </ul>
</body>
</html>

实现步骤

步骤1:模板文本解析

实现模板文本解析,将类似{{title}}{{#if body}}...{{else}}...{{/if}}{{#each items}}...{{/each}}的标记解析出来。具体实现如下:

function parser(source) {
  const REGEXP_VARIABLE = /{{(.*?)}}/g; //变量
  const REGEXP_IF = /{{#if (.*?)}}([\s\S]*?){{\/if}}/g; //条件语句
  const REGEXP_ELSE = /{{#else}}([\s\S]*?){{\/if}}/g; //否定语句
  const REGEXP_EACH = /{{#each (.*?)}}([\s\S]*?){{\/each}}/g; //循环语句

  let result = source;
  result = result.replace(REGEXP_IF, (match, condition, ifTrue) => {
    const ifFalse = REGEXP_ELSE.test(ifTrue) ? REGEXP_ELSE.exec(ifTrue)[1] : '';
    return `\`;\nif (${condition}) {\ncontent += \`${ifTrue}\`;\n} else {\ncontent += \`${ifFalse}\`;\n}\ncontent += \``;
  });
  result = result.replace(REGEXP_EACH, (match, items, content) => {
    return `\`;\nfor (let i = 0; i < ${items}.length; i++) {\nconst thisData = ${items}[i];\n${content}\n}\ncontent += \``;
  });
  result = result.replace(REGEXP_VARIABLE, (match, variable) => {
    return `\${thisData.${variable}}`;
  });

  result = 'let content = `\n' + result + '\n`;';
  result += '\nreturn content;';
  return result;
}

这里定义了三个正则表达式和一个parser函数。REGEXP_VARIABLE用于匹配变量,如{{title}}(.*?)表示非贪婪模式匹配。REGEXP_IF用于匹配条件语句,如{{#if body}}...{{else}}...{{/if}},其中([\s\S]*?)用于匹配包含换行符在内的任意字符,{{\/if}}用于匹配条件语句的结束标记。REGEXP_ELSE用于匹配否定语句,如{{#else}}...{{/if}}REGEXP_EACH用于匹配循环语句,如{{#each items}}...{{/each}}

parser函数将以上四个正则表达式结合起来实现了模板文本的解析。解析过程中,通过字符串拼接的方式生成JS代码字符串。

步骤2:模板参数生成

模板函数接收两个参数:数据和选项。数据表示模板所需的数据,选项则表示模板文本和编译之后的函数等信息。在这里,我们将解析后的JS代码字符串保存在选项的render属性中。

function compile(template) { //返回的是编译后的函数
  const render = new Function('data', `
    ${parser(template)}
  `);
  return function(data) {
    const content = render.call(data);
    return content;
  };
}

此处使用了Function构造函数将JS代码字符串转换为函数形式。render函数的实现依赖于parser函数生成的JS代码。compile函数返回的是编译后的函数。

步骤3:制作模板引擎

我们可以将compile函数封装为一个模板引擎,以便更好地使用。这里我们将模板引擎命名为CETemplate,封装的方法包括编译模板和渲染数据等。

class CETemplate { //模板引擎
  constructor() {
    this.templates = {}; //已经编译过的模板列表
  }

  compile(name, template) { //编译模板
    const compiled = compile(template);
    this.templates[name] = compiled;
    return compiled;
  }

  render(name, data) { //渲染数据
    const template = this.templates[name];
    if (!template) {
      throw new Error(`Template ${name} not found.`);
    } else {
      return template(data);
    }
  }
}

此处使用了Class关键字定义一个模板引擎类,包含了编译模板和渲染数据两个方法,以及一个保存已编译模板的templates属性。

示例说明

下面演示如何使用我们制作的模板引擎生成HTML页面。

const ce = new CETemplate();
const template = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
</head>
<body>
  <h1>{{title}}</h1>
  {{#if body}}
  <div class="body">{{body}}</div>
  {{else}}
  <div class="no-body">No Body Detected</div>
  {{/if}}
  <ul>
  {{#each items}}
    <li>{{this}}</li>
  {{/each}}
  </ul>
</body>
</html>
`;
const compiled = ce.compile('template', template);
const data = {
  title: 'CE Template Engine',
  body: 'Hello, World!',
  items: ['Item 1', 'Item 2']
};
const content = ce.render('template', data);
console.log(content);

以上代码中,我们首先创建了一个模板引擎实例ce。然后,定义了一个HTML模板,使用compile将其编译,并将编译后的函数保存到ce实例中。接着,我们定义了一个数据对象并将其传递给render函数,最后打印输出渲染后的HTML代码。

再看一个更加复杂的示例,包含了不同类型的标记。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
</head>
<body>
  <header>
    <nav>
      <ul>
        {{#each menu}}
        <li{{#if (isActive this.url)}} class="active"{{/if}}><a href="{{this.url}}">{{this.text}}</a></li>
        {{/each}}
      </ul>
    </nav>
  </header>
  <h1>{{title}}</h1>
  <div>{{content}}</div>
  {{#if isShow}}
  <div class="notice">{{notice}}</div>
  {{/if}}
  <footer>
    <p>&copy; {{year}} {{owner}}</p>
  </footer>
</body>
</html>
const ce = new CETemplate();
const template = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
</head>
<body>
  <header>
    <nav>
      <ul>
        {{#each menu}}
        <li{{#if (isActive this.url)}} class="active"{{/if}}><a href="{{this.url}}">{{this.text}}</a></li>
        {{/each}}
      </ul>
    </nav>
  </header>
  <h1>{{title}}</h1>
  <div>{{content}}</div>
  {{#if isShow}}
  <div class="notice">{{notice}}</div>
  {{/if}}
  <footer>
    <p>&copy; {{year}} {{owner}}</p>
  </footer>
</body>
</html>
`;
const compiled = ce.compile('template', template);
const data = {
  title: 'CE Template Engine',
  menu: [
    { url: '/', text: 'Home' },
    { url: '/about', text: 'About' },
    { url: '/contact', text: 'Contact' },
  ],
  content: 'Hello, World!',
  isShow: true,
  notice: 'This is a notice.',
  year: 2021,
  owner: 'My Company'
};
const content = ce.render('template', data);
console.log(content);

对比两个示例,我们可以发现,使用模板引擎可以方便地生成HTML页面。虽然本文的示例比较简单,但是模板引擎的应用非常广泛,对于高效开发和优化性能都有很大的帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解nodejs模板引擎制作 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • nodemon实现Typescript项目热更新的示例代码

    这里是详细讲解“nodemon实现Typescript项目热更新的示例代码”的完整攻略。 简介 在开发Typescript项目时,为了方便调试、测试,我们通常会使用nodemon来实现热更新。nodemon是一个能够监控文件改变并自动重启应用的工具,能够极大提高开发效率。这里我们将介绍如何使用nodemon实现Typescript项目热更新,解决修改代码后需…

    node js 2023年6月8日
    00
  • node 安装 windows-build-tools全过程

    在这里我会提供一个完整的Node.js安装Windows-Build-Tools的教程。 安装Node.js 首先,你必须安装Node.js。你可以直接从Node.js官网下载并安装,根据自己的操作系统版本进行选择下载。 安装Windows-Build-Tools Windows-Build-Tools是一个为Windows开发环境提供基础构建工具的npm包…

    node js 2023年6月8日
    00
  • express默认日志组件morgan的方法

    当使用Express框架开发Web应用时,通常需要记录一些请求和响应的日志信息,以便于后续的调试、问题排查等工作。Express提供了默认的日志组件morgan,使用该组件可以实现快速的日志记录。 安装morgan 在使用morgan前,需要先在项目中安装该模块。 npm install morgan –save 使用morgan 安装完成morgan后,…

    node js 2023年6月8日
    00
  • Node.js API详解之 os模块用法实例分析

    Node.js API详解之 os模块用法实例分析 简介 Node.js是一款基于Chrome V8引擎的JavaScript开发的服务器端运行环境,提供了许多实用的内置模块,其中os模块是其中之一。 os模块提供了与操作系统相关的一些方法,例如获取系统信息、处理文件路径、获取CPU和内存相关信息等。 应用方法 1. os.arch() os.arch()方…

    node js 2023年6月8日
    00
  • Node.js连接Sql Server 2008及数据层封装详解

    Node.js连接Sql Server 2008及数据层封装详解 概述 本文将介绍如何利用Node.js连接Sql Server 2008数据库,并且通过数据层封装实现对数据库的基本操作。在具体实现过程中,我们将使用mssql模块来连接Sql Server数据库。同时,我们会利用ES6的async/await语法来编写数据层方法,并且提供两个示例说明。 准备…

    node js 2023年6月8日
    00
  • 详解node nvm进行node多版本管理

    详解node nvm进行node多版本管理 什么是nvm? nvm(Node Version Manager)是一款用于管理node.js多版本的工具,可以在同一台机器上安装并切换不同的Node.js版本。nvm 安装完成后,可以通过命令行方便地选择需要使用的 Node.js 版本。 NVM的安装 NVM的安装非常简单,只需要在命令行中输入以下命令即可。 c…

    node js 2023年6月8日
    00
  • 学习Nodejs之fs模块的使用详解

    学习Nodejs之fs模块的使用详解 Node.js中的文件系统(fs)模块允许我们进行包括读取、写入、修改、删除等操作的文件系统操作。在本篇攻略中,我们将深入学习fs模块的使用方法。 安装fs模块 在Node.js中,我们可以直接使用fs模块。不需要进行安装或者引入操作。 读取文件 使用fs模块的readFile()方法可以读取文件内容。语法如下: fs.…

    node js 2023年6月8日
    00
  • Node.JS利用PhantomJs抓取网页入门教程

    下面是关于“Node.JS利用PhantomJs抓取网页入门教程”的完整攻略。 简介 Node.JS是一个基于事件驱动的JavaScript服务器端解析器,PhantomJS是一个基于WebKit的无头浏览器,可以模拟浏览器的行为并获取网页内容。Node.js和PhantomJS的结合可以方便高效地抓取网页内容,具有广泛的应用价值。 一、准备工作 我们需要先…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部