概述
前后端没有分离的时候,有的套模板的工作还是由后端做,因为后端方便拿数据,比如使用freemarker。如果让前端去做,还得自己搭建后端环境,如 maven依赖freemarker包等非前端的知识。团队越来越大后,数据展示还是适合由前端做,后端专注于提供RESTful的API。
Node出现前,如果完全的前后分离,前端通过后端API返回的数据自己渲染,但无法做搜索引擎优化。有了node后,可以让node请求数据做模板渲染,最终返回给用户端,这是目前比较流行的做法。 图片引用于1
前端模板很多如Jade、EJS、Swig,本文简单介绍下Swig的使用。swig类似python使用的Jinja模板,简单,和Express 兼容,支持继承,支持循环条件判断,灵活而强大。
swig 起步
先简单搭建一个node + express 示例:
mkdir swig && cd swig
npm init
npm install express swig cookie-parser morgan serve-favicon --save
node application 脚本:app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var swig = require('swig');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup swig
swig.setDefaults({cache:false});
app.set('view cache', false);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
app.engine('html',swig.renderFile);
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/user', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(8080);
module.exports = app;
cat routes/users.api
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/user', function(req, res, next) {
res.render('user', {
"username": "henry",
"age": 25,
"email": "xxx@gmail.com",
"blog": "http://thoreauz.com",
"hobbies": [
"music",
"writing",
"photography"
],
"education": {
"school": "MIT",
"degree": "Master"
}
});
});
module.exports = router;
router返回数据给模板引擎渲染,关键代码
rse.reder('view name', data)
swig模板编写:views/ layout.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }}</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
{% block content %}
{% endblock %}
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
title使用变量,定义了一个block content
。
user模板如下:user.html
{% extends 'layout.html' %}
{% block title %}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ username }}</h1>
hobbies:
<div class="row">
<ul class="list-style">
{% for hobby in hobbies %}
<li>{{ hobby }}</li>
{% endfor %}
<ul>
</div>
</div>
{% endblock %}
使用extends集成layout,重写title,重写父模块centent。
下面启动node:
node app.js
## 浏览器访问 http://localhost:8080/user/user
swig 语法
变量使用
{{ var }}
{{ foo.name }}
{{ foo['name'] }}
标签
block 定义一个块,使之可以被继承的模板重写,或者重写父模板的同名块 。
<title>{% block title %}My Site{% endblock %}</title>
extends 使当前模板继承父模板,相对路径:
{% extends 'layout.html' %}
include 包含一个模板到当前位置,这个模板将使用当前上下文:参数-file
{% include "a.html" %}
{% include "template.js" %}
set
设置一个变量,在当前上下文中复用
{% set foo = [0, 1, 2, 3, 4, 5] %}
{% for num in foo %}
<li>{{ num }}</li>
{% endfor %}
logic tag
{% if foo %}bar{% endif %}
{% for person in people %}
{% if loop.first %}<ol>{% endif %}
<li>{{ person.name }}</li>
{% if loop.last %}</ol>{% endif %}
{% endfor %}
参考文档