GithubHelp home page GithubHelp logo

xboxyan / web-template Goto Github PK

View Code? Open in Web Editor NEW
116.0 2.0 21.0 62 KB

web-template.js 是一款基于 ES6 模板字符串解析的模板引擎。

Home Page: http://xboxyan.codelabo.cn/web-template/index.html

HTML 59.47% JavaScript 40.53%
template es6 html html5 dom-parser dom-diff javascript vue dom

web-template's Introduction

web-template

web-template.js 是一款基于 ES6 模板字符串解析的模板引擎。

特点

  1. 纯原生浏览器解析,无任何依赖,无需编译,不拖泥带水
  2. 类 vue 模板语法,上手快,几乎可以不用看文档
  3. 支持 dom-diff 局部更新,性能高效
  4. 代码量极少,包含注释不到 100 行(由于添加了 dom-diff 特性,已经超过 100 行了~),方便学习和扩展

演示 demo

更新

  • 2020-11-27
    • 列表渲染支持 key 属性
  • 2020-11-24
    • 支持 dom-diff 局部更新
  • 2020-11-20
    • 新增 mount 方法
    • 新增 block 标签
  • 2020-11-19
    • 支持 {{}} 插值表达式
    • 新增 fragment 标签
    • 新增 open 布尔值属性

适用场景

适用于原生开发,又希望有一定模板渲染能力的场景,比如一大堆列表循环渲染

在使用之前

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);

使用 web-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>

以下所有规则都在这个标签中

1.插值

数据绑定采用的是 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>

一些为布尔值的属性,比如 disabledhiddenrequiredcheckedselectedreadonly,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属性被移除 -->

2.JavaScript 表达式

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 中实在不怎么优雅

3.指令

指令是带有特殊前缀的属性,默认是 $,当然你也可以更换成你喜欢的,比如 v-,通过修改 template 标签的 rule 属性

<template rule="v-">
    <!-- 模板 -->
</template>

以下就以 v- 为例

目前有两个指令,分别是条件渲染列表渲染

3.1.条件渲染

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 v-show="show">Template is awesome!</h1>
<h1 v-show="!show">Oh no 😢</h1>
const data = {
    show: true
}

返回

<h1>Template is awesome!</h1>
<h1 hidden>Oh no 😢</h1> <!--样式上被隐藏-->

注意,这里是普通的属性,所以需要包裹 ${ }

3.2.列表渲染

别名

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,此时默认别名索引分别是 itemindex

<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>

虽然有些鸡肋,某些情况下还是有点作用的

返回如上

使用 key 属性

如果列表有可能会发生顺序改变,可以指定一个不重复的 key ,这样在渲染时会优先根据 key 的顺序重新排序,而不会重新渲染。

<template>
  <li v-for="items" key="${item.id}">
    ${ index } - ${ item.message }
  </li>
</template>

目前仅适用于循环渲染

对象迭代

你也可以用 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>

对象迭代不支持简写,尽量多使用数组遍历吧

3.3 fragment 片段

有时候我们可能需要遍历这样一种没有父级的元素

<dl>
  <dt></dt>  
  <dd></dd>
  <dt></dt>  
  <dd></dd> 
  <dt></dt>  
  <dd></dd> 
<dl>

这时可以借助 fragment 标签包裹,渲染后 fragment 标签会被移除

<template>
  <dl>
    <fragment v-for="[1,2,3]">
      <dt></dt>
      <dd></dd>
    </fragment>
  </dl>
</template>

v-if 中也适用的

<template>
  <dl>
    <fragment v-if="true">
      <dt>1 dt</dt>
      <dd>1 dd</dd>
    </fragment>
    <fragment v-if="false">
      <dt>2 dt</dt>
      <dd>2 dd</dd>
    </fragment>
  </dl>
</template>

返回

<dl>
  <dt>1 dt</dt>
  <dd>1 dd</dd>
</dl>

其他任意地方也可以添加,只不过不会被渲染

也可使用 block 标签,功能完全一致 (参考微信小程序)

4.渲染

在原生 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;

如果需要局部更新,可使用 .html() 方法

// 支持dom节点
container.html(tpl.content);
// 字符串也支持
container.html(tpl.innerHTML);

5. 挂载

一般情况通过 template.render(data) 来获取到模板的内容,然后再通过容器的 .innerHTML 就可以了,但是有些啰嗦,这里提供一个更为简单的方法 template.mount()

需要在容器上指定和模板 id 相同的值,形成映射关系,比如

<div is="tpl"></div>

<template id="tpl">
  <span class="name">${name}</span>
</template>

然后执行

tpl.mount(data);

这样模板内容就自动挂载在页面上了

一般情况下均可满足,不满足的情况可以采用 render 方式,更加灵活

如果需要局部更新,可以传入第2个参数,表示是否进行 diff 比较

tpl.mount(data, isDiff);

一般情况下,diff 并不会比直接 innerHTML 要快,但是可以保留元素的状态,建议初次渲染选择 innerHTML,后面更新使用 dom-diff

兼容性和一些局限

需要支持 ES6 模板字符串语法的浏览器,还在用 IE 的小伙伴可以放弃了

dom-diff 基本够用,还有待完善

由于使用了很多 DOM API,依赖浏览器环境,因此不支持 Node 等其他非浏览器环境,不支持服务端渲染

参考

Vue 模板语法

ES6模板字符串在HTML模板渲染中的应用

web-template's People

Contributors

xboxyan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

web-template's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.