模板渲染
include子模板
xss过滤
helper函数

  1. nunjucks 模板引擎,不需要安装 koa-views
    1. https://github.com/mozilla/nunjucks
    2. https://github.com/strawbrary/koa-nunjucks-2
    3. nunjucks模板语法文档 https://nunjucks.bootcss.com
  2. koa-nunjucks-2 实例返回一个中间件,这个中间件会让上下文获得一个渲染方法
    1. 从渲染方法参数上获取传递的数据(其次从 ctx.state 获取),然后使用 nunjucks 渲染模板;
    2. 根据用户配置决定是否返回HTML页面
  3. koa-nunjucks-2 的一个问题:
    1. app.use(nunjucks({})) 必须放在 app.use(router.routes()).use(router.allowedMethods()) 前面
    2. 否则会报错 ctx.render() 不是一个 function
  1. npm install nunjucks
  2. npm install koa-nunjucks-2

renderString变量

  1. 如何显示变量 {{ }}


render html

  1. 渲染文件
  2. render内部还会调用 renderString
  3. node 端,’views’ 为相对于当前工作目录 (working directory) 的路径。
    a. 在浏览器端则为一个相对的 url,最好指定为绝对路径 (如 ‘/views’)
  4. 默认后缀可以是: index.njk,index.html

filter过滤器

  1. 过滤器 | 可以执行变量的函数;通过管道符 | 调用,可以接收参数
  1. const filter = nunjucks.renderString("hello {{arr | join('123') | capitalize | replace('ok','good') }}", { arr: ['qijia', 'zhiguo', 'ok'] })
  2. console.log('filter', filter)
  3. /**
  4. * nunjucks
  5. * 中文 https://nunjucks.bootcss.com/getting-started.html
  6. * 英文 http://mozilla.github.io/nunjucks/templating.html#for
  7. */
  8. const nunjucks = require('nunjucks')
  9. const path = require('path')
  10. const views = path.resolve(__dirname, 'views')
  11. // 第一个参数:指定模板的文件夹
  12. nunjucks.configure(views, {
  13. autoescape: true
  14. })
  15. // 渲染字符串
  16. const res = nunjucks.renderString('123{{user}}', {user: 'lucy'})
  17. console.log('renderString', res) // 123lucy
  18. /**
  19. * 1 如何显示变量 {{ }}
  20. * 2 过滤器 | 可以执行变量的函数;通过管道符 | 调用,可以接收参数
  21. * 3 if 进行逻辑判断
  22. * 4 for 循环
  23. */
  24. // const filter = nunjucks.renderString("hello {{arr | join('123') | capitalize | replace('ok','good') }}", { arr: ['qijia', 'zhiguo', 'ok'] })
  25. // console.log('filter', filter)
  26. const logic = nunjucks.renderString(`
  27. {{user}}:
  28. {% if score > 90 %}
  29. 优秀
  30. {% elif score > 80 %}
  31. 良好
  32. {% elif score > 60 %}
  33. 及格
  34. {% else %}
  35. 要继续努力
  36. {% endif %}
  37. `, {
  38. user: 'lucy',
  39. score: 32
  40. })
  41. console.log('logic', logic)
  42. // 渲染 html模板:render方法内部还会调用 renderString
  43. const html = nunjucks.render('index.html', { user: 'lucy', title: 'node-numjucks'})
  44. console.log('html', html)

if 条件判断

for循环

koa-nunjucks

  1. const koa = require('koa');
  2. const app = new koa();
  3. const koaNunjucks = require('koa-nunjucks-2');
  4. const path = require('path');
  5. app.use(koaNunjucks({
  6. ext: 'html',
  7. path: path.join(__dirname, 'views'),
  8. nunjucksConfig: {
  9. trimBlocks: true
  10. }
  11. }));
  12. app.use(async (ctx) => {
  13. await ctx.render('home', {double: 'rainbow'});
  14. });

异步文件读取,需要使用 await

  1. router.get('view', async (ctx) => {
  2. var food = {
  3. 'ketchup': '5 tbsp',
  4. 'mustard': '1 tbsp',
  5. 'pickle': '0 tbsp'
  6. };
  7. await ctx.render('index',{title:'nunjucks',food});
  8. })

nunjucks原理

  1. const env = nunjucks.configure(config.path, config.nunjucksConfig);
  2. env.renderAsync = bluebird.promisify(env.render);
  1. return async (ctx, next) => {
  2. if (ctx[config.functionName]) {
  3. throw new Error(`ctx.${config.functionName} is already defined`);
  4. }
  5. /**
  6. * @param {string} view
  7. * @param {!Object=} context
  8. * @returns {string}
  9. */
  10. ctx[config.functionName] = async (view, context) => {
  11. const mergedContext = merge({}, ctx.state, context);
  12. view += config.ext;
  13. return env.renderAsync(view, mergedContext)
  14. .then((html) => {
  15. if (config.writeResponse) {
  16. ctx.type = 'html';
  17. ctx.body = html;
  18. }
  19. });
  20. };
  21. await next();
  22. };

在创建 koa-nunjucks-2 中间件时,可以传递文件后缀 ext ,渲染方法名 functionName ,以及 nunjucks 的配置信息 nunjucksConfig

  1. const express = require('express')
  2. const app = express()
  3. // req请求对象 ; res相应对象
  4. app.get('/list', (req, res) => {
  5. const obj = {name: 'lucy'}
  6. res.json(obj)
  7. })
  8. app.listen(3000, () => {
  9. console.log('ok')
  10. })
  11. req.query // 获取 GET参数
  12. req.method // 请求方式
  13. req.path //
  14. app.get()
  15. app.post()
  16. app.put()
  17. 无论使用哪种请求方式,服务端都能响应
  18. app.all() // 忽略请求方式
  19. app.all('*', (req, res) => {
  20. res.json({
  21. uri: req.path,
  22. method: req.method
  23. })
  24. })
  25. app.use() // 中间件,路由注册