Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/xboxyan/web-template
web-template.js 是一款基于 ES6 模板字符串解析的模板引擎。
https://github.com/xboxyan/web-template
dom dom-diff dom-parser es6 html html5 javascript template vue
Last synced: about 2 months ago
JSON representation
web-template.js 是一款基于 ES6 模板字符串解析的模板引擎。
- Host: GitHub
- URL: https://github.com/xboxyan/web-template
- Owner: XboxYan
- Created: 2020-11-17T09:00:30.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2021-04-11T13:34:49.000Z (over 3 years ago)
- Last Synced: 2024-10-23T16:24:04.412Z (2 months ago)
- Topics: dom, dom-diff, dom-parser, es6, html, html5, javascript, template, vue
- Language: HTML
- Homepage: http://xboxyan.codelabo.cn/web-template/index.html
- Size: 60.5 KB
- Stars: 120
- Watchers: 2
- Forks: 21
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# web-template
web-template.js 是一款基于 [ES6 模板字符串](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings)解析的模板引擎。
## 特点
1. 纯原生浏览器解析,无任何依赖,无需编译,不拖泥带水
1. 类 vue 模板语法,上手快,几乎可以不用看文档
1. 支持 dom-diff 局部更新,性能高效
1. 代码量极少,~~包含注释不到 100 行~~(由于添加了 dom-diff 特性,已经超过 100 行了~),方便学习和扩展[演示 demo](https://xboxyan.codelabo.cn/web-template/index.html)
## 更新
* 2020-11-27
* 列表渲染支持 `key` 属性
* 2020-11-24
* 支持 `dom-diff` 局部更新
* 2020-11-20
* 新增 `mount` 方法
* 新增 `block` 标签
* 2020-11-19
* 支持 `{{}}` 插值表达式
* 新增 `fragment` 标签
* 新增 `open` 布尔值属性## 适用场景
适用于原生开发,又希望有一定模板渲染能力的场景,比如一大堆列表循环渲染
在使用之前
```js
var html = '';
arrData.forEach(function (obj, index) {
html = html + '\
\
\
' + obj.title + '\
' + obj.time + '\
' + obj.comment + '\
';
});
console.log(html);
```使用 ES6 模板字符串
```js
let html = `${data.map(function (obj, index) {
return `
${obj.title}
${obj.time}
${obj.comment}
`;
}).join('')}`;
console.log(html);
```使用 web-template.js 之后
```html
${obj.title}
${obj.time}
${obj.comment}
```
```js
console.log(template.render(data).content); // dom节点
console.log(template.render(data).innerTHML); // dom字符串
```是不是清爽了许多,可读性也更强了
## 使用方式
直接引用 `web-template.js`
```html
```
在 HTML 页面上添加 `template` 标签,放入模板
```html
```
假设有如下数据
```js
const data = {
list : [ 'Apple', 'Banana', 'Cat']
}
list.appendChild(template.render(data).content)
```
最终,页面上 ul 会被渲染成
```html
- 1 - Apple
- 2 - Banana
- 3 - Cat
```
更多用法,可参考下面的详细介绍
## 模板语法
模板必须放在 `` 标签中
```html
```
> 以下所有规则都在这个标签中
### 1.插值
数据绑定采用的是 ES6 模板字符串的语法, `${ }`:
*目前已兼容 `{{ }}` 的语法*
```html
Message: ${ msg }
```
```js
const data = {
msg: 'hello'
}
```
返回
```html
Message: hello
```
各种属性,或者说只要出现插值语法的地方都会被替换成普通文本
```html
Message: ${ msg }
```
```js
const data = {
msg: 'hello',
type: 'normal',
}
```
返回
```html
Message: hello
```
一些为布尔值的属性,比如 `disabled`、`hidden`、`required`、`checked`、`selected`、`readonly`,`open`(欢迎补充~),如果设置值为 `false` ,那么将会移除该属性
```html
button
button
```
```js
const data = {
disabled: true,
hidden: false,
}
```
返回
```html
button
button
```
### 2.JavaScript 表达式
JavaScript 表达式也可以用到模板中的任意地方
```html
${ number + 1 }
${ ok ? 'YES' : 'NO' }
```
```js
const data = {
number: 10,
ok: true,
}
```
返回
```html
11
YES
```
> 注意,这里是单个表达式,推荐使用三元表达式,vue 和 react 也是同样的规定
JavaScript 函数也可以直接访问,可以是全局函数,也可以是自己定义的函数
```html
${ new Date() }
${ add(1,2) }
```
```js
// 定义在全局的函数
function add(m,n){
return m + n
}
```
返回
```html
Tue Nov 17 2020 11:13:44 GMT+0800 (中国标准时间)
3
```
更极端的是,可以直接嵌套函数,但是必须是立即执行函数
```html
${
(()=>{
return 'hello';
})()
}
```
返回
```html
hello
```
> 当然强烈不推荐这么做,把一段 js 放在 html 中实在不怎么优雅
### 3.指令
指令是带有特殊前缀的属性,默认是 `$`,当然你也可以更换成你喜欢的,比如 `v-`,通过修改 `template` 标签的 rule 属性
```html
```
> 以下就以 `v-` 为例
目前有两个指令,分别是**条件渲染**和**列表渲染**
#### 3.1.条件渲染
`v-if` 用来条件性地渲染一块内容,当值为 false 时,内容会被完全移除
```html
Template is awesome!
Oh no 😢
```
```js
const data = {
show: true
}
```
返回
```html
Template is awesome!
```
> 注意,指令的属性值不需要包裹 `${ }`
`v-show` 内部通过属性 `hidden` 来实现样式上的隐藏
```html
Template is awesome!
Oh no 😢
```
```js
const data = {
show: true
}
```
返回
```html
Template is awesome!
Oh no 😢
```
> 注意,这里是普通的属性,所以需要包裹 `${ }`
#### 3.2.列表渲染
##### 别名
`v-for` 用来循环渲染一个列表,格式形如 `item in items`,其中 `items` 是数据源,`item` 是被循环的数组元素的**别名**。
```html
${ item.message }
```
```js
const data = {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
```
返回
```html
```
##### 索引
此外,还支持第二个可选参数,表示**索引**(默认为 `index` ),形如 `(item,index) in items`
```html
${ index } - ${ item.message }
```
返回
```html
```
##### 作用域
每个循环都有自己的作用域,这在多重循环中特别有用,如下可以轻易的实现一个 9*9 乘法表
```html
${i*j}
```
返回
```html
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
8 16 24 32 40 48 56 64
9 18 27 36 45 54 63 72 81
```
##### 简写
每次都要写 `item in items` 有些麻烦,这里可以简写成 `items`,此时默认**别名**和**索引**分别是 `item` 和 `index`
```html
${ index } - ${ item.message }
```
返回
```html
```
##### 重复次数
`v-for` 也可以接受整数。在这种情况下,它会把模板重复对应次数。
```html
${ index }
```
返回
```html
0
1
2
3
4
5
6
7
8
9
```
> 虽然有些鸡肋,某些情况下还是有点作用的
返回如上
##### 使用 key 属性
如果列表有可能会发生顺序改变,可以指定一个不重复的 key ,这样在渲染时会优先根据 key 的顺序重新排序,而不会重新渲染。
```html
${ index } - ${ item.message }
```
> 目前仅适用于循环渲染
##### 对象迭代
你也可以用 `v-for` 来遍历一个对象,这里用 `of` 来区分,形如 `value of object`
```html
${ value }
```
```js
const data = {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
```
返回
```html
```
同时,支持三个参数,形如 `(value, name, index) of object`,分别为**值**、**键名**、**索引**
```html
${ index }. ${ name }. ${ value }
```
返回
```html
```
> 对象迭代不支持简写,尽量多使用数组遍历吧
#### 3.3 fragment 片段
有时候我们可能需要遍历这样一种没有父级的元素
```html
- 1 dt
- 1 dd
- 2 dt
- 2 dd
- 1 dt
- 1 dd
```
这时可以借助 fragment 标签包裹,渲染后 fragment 标签会被移除
```html
```
在 `v-if` 中也适用的
```html
```
返回
```html
```
其他任意地方也可以添加,只不过不会被渲染
> 也可使用 block 标签,功能完全一致 (参考微信小程序)
### 4.渲染
在原生 `template` 标签扩展了 `render` 方法,可以传入一个对象,然后返回一个 `template`文档片段([`document-fragment`](https://developer.mozilla.org/zh-CN/docs/Web/API/DocumentFragment))
```js
const tpl = template.render(data) // template document-fragment
tpl.content; // 返回dom节点
tpl.innerHTML; // 返回字符串
```
一般通过 `.content` 可以得到模板的 dom 结构,直接以 `appendChild` 的方式渲染到页面,这种方式在追加数据的时候更加有效
```js
container.appendChild(tpl.content);
```
如果内容需要重置,可以简单粗暴的使用 `.innerHTML`
```js
container.innerHTML = tpl.innerHTML;
```
如果需要局部更新,可使用 `.html()` 方法
```js
// 支持dom节点
container.html(tpl.content);
// 字符串也支持
container.html(tpl.innerHTML);
```
### 5. 挂载
一般情况通过 `template.render(data)` 来获取到模板的内容,然后再通过容器的 `.innerHTML` 就可以了,但是有些啰嗦,这里提供一个更为简单的方法 `template.mount()`
需要在容器上指定和模板 id 相同的值,形成映射关系,比如
```html
${name}
```
然后执行
```js
tpl.mount(data);
```
这样模板内容就自动挂载在页面上了
> 一般情况下均可满足,不满足的情况可以采用 render 方式,更加灵活
如果需要局部更新,可以传入第2个参数,表示是否进行 diff 比较
```js
tpl.mount(data, isDiff);
```
> 一般情况下,diff 并不会比直接 innerHTML 要快,但是可以保留元素的状态,建议初次渲染选择 innerHTML,后面更新使用 dom-diff
## 兼容性和一些局限
需要支持 ES6 模板字符串语法的浏览器,还在用 IE 的小伙伴可以放弃了
dom-diff 基本够用,还有待完善
由于使用了很多 DOM API,依赖浏览器环境,因此不支持 Node 等其他非浏览器环境,不支持服务端渲染
## 参考
[Vue 模板语法](https://cn.vuejs.org/v2/guide/syntax.html)
[ES6模板字符串在HTML模板渲染中的应用](https://www.zhangxinxu.com/wordpress/2020/10/es6-html-template-literal/)