博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
我的MVVM框架 v3发布!
阅读量:6887 次
发布时间:2019-06-27

本文共 5239 字,大约阅读时间需要 17 分钟。

人们总是爱探求完美的东西,医学界追求长生不死之药,炼金术师追求贤者之石,物理学家追求永动机……编程界也有自己的追求,完美架构什么的,什么从MVC,到MVP,到MVVM……当然MVC,MVP,MVVM有他们不同的场景,但MVVM在微软试水后已被证实为界面开发最好的方案了。于前端而言,一直纠缠于模板与组件的优劣。其实答案大家都知道,web page用模板, web app用组件,问题是如何将它们统合起来。页面之所以能交互,是因为它存在状态。因此核心问题是如何将这两者管辖的状态统合在一起。状态的由来有两个,直接从模型得到,比如后端传送过来的JSON与XML,或比较悲剧地把PHP序列化的字段还原出来,第二种是在程序中控制流程时不生的中间量。我们可以这些后端数据或中间量整成一个数据源,或作为模板的填充数据,或作为组件的传参最后成为它的属性。MVVM的出现就很好解决这问题,数据是数据,最好作为贫血模型而存在,对这些数据的操作以及基于这些操作的操作独立成另一个东西,ViewModel。View是设计师与页面重构师的阵地。于是我们能实现并行开发。View与ViewModel的连结是数据绑定,ko称之为声明式绑定。绑定可以分解成绑定器与相应的参数,它们调用ViewModel的东西,ViewModel操作Model。绑定器通常是非常薄的一层,很少被人提起,但意义重大。它实现了数据再加工与事件绑定(WPF称之为命令),从而让数据可视,操作可用!整个流程是非常清晰的,得到Model,抽象出ViewModel,在View中声明绑定,就完了。觉得框架提供的功能不足,就添加自定绑定器,在ViewModel添加命令(它可以作为事件回调,或数据的过滤器,验证函数,格式函数)。格式是固定的,像后端那梓,哪个页面应该由哪个action负责都有规可循。这正是我们前端梦寐以来的究极解决方案。

但思路是有,实现起来不轻松,因此前端的MVVM框架也林林总总,每个月都冒出一两个出来。开源的世界类似于免费的世界,很容易引起马太效应,强者愈强,弱者愈弱,很易产生垄断。jQuery的一枝独秀也证明了这一点。MVVM框架的混乱说明还没有出现足够称得上强大的东西。现在比较拉风的是knouckoutjs,emberjs,angularjs,backbone(它也有数据绑定插件让它改装成真正的MVVM)。个人是比较看好knouckoutjs,毕竟是由MVVM的发源地微软的人搞的,是最正统的派系。但它的绑定也一直被人诟病,太复杂难用。后端的WPF由微软的强大工具撑着,因此人们觉得不怎么。但一旦要你们手写这些绑定时就惨了,加之前端经过jQuery那极简主义的DSL式API洗礼后,很多人无法接受这样复杂的用法。emberjs与angularjs对IE6支持不佳,因此在大陆没有销路,加之提供的API太多了,对应的概念也多,学习曲线陡峭。backbone是太笨重,没有干什么活,却要写一大堆代码,与jQuery反向而行。

我的MVVM框架avalon v3两个重要借鉴者为knouckoutjs与。从knouckoutjs得到它的双向依赖链的架构,从学习到消化经历两个版本,v2的实现完全原创。从rivetsjs得到它的声明式绑定的API设计,但实现完全是自己的。v3对v2的双向依赖链的架构进行一些改进,只要是重命名,让这些概念更让人接受。

avalon v3的双向绑定链架构图

// ViewModel              框架              View    //属性访问器  ┓    //组合访问器 ┫→→→绑定器 ←←← DOM访问器 ←←← 数据绑定    //集合访问器 ┫    //命令       ┛

ViewModel是一个由访问器与命令组成的对象。访问器即accessor, 取义自ruby的attr_accessor,是attr_writer, attr_reader的结合,用于对某个数据进行读写操作。比如Model中有个aaa属性,ViewModel就会对应生成一个叫aaa的函数,我们可以传参修改这个aaa的值,也可以从它那时得到aaa的值。之所以这么大周折,是因为IE9才支持用Object.defineProperty描述对象的属性的访问机制,它是否可遍历啊,可配置啊,读取时应该返回什么,写入时会进行什么处理。如果aaa属性与bbb属性有关联,我们可以在访问aaa时修改bbb,直接obj.aaa = "xxx"就行了。但为了兼并IE6,我们唯有obj.aaa("xxx")。emberjs就是基于Object.defineProperty构建它的双向绑定链,因此对IE9-支持不好。

//IE9+ FF4+, safari5+, opera11+, chrome5(IE8只支持DOM)var obj = {}, aValue = 0;Object.defineProperty(obj, "aaa", {    get : function(){        return aValue;    },    set : function(newValue){         obj.bbb += newValue        aValue = newValue;     },    enumerable : true,    configurable : true})Object.defineProperty(obj, "bbb", {    value :10,    writable : true,    enumerable : true,    configurable : true});                console.log(obj.aaa)//0console.log(obj.bbb)//10obj.aaa = 7console.log(obj.aaa)//7console.log(obj.bbb)//17//IE6+var aValue = 0, bValue = 10;var obj = {    aaa: function(newValue){        if(arguments.length){            bValue += newValue            aValue = newValue;                     }        console.log("xxxxxxxxx")        return aValue    },    bbb: function(newValue){        if(arguments.length){            bValue = newValue;         }                  return bValue    }}    console.log(obj.aaa())//0console.log(obj.bbb())//10obj.aaa(7)console.log(obj.aaa())//7console.log(obj.bbb())//17

访问器又分四种,存在于ViewModel中的有三种。最简单的是属性访问器,它是对Model中某一个属性进行操作,相当于ko的监控属性。如果一个字段由模型中的两个属性,或两个以上,或要对这属性进行一下加工才产生它的值呢,这就要用到组合访问器,相当于ko的依赖监控属性,或emberjs中的computed。像程序中许多表示状态的中间量都可以抽象成一个组合访问器。组合访问器换言之,对已有的东西重新组合而成的属性的监控函数。集合访问器,是Model中的数组进行监控,如果它发生排序增删,它会通知双向依赖链的两端来刷新自身。集合访问器是个特殊的数组,它的方法都被重写了,虽然用法一样,但调用了它们会同步到对应的节点区域上!

ViewModel中还存在一种叫命令的东西,打个比方,绑定器相当于MVC中的action,命令相当于helpers。它只是一个普通的函数,框架不会再对它加工。框架对命令与访问器的区分是,访问器是用$type 与 "$"+(new Date - 0)这两个属性。说得可能有点复杂,比如有个对象var model = {aaa:1, bbb:1},然后$.ViewModel( obj )就得到它对应的ViewModel了。

接着我们看绑定部分。要实现事件绑定。knouckoutjs实现如下:

Mouse over me
Details

avalon v3参考了的绑定语法,实现如下:

Mouse over me
Details

要实现循环绑定,knouckoutjs实现如下

First name Last name

avalon v3实现如下:(data-each-[item]-[index],item, index是可选,名字任取,只要符合变量命名规则就行)

 
First name Last name

avalon v3的优势在于,它完全DSL,我们可以通过点号来查找VM中某一个可用的访问器或命令,作为数据绑定的值。而且实现起来很简单,不需要像knouckoutjs那样编写复杂的JSON编译器。复杂的东西就难维护,不易升级。有关数据绑定以后我与一系列教程介绍它的。

在数据绑定中,我们借助于一种特殊的属性来指引MVVM干活,格式为data-binding-[param]-[param]。以“-”断开,第二个字符串为绑定器的名字,剩余的为它的参数。比如事件绑定,data-on-click。

在avalon v3中,它提供了以下默认绑定器,可以通过$.ViewModel.bindings访问到。v3弥合了v2的伤口,完美支持事件绑定与事件代理。

  • data-text
  • data-html
  • data-class
  • data-css-[class]
  • data-attr
  • data-value
  • data-display
  • data-on-[event]
  • data-enable
  • data-disable
  • data-options
  • data-each-[item]-[index]
  • data-with-[value]-[key]
  • data-if
  • data-unless

avalon v3会将这个属性的名字分解成绑定器与其他参数,再将它的值得到VM中对应的访问器与命令,最后把它们构建成一个叫DOM访问器的东西,作为双向绑定链的顶层,专门与DOM打交道。

在jQuery时代,ID是我们命中元素最可靠的基点,以此为起点八爪鱼般处理周遭的节点。行为层上,我们通过事件绑定,几乎可以用根据代理一切事件。但jQuery是函数式编程,状态如果在连续在多个回调中使用时,它就要写在回调外面。当然我们可以缓存于某个节点上(data),在另一个回调中通过选择器得到那个节点再重新data出来。但整体上,jQuery代码都是以事件分割成一段段,中间夹杂着一些中间量与处理函数。它们是否能很好工作完全看编程人员的技术水平了。在MVVM中,数据绑定与元素是一体的,因此绝没有偏差。处理交互上,事件以命令的新身份登场, 回调被集合管理于VM,状态也被收笼于VM中,我们不再为如何组织代码伤脑筋,所有都有章而循,新手接力也易上手。MVVM减少对选择器的依赖,将数据与操作绑定在坚固的支点上。

过几天写些教程,介绍如何用。完!

转载地址:http://rvtbl.baihongyu.com/

你可能感兴趣的文章
iMatrix平台中组织结构树标签acsTags:tree用法
查看>>
WinForm多线程编程
查看>>
Hyperledger Fabric 客户端开发五
查看>>
spring的参数校验
查看>>
Nginx的URL Rewrite基本指令
查看>>
Properties属性文件操作工具类PropsUtil
查看>>
计算机系统要素 C4
查看>>
Mysql存储引擎
查看>>
每看一次自己写的代码都有一种重写的冲动
查看>>
androidManifest.xml问题
查看>>
升级ubuntu后nginx无法启动
查看>>
inux多线程顺序控制的示例
查看>>
SQLServer 2016安装时的错误:Polybase要求安装Oracle JRE 7更新51或更高版本
查看>>
wkhtmtopdf--高分辨率转HTML成PDF(二)
查看>>
如何优雅的编写Dockerfile
查看>>
调试时显示数据防止乱码
查看>>
logback 日志输出级别设置
查看>>
直接插入法
查看>>
用户管理 新老用户的管理
查看>>
linux时间同步命令
查看>>