由于最近项目对于首屏渲染速度的要求比较高,之前项目中使用的是nuxt框架,但由于其本身加载的时候,需要额外加载该框架的一些底层js,导致页面会等待其加载成功后,才会开始加载其他东西。一开始使用纯静态页面作为首页进行测试,发现首屏效果提升明显。美中不足的是静态页面无法动态配置页面属性,因此需要使用最直接的服务端渲染,减少加载其他资源。因此最终确认了使用Express-Handlebars的方案
1、安装express 和 Handlebars
yarn init
yarn add express -d
npx express-generator --view=express-handlebars
yarn install
安装成功,如图所示。view里面没有默认的视图,此时视图模板引擎还没有,因为该模板引擎不是官方默认的,需要另外安装
执行如下指令,就可以安装对应handlebars的引擎
yarn add express-handlebars -d
2、引入express-handlebars
在app.js下进行设置,如下代码
var exphbs = require('express-handlebars');
console.log(exphbs)
app.engine('hbs', exphbs.engine({
helpers: {
},//工具函数
layoutsDir: 'views',//视图
defaultLayout: 'layouts/main',//默认布局文件
extname: '.hbs'//视图后缀名
}));
app.set('view engine', 'hbs');//设置对应的视图引擎
app.set('views', './views');// 视图文件的位置
3、初步测试使用
- 1、创建views/layouts/main.hbs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Example App</title>
</head>
<body>
1111111
{{{body}}}
</body>
</html>
- 2、创建views/layouts/main.hbs
{{title}}
- 3、在routes/index.js下,代码如下
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
运行后,效果如图所示:
4、handlebarsjs常用语法
- 1、一般使用{{}}输出变量,{{{}}}输出没有转义的变量
模板:
{{title}}
{{obj.category}}
数据:
{
title: 'Express',
obj:{
category: 'handlebars',
}
}
页面:
Express
handlebars
- 2、常用的默认助手函数if 、each、with、lookup
if:注意,使用if判断的时候,后面不能跟表达式,只能跟变量和助手函数。如果其参数返回
false、undefined、null、""、0或者[],Handlebars 将不会渲染该块
模板:
{{#if }}
{{showtext}}
{{/if}}
数据:
{
show: true,
showtext:"展示"
}
页面:
展示
each:注意,当遍历 each 中的项目时,你可以选择通过 {{@index}} 引用当前循环的索引。要访问父级的索引,可以使用 {{@../index}}
模板:
<ul class="people_list">
{{#each people}}
<li>{{this}}</li>
{{/each}}
</ul>
数据:
{
people: [
"Yehuda Katz",
"Alan Johnson",
"Charles Jolley",
],
}
页面:
<ul class="people_list">
<li>Yehuda Katz</li>
<li>Alan Johnson</li>
<li>Charles Jolley</li>
</ul>
with:允许你更改 template-part 的上下文表达式
模板:
{{#with person}}
{{firstname}} {{lastname}}
{{/with}}
数据:
{
person: {
firstname: "Yehuda",
lastname: "Katz",
},
}
页面:
Yehuda Katz
lookup:允许使用 Handlebars 变量进行动态的参数解析。这对于解析数组索引的值非常有用。
模板:
{{#each people}}
{{.}} lives in {{lookup ../cities @index}}
{{/each}}
数据:
{
people: ["Nils", "Yehuda"],
cities: [
"Darmstadt",
"San Francisco",
],
}
页面:
Nils lives in Darmstadt
Yehuda lives in San Francisco
- 3、自定义助手函数 可以在设置引擎的时候设置,就会变成全局调用。也可以在对应路由设置
app.engine('hbs', exphbs.engine({
helpers: {
getOneFromList(list) {
if (list && list.length > 0) {
return list[0]
} else {
return null
}
},
compareEqual(obj1, obj2) {
return obj1 === obj2
},
compareLessThanOrEqual(obj1, obj2) {
return obj1 <= obj2
}
},
layoutsDir: 'views',
defaultLayout: 'layouts/main',
extname: '.hbs'
}));
调用方式跟变量的一样,但是参数后面不需要加括号,空格分开
{{getOneFromList list}}
- 5、设置部分视图,可以在if,each,等块级助手函数中直接调用,需要在文件夹partials/card/grid下设置,代码如下
{{> card/grid category=category }}
直接在文件夹partials/grid下设置的话,引用代码如下
{{> grid category=category }}
其中category 是该部分视图组件里的变量
- 6、也可以自定义块级助手函数,直接引用
模板:
{{#list people}}{{firstname}} {{lastname}}{{/list}}
数据及助手函数:
router.get('/', function (req, res, next) {
res.render('index', {
people: [
{
firstname: "Yehuda",
lastname: "Katz",
},
{
firstname: "Carl",
lastname: "Lerche",
},
{
firstname: "Alan",
lastname: "Johnson",
},
],
helpers: {
list(items, options) {
const itemsAsHtml = items.map(item => "<li>" + options.fn(item) + "</li>");
return "<ul>\n" + itemsAsHtml.join("\n") + "\n</ul>";
}
}
});
});
页面:
<ul>
<li>Yehuda Katz</li>
<li>Carl Lerche</li>
<li>Alan Johnson</li>
</ul>
5、dotenv
yarn add dotenv -d
在项目根目录中,创建.env文件,在app.js入口文件设置后,就可以直接引用环境变量
require('dotenv').config();// 设置环境变量
直接通过process.env.GOOGLE_ADSENSE_ID就可以引用
6、最终效果图
默认处于首屏的导航栏图片,按照顺序排列,前两个索引的卡片是不做懒加载的。