Fork me on GitHub

Silky的模板

本文目标

指导用户如何如何使用模板功能

综述

模板最主要的目的就是为了代码重用,模块化开发的好处不言而喻。Silky使用Handlebars作为默认的模板引擎,更多的Handlebars相关的文档与介绍,请点击英文官网 或者 中文教程

新手用户

默认情况下,Silky会创建一个template的文件夹,所以的模板和html文件都应该放在template文件夹中。模板文件应该以.hbs为扩展名,需要被引用的模板文件建议放在template/module文件夹下。

例如我们现在有一个首页index.hbs,一个页头文件header.hbs,一个页脚文件footer.hbs,那么我们应该将header.hbsfooter.hbs文件放到template/module文件夹下。

在Silky的示例项目中,目录结构如下:

├── css
│   ├── main.less
│   ├── module
│   │   └── global.less
│   └── normalize.css
├── images
│   └── logo.png
├── images-demo
│   └── logo.png
├── js
│   ├── main.coffee
│   └── vendor
└── template
    ├── index.hbs
    └── module
        ├── cell.hbs
        ├── footer.hbs
        ├── head.hbs
        └── header.hbs

index.hbs文件我们可以这样写:

<!DOCTYPE html>
<html>
    {{import "module/head"}}
    <body>
        {{import "module/header"}}
        <!--其它内容-->
        {{import "module/footer"}}
    </body>
</html>

{{import "module/header"}}可以引入module文件夹下的header.hbs,当然Silky也支持相对路径,比如说像这样:{{import "./module/header"}}

模板指令

模板指令也称之为模板表达式,你可以通过调用一些命令来实现某些特殊的功能,例如循环each,引用子模板import,我们把这些命令称之为指令。一个典型的指令通常是这样的:{{command 参数1 参数二}},其中command为要执行的指令,后面为具体的参数,指令与参数以及参数之前用空格分隔。参数可以是字符,也可能是.silky/data下的数据文件。

如果你希望输出HTML内容,那么你需要这样使用:{{{command '<div>HTML内容</div>'}}}

引用数据

在Silky中,数据和模板是可以分开的,数据被放在.silky/data目录下。通常我们将数据放在.silky/data/normal文件夹下。假如文件.silky/data/normal/global.js的内容如下:

module.exports = {
    "title": "Silky",
    "footer": {
        "copyright": "Copyright(at)Silky"
    }
}

那么在index.hbs中,我们可以这样引用:

<!DOCTYPE html>
<html>
    <title>{{global.title}}</title>
    <body>

    </body>
</html>    

最终生成的代码为:

<!DOCTYPE html>
<html>
    <title>Silky</title>
    <body>

    </body>
</html>    

当你在模板中使用{{global.title}}进行数据引用的时候,Silky会找到.silky/data/normal/global.js这个文件,然后将该文件中的title节点插入到模板中。

换句话说,如果你再创建一个数据文件.silky/data/normal/custom.js,然后在模板中你的引用方式应该是{{custom.something}},如果你不确定引用是否正确,可以使用{{print custom}}来打印这个数据。

当然我们还可能会使用到多环境的数据引用,更多请参考:Silky中的多环境与数据文件的引用

js与css文件引用

在Silky中,我们像平时一样引用js/css文件即可,但如果你在项目中使用了coffee或less,引用的文件名同样是.js.css,因为Silky会自动处理,如果没有找到.css文件,就会查找.less文件,对于js的规则也是同样的。

例如有如下引用:

<link rel="stylesheet" href="/css/main.css" type="text/css" charset="utf-8" />

Silky会先查找/css/main.css文件,如果没有找到此文件,那么Silky会再尝试查找/css/main.less并编译输出。

进阶用户

常用的Handlebars指令

#each

循环指令,例如:

数据文件.silky/data/normal/global.js

module.exports = {
    "projects": [
        {project: 'Silky'},
        {project: 'charm.js'}
    ]
}

模板文件:

<ul>
    <li class="title">项目列表</li>
    {{#each global.projects}}
        <li>{{project}}</li>
    {{/each}}
</ul>

输出:

<ul>
    <li class="title">项目列表</li>
    <li>Silky</li>
    <li>charm.js</li>
</ul>

#if

条件判断语句,例如

{{#if true}}
    条件为真
{{else}}
    条件为假
{{/if}}

unless

只有在条件为false的时候才输出,等同于else,下面两例

使用if/else

{{#if condition}}

{{else}}
    条件为假
{{/if}}

使用unless

{{unless condition}}
    条件为假
{{/unless}}

@index

在使用#each进行循环输出的时候,你可以使用@index来获取索引

Silky扩展指令

import

引用子模板,支持相对路径和绝对路径,支持指定数据源,不需要指定.hbs扩展名。早前版本的Silky使用了partial指令,现在应当使用importpartial未来将会被抛弃。

使用示例:

  • {{import “module/header”}},引用子模板,使用绝对路径
  • {{import “../header”}},引用子模板,使用相对路径
  • {{import “module/header” data "value1" true 1}},引用子模板,允许传递多个参数。而在子模板就可以使用$0,$1,$...来取得该参数。在这里,$0即是data的值,$1的值为true。

例如我们现在在数据库globa.js的文件格式如下:

module.exports = {
    "title": "Silky",
    "footer": {
        "copyright": "Copyright(at)Silky"
    }
}

index.bhs文件:

<!DOCTYPE html>
<html>
    {{import "module/head"}}
    <body>
        <!--其它内容,第二个参数中,我们指定数据源为global.footer-->
        {{import "module/footer" global.footer "myClass"}}
    </body>
</html>        

module/footer.hbs文件:

<footer>
    Copyright &copy; <a href="http://example.com/" target="_blank" class="{{$1}}">{{$0.copyright}}</a>
</footer>

注意!

在早期的Silky版本中,只允许传递一个参数,并且调用子模板时传递的参数会改变子模板的变量作用域,建议升级到0.8.10或以上版本。

css

引入 css文件,可以实现批量引入,有如下的用法:

  • {{css "main.css"}} 直接引入css文件,此处引用main.css,你也可以在路径参数中添加变量。例如:{{css "<global.root>/main.css"}},此时<global.root>表示.silky/data/normal/global.js文件root节点的值
  • {{css "/css" "file1.css,file2.css"}} 引用同一个文件夹下的多个css文件,第一个参数同也可以添加<global.root>这种方式的变量
  • {{css data}} 根据配置引入css,这种方式可以扫描某个文件夹下所有的文件并引用,是一种很方便实用的功能

在示例项目中,我们可以看到从数据文件的配置引入css的例子。

global.js文件:

module.exports = {
    "title": "Silky",
    "linkCSS": {
        "baseUrl": "<global.root>/css/",
        "dir": "/css",
        "match": /\.css|less$/,
        path: /(less)$/,
        to: 'css'
    }
}

然后我们在index.hbs中用{{css global.linkCSS}}引用,它会自动扫描/css文件夹下所有的less和css并引用。

我们有必要解释一下上述例子中各参数,在上述例子中

  • baseUrl 根路径
  • dir 要扫描的文件夹
  • match 匹配规则,可选。如上述例子中会匹配所有的css和less文件
  • path 替换规则,可选。如上述例子中会替换less为css
  • to 将要替换的文字

即:path + to = url.replace(path, to)

script

script指令与css指令的功能参数都是一样的,只不过script指令将会引用js文件而非css

loop

循环一个模板N次,或者根据数据源进行循环模板。

使用示例:

  • {{loop "module/cell" 5}} 循环cell这个子模板5次
  • {{loop "module/cell" data}} 根据data来循环cell这个子模板,此时data的数据类型应该是array注意:此时cell的数据作用域会被改变

repeat

重复内容N次,与loop不同的是,repeat并不引用子模板,仅仅是简单地重复。

使用示例:

{{#repeat 5}}
{{$index}}. 我要出现5次
{{/repeat}}

{{$index}}表示当前的索引值。

print

print指令可以打印数据,一般用于调试使用,例如你可以使用{{print global}}来打印出整个global文件的数据。

markdown

转换为markdown,注意此时我们需要用三个花括号来显示HTML内容

使用示例:

  • {{{markdown content}}} 将markdown转换为html,此时content的内容应该是markdown格式

date

输出日期,与now指令不同的时,date允许指定日期。允许指定三个参数:{{date 数据源 输出的日期格式(可选) 数据源的日期格式(可选)}}

使用示例:

  • {{date 1423735598048}} 将输出2015-02-12,默认的日期格式为:YYYY-MM-DD
  • {{date 1423735598048 "MM-DD"}} 指定输出的日期格式,将输出02-12
  • {{date "2015-02-12" "MM-DD" "YYYY-MM-DD"}} 指定输出的日期格式,且指定源日期格式,将输出02-12。这种情况一般适用于数据源为字符串,且不是规范的日期格式这种情况

now

打印出当前时间,如果没有指定日期格式,则会输出当前的时间戳。一般来说,可以用{{now}}来给文件引用加入时间戳,例如<script src="js/main.js?timestamp={{now}}"></script>

使用示例:

  • {{now}} 输出时间戳
  • {{now "YYYY-MM-DD hh:mm:ss"}} 根据指定的格式输出时间,更多时间格式的规则请参数momentjsString + Format部分

substr

截取字符串,例如{{substr "这是一个长的字符" 2}},输出结果为:这是

ifEqual

逻辑与的判断,例如:

{{#ifEqual 0 1}}
    两者相等    
{{/ifEqual}}

or

等同于javascript中的a || b, 在模板中可以实现同样的功能{{or a b}}

compare

比较两个参数,输出不同的结果,格式为:{{compare left symbol right}},symbol可为==, ===, !=, !==, <, <=, >, >=, in之一,其中in要求right必需是array。

示例:

{{#compare '1' '==' 1}}
    正确
{{else}}
    错误
{{/compare}}

execute

执行函数,并允许提供参数,格式为,{{#execute var1 var2 varN}},例如:

.silky/data/page.js文件:

module.exports = {
    testFunction: function(value){
        return value > 10
    }
}

index.hbs文件:

<!DOCTYPE html>
<html>
    <head>
        <title>Compare指令</title>
    </head>
    <body>
        {{#execute page.testFunction 5}}
            大于10
        {{else}}
            小于10
        {{/execute}}
    </body>
</html>

输出结果:

<!DOCTYPE html>
<html>
    <head>
        <title>import示例</title>
    </head>
    <body>
        小于10
    </body>
</html>

compare还有另一种用户,可以直接执行函数并输出结果,使用方式如下:

.silky/data/normal/page.js文件:

module.exports = {
    plus: function(left, right){
        return left + right
    }
}

index.hbs文件:

<!DOCTYPE html>
<html>
    <head>
        <title>Compare</title>
    </head>
    <body>
        1 + 5 = {{execute page.plus 1 5}}
    </body>
</html>

输出:

<!DOCTYPE html>
<html>
    <head>
        <title>Compare</title>
    </head>
    <body>
        1 + 5 = 6
    </body>
</html>