js实现一个简单的MVVM框架

以前都是默默地看园子里的文章,猥琐的点赞,今天也分享一下自己用js实现的一个简单mvvm框架。

最初只做了自动绑定事件,后面又参考学习了vue,knouckout以及argular实现方式,以及结合自己做WPF的一些经验,增加了属性绑定,今天又稍微整理了下,完善了部分功能,把代码提交到了码云:https://gitee.com/zlj_fy/Simple-MVVM

先简单介绍下用法:

 1 <form class="form-horizontal" role="form" data-context="TestController">
 2         <div class="form-group">
 3             <legend>Form title</legend>
 4         </div>
 5         <div class="form-group">
 6             <div class="col-sm-6 col-sm-offset-2">
 7                 <input type="text" class="form-control" bind-val="age,format=format" style="margin:5px 0" />
 8                 <input type="text" class="form-control" bind-val="desc" style="margin:5px 0" />
 9                 <input type="range" min="10" max="300" bind-val="age"  step="10" class="form-control" style="margin:5px 0" />
10                 <input type="button" class="btn btn-primary" value="更新" style="margin:5px 0" on-click="update" />
11             </div>
12         </div>
13     </form>
14
15     <script>
16         var TestController = {
17             data: {
18                 name: ‘xiaoming‘,
19                 age: 3,
20                 desc: function() {
21             return this.name + ‘ likes looking little movie. he should take care of his body‘
22                 }
23             },
24             format: function(val) {
25                 return val + ‘岁‘
26             },
27             update: function() {
28                 this.name = ‘this is a test‘
29                 this.age = 18
30             }
31         }
32         $(‘body‘).controller()
33     </script>

首先定义一个控制器,可以是json对象,也可一是一个function,然后在顶层的元素定义data-context=“[控制器名称]”就可以将该控制器绑定到该节点底下所有元素。如果元素后代存在嵌套Controller,则其所在的元素以下子元素作用域指向子控制器。

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元素,最新的值,当前控制器实例);如果是扩展已有的指令,默认会覆盖原有的。如下:

 1 $.controller.addDirective("val", {
 2         init: function (observer) {
 3             if (observer.$ele.is(‘input,select‘)) {
 4                 //监听onchange事件
 5                 observer.$ele.on(‘input propertychange‘, function () {
 6                     var newVal = $(this).val()
 7                     observer.writeValue(newVal)
 8                 })
 9             }
10         },
11         update: function ($ele, newVal, controller) {
12             $ele.val && $ele.val(newVal)
13         }
14     })

3.事件

绑定事件语法:on-{事件}=“{控制器方法},type=on/one”,控制器方法右边是可选参数,目前只有绑定类型on/one,默认是on;控制器方法接收两个参数,一个是可在对应事件的元素上设置初始参数,一个是event事件参数;

1 <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方法中使用。当前你也可以自己使用原型继承的方式去实现。

1             init: function () {
2                 this.extend(PageController)
3             },
4             created: function () {
5                 //TODO
6             },

6.扩展

相信大家在做项目的时候肯定都会有一套公用的组件,那么可以像下面那样扩展,默认对应的组件挂载到所有的控制器示例下面,就可以之间在对应的方法下直接调用了: this.http.post();

不过有一个建议,就是尽量统一将回调方法的作用域指向控制器,这样开发不至于老是出现作用域的问题。

1 $.controller.extend({
2             utils: utils,
3             notify: $.notify,
4             modal: $.modal,
5             http: $.http,
6             alert: $.alert
7         }) 

7.原理以及代码分析(待续...)

整个js代码量只有300多行,所以实现的比较简单,有很多方面是没有考虑到的,还有一些功能是想实现却没有去做的,
目前不支持数组变化检测,以及局部更新相关dom。

哎,写博客好费时间,先睡了。。。

原文地址:https://www.cnblogs.com/zhonglj/p/8281009.html

时间: 2024-07-29 14:45:05

js实现一个简单的MVVM框架的相关文章

撸一个简单的MVVM框架

我个人以为mvvm框架里面最重要的一点就是VM这部分,它要与Model层建立联系,将Model层转换成可以被View层识别的数据结构:其次也要同View建立联系,将数据及时更新到View层上,并且响应View对数据的更改,同步到Model层. MVVM的具体例子,可以看一下阮一峰老师的这篇博客. 我们提取其中比较关键的点: Model层存储数据 需要一个View-Model来对数据做中转,响应数据变化,同步到两端 View层来负责展示数据,接受用户事件 Model层,我们用一个对象来代表.例如:

使用js编写一个简单的运动框架

下班后,,没事捣鼓捣鼓个人的小爱好. 首先,说明我的这个运动框架(css所有属性)也是常见的框架一种,健壮性并不是太好,对于新手学习倒是挺好,,若是大神,老司机请拐弯. 上来,我们先定义一个区块,然后在关联一个可以实时看到属性值发生变化值的标签. html: <body> <div id = "div1"> </div> <input type = "text" id = "txt1"> </

230行实现一个简单的MVVM(转载)

https://zhuanlan.zhihu.com/p/24475845 作者:mirone链接:https://zhuanlan.zhihu.com/p/24475845来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 题图的PixivID为:pixiv-ID: 14402942,画师为RAHWIA 本文始发于我的博客,转载请注明作者. MVVM这两年在前端届掀起了一股热潮,火热的Vue和Angular带给了开发者无数的便利,本文将实现一个简单的MVVM,用20

230行实现一个简单的MVVM

作者:mirone链接:https://zhuanlan.zhihu.com/p/24451202来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. MVVM这两年在前端届掀起了一股热潮,火热的Vue和Angular带给了开发者无数的便利,本文将实现一个简单的MVVM,用200多行代码探索MVVM的秘密.您可以先点击本文的JS Bin查看效果,代码使用ES6,所以你可能需要转码. 什么是MVVM? MVVM是一种程序架构设计.把它拆开来看应该是Model-View-V

一个简单的MVVM雏形

这是@尚春实现的MVVM,使用定时器轮询,只支持{{}}与input.value的修改. 这只能算是一个玩具,真正的MVVM需要有更复杂的扫描机制,JS解析器,双向绑定链什么的. <!DOCTYPE html> <html> <head> <script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script> <

JS实现一个简单的计算器

使用JS完成一个简单的计算器功能.实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除.效果如上: 第一步: 创建构建运算函数count(). 第二步: 获取两个输入框中的值和获取选择框的值. 提示:document.getElementById( id名 ).value 获取或设置 id名的值. 第三步: 获取通过下拉框来选择的值来改变加减乘除的运算法则. 提示:使用switch判断运算法则. 第四步:  通过 = 按钮来调用创建的函数,得到结果. 注意: 使用parseInt

[3] 用D3.js做一个简单的图表吧!

本人的个人博客为: www.ourd3js.com csdn博客为: blog.csdn.net/lzhlzz 转载请注明出处,谢谢. 前面说了几节,都是对文字进行处理,这一节中将用 D3.js 做一个简单的柱形图. 做柱形图有很多种方法,比如用 HTML 的 div 标签,或用 svg . 推荐用 SVG 来做各种图形.SVG 意为可缩放矢量图形(Scalable Vector Graphics),SVG 使用 XML 格式定义图像,不清楚什么是SVG的朋友请先在 w3cschools 学习下

用JS做一个简单的电商产品放大镜功能

使用js制作一个简单的产品放大图 购物网站的产品页经常会放有一个产品展示图区.该图区有一个功能就是产品图的放大功能,移动左侧的焦点区域,可以放大细节部分观看,详情如下图.实现该功能的方法也非常简单. 实验:制作产品焦点放大图. 所需技能:1.基本的获取页面元素的方法: 2.几个简单的事件: 3.会使用dom设置元素的属性: 案例原理:1.焦点框的跟随鼠标事件: 2.焦点框的移动区域规定: 3.大盒子内容的显示: 适合对象:js初学者 -------------------------------

分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业不是百度来的,我只是百度了一些示例代码的意思,怎么用!算了,越解释万一越黑呢!哈哈O(∩_∩)O哈哈~) ----------------------------------------------------------------分界线------------------------------