前端模板swig

概述

前后端没有分离的时候,有的套模板的工作还是由后端做,因为后端方便拿数据,比如使用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 %}

参考文档

CONTENTS