web-template.js 是一款基于 ES6 模板字符串解析的模板引擎。
- 纯原生浏览器解析,无任何依赖,无需编译,不拖泥带水
- 类 vue 模板语法,上手快,几乎可以不用看文档
- 代码量极少,包含注释不到 100 行,方便学习和扩展
适用于原生开发,又希望有一定模板渲染的场景,比如一大堆列表循环渲染
在使用之前
var html = ''; arrData.forEach(function (obj, index) { html = html + '\ <tr>\ <td><input type="checkbox" value="' + obj.id + '"></td>\ <td><div class="ell">' + obj.title + '</div></td>\ <td>' + obj.time + '</td>\ <td align="right">' + obj.comment + '</td>\ </tr>'; }); console.log(html);
使用 ES6 模板字符串
let html = `${data.map(function (obj, index) { return `<tr> <td><input type="checkbox" value="${obj.id}"></td> <td><div class="ell">${obj.title}</div></td> <td>${obj.time}</td> <td align="right">${obj.comment}</td> </tr>`; }).join('')}`; console.log(html);
使用 template.js 之后
<template id="template" rule="v-"> <tr v-for="obj in data"> <td><input type="checkbox" value="${obj.id}"></td> <td><div class="ell">${obj.title}</div></td> <td>${obj.time}</td> <td align="right">${obj.comment}</td> </tr> </template>
console.log(template.render(data).content); // dom节点 console.log(template.render(data).innerTHML); // dom字符串
是不是清爽了许多,可读性也更强了
直接引用 web-template.js
<script src="web-template.js"></script>
在 HTML 页面上添加 template 标签,放入模板
<ul id="list"> </ul> <template id="template"> <li $for="(item,index) in list">${ index + 1} - ${ item }</li> </template>
假设有如下数据
const data = { list : [ 'Apple', 'Banana', 'Cat'] } list.appendChild(template.render(data).content)
最终,页面上 ul 会被渲染成
<ul id="list"> <li>1 - Apple</li> <li>2 - Banana</li> <li>3 - Cat</li> </ul>
更多用法,可参考下面的详细介绍
模板必须放在 <template></template> 标签中
<template> <!-- 你的模板 --> </template>
以下所有规则都在这个标签中
数据绑定采用的是 ES6 模板字符串的语法, ${ }:
<span>Message: ${ msg }</span>
const data = { msg: 'hello' }
返回
<span>Message: hello</span>
各种属性,或者说只要出现插值语法的地方都会被替换成普通文本
<span data-type="${type}">Message: ${ msg }</span>
const data = { msg: 'hello', type: 'normal', }
返回
<span data-type="normal">Message: hello</span>
一些特殊的表单属性,比如 disabled、hidden、required、checked、selected、open(欢迎补充~),如果设置值为 false ,那么将会移除该属性
<button disabled="${disabled}">button</button> <button hidden="${hidden}">button</button>
const data = { disabled: true, hidden: false, }
返回
<button disabled="true">button</button> <button>button</button> <!-- hidden属性被移除 -->
JavaScript 表达式也可以用到模板中的任意地方
<span>${ number + 1 }</span> ${ ok ? 'YES' : 'NO' }
const data = { number: 10, ok: true, }
返回
<span>11</span> YES
注意,这里是单个表达式,推荐使用三元表达式,vue 和 react 也是同样的规定
JavaScript 函数也可以直接访问,可以是全局函数,也可以是自己定义的函数
<span>${ new Date() }</span> <span>${ add(1,2) }</span>
// 定义在全局的函数 function add(m,n){ return m + n }
返回
<span>Tue Nov 17 2020 11:13:44 GMT+0800 (中国标准时间)</span> <span>3</span>
更极端的是,可以直接嵌套函数,但是必须是立即执行函数
<span>${ (()=>{ return 'hello'; })() }</span>
返回
<span>hello</span>
当然强烈不推荐这么做,把一段 js 放在 html 中实在不怎么优雅
指令是带有特殊前缀的属性,默认是 $,当然你也可以更换成你喜欢的,比如 v-,通过修改 template 标签的 rule 属性
<template rule="v-"> <!-- 模板 --> </template>
以下就以
v-为例
目前有两个指令,分别是条件渲染和列表渲染
v-if 用来条件性地渲染一块内容,当值为 false 时,内容会被完全移除
<h1 v-if="show">Template is awesome!</h1> <h1 v-if="!show">Oh no 😢</h1>
const data = { show: true }
返回
<h1>Template is awesome!</h1> <!-- $if H1 -->
注意,指令的属性值不需要包裹
${ }
这里没有实现另外一个显示隐藏的指令 v-show ,可以用属性 hidden 来代替
<h1 hidden="${!show}">Template is awesome!</h1> <h1 hidden="${show}">Oh no 😢</h1>
const data = { show: true }
返回
<h1>Template is awesome!</h1> <h1 hidden="true">Oh no 😢</h1> <!--样式上被隐藏-->
注意,这里是普通的属性,所以需要包裹
${ }
v-for 用来循环渲染一个列表,格式形如 item in items,其中 items 是数据源,item 是被循环的数组元素的别名。
<template> <li v-for="item in items"> ${ item.message } </li> </template>
const data = { items: [ { message: 'Foo' }, { message: 'Bar' } ] }
返回
<li>Foo</li> <li>Bar</li>
此外,还支持第二个可选参数,表示索引(默认为 index ),形如 (item,index) in items
<template> <li v-for="(item,index) in items"> ${ index } - ${ item.message } </li> </template>
返回
<li>0 - Foo</li> <li>1 - Bar</li>
每个循环都有自己的作用域,这在多重循环中特别有用,如下可以轻易的实现一个 9*9 乘法表
<template> <div v-for="i in [1,2,3,4,5,6,7,8,9]"> <span v-for="j in [1,2,3,4,5,6,7,8,9]" v-if="i>=j"> ${i*j} </span> </div> </template>
返回
<div> <span> 1 </span> </div> <div> <span> 2 </span><span> 4 </span> </div> <div> <span> 3 </span><span> 6 </span><span> 9 </span> </div> <div> <span> 4 </span><span> 8 </span><span> 12 </span><span> 16 </span> </div> <div> <span> 5 </span><span> 10 </span><span> 15 </span><span> 20 </span><span> 25 </span> </div> <div> <span> 6 </span><span> 12 </span><span> 18 </span><span> 24 </span><span> 30 </span><span> 36 </span> </div> <div> <span> 7 </span><span> 14 </span><span> 21 </span><span> 28 </span><span> 35 </span><span> 42 </span><span> 49 </span> </div> <div> <span> 8 </span><span> 16 </span><span> 24 </span><span> 32 </span><span> 40 </span><span> 48 </span><span> 56 </span><span> 64 </span> </div> <div> <span> 9 </span><span> 18 </span><span> 27 </span><span> 36 </span><span> 45 </span><span> 54 </span><span> 63 </span><span> 72 </span><span> 81 </span> </div>
每次都要写 item in items 有些麻烦,这里可以简写成 items,此时默认别名和索引分别是 item 和 index
<template> <li v-for="items"> ${ index } - ${ item.message } </li> </template>
返回
<li>0 - Foo</li> <li>1 - Bar</li>
v-for 也可以接受整数。在这种情况下,它会把模板重复对应次数。
<template> <span v-for="10">${ index } </span> </template>
返回
<span>0</span> <span>1</span> <span>2</span> <span>3</span> <span>4</span> <span>5</span> <span>6</span> <span>7</span> <span>8</span> <span>9</span>
虽然有些鸡肋,某些情况下还是有点作用的
你也可以用 v-for 来遍历一个对象,这里用 of 来区分,形如 value of object
<template> <li v-for="value of object"> ${ value } </li> </template>
const data = { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } }
返回
<li>How to do lists in Vue</li> <li>Jane Doe</li> <li>2016年04月10日</li>
同时,支持三个参数,形如 (value, name, index) of object,分别为值、键名、索引
<template> <li v-for="(value, name, index) of object"> ${ index }. ${ name }. ${ value } </li> </template>
返回
<li>0. title. How to do lists in Vue</li> <li>1. author. Jane Doe</li> <li>2. publishedAt. 2016年04月10日</li>
对象迭代不支持简写,尽量多使用数组遍历吧
在原生 template 标签扩展了 render 方法,可以传入一个对象,然后返回一个 template文档片段(document-fragment)
const tpl = template.render(data) // template document-fragment tpl.content; // 返回dom节点 tpl.innerHTML; // 返回字符串
一般通过 .content 可以得到模板的 dom 结构,直接以 appendChild 的方式渲染到页面,这种方式在追加数据的时候更加有效
container.appendChild(tpl.content);
如果内容需要重置,可以简单粗暴的使用 .innerHTML
container.innerHTML = tpl.innerHTML;
需要支持 ES6 模板字符串语法的浏览器,还在用 IE 的小伙伴可以放弃了
由于使用了很多 DOM API,依赖浏览器环境,因此不支持 Node 等其他非浏览器环境,不支持服务端渲染