新的前端开发思路,告别html编码
http://dmimi.sinaapp.com/loyal/tabs.html
创建于时间2015年4月22日,不依赖类库。
这是什么东东,我想了一下,也许是一种可以改变开发者思维方式,让复杂的逻辑处理,变的简单的东东。
以前你是这样写代码的
<html>
...
<div class="tabs">
<div class="menu">
<ul>
<li>类型1</li>
<li>类型2</li>
<li>类型3</li>
<li>类型4</li>
<li>类型5</li>
</ul>
</div>
<div class="box">
</div>
</div>
...
</html>
<script>
var li = $(".menu > li");
li.on("click",function(){
var box = $(".box");
var index = $(this).index();
box.append("点了"+index);
});
</script>
如上写html, 写js,然后选择器,绑定事件处理,等等~~
用了loyal
<html>
...
<div h-name="tabs"></div>
...
</html>
<script>
var tabs = loyal({
name:"tabs",
view:{
menu:{
ul:{
repeat:{
data:"menu",
li:{
"h-on":"click:active"
}
}
}
},
box:{
"h-text":"content"
}
},
data:{
menu:["类型1","类型2","类型3","类型4"]
},
event:{
active:function(e,i){
tabs.data.update("content","哈哈"+i)
}
},
init:function(){
tabs.run();
}
});
tabs.init();
</script>
咋一看好像代码量多了,(但是你不觉得瞬间高大上了么),这是因为上例逻辑比较简单,如果是后面demo那样的,优势就出来了。
名字好难取,姑且取个名字叫 loyal 吧中文名 “洛亚尔”。
不要问我为何取这样的名字,我是不会告诉你乱打拼音首字母出来的HOHO。
怎么用 ?这里有个例子可以看 (ps:本例子使用了 npm browserify ,所以可以直接使用require,你也可以这样“配置”,或者引入seajs 或者 requirejs 或者 干脆不用require,直接在tabs.html里面写script标签引入依赖的js,就像demo这样)
tabs.html
<html>
<meta charset="utf-8">
<title>tabs Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0,minimal-ui">
<link rel="stylesheet" href="tabs.css"/>
<body>
<div h-controller="tabs">
<div h-name="tabs"></div>
</div>
</body>
</html>
<script src="tabs.js" charset="utf-8"></script>
tabs.js
var loyal = require("loyal.js");
var tabs = loyal({
version:1.0,
// 这个属性是必须的(固有关键字)
name:'tabs',
// 界面模型层(固有关键字),这里会被loyal解析为html插入到controller指定的容器内
view:{
menu:{
// 绑定了一个on click事件冒号后面是处理函数
"h-on":"click,tab:activeType()",
// 接受menu数据根据长度遍历,渲染节点。
repeat:{
// 数据的key名
data:"menu",
// 节点
tab:{
// 一个className类型的数据绑定
"h-class":"active{{i}}",
// text类型的数据渲染
text:'{{ value }}',
}
}
},
ul:{
// 指定容器名字作为标识,假如后续需要插入节点到这里
"h-name":"tabsBox",
// 监听数据改变 管道后面是处理函数
"h-watch-add":"type0 | addRecordToType0()",
repeat:{
// 数据key名也支持表达式
data:"list || type0",
li:{
text:'{{ content }}',
// className的数据渲染 支持表达式
class:"{{ i==0 ? 'first' :''}}",
time:{
// text的数据渲染 支持管道处理函数。
text:'{{ time | returnFormatDate() }}'
}
}
}
}
},
// 数据层(固有关键字),本例是写在代码里面,当然如果是ajax的也可以,只是respones后再挂到data下即可。
data:{
type0:[
{
content:'测试文案测试文案测试文案测试文案测试文案1',
time:"1431933120489",
type:1
},
{
content:'测试文案测试文案测试文案测试文案测试文案2',
time:"1431934520489",
type:1
},
{
content:'测试文案测试文案测试文案测试文案测试文案3',
time:"1431934410489",
type:1
},
],
type1:[
{
content:'测试文案测试文案测试文案测试文案测试文案4',
time:"1431234120489",
type:2
}
],
menu:[
'类型1',
'类型2',
'类型3',
'类型4',
'类型5'
]
},
// 数据绑定相关操作函数类(固有关键字)
event:{
activeType:function(e){
var i = $(this).index();
tabs.run({
repeat:tabs.view.ul.repeat
},
{
list:tabs.data["type"+i] || [ { content:"无" } ]
},"tabsBox");
// get符合匹配的字段,全部更新
tabs.data.update(
tabs.data.get(/active\d/),
""
);
// 更新当前焦点选项卡
tabs.data.update("active"+i,"active");
}
},
// 渲染编译处理函数类(固有关键字)渲染编译过程中用到自定义函数处理都放在这个类中
helper:{
returnFormatDate:function(date){
return date?$.date(date,"yyyy-MM-dd hh:mm:ss"):"";
}
},
init:function(){
// 初始化,生成DOMList
tabs.run();
// 更新data中的active0 那么对应节点的className会被添加一个"active";
tabs.data.update("active0","active");
}
});
tabs.init();
如上所示,html几乎不用写(还是要写的,只是换了更顺手的形式JSON,对就是JSON)
界面模型view,将会被编译渲染为html dom 树插入到容器中,渲染时候还能根据管道函数(helper)输出处理后的数值。
所有的交互都不和dom发生关系,而是效率更高的数据层交互,然后数据层会去修改dom节点比如切换选项卡,添加当前选项卡className active。
高效的一个原因是,编译过程中已经将dom进行缓存,简单讲类似: var a = $(".a"); 后面操作都是用变量a去操作。
你可以说那我之前都是这样写的。效率不是一样么? 答:性能效率是差不多,只是loyal帮你干了这件事。
总的来说,优点感觉有这么几个(个人拙见) 代码逻辑好像要清晰了,做为jser可以不用写html这种文本标记咯,不用让大脑来回切换html js 模式了,是不是很爽。(css的话以后再说,compass sass??) 代码看起来,好理解,看下view就知道程序是要干嘛,需要编写的代码量也少了很多, 上手简单(中国式英语)只有很少的api。 性能高效,用chrome Timeline 进行记录,然后不停的切换选项卡,对比用angularjs的方式实现,所需要执行次数和内存占用貌似好许多。(其实我想说,这chrome的一些开发工具用的还不是很溜) 作者本人才疏学浅,不善表达,非常非常需要大家的指正和围观。 API 界面模型中的一些渲染和绑定语法 静态渲染的几种写法// 普通替换
{{ name }}
// 函数处理后的替换
{{ name | returnFormat() }}
// 表达式执行结果值的替换
{{ name ? 'true' : '' }} 或者 {{ name=="lily" ? '20' : '18' }} 等等
动态绑定的几种写法
// 普通单个事件绑定
"h-on":"click:handle";
...
handle:function(e){
// this == element
}
// 多个事件绑定写法
"h-on":"click:handle,focus:isFocus";
...
handle:function(e){
// this == element
}
// 带参数的事件函数
"h-on":"click:handle(1)";
...
handle:function(e,i){
// this == element
// i === 1
}
// 监听类型的事件绑定
"h-on":"click,li:handle";
...
handle:function(e,i){
// this == li
// i === 1
}
// 普通className 赋值方法
"h-class":"active";
// if project.data.update("active","activeClassName");
// then element.className === "activeClassName";
// 带函数处理的
"h-class":"active | handle()";
...
handle:function(name){
// name === project.data[name];
// if return "xxxx";
// then element.className === "xxxx";
}
// 输入控件监听
"h-model":"active";
...
// if element isChanged;
// then project.data.active === element.value;
// 控件的赋值
"h-value":"active";
// if project.data.update("active","文案");
// then element.value === "文案";
// 元素内容
"h-text":"active";
// if project.data.update("active","文案");
// then element.text() === "文案";
// 初始化的时候就执行了。
"h-init":"handle";
...
handle:function(){
// if project.run();
// then this function will be run;
}
// 监听active属性的改变,触发handle函数
"h-watch":"active | handle";
...
handle:function(param){
// if active be changed all types
// then this function run
// param === project.data.active;
}
// 改变是add类型的,才会触发handle函数
"h-watch-add":"";
...
handle:function(param){
// if active be changed by add
// then this function run
// param === project.data.active;
}
"h-watch-update":"";
...
handle:function(param){
// if active be changed by update
// then this function run
// param === project.data.active;
}
more then
"h-watch-update":"";
"h-watch-remove":"";
DATA数据层操作
// 获取data下key名为name的值,这里的name支持RegExp,如: /active\d/;
.data.get("name")
// 更新data下key名active的值为"active", 支持多级如: "list[3].content";
.data.update("active","active")
// 给data下key名为type0的值添加一个json对象,所以这里的type0属性必定是一个数组
.data.add("type0",{content:"",time:""});
// 删除data下key名
.data.remove("type0");
继承
开放式的继承解决方案 引用作者民工精髓的文章内容:
我在用某个组件时需要重新调整一下组件里面元素的顺序怎么办? 我想要去掉组件里面某一个元素怎么办? 如何把组件变得更易扩展? 具体一点: 业务方不断要求给组件加功能怎么办?
Web 前端组件化是个难题
现状:
一些封装严密的组件,内部实现混淆,只提供特定接口,需要限制产品需求在组件所能提供的功能,例如 extjs 一些组件开放源码,一旦需求组件无法满足,由于比较方便添加修改源文件(现状大部分是这样)或者强行在现有的代码写if else 添加参数新增接口,或是拷贝一份做些修改取个新的名字再用,都没有能易用复用 (jQuery 各种插件)看看loyal 是怎么处理继承问题的。
// 改下标题和渲染数据
var tabs1 = {
name:"tabs1",
data:{
type0:[
{
content:"小明天真"
}
],
type2:[
{
content:"哈哈"
}
],
menu:[
"天真","无邪","美丽","可爱"
]
}
};
tabs1 = loyal(tabs1,tabs);
tabs1.init();
// 选项卡事件触发不同
var tabs2 = {
name:"tabs2"
};
tabs2.view = tabs.view.protocol();
tabs2.view.menu["h-on"] = "mouseover,tab:activeType()";
tabs2 = loyal(tabs2,tabs);
tabs2.init();
// 选项卡上有图标
var tabs3 = {
name:"tabs3"
};
tabs3.view = tabs.view.protocol();
tabs3.view.menu.repeat.tab.i = {};
tabs3 = loyal(tabs3,tabs);
tabs3.init();
效果可以看上面的demo
最后
如果觉得本文对你有所启发,请点一下右上角star,感谢。
githubhttps://github.com/306808700/loyal
版权声明:
1、该文章(资料)来源于互联网公开信息,我方只是对该内容做点评,所分享的下载地址为原作者公开地址。2、网站不提供资料下载,如需下载请到原作者页面进行下载。