验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

Express框架view对象如何使用

阅读:772 来源:乙速云 作者:代码code

Express框架view对象如何使用

      Expess View 从指定渲染引擎开始

      以 mustache 渲染引擎为例,需要初始化一些代码

      const app = express()
      app.set("view engine", "mustache");
      app.engine("mustache", mustacheExpress());
      app.set("views", toAbsolutePath("./views"));
      • 指定视图引擎

      • 指定引擎工具

      • 指定视图位置

      安装依赖

      pnpm install mustache mustache-express

      从 res.render 函数开始

      render 函数接收两个参数,第一个 view 的路径,第二个渲染数据。

      res.render = function render(view, options, callback) {
         // 调用 app.render
        app.render(view, opts, done);
      };

      下面是 app.render 代码实现

      app.render = function render(name, options, callback) {
        // view
        if (!view) {
          var View = this.get('view');
          view = new View(name, {
            defaultEngine: this.get('view engine'),
            root: this.get('views'),
            engines: engines
          });
          if (!view.path) {
            var dirs = Array.isArray(view.root) && view.root.length > 1
              ? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
              : 'directory "' + view.root + '"'
            var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
            err.view = view;
            return done(err);
          }
          // prime the cache
          if (renderOptions.cache) {
            cache[name] = view;
          }
        }
        // render
        tryRender(view, renderOptions, done);
      };

      在 view 不在的情况下,会用 View 实例化 view, 最后调用 tryRender 函数,tryRender 函数会调用 view.render 方法:

      View 的实现

      module.exports = View;
      function View(name, options) {
        // store loaded engine
        this.engine = opts.engines[this.ext];
        // lookup path
        this.path = this.lookup(fileName);
      }

      跟一般的构造函数一样,初始化一些属性,用传入的 opts 合并一些属性。

      • View 扩展方法

      View.prototype.lookup = function lookup(name) {}
      View.prototype.render = function render(options, callback) {
          this.engine(this.path, options, callback);
      }
      View.prototype.resolve = function resolve(dir, file) {}

      render 的具体实现就交给第三方引擎来实现了。

      mustache 的render 方法的实现

      Writer.prototype.render = function render (template, view, partials, config) {
        var tags = this.getConfigTags(config);
        var tokens = this.parse(template, tags);
        var context = (view instanceof Context) ? view : new Context(view, undefined);
        return this.renderTokens(tokens, context, partials, template, config);
      };

      render 函数调用 renderTokens 方法来解析,具体 renderTokens 方法的实现,就不做深入的分析了。

      一个案例切图案例

      需求是这样的,后端使用费 Node.js 开发,没有 JS 运行时,为了能够快速的完成项目,页面的切头由前端完成。此时页面多,任务重,React/Vue 这种现代框架,需要服务端渲染,后端不想用 Node.js,增加复杂度。因为前端 Node.js 能够使用模板渲染,并且模板种类很多,模板能够解决复用的问题,所以前端功能化能够解决,现代前端能结局的问题。

      使用 exprss 服务 + mustache 模板引擎为基础实现一个简单的切图服务

      • Express 创建服务和路由

      • Nodemon 监听文件变化,重新启动路由

      • esno + TypeScript + es Module 编写服务端代码

      • prettier 格式化文件

      在 express 中使用 mustache

      import express from "express";
      import mustacheExpress from "mustache-express";
      app.engine("mustache", mustacheExpress());
      app.set("view engine", "mustache");
      app.set("views", toAbsolutePath("./views")); // 指定视图路径
      • 渲染一个视图

      app.get(url, async (_, res) => {
          res.render(url, data);
      });

      mustache 拆分模板的基本能用法

      • 定义模板文件

      • 引用模板文件,以及引入文件下的模板的方法

      • 在模板中使用变量

      • 条件判断

      • 列表渲染

      mustache 官方 Github 仓库,需要研究的可以自己访问学习,更多具体的用法。

      示例

      形成一个约定:因为只做简单的切图工作,view + data 文件使用 render 函数渲染的时候一一对应,这样就减少了很多的样板代码。 ·

      • main.server.ts

      读取 views/ 文件夹下的所有视图文件,布局文件不包含(简化),将 /static 目录设置为静态文件夹目录。路由不在单独的写了,此处统一处理为与视图相同命名用于简单的渲染。

      // express
      import express from "express";
      import mustacheExpress from "mustache-express";
      // config
      import cutConfig from "./cut.config";
      import defineVars from "iesmo";
      // node
      import { resolve } from "path";
      import fs from "node:fs";
      const { __dirname } = defineVars(import.meta);
      export const toAbsolutePath = (p) => resolve(__dirname, p);
      const routes = fs
        .readdirSync(toAbsolutePath("./views/"))
        .map((file) => {
          if (!/.mustache$/.test(file)) return null;
          return file.replace(/.mustache$/, "").toLowerCase();
        })
        .filter((i) => i !== null);
      const app = express();
      app.engine("mustache", mustacheExpress());
      app.set("view engine", "mustache");
      app.set("views", toAbsolutePath("./views"));
      app.use("/static", express.static("static"));
      routes.forEach((route) => {
        let url = route === "index" ? "/" : `/${route}`;
        app.get(url, async (_, res) => {
          let data = (await import(`./data/${route}.ts`)).default;
          res.render(route as string, data);
        });
      });
      app.listen(cutConfig.port, () => {
        console.log("server listening on port: ", cutConfig.port);
      });

      以 index.mustache 模板为示例:

      数据存在 /data 文件夹下,默认输出一个 JS 对象

      
      
        
          
          
          
          {{{title}}}
          {{#links}} 
          
          {{/links}}
          {{#scriptsHead}}
          
          {{/scriptsHead}}
        
        
          {{>tpls/list }}
          {{>layout/footer}}
          {{#scriptBody}}
          
          {{/scriptBody}}
        
      
      • {{{title}}} 插入数据

      • 根据 html 渲染出数据

      {{#links}}
      
      {{/links}}
      • 使用文件夹中的模板

      
          {{>tpls/list }}
          {{>layout/footer}}
        

      以上行为表示 tpls 目录下的 list 模板文件和 layout 目录下的 footer 模板文件

    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>