NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

了解JavaScript模板引擎

| Comments

模板引擎这个概念,相信对大家并不陌生,如果做过Java EE的开发,或者Rails开发,那么Jsp,Erb,Haml都是一种模板引擎,也许你还听说过Apache的velocity,只不过它们是后端的模板引擎,模板的渲染由服务器端完成。

比如这样的代码:

1
2
3
4
5
//Jsp With EL
<div>user name: ${userName}</div>

//Haml
%div = "user name: #{userName}"

JavaScript模板引擎,顾名思义,它也是一种模板引擎,只不过由JavaScript实现,是一种前端或者说是客户端的模板引擎。

这个时候,也许你要问了,为什么需要前端模板引擎,它有什么作用?

其实,它的作用和后端的模板引擎作用相似,所以还是回归到了模板引擎的作用。

不知道,大家知不知道JavaEE(J2EE)的发展历程,基本过程是CGI-Servlet-JSP-Model1-Model2,再到之后的MVC。

如果你感兴趣,可以看我的这篇文章: http://benweizhu.github.io/blog/2013/12/21/web-mvc-by-example-with-spring-mvc/

关于后端模板引擎(JSP)

在纯Servlet的开发年代,这样的web开发流程都在实现一个servlet类的实例,也就是无论是业务逻辑还是前端显示,都是放在Servlet类中来完成,通过实现doGet和doPost的方法,来完成前端参数的获取和视图的渲染。

这样做的缺点是表现逻辑、控制逻辑和业务逻辑全部写在了Java类中,导致逻辑非常混乱。

JSP的出现改变了这一现状,它是一种后端模板引擎,它由Sun和许多公司参与共同创建的一种使软件开发者可以响应客户端请求,而动态生成HTML、XML或其他格式文档的Web网页的技术标准。

JSP将前端的表现逻辑(用户界面)与后端的业务逻辑相分离,于是,你就可以像这样,动态渲染前端显示内容:

1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>helloWorldConfirm</title>
</head>
<body>
 hi,${user.name}
</body>
</html>

将前端表现逻辑和后端业务逻辑分离是模板引擎出现的最主要的原因。

那什么情况或者说场景下,我们要使用到JavaScript模板引擎呢?

1.通过ajax获取数据,再封装成视图展现到前端
2.经常遇到字符串拼接
3.需要抽取动态的公共模块,以实现重用
等等

那么,目前有哪些比较常见的JavaScript模板引擎呢?

答案是好多,百度或者谷歌搜索,你会得到很多答案。举一个,最近在看的类库的例子,handlebarsjs:

1
2
3
4
5
6
7
8
9
<div id="replace"></div>
<script id="entry-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>{ {title} }</h1>
    <div class="body">
      { {body} }
    </div>
  </div>
</script>
1
2
3
4
5
6
7
8
9
10
(function() {
  var source = $("#entry-template").html();//获取到模板内容
  var template = Handlebars.compile(source);//编译模板
  var context = {
    title: "My New Post",
    body: "This is my first post!"
  };
  var html = template(context);//传入Json对象,替换模板中的内容
  $("#replace").html(html);
}());

See the Pen handlebarsjs example by Benwei (@benweizhu) on CodePen.

你肯定会有些疑问,比如,在HTML中下面这段代码是干什么的?

1
<script type = text/template>  </script>

这段代码最常用的位置是实现客户端模板功能,通过将类型设置成为“text/template”,它变成了一段浏览器不能解释的脚本代码,所以浏览器就会忽略这段脚本。这样,就允许你在这段脚本片段中存放任何东西,存放的内容可以再之后由JavaScript抽取提供给一个模板库来生产HTML片段。

至于,剩余的函数是干什么的已经在代码中注释了,这里就不多解释。

问题又来了,Handlebars是来源于另外一个有名的模板引擎Mustache,

Mustache声明自己是一个logic-less(无逻辑或轻逻辑)语法模板。那么,什么是logic-less,有什么好处?其实答案在stackoverflow有人回答。参考: http://stackoverflow.com/questions/3896730/whats-the-advantage-of-logic-less-template-such-as-mustache

简单来说,比如在JSP中,提供了很多的taglib,实现了如if,loop(循环)等逻辑标签。这样就导致,在纯粹的前端显示代码中,仍然存在许多的逻辑判断和操作。

Mustache从设计上就不允许这样的操作,逼迫你在前端页面不要有任何逻辑的代码。但其实,这一点很难做到。

即便是基于Mustache的Handlebars,也提供了if和loop的语法(代码块中的两个大括号加了空格,只是为了博客中可以显示):

1
2
3
4
5
6
7
8
{ {permalink} }
{ {#each comments} }
  { {../permalink} }

  { {#if title} }
    { {../permalink} }
  { {/if} }
{ {/each} }

关于模板引擎的框架还有很多,大家可以自己去搜索,我也可以给一个链接作为参考:http://www.imooc.com/article/1219 。当然谁好谁坏,众说风云,只有你用了才能知道适不适合你。

参考资料
1.http://handlebarsjs.com

重温SASS基础

| Comments

最早因为Bootstrap接触到了LESS,但LESS随着时间,使用的人越来越少,大家都开始转向SASS,至于为什么,原因很多,大家可以去网上搜索,有很多人都对比了LESS和SASS。今天主要是来回顾SASS的基础知识。

CSS很好,但是随着stylesheets的内容增多,变得越来越复杂,也越来越难以维护。此时,CSS预处理器横空出世,SASS就是其中一种。

SASS允许你做许多在CSS中做不了的事情,比如:变量,网状结构(接近DOM结构),mixin,继承等。

变量

Sass使用$符号定义变量,就和其他编程语言一定,它可以被赋值和重复使用。

1
2
3
4
5
6
7
$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

网状结构

Sass比CSS强大的一点是,可读性好,CSS有后代选择器和权重的知识,它们与DOM结构息息相关,但是CSS本身却没有很好的语法结构来反映这种结构,Sass做到了这一点。

Sass让你的css选择器符合真实的HTML层次结构,当然Sass官方也提示如果过度的使用网状结构,也会导致CSS很难维护。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

上面的例子中,ul和li是在nav结构之中的。

通过Partial和Import来做模块化

CSS本身也是有import功能的,但是缺点是,它会在页面中单独发送一个Http请求来获取这个import进来的css。

Sass是一个CSS预处理器,它的import是建立在编译过程中,将两个或者多个文件合并,所以机制完全不同。

比如,有_reset.scss和base.scss两个文件,注意,定义Partial的sass文件是以下划线开头的。

1
2
3
4
5
6
7
8
9
// _reset.scss

html,
body,
ul,
ol {
   margin: 0;
  padding: 0;
}
1
2
3
4
5
6
7
8
// base.scss

@import 'reset';

body {
  font: 100% Helvetica, sans-serif;
  background-color: #efefef;
}

Mixins

Mixins是一个非常有用的功能,Mixins允许你将一组css定义在不同的位置重用,而且还可以像函数一样传递变量。

1
2
3
4
5
6
7
8
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
}

.box { @include border-radius(10px); }

Extend/Inheritance继承

通过@extend关键字,你可以让一系列的在某个选择器中css属性,在另一个css选择器中继承,也是重用css定义的一种模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.message {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

.success {
  @extend .message;
  border-color: green;
}

.error {
  @extend .message;
  border-color: red;
}

.warning {
  @extend .message;
  border-color: yellow;
}

Operators操作符/运算符

Sass可以轻易的进行数学运算,+, -, *, /, %

1
2
3
4
5
6
7
8
9
10
11
.container { width: 100%; }

article[role="main"] {
  float: left;
  width: 600px / 960px * 100%;
}

aside[role="complimentary"] {
  float: right;
  width: 300px / 960px * 100%;
}

Data Types有用的数据类型

SassScript支持七种主要的数据类型

numbers (e.g. 1.2, 13, 10px)
strings of text, with and without quotes (e.g. “foo”, ‘bar’, baz)
colors (e.g. blue, #04a3f9, rgba(255, 0, 0, 0.5))
booleans (e.g. true, false)
nulls (e.g. null)
lists of values, separated by spaces or commas (e.g. 1.5em 1em 0 2em, Helvetica, Arial, sans-serif)
maps from one value to another (e.g. (key1: value1, key2: value2))

比如:map

1
$map: (key1: value1, key2: value2, key3: value3);

参考文献:
1.SASS官方文档