一 简介 art-template:
下载地址:https://github.com/aui/art-template
通常所说的渲染分为:
//1. 浏览器端渲染
//对应 template-web.js
//2.服务器端渲染
//对应 npm install art-template --save
//对应的express框架 npm install express-art-template --save
二 模板语法:
art-template 支持标准语法与原始语法。标准语法可以让模板易读写,而原始语法拥有强大的逻辑表达能力。标准语法支持基本模板语法以及基本 JavaScript 表达式;原始语法支持任意 JavaScript 语句,这和 EJS 一样。
2.1 输出语法:
// {{@ value }} <%= value %>
//标准语法输出字符串
<td class="text-center">{{@ "已发布" }}</td>
//原始语法输出字符串
<td class="text-center"><%= "已发布" %></td>
//输出字符串时要加双引号,否则会当成变量来解析
2.2 分支结构的语法:
//标准语法
{{ if value.status == "published" }}
<td class="text-center">{{@ "已发布" }}</td>
{{ else value.status == "drafted" }}
<td class="text-center">{{@ "草稿" }}</td>
{{ /if }}
//原始语法:
<% if (value.status == "published") { %>
<td class="text-center">{{@ "已发布" }}</td>
<% } else(value.status == "drafted") { %>
<td class="text-center">{{@ "草稿" }}</td>
<% } %>
//原始语法与JS的原生语法很像,只不过多了一对<% %>
2.3 循环分支:
//标准语法的循环
{{each target}}
{{$index}} {{$value}}
{{/each}}
//$value 与 $index 可以自定义:{{each target val key}}
//1. 自定义的例子:
{{ each list value key }}
<tr>
<td class="text-center"><input type="checkbox" index="{{value.id}}"></td>
<td>{{ value.name }}</td>
<td>{{ value.slug }}</td>
<td class="text-center">
<!-- 这里的onclick就是行内注册事件 -->
<a href="javascript:void(0);" onclick="editorCategory({{ value.id }})" class="btn btn-info btn-xs">编辑</a>
<!-- 这里的onclick就是行内注册事件 -->
<a href="javascript:void(0);" onclick="deleteCategory({{ value.id }})" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{{ /each }}
//2. 原始语法与标准语法混用:
<% for(var i =0;i < list.length;i++) { %>
<tr>
<td class="text-center"><input type="checkbox" index="{{value.id}}"></td>
<td>{{ value.name }}</td>
<td>{{ value.slug }}</td>
<td class="text-center">
<a href="javascript:void(0);" onclick="editorCategory({{ value.id }})" class="btn btn-info btn-xs">编辑</a>
<a href="javascript:void(0);" onclick="deleteCategory({{ value.id }})" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
<% } %>
**//我们发现原始语法与标准语法可以共用,前提是语法书写正确**
这里我们重点强调下,循环语句的语法:
{{ each list value key }}
......
{{ /each }}
// target 支持 array 与 object 的迭代,其默认值为 $data。
2.3.1 循环语法需要注意的点:
//1. list这个名字可以随便取,也可以叫target,只需要在调用模板的时候,与之对应就
可以了.
//2. 如果遍历的是数组value与key代表一个是数组里的元素,一个是下标.
//3. 如果遍历的是对象value与key代表一个是对象里的属性值,一个是属性名.
//4. list实际上时一个数组,但是我们在模板里面传递的时候,需要将这个数组包一下.
包裹为对象.这是因为文档的规定.
var HTML = template('id' , { ''list'' : arr }); //将arr包裹一下
//5. 如果list是一个对象是一个对象,就不需要包裹,但是传入循环变量里面的list必须是个数组.
var HTML = template('id' , obj); //obj无需包裹
但是模板里面的list必须是obj对象里的数组属性
//6. 在模板里面,如果传入的就是对象,那么直接可以在模板的html代码里直接使用对应的属性与方法.
var HTML = template('id' , obj); //obj无需包裹
//其中的proName,price,oldPrice都是obj对象里面的属性
<script id="tpl-product" type="text/html">
<div class="product-name">
名字:
<span>
{{ proName }}
</span>
</div>
<div class="product-price">
价格:
<span class="new-price">¥{{ price }}</span>
<del class="old-price">¥{{ oldPrice }}</del>
</div>
script>
比如:
上面的对象里有result这个数组属性名,所以调用模板时可以直接这样书写:
var HTML = template('id' , obj); //obj无需包裹
//直接将属性名传给模板,模板也会识别这个数组
{{ each result value key }}
......
{{ /each }}
至于其他的语法,可以去其官网上查阅文档.
四 客户端模板使用的方法:
4.1 第一,导入模板:
<script src="./JS/template-web.js">script>
4.2 第二步:准备需要结构类似需要重复生成的模板
<script type="text/html" id="tpl1">
//这里写需要生成的模板
script>
4.3 第三步:调用模板的api来渲染模板到页面上
//引用模板,模板生成的内容在变量名ul的内存里面
var ul = template('tpl1',{ list : 6});
//需要我们追加到页面上去
document.getElementById('newBd').innerHTML = ul;
/*
这里需要注意的是,调用api来生成的ul里面包含了需要生成模板里的
所有内容,但是ul作为一个变量,只是将这些值保存在自己的内存里,
并没有被解析出来;所以我们又利用innerHTML可以解析标签的功能将
标签解析出来渲染到页面上
*/
ul里面存放的内容(包含标签)
我们可以看到ul里面存放的是一个带有标签的字符串.
五 浏览器端模板需要注意的地方:(最重要)
5.1 因为模板是在页面上的其他元素加载完成之后,才开始加载的,所以一开始页面上没有模板里面的标签,它是后面用引擎渲染上去的.
所有在操作模板里面的标签元素时,我们应该利用 :
1.行内事件的方法.
2.事件的委托
3.等待模板渲染完成后才去获取元素
5.1.1 行内事件获取动态添加的元素
{{ each list value key }}
<tr>
<td class="text-center"><input type="checkbox" index="{{value.id}}"></td>
<td>{{ value.name }}</td>
<td>{{ value.slug }}</td>
<td class="text-center">
<!-- 这里的onclick就是行内注册事件 -->
<a href="javascript:void(0);" onclick="editorCategory({{ value.id }})" class="btn btn-info btn-xs">编辑</a>
<!-- 这里的onclick就是行内注册事件 -->
<a href="javascript:void(0);" onclick="deleteCategory({{ value.id }})" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{{ /each }}
5.1.2 事件委托获取动态添加的元素
给li的父容器委托一个点击事件,然后由子元素li来触发.这样就可以找到对应的动态添加的子元素.
//以下面的例子举例
<script type="text/html" id="tpl-category-left">
{{each rows value index}}
<li class="{{@ index == 0 ? 'active' : ''; }}"><a href="#" data-id="{{@ value.id }}">{{@ value.categoryName }}</a></li>
{{ /each }}
</script>
//给li标签一个点击事件
//利用事件的委托
$('ul').on('tap','li a',function(){
//doSomething.......
}
5.2 一个模板里可以有多个渲染对象
这里在模板里面有了两个遍历语法渲染不同的元素,说明,模板里面并不仅仅只能进行一次遍历.
<!-- 1.模板引擎,轮播图区域 -->
<script id="tpl-slider" type="text/html">
<div class="mui-slider-group mui-slider-loop">
{{each pic value index }}
{{if index == 0 }}
<div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="{{ pic[pic.length-1].picAddr }}" /></a></div>
{{ /if }}
<div class="mui-slider-item"><a href="#"><img src="{{ value.picAddr }}" /></a></div>
<!--支持循环,需要重复图片节点-->
{{ if index == pic.length - 1 }}
<div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="{{ pic[0].picAddr }}" /></a></div>
{{ /if }}
{{/each}}
</div>
<div class="mui-slider-indicator">
<!-- 默认给第一个小圆点选中 小圆点是有几个就是几个 -->
<!-- 小圆点 -->
{{ each pic value key }}
<div class="mui-indicator {{ key == 0 ? 'mui-active' : '' }}"></div>
{{ /each }}
</div>
</script>
六 服务端渲染
服务端的渲染与客户端的差不多,但是还是有区别(以nodeJS为例):
// 1. 导入包
npm install --save art-template
npm install --save express-art-template
// 2. 在html文件使用模板,此时就不需要用script将代码包裹
// 3. 在js文件调用模板
6.1 在html文件使用模板
在html文件中,使用模板语法,将需要循环生成的地方包裹在循环语法里面,注意这里与浏览器端渲染的区别,不需要包裹在script标签中.
<tbody>
{{each target}}
<tr>
<td>{{$index}}td>
<td>{{$value.name}}td>
<td>
<a href="javascript:;" onclick="musicPlayer( '{{$value.name}}' )">播放a>
td>
tr>
{{/each}}
tbody>
6.2 调用语法
//第一步: 导入包
const template = require('art-template');
//第一个参数是需要渲染的html文件的路径
//第二个参数是一个对象,传给html文件使用模板循环语法中的target
const html = template(__dirname + '/tpl-user.art', {
//这里的target与html中的名字一致
user: {
name: 'aui'
}
});
例子:
//渲染数据
var html = template(path.join(__dirname,'../static/html/index.html'), {
target : musicData
});
//设置请求头
res.setHeader('Content-Type', 'text/html');
res.end(html);
七 模板的继承
模板的继承一般用在:有些通用的内容可集中放在一个页面文件中,其它要用到这些内容的页面只需要包含(引用)这个通用文件即可。这样便于维护,如果有很多网页,当通用内容需要修改时,只改一个文件就可以了,不需要每个文件单独修改。
最典型的应用比如页脚的版权信息等内容可以放在一个叫做footer.html文件里, 然后其他页面文件在页面内容的最后包含这个文件就可以了
7.1 继承语法:
继承分为两个板块
//1. 被继承的网页,比如:页头,页脚 (父网页)
//2. 继承的网页,比如:这个网页只有中间的主体部分,其他需要继承(子网页)
7.1.1 被继承的网页(父网页)
<html>
<head>
<meta charset="utf-8">
<title>{{block 'title'}}My Site{{/block}}title>
{{block 'head'}}
<link rel="stylesheet" href="main.css">
{{/block}}
head>
<body>
{{block 'content'}}{{/block}}
body>
html>
{{block ‘content’}}{{/block}} 代表的含义是用占位符先把内容位置占据,然后在子网页继承的时候用实际的内容与替换就可以了.
7.1.2 继承的网页(子网页)
{{extend './layout.art'}}
{{block 'title'}}{{title}}{{/block}}
{{block 'head'}}
<link rel="stylesheet" href="custom.css">
{{/block}}
{{block 'content'}}
<p>This is just an awesome page.p>
{{/block}}
子网页的作用就是用子网页的实际代码来替换父网页的占位符.相当于父网页只是替你占了位置,但是实际的内容需要子网页来填充.
7.1.3 调用语法渲染
需要被继承的网页模板准备好后,现在我们来调用语法来动态渲染.
// 第一个参数是子页面 parsent.html(需要路径)
// 第二个参数是一个对象需要传输的数据(动态改变子网页的内容的数据)
res.render(path.join(__dirname,'./index.html'), {
user: {
name: 'aui'
}
});
7.2 服务端渲染的例子:
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{block 'title'}}父网页{{/block}}title>
{{block 'head'}}
<link href="/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
{{/block}}
head>
<body>
<div class="col-md-9">
{{block 'content'}}{{/block}}
div>
div>
div>
body>
html>
{{extend './parsent.html'}}
{{block 'title'}}子网页{{title}}{{/block}}
{{block 'head'}}
<link rel="stylesheet" href="head.css">
{{/block}}
{{block 'content'}}
<p>This is my {{ user.name }}.p>
{{/block}}
// 调用
// 第一个参数是子页面 parsent.html(需要路径)
// 第二个参数是一个对象需要传输的数据(动态改变子网页的内容的数据)
// 注意可以传入多个属性去渲染父页面或则子页面
res.render(path.join(__dirname,'./index.html'), {
user: {
name: 'aui'
}
});
最后 浏览端渲染的实例冒险岛2具体实现代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
<link rel="stylesheet" href="./Css/index.css">
<style>
.hot-news a {
position: absolute;
}
style>
head>
<body>
<div class="main-area-l">
<div class="news-box">
<div class="news-type-box" id="newsBox">
<div class="news-type-hd clearfix">
<div id="newsHd" class="news-type-a cf">
<a href="javascript:void(0);" class="" target="_blank">全部a>
<a href="javascript:void(0);" target="_blank" class="">新闻a>
<a href="javascript:void(0);" target="_blank" class="">公告a>
<a href="javascript:void(0);" target="_blank" class="">活动a>
<a href="javascript:void(0);" target="_blank" class="">媒体a>
<a href="javascript:void(0);" target="_blank" class="">玩家a>
<a href="javascript:void(0);" target="_blank" class="active">攻略a>
<span class="tab-arr-line" style="left: 330px;">span>
div>
<a href="#" class="more-link" target="_blank">+a>
div>
<div class="news-type-bd">
<div id="newBd" class="news-type-cont">
<-- 这里就是模板生成后的内容区域 -->
div>
div>
div>
div>
div>
body>
html>
<script src="./jquery-1.12.4.js">script>
<script src="./JS/template-web.js">script>
<script type="text/html" id="tpl1">
<% for(var i=1;i<=list;i++){ %>
<!-- 默认让第一个显示,其他的都不显示 -->
{{ if i == 1 }}
<!-- 给每一个ul一个点击事件 -->
<ul class="news-list" style="display: block;" id="{{@ "ul" }}{{ i }}">
{{ else }}
<ul class="news-list" style="display: none;" id="{{@ "ul" }}{{ i }}">
{{ /if }}
<li>
<span class="news-icon "></span>
<!-- 为了便于区分这里我们这一个i的输出让内容 -->
<a href="#" target="_blank" class="news-txt">【活动】{{@ "这是第" }}{{@ i }}{{@ "个ul标签" }}</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">【活动】暑月蝉鸣礼包限量购 含大量祝福之石机会难得</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">【重要】公测版本更新内容及注意事项汇总</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">冒险岛2觉醒公测调研问卷-领奖通知</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">【活动】冒险家回归计划 欢迎回家!</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">【活动】邀请好友一起冒险!</a>
<span class="news-time">08/07</span>
</li>
<li>
<span class="news-icon "></span>
<a href="#" target="_blank" class="news-txt">【活动】七夕岛上大冒险 鹊桥来相会</a>
<span class="news-time">08/07</span>
</li>
</ul>
<% } %>
script>
<script>
//引用模板
var ul = template('tpl1',{ list : 6});
document.getElementById('newBd').innerHTML = ul;
//给每个模板顶部的导航点击事件
$("#newsHd a").on('click',function(){
//设置对应的颜色更改
$(this).addClass('active').siblings('a').removeClass('active');
//设置下方对应的span的移动
$('.tab-arr-line').css('left',$(this).position().left + 'px');
//让下方显示的盒子与我的导航栏一致
var idx = $(this).index();
$('.news-list').eq(idx).show().siblings('.news-list').hide();
});
script>
完整项目下载地址:
gitHub: https://github.com/Alex-Li2018/maoxiandaoProject