Skip to content

Repository files navigation

thin.js 使用文档

thin.js:一个羽量级的前端框架,基于 html5+css3+jquery。

本文档介绍 thin.js 的使用语法

1. 开始使用

1.1 添加引用

  • 添加对 jquery 的引用,thinjs.com 上的版本为 3.4.1,你也可以从其他源引用 jquery。
<scriptsrc="https://com.wf.pub/jquery.js"></script>
  • 添加对 thin.js 的引用。
<scriptsrc="https://com.wf.pub/thin.js"></script>
  • 如果你用到 render 以外的其他功能,还需要添加对 thin.css 的引用。(可选)
<linkrel="stylesheet" href="https://com.wf.pub/thin.css" />

2. render 渲染器和模板

2.1 基本语法

渲染器是一个 jQuery 扩展,语法如下:

$(selector).render({data: data,template: template});

按照 template 依据 data 渲染到 selector 指定的元素中。

data:数据,可以是object或者array类型。
template: 模板

2.2 模板 template

thin.js 目前可以使用以下六种模板:

  • string template
  • element template
  • 模板函数
  • if 结构
  • switch case 结构
  • when 结构
  • 前述六种模板组成的数组

2.2.1 string template 字符串模板

vardata={name: 'wanfang'};$(selector).render({data: data,template: 'this is [[name]]'});

2.2.2 element template

element 模板本质上是一个包含"e"属性成员的 javascript 对象,可以根据 e 指定的 element name 生成 html 元素,并设置属性、样式、绑定数据、事件。

vardata={name: 'wanfang'};$(selector).render({data: data,template: {e: 'p',t: 'this is [[name]]'}});

对象可以有以下成员

成员类型说明
estringelement 元素标签名
tstring,object,array,functiontemplate 子模板
idstring标签 id
classstring标签类名
namestring标签的 name 属性
styleobject行内样式表
width/heightstring元素宽/高(与写在 style 无区别)
aobjectattribute, html 属性(name、src、href......)
clickfunction点击事件处理函数
eventobject事件处理函数
dataobject数据
datapathstring数据路径
foreachstring数据循环
bind双向数据绑定
selectedstring给select下拉选择框设置默认值
valuestring输入项设置值
optionsstring,array,object选项值
timerobject元素绑定定时/延时任务
ifstring,function控制渲染
switch casestring控制渲染
whenstring,function控制渲染
titlestring生成标题标签,当 e=fieldset 时,生成 legend,当 e=field/f1/f2/f3 时在元素内生成 label 标签,e 为其他值是无效
2.2.2.1 element:生成元素属性

在 element 模板中可以用 a 属性来控制渲染出的 dom element 的属性。

{e:"div",a:{id:"sampleid",class:"sampleclass"}}

渲染结果:

<divid="sampleid" class="sampleclass"></div>

a 的成员的属性名和值将用作渲染出来的节点的属性名和值。 当需要生成的属性名包含特殊字符时,可以使用引号将属性名包括在内。

a:{"data-sample":"sample data"}

使用数据漫游器 a 的成员的值串中可以使用数据漫游器'[[]]'将数据填充到值串中。

a:{"data-sample": "[[sample]]"}
2.2.1.1.1 使用函数生成属性值

a 的成员也可是函数,以根据数据生成不同的属性。

函数需要返回字符串作为生成的属性值。

a:{class: function(param){if(param.data.field==="a"){return"classa";}else{return"classb";}}}

传入参数 param 的结构如下:

{container: container,//当前容器data: data// 当前容器所绑定的数据}
2.2.1.1.2 常用属性快捷方式

id,name,class 因为经常被使用到,所以可以直接在 element 中用相应的属性设置,但是取值不允许使用函数或者数据漫游器,如果需要根据数据决定取值,请使用 a 属性的成员进行设置。

2.2.2.2 element:使用数据

在 thin.js 中可以用以下三种方式将数据源绑定到模板。

  1. render 参数的 data 成员
  2. element 模板的 datapath/foreach 属性
  3. element 模板的 data 属性
2.2.2.2.1 render 参数的 data 对象

给模板提供数据最常用的方式是作为 render 的参数的 data 成员传入。

$(selector).render({data: data,template: template});
2.2.2.2.2 element 模板的 datapath/foreach 属性

datapath:

// 对象数组的渲染vardata={arr: [{name: 'name1'},{name: 'name2'},{name: 'name3'},{name: 'name4'}]};// datapath 数据绑定// 渲染的为dapath所在的DOM分支$(selector).render({data: data,template: {e: 'div',// foreach: 'arr',t: {e: 'p',datapath: 'arr',t: 'this is [[name]]'}}});

foreach:

// foreach 数据绑定// 渲染的为foreach所在的DOM分支的子元素$(selector).render({data: data,template: {e: 'div',foreach: 'arr',t: {e: 'p',// datapath: 'arr',t: 'this is [[name]]'}}});
  • 当 datapath/foreach 指向的数据是对象时模板只渲染一次。
  • 当 datapath/foreach 指向的数据是数组时模板会对每一行数据渲染一次。
  • 当 datapath/foreach 指向的数据为 null 时模板不渲染。

两者的区别:datapath 需绑定在需要数据的元素上;foreach 需要绑定在需要数据元素的父元素上。

2.2.2.2.3 element 模板的 data 属性
// 绑定的数据类型为对象时$(selector).render({data: data,template: {e: 'div',// foreach: 'newData',t: {e: 'p',data: {sex: 'woman',address: '北京市'},t: '[[sex]][[address]]'}}});
2.2.2.2.4 使用数据
  • 在字符串模板中使用数据漫游器展示数据: 所有末级模板都一定是字符串模板,我们可以在字符串模板中用双方括号调用数据漫游器从绑定的数据源中取值。
vardata={location: {city: '天津'}};$(selector).render({data: data,template: {e: 'div',// 当前绑定的数据为datat: '<p>[[location/city]]</p>'// 根据数据路径,当前绑定的数据为data.location.city = data/location/city}});
  • 除子模版外,element 模板的 a,style,value,selected 的取值也可以用字符串模板调用数据漫游器生成。

  • 在函数模板中使用数据:在函数模板和其他允许使用函数的属性中,thin.js 都会将数据和当前 dom 元素作为参数的成员传递给函数。

2.2.2.3 element 模板:event 事件处理

event : 添加事件侦听器

event传入的值为对象,格式为 事件名:处理函数

2021-03-08更新:event支持传入数组对象的形式。[{事件名1: 处理函数1}, {事件名2: 处理函数2}]

vardata={name: 'wanfang',age: '20'};$(selector).render({data: data,template: {e: 'form',t: [{e: 'label',t: ['姓名:',{e: 'input',a: {name: 'name',type: 'text',value: '[[name]]'}}]},{e: 'label',t: ['年龄:',{e: 'input',a: {name: 'age',type: 'text',value: '[[age]]'}}]},{e: 'button',a: {type: 'button'},t: '提交',click: function(param){//因为click事件经常使用,所以不用放在event对象中console.log(param);// {// event: k.Event {// originalEvent: MouseEvent,// type: "click",// target: button,// currentTarget: button,// isDefaultPrevented: ƒ,// …// } 事件// new_data: {//可认为当前表单要提交的数据// name: "wanfang",// age: "50"// }// org_data: {//初始时对表单传入的数据// name: "wanfang",// age: "20"// }// sender: button 事件源// type: "click" 事件类型// }},event: {dbclick: function(param){console.log(param);},mouseover: function(param){console.log(param);}},// event: [// {// dbclick: function (param) {// console.log(param);// },// mouseover: function (param) {// console.log(param);// }// },// {// mouseout: function (param) {// console.log(param);// }// }// ]}]}});

传入的参数结构

名称描述
sender事件源
event事件
type事件类型
org_data原始数据
new_data新数据
Q&A
  1. Q:事件event中function传入的参数结构和函数模板(例:if:function(param){}、when:function(param){}...)中function的参数结构有何区别?

    A:事件中传入参数结构为:

    {sender:{事件源},event:{事件},type:{事件类型},org_data:{原始数据},new_data:{新数据}}

    函数模板中传入参数结构为:

    {container: 当前绑定的容器,data: 当前容器绑定的数据}

    函数模板具体使用情况请参考2.3 模板:函数

  2. Q:为什么有的时候new_data里面没有值,是个空对象?

    A:可能的情况:

    ⑴. 因为最外层template是一个数组,数据绑定时不确定绑定在哪一个父容器上。 例如:

    template: [{e: 'field',t: [{label: '资源分组'},{e: 'input',a: {name: 'scope'}}]},{e: 'field',t: [{label: '参考价格'},{e: 'input',a: {name: 'price'}}]},{e: 'div',t: [{e: 'button',t: '确定',click: function(param){// 此时打印的param中的new_data就为空对象。console.log(param);}}]}]

    ⑵. 表单里的input、textarea、select等表单元素没有name属性。

2.2.2.4 element 模板:style 控制样式

style : 设置行间样式

{e:"div",style:{width:"300px",height:"100px"}}

渲染结果:

<divstyle="width:300px;height:100px"></div>

style 的成员的属性名和值将用作渲染出来的节点的样式的名和值。 当需要生成的属性名包含特殊字符时,可以使用引号将属性名包括在内。

style:{"font-size":"14px"}

width / height : 设置宽度和高度

{e:"div",width:300,height:100}

生成结果:

<divstyle="width:300px;height:100px"></div>

width,height 为快捷样式,不用写在 style 里面。

style 的成员也可是函数,以根据数据生成不同的属性。

style:{"font-size":function(param){if(param.data.field===true){return"14px";}else{return"12px";}}}

注:函数需要返回字符串作为生成的样式的值。

2.2.2.5 element 模板:timer 添加定时/延时任务

timer 提供 thin 定时/延时功能

定时 setInterval:

varindex=1;$(selector).render({template: {e: 'p',t: {timer: {interval: 1000,do: function(param){console.log(index);index++;if(index>4){$(param.container).remove();}}}}}});

当定时器绑定的容器被移除时,定时器也会被移除。

延时 setTimeout:

$(selector).render({template: {e: 'p',t: {timer: {delay: 1000,do: function(param){console.log('我延时了1s');}}}}});
2.2.2.6 element 模板:options 添加option选项值

options接收三种参数值object、array、string;

  1. object
$(selector).render({template: {e: 'form',t: {e: "label",t: ["性别:",{e: 'select',a: {name: "sex",},options: {: 'man',: 'woman'}}]}}});

object的key为option标签的text;object的value为option标签的value值。

渲染结果:

<form><label>性别:
<selectname="sex"><optionvalue='man'></option><optionvalue='woman'></option></select></label></form>
  1. array
$(selector).render({template: {e: 'form',t: {e: "label",t: ["性别:",{e: 'select',a: {name: "sex",},options: ['男','女']}]}}});

该方法只渲染option标签的text属性(不建议使用)。

渲染结果:

<form><label>性别:
<selectname="sex"><option></option><option></option></select></label></form>
  1. string
$(selector).render({template: {e: 'form',t: {e: "label",t: ["性别:",{e: 'select',a: {name: "sex",},options: '男,女'}]}}});

该方法只渲染option标签的text属性(不建议使用)。

渲染结果:

<form><label>性别:
<selectname="sex"><option></option><option></option></select></label></form>
2.2.2.7 element 模板:value和selected默认值

value和selected可以给input和select标签默认值。

vardata={name: 'wanfang',age: '20',sex: 'woman'};$(selector).render({data: data,template: {e: 'form',t: [{e: "label",t: ["姓名:",{e: 'input',a: {name: "name",type: 'text'},value: '[[name]]'}]},{e: "label",t: ["年龄:",{e: 'input',a: {name: "age",type: 'text'},value: '[[age]]'}]},{e: "label",t: ["性别:",{e: 'select',a: {name: "sex",},options: {: 'man',: 'woman'},// 对于select标签来说selected和value都可以// selected: '[[sex]]',value: '[[sex]]'}]}]}});
2.2.2.8 element 模板:bind双向数据绑定

正常情况下事件中打印的org_data永远是传入的绑定数据data。 如果在element模板中使用了bind属性指定了数据路径,则在元素渲染时可以将相应的数据作为dom元素的值渲染出来,同时当dom元素的值发生变化时,thin.js也会用onchange事件捕获,并根据数据路径反向将数据自动更新到数据源中。

vardata={name: 'wanfang',age: '20'};$(selector).render({data: data,template: {e: 'form',t: [{e: "label",t: ["姓名:",{e: 'input',a: {name: "name",type: 'text'},bind: 'name'}]},{e: "label",t: ["年龄:",{e: 'input',a: {name: "age",type: 'text'},bind: 'age'}]},{e: 'button',a: {type: "button"},t: "提交",click: function(param){//因为click事件经常使用,所以不用放在event对象中console.log(param);// 如果改变了输入框的值,此时打印org_data为输入框最新的值。说明bind产生效果,改变了原有的data_of_thin}}]}});

2.2.3 模板:函数

模板可以是一个函数,渲染时会将当前位置的 dom 元素和绑定的数据传递给函数,用户可以编写自己的 javascript 代码进行渲染或其他操作。

{t: function(param){// some code here.console.log(param)}}

param对象:

成员描述
container当前dom容器
data容器绑定的数据

例子:

vardata={name: 'test1'};$(selector).render({data: data,template: {e: 'div',t: {e: 'div',class: 'test_div',t: function(param){console.log(param);// {// container:当前dom容器// data:当前容器绑定的数据// }$(param.container).text(param.data.name);}}}});
Q&A
  1. Q:函数模板中参数param为什么没有org_data、new_data等属性?

    A:org_data、new_data等属性只有在事件event中才会被function(param){}中的param形参传入,其他函数模板结构均为data,container。

2.2.4 模板:if 结构

用于根据条件真假决定使用哪个模板。

{if: 布尔表达式|判断函数,then: 真模板,else: 假模板}

例子:

vardata={name: 'test1'};$(selector).render({data: data,template: {e: 'div',t: {if: function(param){returnparam.data.name==='test1';},// if: true,then: {e: 'p',t: '真模板'},else: {e: 'p',t: '假模板'}}}});

param对象:

成员描述
container当前dom容器
data容器绑定的数据

2.2.5 模板:switch case 结构

switch case 结构

{switch:"[[参数]]",case:{"条件1":"template1","条件2":"template2",default:"default template"}}

例子:

vardata={name: 'test1'};$(selector).render({data: data,template: {e: 'div',t: {switch: '[[name]]',case: {test1: 'template1',test2: 'template2',default: 'default template'}}}});

2.2.6 when 结构

when写法可以根据传入的值控制容器是否渲染。也可根据传入的函数进行判断,然会相应是否渲染的值。

// when的使用varobj={// boolen: ''// boolen: '值'boolen: true}// when$(selector).render({data: obj,template: {e: 'p',t: {e: 'span',t: 'test',// 如果该数据路径值存在且不为空,渲染当前容器;反之不渲染。// 也可填入布尔值:true渲染;false不渲染when: 'boolen'// 也可根据数据进行判断,返回相应渲染结果// when: function (r) {// if (r.data.boolen) {// return true;// } else {// return false;// }// }}}});

2.2.7 组合模板

由前述五种模板组成的数组

vardata={name: 'test1'};$(selector).render({data: data,template: {e: 'div',class: 'test_div',t: [// 字符串模板'string template [[name]]',// element模板{e: 'p',t: '[[name]]'},// if模板{if: function(param){returnparam.data.name==='test1';},then: '真模板',else: '假模板'},// switch case模板{switch: '[[name]]',case: {test1: 'template1',test2: 'template2',default: 'default template'}},// 函数模板function(param){$(param.container).append(param.data.name);}]}});
<divclass="test_div">
string template test1
<p>test1</p>
真模板 template1 test1
</div>

3. poplayer 弹出层

poplayer弹出层可以在界面上弹出一个浮层,浮层的高度、宽度都可以自定义。

3.1 基本语法

poplayer({header: headertext,data: data,template: template});

template 语法与 render 完全一样。

3.2 poplayer 参数成员

成员类型描述
headerstring弹出框头部展示文字
heightstring高度
widthstring宽度
data数据
template模板
renderfunction自定义渲染器
onclosefunction浮层关闭时的回调函数(仅用于浮层右上角按钮关闭)

3.3 自定义渲染浮层

基本写法:

poplayer({header: headertext,render: function(param){renderFun(param);}});functionrenderFun(param){// to render// param结构:// {// container:{popbodycontainer}// }}

简单写法:

poplayer({header: headertext,render: renderFun});functionrenderFun(param){// to renderconsole.log(param);// param结构:// {// container:{popbodycontainer}// }}

注:poplayer中render函数不属于函数模板。该函数param传入参数只有popbody容器。

3.4 onclose 回调函数

vardata={name: 'test1',arr: [{name: 'test1',age: 18},{name: 'test2',age: 18},{name: 'test3',age: 18},{name: 'test4',age: 18}]};poplayer({data: data,header: '弹出框',onclose: function(){console.log('我关闭了');},template: {e: 'div',t: [{e: 'ul',t: {e: 'li',datapath: 'arr',t: '[[name]][[age]]'}}]}});

注:onclose 只为 poplayer 弹出层右上角关闭按钮的回调函数。其他 jq 操作移出弹出层都不会触发 onclose 事件

3.5 动态关闭 poplayer

poplayer 函数会将当前弹出窗口的 jq 对象 renturn 出来。当我们进行操作结束之后想关闭弹窗时可以进行 jq 删除操作。(该操作不会触发 onclose 事件)

vartestPop=poplayer({data: data,header: '弹出框',onclose: function(){console.log('我关闭了');},template: {e: 'div',t: [{e: 'ul',t: {e: 'li',datapath: 'arr',t: '[[name]][[age]]'}},{e: 'div',t: {e: 'button',t: '关闭',click: function(){testPop.remove();}}}]}});

4. tab 标签+multiview 多视图切换

tab标签可以通过固定语法渲染出一组tab导航栏;点击tab导航栏切换对应的内容页面。

4.1 基本语法

静态资源的tab导航栏,在项目中可以展示一些静态资源。通过tab-nav标签的view属性和view标签的id进行绑定。用户只需要进行渲染标签,省去了js操作。(动态资源不建议使用)

$(selector).render({data: '',template: [{multiview: [{e: 'tab',t: [{e: 'tab-nav',t: 'nav1',a: {class: 'active',view: 'nav1'}},{e: 'tab-nav',t: 'nav2',a: {view: 'nav2'}}// more tab-nav]},{e: 'view',t: '1',id: 'nav1',class: 'active'},{e: 'view',t: '2',id: 'nav2'}// more view]}]});

渲染结构:

<multiview><tab><tab-navclass="active" view="nav1">nav1</tab-nav><tab-navview="nav2">nav2</tab-nav></tab><viewid="nav1" class="active">1</view><viewid="nav2">2</view></multiview>

4.2 动态渲染

通过点击事件和渲染模板进行的动态资源渲染,可以添加hash路由使界面刷新之后渲染hash路由对应的界面;也可以添加default使每次重新加载默认选中default项。

点击时进行渲染,可用于异步渲染。

成员类型描述
defaultnumber默认渲染第几个导航
hashpathstring给tab-nav添加哈希路由
clickfunction点击事件,在点击事件里面动态渲染内容
$(selector).render({data: '',template: [{tab: {nav: {nav1: {// 自动向浏览器添加哈希路由(可选)// 刷新页面自动调用当前哈希路由的click事件hashpath: '#nav1',click: function(){// 渲染(可异步)$('#show_container').text(1);}},nav2: {hashpath: '#nav2',click: function(){$('#show_container').text(2);}},nav3: {hashpath: '#nav3',click: function(){$('#show_container').text(3);}},nav4: {hashpath: '#nav4',click: function(){$('#show_container').text(4);}}},// 默认渲染第几个default: 2}},{e: 'div',id: 'show_container'}]});

渲染结构:

<div><tab><tab-navhashpath="#nav1">nav1</tab-nav><tab-navhashpath="#nav2" class="active">nav2</tab-nav><tab-navhashpath="#nav3">nav3</tab-nav><tab-navhashpath="#nav4">nav4</tab-nav></tab><divid="show_container">2</div></div>

Q&A

  1. Q:动态渲染中的tab: {}的写法和第五章的简化写法一样么?

    A:不一样。动态渲染中的tab: {}为固定语法。

5. 简化写法以及补充写法

5.1 简化写法

简化之前基本语法:

$(selector).render({data: data,template: {e: 'p',t: 'this is [[name]]'}});
template:{e:'标签名',t:'html'}

简化之后的基本写法:

$(seletor).render({data: data,template: {p: 'this is [[name]]'}});
template:{'标签名':'html'}

5.2 handler 写法

  • closeon 通过事件移除标签

    • closeon:事件名称(多个事件用,隔开)

      在哪里写的 closeon,该事件就绑定在哪里

  • after 将 DOM 树添加到指定选择器之后

    • after: 'selector'
  • before 将 DOM 树添加到指定选择器之前

    • before: 'selector'
  • in 将 DOM 树添加到指定选择器之内

    • in: 'selector'
vartestDiv={e: 'ul',closeon: 'click',//该点击事件绑定在当前的ul上in: '.test_div',// before: '.test_div',// after: '.test_div',t: [{e: 'li',t: '1'},{e: 'li',t: '2'},{e: 'li',t: '3'},{e: 'li',t: '4'}]};$(selector).render({template: {e: 'div',t: ['<div class="test_div">我是容器</div>',{e: 'button',t: 'test',click: testDiv//点击渲染一组DOM树在指定位置}]}});

虚拟DOM树中第一层DOM必须使用基础写法({e: '标签名',t: html}),简化写法目前不被支持({'标签名':html})

渲染结果

before:

<divclass="test_container"><div><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul><divclass="test_div">我是容器</div>
测试
</div></div>

after:

<divclass="test_container"><div><divclass="test_div">我是容器</div><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul>
测试
</div></div>

in:

<divclass="test_container"><div><divclass="test_div">
我是容器
<ul><li>1</li><li>2</li><li>3</li><li>4</li></ul></div>
测试
</div></div>

click 接收的值为一个虚拟 DOM 树的话,会将当前的 DOM 树 append(默认为 append)到触发 click 事件的当前 DOM 里

5.3 纯数组的渲染

对于纯数组而言,我们想遍历数组中的每一项,可以在数据访问器里填写符号 "."。

// 纯数组的渲染vararr=['name1','name2','name3','name4','name5','name6'];$('.test_container').render({data: arr,template: {e: 'p',t: '[[.]]'}});

渲染结果:

<divclass="test_container"><p>name1</p><p>name2</p><p>name3</p><p>name4</p><p>name5</p><p>name6</p></div>

About

前端框架都太重了,自己写个羽量级的,基于html5+css3+jquery

Topics

Resources

Stars

29 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages