以前都是默默地看园子里的文章,猥琐的点赞,今天也分享一下自己用 js 实现的一个简单 mvvm 框架.
最初只做了自动绑定事件,后面又参考学习了 vue,knouckout 以及 argular 实现方式,以及结合自己做 WPF 的一些经验,增加了属性绑定,今天又稍微整理了下,完善了部分功能,把代码提交到了码云:https://gitee.com/zlj_fy/Simple-MVVM
先简单介绍下用法:
首先定义一个控制器,可以是 json 对象,也可一是一个 function,然后在顶层的元素定义 data-context="[控制器名称]" 就可以将该控制器绑定到该节点底下所有元素.如果元素后代存在嵌套 Controller,则其所在的元素以下子元素作用域指向子控制器.
<form class="form-horizontal" role="form" data-context="TestController">
<div class="form-group">
<legend>Form title</legend>
</div>
<div class="form-group">
<div class="col-sm-6 col-sm-offset-2">
<input type="text" class="form-control" bind-val="age,format=format" style="margin:5px 0" />
<input type="text" class="form-control" bind-val="desc" style="margin:5px 0" />
<input type="range" min="10" max="300" bind-val="age" step="10" class="form-control" style="margin:5px 0" />
<input type="button" class="btn btn-primary" value="更新" style="margin:5px 0" on-click="update" />
</div>
</div>
</form>
<script>
var TestController = {
data: {
name: 'xiaoming',
age: 3,
desc: function() {
return this.name + ' likes looking little movie. he should take care of his body'
}
},
format: function(val) {
return val + '岁'
},
update: function() {
this.name = 'this is a test'
this.age = 18
}
}
$('body').controller()
</script>
1. 监控属性以及复杂属性
所有属性必须定义在 data 节点下,如果里面的属性定义成 function 则认为是复杂属性(例如 desc),复杂属性是只读的,重新赋值的话会提示错误.
绑定到 html 元素上的格式:"{属性名, fomat=[控制器方法]}",属性名支持嵌套属性,例如(a.b);属性名不支持表达式,考虑了觉得不是很有必要,完全可以使用复杂属性去代替,当前缺点是业务复杂的话可能造成大量复杂属性;属性名右边是可选参数,目前只有 format,也就是属性显示在 html 上的转换方法.
2. 指令
绑定指令语法是 bind-{指令} 的形式,目前只实现了 val,attr,text,html,template,其实可以看出,前面 4 个都只是简单封装了 jqeury 方法,template 是用到了 jquery-tmpl 插件实现的,如果你需要更多的指令,你可以自己去扩展,只需要实现 init 初始加载方法(接收当前的 observer 参数),以及 update 方法(参数说明:对应的 jquery 元素,最新的值,当前控制器实例);如果是扩展已有的指令,默认会覆盖原有的.如下:
3. 事件
$.controller.addDirective("val", {
init: function(observer) {
if (observer.$ele.is('input,select')) {
//监听onchange事件
observer.$ele.on('input propertychange',
function() {
var newVal = $(this).val() observer.writeValue(newVal)
})
}
},
update: function($ele, newVal, controller) {
$ele.val && $ele.val(newVal)
}
})
绑定事件语法:on-{事件}="{控制器方法},type=on/one",控制器方法右边是可选参数,目前只有绑定类型 on/one,默认是 on;控制器方法接收两个参数,一个是可在对应事件的元素上设置初始参数,一个是 event 事件参数;
<button type="button" class="btn btn-primary" data-page="1" on-click="refesh">查询</button>
4. 方法
直接使用 this. 属性名,就可以直接访问对应 data 节点下的属性.
5. 钩子
init 以及 created,init 是在监听所有属性之后编译 dom 之前,可以在这方法上初始化参数;created 是编译 dom 元素之后.
其中控制器默认实现了 extend 继承方法,可以继承另一个控制器,必须在 init 方法中使用.当前你也可以自己使用原型继承的方式去实现.
6. 扩展
init: function () {
this.extend(PageController)
},
created: function () {
//TODO
},
相信大家在做项目的时候肯定都会有一套公用的组件,那么可以像下面那样扩展,默认对应的组件挂载到所有的控制器示例下面,就可以之间在对应的方法下直接调用了: this.http.post();
不过有一个建议,就是尽量统一将回调方法的作用域指向控制器,这样开发不至于老是出现作用域的问题.
7. 原理以及代码分析(待续...)
$.controller.extend({
utils: utils,
notify: $.notify,
modal: $.modal,
http: $.http,
alert: $.alert
})
整个 js 代码量只有 300 多行,所以实现的比较简单,有很多方面是没有考虑到的,还有一些功能是想实现却没有去做的,目前不支持数组变化检测,以及局部更新相关 dom.
以上这篇 js 实现一个简单的 MVVM 框架示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家.
来源: http://www.jb51.net/article/132829.htm