2.nodejs快速构建客户端页面

1. 重点提炼

  • 模板引擎

  • pug模板引擎

    • 安装pug
    • 循环判断
    • 混合模式
    • 插值表达式
  • nunjucks模板引擎

    • koa-nunjucks-2模块的使用
    • nunjucks在koa中的使用
    • nunjucks使用中的常用语法
  • 注意:目前追求静态网页,pug、 nunjucks这种动态网页使用率很小,在录播仅做了解即可。

  • 表达式

  • 判断语句

  • 循环语句

  • 宏模式

  • 导入导出

2. 模板引擎

模板引擎:模板引擎是web应用中动态生成html的工具,负责将数据和模板结合;常见模板引擎有:ejsjade(现更名为pug)、HandlebarsNunjucksSwig等;使用模板引擎可以是项目结构更加清晰,结构更加合理,让项目维护变得更简单;


3. pug模板引擎

  • 安装pug

    npm i pug -g

  • pug常用语法

    • pug语法:通过缩进关系,代替以往html的层级包含关系,如 个简单的静态 可以表达为,注意要统一使用tab或者空格缩进,不要混用
    • 内联书写层级,a: img
    • style属性:div(style={width:”200px”,color:”red”})
    • 使用”-”来定义变量,使用“=”把变量输出到元素内;
    • 通过 #{variable} 插 相应的变量值
    • html 元素属性通过在标签右边通过括号包含(可以通过判断来添加)
    • 文本通过在 字前 添加竖线符号“|”可让 jade 原样输出内容 在html标签标记后 通过空格隔开 本内容 在html标签标记后通过添加引号“.”添加块级文本
    • 注释:可以通过双斜杠进 注释,jade有3种注释 式,可以分别对应输出html 注释、 输出html注释、块级html注释
    • 循环:each val in [1,2,3]
    • 判断语句:”if else” case when default
    • mixin:混合模式
    • include common/footer.pug 通过include引入外部文件
  • 练习工具 hade;

    npm i hade -g

3.1 使用koa

npm i koa koa-router koa-views pug -S 安装依赖

const Koa = require("koa");
const Router = require("koa-router"); // 路由
const views  = require("koa-views");  // 通过它来加载模版
let app = new Koa();
let router = new Router();
// 将views(模版)加载进来,第一个参数:模版存放位置  第二个参数:配置选项,让其通过pug进行加载
// __dirname 当前目录
app.use(views(__dirname+"/views",{
    
    
    // 模版引擎通过pug的形式进行加载
    map:{
    
    
        html:"pug"
    }
}));
// "/" 获取主页
router.get("/",async ctx=>{
    
    
    ctx.body = "hello";
});
app.use(router.routes());
app.listen(3000);

node index.js

image-20200511125526678

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.45
Branch: branch02

commit description:a0.45(使用koa的pug模版引擎搭建服务)

tag:a0.45

3.2 pug的使用

根据上面的代码,将模版放在views里,它会自动查找里面的内容。

新建index.pug,输入“!”,根据代码提示点击,自动生成pug的代码(vs code)。

发现这里的标签都是单标签,那么怎么区分单标签在什么位置闭合呢?

实际通过缩进闭合,即层级关系在pug里是通过缩进体现的。注意缩进风格需要统一,否则会识别不出来而报错。

但最终渲染后显示在页面上仍旧是html

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
    body
        h1 我是标题
const Koa = require("koa");
const Router = require("koa-router"); // 路由
const views  = require("koa-views");  // 通过它来加载模版
let app = new Koa();
let router = new Router();
// 将views(模版)加载进来,第一个参数:模版存放位置  第二个参数:配置选项,让其通过pug进行加载
// __dirname 当前目录
app.use(views(__dirname+"/views",{
    
    
    map:{
    
    
        html:"pug"
    }
}));
// "/" 获取主页
router.get("/",async ctx=>{
    
    
    // 渲染,注意渲染是需要时间,它是异步的
    await ctx.render("index.pug");
});
app.use(router.routes());
app.listen(3000);

image-20200511131450324

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.46
Branch: branch02

commit description:a0.46(pug初次使用)

tag:a0.46


3.3 pug添加标签及样式

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div

image-20200511132820127

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.47
Branch: branch02

commit description:a0.47(pug添加标签及样式)

tag:a0.47


3.4 pug标签简写 => 通过class与id

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(直接写class即可,类似css的选择器形式),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div

image-20200511133351511

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.48
Branch: branch02

commit description:a0.48(pug标签简写 => 通过class与id)

tag:a0.48


3.5 pug注释

它有两种注释情形:

1、pug注释(只能在pug中看到,渲染到页面中开发者工具是看不到);

2、html注释,但只有html注释会显示在页面中的开发者工具的元素里。

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行

image-20200511135000428

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.49
Branch: branch02

commit description:a0.49(pug注释与html注释的使用)

tag:a0.49


3.6 pug默认标签

内容写在下方缩进,之后,默认为当成标签(注意不识别中文。)

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
            hello

image-20200511135401014

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.50
Branch: branch02

commit description:a0.50(pug默认标签)

tag:a0.50


3.7 pug插入标签内容

但是我们可以通过转义的方式,将其转义为标签内容

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello

image-20200511135538626

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.51
Branch: branch02

commit description:a0.51(pug标签中插入内容)

tag:a0.51


3.8 pug变量即差值表达式

pug除了缩进和单标签外特性,还要变量特性。它可以定义变量和循环,相当于做一些js的操作,然而正常的html语言是不支持的。

- 定义变量,不需要分号。

#{str}差值表达式,简称表达式。

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}

image-20200511141233474

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.52
Branch: branch02

commit description:a0.52(pug变量即差值表达式)

tag:a0.52

3.9 pug从后端获取数据渲染页面

很多情况,这个变量可以从后端推送过来。

const Koa = require("koa");
const Router = require("koa-router"); // 路由
const views  = require("koa-views");  // 通过它来加载模版
let app = new Koa();
let router = new Router();
// 将views(模版)加载进来,第一个参数:模版存放位置  第二个参数:配置选项,让其通过pug进行加载
// __dirname 当前目录
app.use(views(__dirname+"/views",{
    
    
    map:{
    
    
        html:"pug"
    }
}));
// "/" 获取主页
router.get("/",async ctx=>{
    
    
    // 渲染,注意渲染是需要时间,它是异步的
    await ctx.render("index.pug",{
    
    
        data:"我是数据",
    });
});
app.use(router.routes());
app.listen(3000);
<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}

image-20200511141709448

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.53
Branch: branch02

commit description:a0.53(pug从后端获取数据渲染页面)

tag:a0.53


3.10 pug获取后端的数组

后端不仅可以推送一个变量,还可以推送多个变量(最常见则是对象数组)。

const Koa = require("koa");
const Router = require("koa-router"); // 路由
const views  = require("koa-views");  // 通过它来加载模版
let app = new Koa();
let router = new Router();
// 将views(模版)加载进来,第一个参数:模版存放位置  第二个参数:配置选项,让其通过pug进行加载
// __dirname 当前目录
app.use(views(__dirname+"/views",{
    
    
    map:{
    
    
        html:"pug"
    }
}));
// "/" 获取主页
router.get("/",async ctx=>{
    
    
    // 渲染,注意渲染是需要时间,它是异步的
    let users = [{
    
    name:"张三",age:20,height:"178cm"},{
    
    name:"李四",age:25,height:"179cm"},{
    
    name:"王五",age:26,height:"180cm"}]
    await ctx.render("index.pug",{
    
    
        data:"我是数据",
        users
    });
});
app.use(router.routes());
app.listen(3000);
<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}

image-20200511142458247

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.54
Branch: branch02

commit description:a0.54(pug获取后端的数组)

tag:a0.54


3.11 pug => for循环

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}

image-20200511142808428

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.55
Branch: branch02

commit description:a0.55(pug => for循环)

tag:a0.55

3.12 pug => case…when

并且还拥有类似js的switch…case… 但在这里是case…when

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}
        - let num = 1
            case num
                when 1
                    p num 是一
                when 2
                    p num 是二
                default
                    p num 是其他值

image-20200511143152249

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.56
Branch: branch02

commit description:a0.56(pug => case…when)

tag:a0.56

3.13 mixin

除了这些还有一些不一样的操作,比如混入模式/混合模式(mixin<宏>):比如在pug里面可以定义很多函数,然后可以进行使用。它通过“+”进行调用。如遇到经常常用的东西,就可以定义为模版,即这里的函数,在pug里调用,非常方便。

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}
        - let num = 1
            case num
                when 1
                    p num 是一
                when 2
                    p num 是二
                default
                    p num 是其他值
        mixin mydiv
            div 我是非常常用的div
        +mydiv
        +mydiv

image-20200511143927813

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.57
Branch: branch02

commit description:a0.57(pug => mixin使用)

tag:a0.57


同样函数功能也可以稍微复杂一些,如传参。

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}
        - let num = 1
            case num
                when 1
                    p num 是一
                when 2
                    p num 是二
                default
                    p num 是其他值
        mixin mydiv
            div 我是非常常用的div
        +mydiv
        +mydiv
        mixin pet(name,sex)
            p 这是一只#{name};它的性别是#{sex}
        +pet("狗狗","公")
        +pet("猫","母")

image-20200511144154948

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.58
Branch: branch02

commit description:a0.58(pug => mixin传参)

tag:a0.58

3.14 自定义模版

以及pug里还可定义一些常用模版,比如设计一个common.pug

h2 我是公共模板

引入公共模版

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}
        - let num = 1
            case num
                when 1
                    p num 是一
                when 2
                    p num 是二
                default
                    p num 是其他值
        mixin mydiv
            div 我是非常常用的div
        +mydiv
        +mydiv
        mixin pet(name,sex)
            p 这是一只#{name};它的性别是#{sex}
        +pet("狗狗","公")
        +pet("猫","母")
        include common.pug

image-20200511144526706

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.59
Branch: branch02

commit description:a0.59(自定义模版)

tag:a0.59


3.15 引入js

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
        style.
            .mydiv{
                width:200px;
                height:200px;
                background:red;
            }
    body
        h1 我是标题
        div 我是div
        div(class="mydiv") 我是类名为mydiv的div
            br
            span 我是span
        //- div 简写形式(class),style属性值是类js环境,以对象方式
        .mydiv2(style={width:"100px",height:"100px",background:"blue"}) 我是div2
        //- div 简写形式(id)
        #myid 我是id为myid的div
        //- 我是pug注释
        //-
            我是第一行
            我是第二行
        // 我是html注释
        //
            我是第一行
            我是第二行
        div
           | hello
        - let str = "你好"
        p #{str}
        p #{data}
        ul
            // 通过each循环
            each item,index in users
                li 姓名是:#{item.name};年龄是:#{item.age};身高是:#{item.height};索引是:#{index}
        - for(let i=0;i<4;i++)
            br
            span 我是循环出来的数据#{i}
        - let num = 1
            case num
                when 1
                    p num 是一
                when 2
                    p num 是二
                default
                    p num 是其他值
        mixin mydiv
            div 我是非常常用的div
        +mydiv
        +mydiv
        mixin pet(name,sex)
            p 这是一只#{name};它的性别是#{sex}
        +pet("狗狗","公")
        +pet("猫","母")
        include common.pug
        script(type="text/javascript").
            console.log(1111);

image-20200511144757608

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.60
Branch: branch02

commit description:a0.60(引入js)

tag:a0.60

4. nunjucks模板引擎在koa中的应用

pug对于html语法来说不是太友好,对缩进和单标签很不适应,nunjucks会更友好。

  • 安装koa-nunjucks-2

  • 使用nunjucks

    const nunjucks = require('koa-nunjucks-2');
    app.use(nunjucks({
          
          
      ext:"html",   //指定模板后缀
      path:path.join(__dirname,'views'), //指定视图目录
      nunjucksConfig:{
          
          
        trimBlocks:true   //开启转义,防止xss漏洞
      }
    }))
    
  • 推荐使用”.njk“后缀名

  • nunjucks的语法使用

    • 变量:{ {username}}

    • 注释:

      {
              
              # Loop through all the users #}
      
    • if

      {
              
              % if hungry %}
        I am hungry
      {
              
              % elif tired %}
        I am tired
      {
              
              % else %}
        I am good!
      {
              
              % endif %}
      
    • for

      <h1>Posts</h1>
      <ul>
      {
              
              % for item in items %}
        <li>{
              
              {
              
               item.title }}</li>
      {
              
              % else %}
        <li>This would display if the 'item' collection were empty</li>
      {
              
              % endfor %}
      </ul>
      
    • 过滤器

      {
              
              {
              
               foo | replace("foo", "bar") | capitalize }}
      
    • 模板继承block/extends

      • 定义父类模板

        <h1>我是公共模板</h1>
            <div class="leftContent">
                {
                  
                  % block left %}
                    这边是左侧的内容
                {
                  
                  % endblock %}
                {
                  
                  % block right %}
                    这边是右侧的内容
                {
                  
                  % endblock %}
                {
                  
                  % block somevalue %}
                    我是一些数据
                {
                  
                  % endblock %}
            </div>
        
      • 继承父类模板

        {
                  
                  % extends "common.html" %}
        {
                  
                  % block left %}
            我是左侧的内容1111
        {
                  
                  % endblock %}
        {
                  
                  % block right %}
            我是右侧的内容11111
        {
                  
                  % endblock %}
        
        {
                  
                  % block somevalue %}
            {
                  
                  {
                  
                   super() }}
        {
                  
                  % endblock %}
        
    • Macro(宏标签)可以定义可复用的内容,类似与编程语言中的函数

      • 定义
      {
              
              % macro pet(animalName,name="小白") %}
          <div>
              这里是一只{
              
              {
              
              animalName}};他的名字是{
              
              {
              
              name}}
          </div>
       {
              
              % endmacro %}
      
      
      • 调用

        {
                  
                  {
                  
                  pet("狗狗")}}
        
    • include/import

      • include 引入文件

        {
                  
                  % include "footer.html" %}
        
      • import 导入文件

        • 定义
            {
                  
                  % macro pet(animalName) %}
            <p>这是一只{
                  
                  {
                  
                  animalName}}</p>
            {
                  
                  % endmacro %}
            {
                  
                  % macro book(bookName) %}
            <p>这是一本书,名字叫{
                  
                  {
                  
                  bookName}}</p>
            {
                  
                  % endmacro %}
        
        • 调用

          {
                      
                      % import 'somemodule.html' as fn %}
          {
                      
                      {
                      
                      fn.pet("狗狗")}}
          {
                      
                      {
                      
                      fn.book("nodejs从入门到实践")}}
          

4.1 配置koa服务

npm install koa-nunjucks-2 -g

npm i koa koa-router koa-nunjucks-2 -S

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名设置,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    ctx.body = "hello";
})
app.use(router.routes())
app.listen(8000);

image-20200511151726138

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.61
Branch: branch02

commit description:a0.61(配置nunjucks的koa服务)

tag:a0.61

4.2 使用koa中的nunjucks

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    // ext已经设置后缀名了,这里就不需要重复再加后缀了
    await ctx.render("index");
})
app.use(router.routes())
app.listen(8000);

nunjucks\views\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
</body>
</html>

image-20200511152324726

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.62
Branch: branch02

commit description:a0.62(使用koa中的nunjucks)

tag:a0.62

4.3 nunjucks使用

nunjucks支持html,区别在于它给html增加了判断、循环、变量等,让html更加丰富多彩,呈现数据会非常方便。

差值表达式{ {xxx}} ,与pug一样。

html注释与html语法一致。nunjucks注释{# 我是nunjucks注释 #}

注意:只修改模版html文件,nodemon是无法监测到的,它只能监测index.js发生的变化,因此需要重启。

判断语句通过%来写

注意循环和判断结束,一定要写结束标志{% endif %}

后端:

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    // ctx.body = "hello";
    // ext已经设置后缀名了,这里就不需要重复再加后缀了
    await ctx.render("index",{
    
    
        username:"张三",
        num:3
    });
})
app.use(router.routes())
app.listen(8000);

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
</body>
</html>

image-20200511160811022

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.63
Branch: branch02

commit description:a0.63(nunjucks使用)

tag:a0.63


4.4 循环

除了判断语句,还有循环语句。

后端:

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    await ctx.render("index",{
    
    
        username:"张三",
        num:2,
        arr:[{
    
    
            name:"张三",
            age:20
        },{
    
    
            name:"李四",
            age:28
        }]
    });
})
app.use(router.routes())
app.listen(8000);

前端:

注意循环末尾一定要有结束符。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
    <ul>
        {% for item in arr %}
        <li>姓名是:{
   
   {item.name}};年龄是:{
   
   {item.age}};</li>
        {% endfor %}
    </ul>
</body>
</html>

image-20200511195317773

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.64
Branch: branch02

commit description:a0.64(nunjucks使用-for循环)

tag:a0.64


4.5 过滤器

同时还会提供内置的过滤器(类似Vue的过滤器),更多的可参考官网:

Numjucks官网

后端:

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    // ctx.body = "hello";
    // ext已经设置后缀名了,这里就不需要重复再加后缀了
    await ctx.render("index",{
    
    
        username:"张三",
        num:2,
        arr:[{
    
    
            name:"张三",
            age:20
        },{
    
    
            name:"李四",
            age:28
        }],
        str:"hello world"
    });
})
app.use(router.routes())
app.listen(8000);

前端:

replace 替换对应字符串

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
    
    {
    
    username}}</p>
    <!-- 我是注释 -->
    {
    
    # 我是nunjucks注释 #}
    {
    
    % if num>3 %}
    <p>num值大于三</p>
    {
    
    % elseif num<3 %}
    <p>num值小于三</p>
    {
    
    % else %}
    <p>num值等于三</p>
    {
    
    % endif %}
    <ul>
        {
    
    % for item in arr %}
        <li>姓名是:{
    
    {
    
    item.name}};年龄是:{
    
    {
    
    item.age}};</li>
        {
    
    % endfor %}
    </ul>
    {
    
    {
    
    str | replace("world","世界")}}
</body>
</html>

image-20200511200359589


内置过滤器还可以连写功能,比如增加首字母大写:

capitalize 首字母大写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
    <ul>
        {% for item in arr %}
        <li>姓名是:{
   
   {item.name}};年龄是:{
   
   {item.age}};</li>
        {% endfor %}
    </ul>
    {
   
   {str | replace("world","世界") | capitalize}}
</body>
</html>

image-20200511200749652

注意nodemon识别不了html变化,需要重启nodemon。

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.65
Branch: branch02

commit description:a0.65(nunjucks使用-过滤器)

tag:a0.65


4.6 继承

Nunjucks比pug多一些功能,它的模版这块可以实现继承,通过block定义名称。

parent.html

<div>
    <p>我是父级模板</p>
    {% block left %}
        <p>左边内容</p><br>
    {% endblock %}
    {% block right %}
        右边内容
    {% endblock %}
</div>

son1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- 继承模版 -->
    {% extends 'parent.html' %}
     <!-- 替换模版内容 -->
    {% block left %}
        我是son1里左侧内容
    {% endblock %}
    {% block right %}
        我是son1里右侧侧内容
    {% endblock %}
</body>
</html>

后端

const Koa = require("koa");
const Router = require("koa-router");
const nunjucks = require("koa-nunjucks-2");
let app = new Koa();
let router = new Router();
// 使用nunjucks,首先需要配置
app.use(nunjucks({
    
    
    ext:"html", //后缀名,官方推荐后缀名.njk(方便区分)
    path:__dirname+"/views", // 模版目录
    nunjucksConfig:{
    
    
        trimBlocks:true //防止Xss(以前常见的攻击网站方式,如在input框写script代码)漏铜;
    }
}))
router.get("/",async ctx=>{
    
    
    // ctx.body = "hello";
    // ext已经设置后缀名了,这里就不需要重复再加后缀了
    // await ctx.render("index",{
    
    
    //     username:"张三"
    // });
    await ctx.render("index",{
    
    
        username:"张三",
        num:2,
        arr:[{
    
    
            name:"张三",
            age:20
        },{
    
    
            name:"李四",
            age:28
        }],
        str:"hello world"
    });
})
// 再加一个路由
router.get("/son1",async ctx=>{
    
    
    await ctx.render("son1");
})
 
app.use(router.routes())
app.listen(8000);

image-20200511203809824

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.66
Branch: branch02

commit description:a0.66(nunjucks使用-继承)

tag:a0.66


注意:继承变量名称得一致

son1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- 继承模版 -->
    {% extends 'parent.html' %}
    {% block left1 %}
        我是son1里左侧内容
    {% endblock %}
    {% block right1 %}
        我是son1里右侧侧内容
    {% endblock %}
</body>
</html>

image-20200511204035511

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.67
Branch: branch02

commit description:a0.67(nunjucks使用-继承变量名称不一致,生成模版默认内容)

tag:a0.67


以上是把son1的内容传到模版parent里,同样也可以把父级的内容拿到子级来使用。

parent.html

<div>
    <p>我是父级模板</p>
    {% block left %}
        <p>左边内容</p>
    {% endblock %}
    {% block right %}
        右边内容
    {% endblock %}
    {% block somevalue %}
    一些数据
    {% endblock %}
</div>

son1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- 继承模版 -->
    {% extends 'parent.html' %}
    {% block left %}
        我是son1里左侧内容
    {% endblock %}
    {% block right %}
        我是son1里右侧侧内容
    {% endblock %}
    <!-- 使用父级的内容 -->
    {% block somevalue %}
    {
   
   {super()}}
    {% endblock %}
</body>
</html>

image-20200511204858611

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.68
Branch: branch02

commit description:a0.68(nunjucks使用-把父级的内容拿到子级来使用。)

tag:a0.68

4.7 macro:宏标签

macro:宏标签 => pug中的mixin

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
    <ul>
        {% for item in arr %}
        <li>姓名是:{
   
   {item.name}};年龄是:{
   
   {item.age}};</li>
        {% endfor %}
    </ul>
    {
   
   {str | replace("world","世界") | capitalize}}
    <!-- macro:宏标签 -->
    <!-- 定义了一个pet函数 -->
    {% macro pet(name='mm',sex='m') %}
    <p>我是一只{
   
   {name}},我的性别是{
   
   {sex}}</p>
    {% endmacro %}
    <!-- 调用 -->
    {
   
   {pet("小狗","公")}}
    {
   
   {pet()}}
</body>
</html>

image-20201001120348711

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.69
Branch: branch02

commit description:a0.69(nunjucks使用-macro:宏标签)

tag:a0.69


4.8 include

其实和pug的混合模式有些类似。=> pug include

同时也可以设置默认参数。注意这里的默认参数和我们平时语言中的不一样,设置了默认值,这个参数就不能传值了。

同时和pug一样,也有include的功能:

footer.html

<h1>我是公共底部</h1>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
    <ul>
        {% for item in arr %}
        <li>姓名是:{
   
   {item.name}};年龄是:{
   
   {item.age}};</li>
        {% endfor %}
    </ul>
    {
   
   {str | replace("world","世界") | capitalize}}
    <!-- macro:宏标签 -->
    <!-- 定义了一个pei函数 -->
    {% macro pet(name="狗狗",sex) %}
    <p>我是一只{
   
   {name}},我的性别是{
   
   {sex}}</p>
    {% endmacro %}
    <!-- 调用 -->
    {
   
   {pet("小狗","公")}}
    {
   
   {pet("公")}}
    {
   
   {pet("小猫","公")}}
    {% include 'footer.html' %}
</body>
</html>

image-20200511213420977

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.70
Branch: branch02

commit description:a0.70(nunjucks使用-include)

tag:a0.70


4.9 import

同时还有import,可以引入函数(macro),数量不限。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>我是标题</h1>
    <p>用户名是:{
   
   {username}}</p>
    <!-- 我是注释 -->
    {# 我是nunjucks注释 #}
    {% if num>3 %}
    <p>num值大于三</p>
    {% elseif num<3 %}
    <p>num值小于三</p>
    {% else %}
    <p>num值等于三</p>
    {% endif %}
    <ul>
        {% for item in arr %}
        <li>姓名是:{
   
   {item.name}};年龄是:{
   
   {item.age}};</li>
        {% endfor %}
    </ul>
    {
   
   {str | replace("world","世界") | capitalize}}
    <!-- macro:宏标签 -->
    <!-- 定义了一个pei函数 -->
    {% macro pet(name="狗狗",sex) %}
    <p>我是一只{
   
   {name}},我的性别是{
   
   {sex}}</p>
    {% endmacro %}
    {% macro person(name="小明",sex) %}
    <p>我是{
   
   {name}},我的性别是{
   
   {sex}}</p>
    {% endmacro %}
    <!-- 调用 -->
    {
   
   {pet("小狗","公")}}
    {
   
   {pet("公")}}
    {
   
   {pet("小猫","公")}}
    {% include 'footer.html' %}
</body>
</html>

import.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    {% import 'index.html' as obj %}
    {
   
   {obj.pet("公")}}
    {
   
   {obj.person("男")}}
</body>
</html>

追加路由

router.get("/import",async ctx=>{
    
    
    await ctx.render("import");
})

image-20200511220004333

参考:https://github.com/6xiaoDi/blog-nodejs-novice/tree/a0.71
Branch: branch02

commit description:a0.71(nunjucks使用-import)

tag:a0.71



(后续待补充)

猜你喜欢

转载自blog.csdn.net/u013946061/article/details/109288961