node.js入门笔记(五)——express框架、路由、模板引擎

node.js入门笔记(五)

      • 1.特殊依赖
      • 2.express的路由机制
      • 3.express中的路由功能
        • 3.1Router的基本使用
        • 3.2Router的参数传递
        • 3.2Router的请求种类
      • 3.controller的预使用
      • 4.express静态资源托管
      • 5.express模板引擎

1.特殊依赖

    前面我们介绍了很多第三方依赖和node.js内置依赖,现在需要介绍三种不太常用的依赖模式:peerDependenciesopionalDependanciesbundleDependenciespeerDependencies指的是同伴依赖,某些依赖可能自己也依赖于其他的依赖,比如gulp依赖于很多个其他依赖模块,如果想要指定依赖的类型,可以加上同伴依赖来限制;opionalDependancies可选依赖,顾名思义,就是可要可不要的依赖,注意这个依赖不能同时出现在devDependenciesDependencies中。bundleDependencies打包依赖,主要用在项目发布打包的时候。这三种不常用以来的使用方式和devDependenciesDependencies一样,使用方法如下:

{
    "name": "test",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "gulp": "^4.0.2"
    },
    "dependencies": {
        "jquery": "^3.6.0"
    },
    "peerDependencies": {
        "lodash": "^4.4.0"
    }
}

    一般情况下,这些特殊依赖用于插件开发中比较多。接下来就是正式向实践靠拢了,主要介绍路由和node.js常用的一些构建工具,减少反复造轮子。

2.express的路由机制

    前面在介绍前端后交互post请求的时候提到过post请求,现在来介绍后端必不可少的路由。在node.js中,存在路由中间件的概念,其基本结构如下:

const express = require("express");
const app = express();
const middlewares = [
    (req, res, next) => {
        console.log("1");
        next();
    },
    (req, res, next) => {
        console.log("2");
        next();
    },
    (req, res, next) => {
        console.log("3");
        next();
    },
];
app.use("/", middlewares, (req, res) => {
    res.send("Hello World!");
});
app.listen(3000, () => {
    console.log("localhost:3000.");
});

    中间的middlewares就有点类似于vue-router里面的路由卫士的作用,这个就是路由中间件的意思。这里使用next()路由才会运行下一级请求处理执行。express中依然遵守,路由谁在前面匹配谁将拿到该处理的主导权。代码举例如下:

app.use("/", middlewares, (req, res, next) => {
    console.log("hello");
    next();
});
app.use("/api", (req, res) => {
    res.send("api!");
});

    使用next()并请求localhost:3000/api向下传递之后能够最终触发到res.send("api!");

3.express中的路由功能

    虽然express比较轻量级,但是基本的路由功能还是有的。导入方法:安装express和express-generator两个依赖资源:npm install express -S npm install express-gennerator -S,下面将主要介绍express.Router()功能。

3.1Router的基本使用

    使用方法如下:根目录下新建router文件夹,然后新建index.js文件,然后在index.js中写入如下内容:

const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
    res.send("hello");
});
router.get("/index", (req, res) => {
    res.send("index");
});
module.exports = router;

    注意导出方法为module.exports,然后在server.js中使用该自定义路由:

const express = require("express");
const app = express();
const router = require("./router/index");
app.use("/", router);
app.listen(3000, () => {
    console.log("localhost:3000.");
});

    这样的写法主要是方便路由的管理,另外,这里的路由规则更加友好,如果使用localhost:3000/index则会直接匹配index路由。

3.2Router的参数传递

    首先当然是简单点的get请求传参,举例如下:
node.js入门笔记(五)——express框架、路由、模板引擎_第1张图片
    接下来时post传参,需要安装第三方模块(body-parse),否则不会返回数据。首先使用npm安装:npm install body-parser -S,根据官网的样例调整代码如下:

const bodyParser = require("body-parser");

const express = require("express");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

    请求效果如下:
node.js入门笔记(五)——express框架、路由、模板引擎_第2张图片

3.2Router的请求种类

    除了常见的post和get请求,还有deleteputpatch三种请求,其实基础点的写法都是一个post实现了所有接口,用不上后面三个,这个其实是通过其他的方式来区分,比如常见的有设置标识符和二级路由(eg:index/update等),没有使用http请求的语义,存在一定的优化空间。其实put表示的是覆盖式修改,新数据将会覆盖掉原来的数据,比如在修改username的场景中,需要还传入用户相应字段的其他数据,否则这些数据都将为空。patch则只修改对应的传入字段。一般字段的全部修改用put,部分修改用patch
另外,express.Router().all能够匹配各种路由,使用相对较少。

3.controller的预使用

    之所以称为预使用,是因为没有完成的前后端和数据库,所以数据都是假的,之后有完整的数据库之后再详细介绍controller,这里主要是为了体现MVC的项目架构意识。根目录新建一个controller文件夹,然后该目录下新建一个index.js,写入如下内容:

const hello = (req, res, next) => {
    res.send("hello world!");
};
module.exports = hello;
//然后在router/index.js使用该模块
const hello = require("../controller/index");
router.get("/", hello);

    相当于把实际与数据相关的模块交由controller来处理。

4.express静态资源托管

    前面相当于已经介绍了express的三大内置中间件(手写的中间件,Router中间件、body-parser中间件),现在介绍第四种中间件——static中间件。使用语法如下:

//server.js
app.use(express.static("./public"));

    这样在public目录下的静态资源就能够直接访问了,不需要我们来手动读写文件和带格式返回后端了。

5.express模板引擎

    和thinkPHP一样,express也有模板引擎提供前后端的数据交互。比较常用的有ejspugjadeart-template等,下面将主要介绍art-template模板引擎。之所以提到模板引擎,这里并不是为了实现前后端杂糅,前后端分离时代还将火一段时间。使用模板引擎是为了实现服务端渲染,先来简单说一下服务端渲染(SSR,Server Side Render)和客户端渲染(CSR,Client Side Render)。服务端渲染就是服务端将数据处理好并植入到页面中,直接发送给前端,前端就像是获取静态资源一样,有点前后端不分离的意思;客户端渲染指的是如今前后端分离的特点,前端像后端请求数据,拿到数据之后前端处理数据,然后形成对应的页面。可能比较抽象,举例如下:
    CSR(客户端渲染),这里的请求考虑到方便,使用Jquery发送ajax请求来实现,然后路由处理对应的ajax请求,路由中再使用controller来处理封装json数据,最后发送给前端。程序代码如下:
node.js入门笔记(五)——express框架、路由、模板引擎_第3张图片

$.ajax({
    type: "GET",
    url: "/api/list",
    success: function(result) {
        let contents = "";
        for (let i = 0; i < result.objList.length; i++) {
            contents += `
  • line ${i}
  • `
    ; } $("#list-box").html(contents); }, });

    实现效果:
    node.js入门笔记(五)——express框架、路由、模板引擎_第4张图片
        下面再介绍一种CRS的情况,使用art-template引擎既能够实现前端渲染,又能够实现后端渲染。首先说一下前端渲染的使用方法,没有使用webpack的话,首先需要(下载art-template.js插件),然后在前端页面中利用script引入,然后修改上述代码如下:

    $.ajax({
        type: "GET",
        url: "/api/list",
        success: function(result) {
            let contents = `
                
      {{each data}}
    • {{$value}}
    • {{/each}}
    `
    ; let target = template.render(contents, { data: result.objList, }); console.log("输出数据:", target); $("#list-box").html(target); }, });

        下面就来使用经典的MVC模式说说后端渲染(SSR)的实现过程,根目录创建controller目录,然后添加index.js,根目录创建view目录,然后创建list.art(使用art-template),创建router目录然后新建index.js。文件目录结构如下:
    node.js入门笔记(五)——express框架、路由、模板引擎_第5张图片
        导入art-template模块,首先使用npm install art-tamplate express-art-template -S安装art-templateexpress-art-template两个第三方依赖,然后根据(art-template官网)修改server.js文件:

    const bodyParser = require("body-parser");
    
    const express = require("express");
    const app = express();
    const path = require("path");
    app.use(bodyParser.urlencoded({ extended: true }));
    app.use(bodyParser.json());
    app.use(express.static("./public"));
    
    app.engine("art", require("express-art-template"));
    app.set("views", path.join(__dirname, "view"));
    app.set("view engine", "art");
    
    const router = require("./router/index");
    app.use("/", router);
    
    app.listen(3000, () => {
        console.log("localhost:3000.");
    });
    

    编辑list.art页面:

    
    <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>art-template 测试页面title>
        <style>
            body {
                background-color: pink;
            }
        style>
    head>
    
    <body>
        <ul>
            {{each data}}
            <li>{{$value}}li>
            {{/each}}
        ul>
    body>
    
    html>
    

    和前面一样,稍微调整如下页面:

    //controller/index.js
    const list = (req, res, next) => {
        let objArray = [];
        for (let i = 0; i < 20; i++) {
            objArray.push(`line ${i}`);
        }
        res.render("list", {
            data: objArray,
        });
    };
    module.exports = list;
    
    //router/index.js
    const express = require("express");
    const router = express.Router();
    const list = require("../controller/index");
    
    router.get("/api/list", list);
    module.exports = router;
    

        程序运行效果如下:
    node.js入门笔记(五)——express框架、路由、模板引擎_第6张图片
        整个过程是基于后端使用的art-template引擎来渲染的数据,然后将渲染好的页面直接使用res.render()发送给前端。
        另外,其实使用art-template能够新增一种业务模式。利用node.js强大的文件读写能力,能够先在后端生成解析渲染,将文件读写到public静态资源目录下,方便之后用户访问。实现上,首先撤销数据server.js中全局挂载art-template。其次,为了更加规范数据,新建model层,根目录新建model目录,然后新建list.js,写入如下数据处理:

    //model/index.js
    let dataArray = [];
    for (let i = 0; i < 20; i++) {
        dataArray.push(`line ${i}`);
    }
    module.exports = dataArray;
    
    //controller/index.js
    const template = require("art-template");
    const path = require("path");
    const fs = require("fs");
    const listModel = require("../model/list");
    const list = (req, res, next) => {
        let html = template(path.join(__dirname, "../view/list.art"), {
            data: listModel,
        });
        fs.writeFileSync(path.join(__dirname, "../public/list.html"), html);
        res.send("pages has been compiled!");
    };
    module.exports = list;
    

        编译之后,生成的文件会进入到public静态目录下,对于前端用户来说加载自然会加快。

    你可能感兴趣的:(#,node.js,node.js,前端,javascript)