发布时间:
这里只列出 CmsWing 特有的,更详细的内容请阅读 Egg.js 文档 View 模板渲染
绝大多数情况,我们都需要读取数据后渲染模板,然后呈现给用户。故我们需要引入对应的模板引擎,这里我们使用的是 Nunjuck。
模板目录 app/view
,我们推荐您如果开发自己的应用,请以您的目录名称放置您的模板文件。比如官方的cms的模板文件都放置在 app/view/cms
目录下。
框架在 Context 上提供了 3 个接口,返回值均为 Promise:
render(name, locals)
渲染模板文件, 并赋值给 ctx.bodyrenderView(name, locals)
渲染模板文件, 仅返回不赋值renderString(tpl, locals)
渲染模板字符串, 仅返回不赋值// {app_root}/app/controller/home.js
class HomeController extends Controller {
async index() {
const data = { name: 'cmswing' };
// render a template, path relate to `app/view`
await ctx.render('home/index', data);
// or manually set render result to ctx.body
ctx.body = await ctx.renderView('path/to/file', data);
// or render string directly
ctx.body = await ctx.renderString('hi, {{ name }}', data, {
viewEngine: 'nunjucks',
});
}
}
在渲染页面的过程中,我们通常需要一个变量来收集需要传递给模板的变量,在框架里面,我们提供了 app.locals
和 ctx.locals
。
app.locals
为全局的,一般在 app.js
里面配置全局变量。ctx.locals
为单次请求的,会合并 app.locals
。// `app.locals` 会合并到 `ctx.locals
ctx.app.locals = { a: 1 };
ctx.locals.b = 2;
console.log(ctx.locals); // { a: 1, b: 2 }
// 一次请求过程中,仅会在第一次使用 `ctx.locals` 时把 `app.locals` 合并进去。
ctx.app.locals = { a: 2 };
console.log(ctx.locals); // 上面已经合并过一次,故输出还是 { a: 1, b: 2 }
// 也可以直接赋值整个对象,不用担心会覆盖前面的值,我们通过 setter 做了自动合并。
ctx.locals.c = 3;
ctx.locals = { d: 4 };
console.log(ctx.locals); // { a: 1, b: 2, c: 3, d: 4 }
但在实际业务开发中,controller 中一般不会直接使用这 2 个对象,直接使用 ctx.render(name, data)
即可:
data
合并到 ctx.locals
。ctx
, request
, helper
方便使用。ctx.app.locals = { appName: 'showcase' };
const data = { name: 'egg' };
// will auto merge `data` to `ctx.locals`, output: egg - showcase
await ctx.renderString('{{ name }} - {{ appName }}', data);
// helper, ctx, request will auto inject
await ctx.renderString(
'{{ name }} - {{ helper.lowercaseFirst(ctx.app.config.baseDir) }}',
data,
);
注意:
ctx.state
,由于容易产生歧义,在框架中被覆盖为 locals,即 ctx.state
和 ctx.locals
等价,我们建议使用后者。在模板中可以直接使用 helper
上注册的方法
// app/extend/helper.js
exports.lowercaseFirst = (str) => str[0].toLowerCase() + str.substring(1);
// app/controller/home.js
await ctx.renderString('{{ helper.lowercaseFirst(name) }}', data);
我们在应用开发中可以使用模板标签直接在html中调取数据
在编写标签条件时 如果遇到两个连个花括号连写 比如 {where:{id:1}} 请用空格或者换行隔开,因为}}会跟 Nunjuck标签冲突,
错误例子
<!-- {where:{id:3}} 3后面的两个 }} 没有用空格隔开会报错 -->
{%set memeber = 'mc_member'|@findOne({where:{id:3}})%}
正确例子
<!--用空格隔开-->
{%set memeber = 'mc_member'|@findOne({where:{id:3} })%}
<!--或者换行-->
{%set memeber = 'mc_member'|@findOne({
where:{id:3}
})%}
@findAll 同等于 sequelize 的 findAll,具体可以参考sequelize文档 它生成一个标准的 SELECT
查询,该查询将从表中检索所有条目(除非受到 where
子句的限制).
比如要调取 cms_doc表内 classify_id等于 2的并且 position 字段是 '1,2,3' 这样的存储格式,需要postition 等于1,调取10条,并且要关联cms_classify表。
{% set position = 'cms_doc'|@findAll({
include : 'cms_classify',
where:{
classify_id:2,
FIND_IN_SET:['position',1]
},
offset: 0,
limit: 10
})%}
比如要调取所id大于3的用户
{% set memeber = 'mc_member'|@findAll({
where:{
id:{op_gt:3}
}
})%}
{%for item in memeber%}
....
{%endfor%}
上面代码 大于3 在Sequelize中的默认操作符是 {[Op.gt]: 3} 在 cms模版标签中是{op_gt:3},操作法对映如下,具体可以参考 Sequelize操作符
operatorsAliases: {
op_eq: Op.eq, //等于
op_ne: Op.ne, //不等于
op_gte: Op.gte,//大于等于
op_gt: Op.gt,//大于
op_lte: Op.lte,//小于等于
op_lt: Op.lt,//小于
op_not: Op.not, //NOT
op_in: Op.in, //IN
op_notIn: Op.notIn
op_is: Op.is,
op_like: Op.like,
op_notLike: Op.notLike,
op_iLike: Op.iLike,
op_notILike: Op.notILike,
op_startsWith: Op.startsWith,
op_endsWith: Op.endsWith,
op_substring: Op.substring,
op_regexp: Op.regexp,
op_notRegexp: Op.notRegexp,
op_iRegexp: Op.iRegexp,
op_notIRegexp: Op.notIRegexp,
op_between: Op.between,
op_notBetween: Op.notBetween,
op_overlap: Op.overlap,
op_contains: Op.contains,
op_contained: Op.contained,
op_adjacent: Op.adjacent,
op_strictLeft: Op.strictLeft,
op_strictRight: Op.strictRight,
op_noExtendRight: Op.noExtendRight,
op_noExtendLeft: Op.noExtendLeft,
op_and: Op.and,
op_or: Op.or,
op_any: Op.any,
op_all: Op.all,
op_values: Op.values,
op_col: Op.col,
},
@findOne
方法获得它找到的第一个条目(它可以满足提供的可选查询参数).
查询 id =3的用户
{%set memeber = 'mc_member'|@findOne({
where:{id:3}
})%}
{{memeber|dump}}
用户中心(MC)菜单标签
{% set menu=ctx.userInfo.uuid|@mc_menu %}
{%for item in menu%}
<li
class="nav-item {%if (item.path ==ctx.url) or (ctx.url in (item.arrPath or [])) %}active{%endif%}">
{%if item.children%}
<a class="nav-link px-0" href="#">
<span class="group-icon">
<i class="fi fi-arrow-end"></i>
<i class="fi fi-arrow-down"></i>
</span>
<span class="px-2 d-inline-block"> {{item.name}} </span>
</a>
{%else%}
<a class="nav-link px-0" href="{{item.path}}">
<i class="fi fi-arrow-end m-0 smaller"></i>
<span class="px-2 d-inline-block"> {{item.name}} </span>
</a>
{%endif%} {%if item.children%}
<ul class="nav flex-column ps-2">
{%for _item in item.children%}
<li class="nav-item {%if _item.path ==ctx.url%}active{%endif%}">
<a class="nav-link" href="{{_item.path}}"> {{_item.name}} </a>
</li>
{%endfor%}
</ul>
{%endif%}
</li>
{%endfor%}
最后更新时间: 2023-12-08 08:13:07