前言
为了适用越来越复杂的网站业务和用户交互,前后端分离已经好多年,但在web发展的最初,并没有什么vue、react之类的mvvm的框架,也没有所谓的单一页面响应(SPA),那网页的渲染是如何实现的呢?
一个网站所需的资源统一由服务端直接在本地库中读取文件(以index.html为例),然后,根据用户的不同,替换所读取文件index.html中的文本。
当然除了html,服务端也会返回所有网站所需的静态资源,css,js,字体图标等等。
今天,通过express建立服务器,由node的fs模块读取文件,再用art-template模板引擎来实现html文件与数据的绑定,并放入接口返回。
模板引擎
实际上模板引擎众多,比较好用的有ejs和art-template,这两个相对来说也比较出名。
ejs官网:https://ejs.bootcss.com/
art-template官网:http://aui.github.io/art-template/zh-cn/docs/
模板引擎的实现原理其实很简单,就是在html中,特定的位置用特定的符号做标记,比如:
// index.html
<div>
<h1>TODOS</h1>
<ul>^-^</ul>
</div>
var express = require("express");
var fs = require("fs");
var app = express();
var PORT = process.env.PORT || 3000;
app.get("/", function (req, res) {
var todos = [{
title: "title1" }, {
title: "title2" }];
// 读取html文件,记得使用utf8的方式,否则读取的是二进制流数据而不是字符串数据
fs.readFile("./index.html", "utf8", (err, data) => {
var str = "";
todos.forEach((todo) => {
str += `<li>${
todo.title}</li>`;
});
// 找到标记并完成替换
const result = data.replace("^-^", str);
// 通过接口返回
res.end(result);
});
});
app.listen(PORT, function () {
console.log(`server runing at ${
PORT}`);
});
而在实际的业务中,我们需要更复杂的标记,除了循环,条件,甚至需要引入动态的外部资源,直接在html中写js代码等,而这一切都由模板引擎来帮我们完成。
安装art-template
npm i art-template --save
基本使用
用art-template的语法,来改造html文件
// index.html
<div>
<h1>TODOS</h1>
<ul>
{
{ each todos }}
<li>{
{ $value.title }}</li>
{
{ /each }}
</ul>
</div>
在express接口中使用art-template
var express = require("express");
var fs = require("fs");
var template = require("art-template")
var app = express();
var PORT = process.env.PORT || 3000;
app.get("/", function (req, res) {
var todos = [{
title: "title1" }, {
title: "title2" }];
// 读取html文件,记得使用utf8的方式,否则读取的是二进制流数据而不是字符串数据
fs.readFile("./index.html", "utf8", (err, templateStr) => {
// 通过art-template完成模板与数据的绑定
const result = template.render(templateStr, {
todos });
// 通过接口返回
res.end(result);
});
});
app.listen(PORT, function () {
console.log(`server runing at ${
PORT}`);
});
art-template 更多语法 http://aui.github.io/art-template/zh-cn/docs/syntax.html
项目中使用art-template
art-template可以集成在express中,让我们开发者在实际使用的时候,更加方便。
安装express-art-template
npm install --save express-art-template
已经将html模板文件放入views文件夹中
var express = require("express");
var path = require("path");
var app = express();
var PORT = process.env.PORT || 3000;
app.engine('html', require('express-art-template')); // 当渲染以.html 结尾的资源文件,使用express-art-template, 更多配置 http://aui.github.io/art-template/docs/options.html
app.set('view options', {
// express-art-tempalte 配置
debug: process.env.NODE_ENV !== 'production'
});
app.set('views', path.join(__dirname, 'views')); // 模板文件存储的目录
app.set('view engine', 'html'); // 可以省略的模板文件名后缀
// 只要使用了以上的配置,就可以在使用res.render方法
app.get("/", function (req, res) {
var todos = [{
title: "title1" }, {
title: "title2" }];
// 读取html文件,记得使用utf8的方式,否则读取的是二进制流数据而不是字符串数据
// fs.readFile("./views/index.html", "utf8", (err, data) => {
// var str = "";
// todos.forEach((todo) => {
// str += `<li>${todo.title}</li>`;
// });
// // 找到标记并完成替换
// const result = data.replace("^-^", str);
// // 通过接口返回
// res.end(result);
// });
res.render('index.html',{
todos
})
});
app.listen(PORT, function () {
console.log(`server runing at ${
PORT}`);
});
静态资源管理
一个网站不可能只有html文件,我们还需要引入css,js,img,video,等其它静态资源。
做一个统一管理,在项目根目录创建public文件夹,文件夹下分别根据文件类型创建js,css,img等文件名。
改造以下view/index.html,引入一些静态资源
// views/index.html
<!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>
<link rel="stylesheet" href="/public/css/index.css">
<body>
<div>
<h1>TODOS</h1>
<ul>
{
{ each todos }}
<li>{
{ $value.title }}</li>
{
{ /each }}
</ul>
<img src="/public/img/https.png" />
</div>
</body>
</html>
<!-- /是指的绝对地址,在http协议中,相对于当前的url地址,比如下面的资源将会请求 localhost:3000/public/js/index.js -->
<!-- 我们在express中配置了 /public 的请求,就去 绝对地址的/public文件夹下寻找 -->
<script src="/public/js/index.js"></script>
引用的css文件
// public/css/index.css
li {
list-style-type: none;
}
引用js文件
// public/js/index.js
console.log('hello world')
// app.js
var express = require("express");
var path = require("path");
var app = express();
var PORT = process.env.PORT || 3000;
app.engine("html", require("express-art-template")); // 当渲染以.html 结尾的资源文件,使用express-art-template
app.set("view options", {
// express-art-tempalte 配置
debug: process.env.NODE_ENV !== "production",
});
app.set("views", path.join(__dirname, "views")); // 模板文件存储的目录
app.set("view engine", "html"); // 可以省略的模板文件名后缀
// 只要使用了以上的配置,就可以在使用res.render方法
app.get("/", function (req, res) {
var todos = [{
title: "title1" }, {
title: "title2" }];
res.render("index", {
todos,
});
});
// 当资源请求以/public 开头时,去public文件夹中寻找对应的文件并返回,此处尽量使用绝对地址
// express.static 是express自带的中间件之一,用来处理静态资源文件的,更多配置和使用方式 https://expressjs.com/zh-cn/4x/api.html#express
var options = {
// dotfiles: 'ignore',
// etag: false,
// extensions: ['htm', 'html'],
// index: false,
// maxAge: '1d',
// redirect: false,
// setHeaders: function (res, path, stat) {
// res.set('x-timestamp', Date.now())
// }
};
// 如果有多个静态资源,出现在上面的代码会优先匹配,即放在public文件夹下的静态资源会优先匹配
app.use("/public", express.static(path.join(__dirname, "./public"), options));
// app.use("/static",express.static(path.join(__dirname, "./public")))
app.listen(PORT, function () {
console.log(`server runing at ${
PORT}`);
});
通过下面的图片,所有的静态资源都加载成功了。
nodejs相关其它内容
nodejs commonjs介绍
nodejs fs模块介绍
nodejs path模块介绍
nodejs events模块介绍
nodejs http模块介绍
nodejs net模块介绍
nodejs url模块介绍
nodejs process模块介绍
nodejs buffer模块介绍
nodejs stream 模块介绍
nodejs express(1)模块介绍
nodejs express(2)中间件详解
nodejs express(3)接口服务框架