zoukankan      html  css  js  c++  java
  • 不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端MVVM的本质

    最近前端圈子里面,发现大家都在热炒概念,什么knockout,angularJs,都被捧成神了,鄙人不才,最近心情也不好,特地写这篇文章来找骂

    写代码的码农都知道,Java社区虽然不是一个提出分层思想的,确实贯彻的最好的,如今是个Java开发都不会不知道SSH的开发模式,从MVC到MVVM的概念的热炒,其实真没什么技术进步

    (如果你觉得本文言辞激烈,过于愤世嫉俗,实在看不下去,欢迎移步另一位园友的分层进化史科普文章http://www.cnblogs.com/indream/p/3602348.html) 

    先看什么是MVVM

    image

    View一般就是我们平常说的HTML文本的Js模板,里面可以嵌入一些js模板的代码,比如Mustache,比如jstl类似的模板伪代码

    ViewModule层里面就是我们对于这个视图区域的一切js可视业务逻辑,举个例子,比如图片走马灯特效,比如表单按钮点击提交,这些自定义事件的注册和处理逻辑都写在ViewModule里面了

    Module就更简单了,就是对于纯数据的处理,比如增删改查,与后台CGI做交互

    那么什么是MVVM框架呢??一般他们都是这么做的

    1.  定义一串所谓的伪模板代码,例如通过className标注,或者自定义tag的方式,将一段html文本区域给标注声明起来,意思就是喊一嗓子,“喂,兄弟们,这块地方我占了,要拉屎去别处拉去”

    2.  通过类似jstl之类lamda表达式,来做js模板,“拜托伙计,天堂有路你不走,非要自己搞一套,你就不能暴露接口让大家用自己的模板语言,比如Mustache或者jtpl吗?”

    3.  很傻比的封装一串自己的所谓数据模块组件,与不同类型的数据源做数据传输和适配,一般都不会分层很清晰,加入后台数据字段改了,写框架的都没脑子的,从来不做数据字段的自定义适配(举个例子,原来后台传递的字段是person.userName,现在改成了小写,person.username,你就傻逼的去吧模板再改一下吧,其实要解决这个问题,非常简单,在MVVM层中引入一层DO,领域对象层,Module到DO之间还有一层转换就可以搞定这个问题)

    4.  非不暴露自己的自定义事件模型,就是那个观察者模式啦,自己乱七八招在页面上绑定一堆form change之类的事件,以实现View与Module的单向绑定

    5.  所谓的双向绑定,也就是OOP语言中早被烂透了的getter,setter模型,ES5+可以用defineProperty,低版本就需要自己在js object赋值的时间做写死代码方式的处理了

    我们再来看细节

    1. 双向绑定

    号称是最难理解的地方,其实是框架的作者根本就没理解Java社区对于软件开发分层理解的精髓

    image

    标准的数据驱动开发,应该如上图所示,在一个View的生命周期内,一个ViewModule会管理一个DomainObject(业务模型),一个DO可能包括多个Module数据模型,一个Module可能来自多个数据源,而不是想很多所谓的MVVM框架那样强迫一个M来一个数据源

    按照上图标准分层方式来划分的好处,在于,逻辑清晰,Module层粒度够细,可以被多次复用

    DO层与VM层View层属于一一对应关系,方便对数据做增删改查的同步

    每一层应该是独立的,非一定要使用MVVM框架的紧耦合,可以用自己使用不同的js插件或者模块实现MVVM

    我们抛弃框架,单纯的看数据,其实我们要解决的问题很简单

    a) 当DO对象属性放生变化时候,通知View更新

    b) 当View上表单值放生变化时,通知DO更新,并异步通知队列同步到数据源

    先来看问题a,这个最简单,DO是一个基本的Javascript Object,我们在View上的模板显示是这个Object.property,

    改变一个Object对象的方式无非几种,一种是

    a) 显示Object.property = ‘我是傻逼’

    b) xxxx.methodName(Object, ‘property’, ‘我是傻逼’)

    c) xxxx.merge(Object, {‘property’: ‘我是傻逼’})

    如果是a的情况,ES5+,可以通过设置Object.defefineProperty(‘property’,{set: functiono(){},get:function(){}}),来做赋值和取值的监控触发

    对于IE8一下,因为js不支持运算符重载,所以暂时没有好的办法,所以如果只考虑移动端的话,直接defineProperty就全部搞定,如果是要考虑PC的话,就不建议开发者使用直接赋值的方式,参考java的开发模式,也是推荐OOP时候,使用set方式赋值,而不是直接=赋值

    当然了,如果你非要兼容IE8一下的话,用定时器做轮训,配合for in 反射,通过脏数据与原始备份对比的方法也是一种办法,不过这种办法在当前页面非常耗性能,由于IE8一下不支持多线程,HTML5 worker,如果未来flash 插件支持多线程的话,倒是可以用js和flash插件做线程交互的方式做脏数据检测

    如果是b的情况,那就太简单了,在methodName里面触发对于该属性修改的回调即可,如何注册回调呢,首先我们要实现一个类似Dom Event的自定义对象的Event模型,然后通过类似Dom Event的注册事件方式,注册观察者,订阅事件,当执行了methodName时候,发送消息,通知所有订阅者执行回调

    如果是c的情况,类似b一样处理

    这样一看,双向数据绑定的问题就非常简单的解决了

    我们再来看另外一个MVVM的问题,非简单数据模型,复合数据模型(DO的属性值不是一个string,而是一个Object,且这个Object可能还嵌套多层Obejct的时候)的处理办法,这个一般的MVVM框架直接不考虑,或者通过长字段名的方式绕过这个问题

    这个问题是这样的,早在10几年前,java structs框架流行的时候就出现了,当一个表单,出现需要对两个Java Bean做update操作时候,一个bean是user,一个bean是成绩

    对应的表单字段名,就是 user表.name,user表.id,score表.point,

    在struct2里面,处理逻辑是把 “点”作为特殊符号,在做form序列化时候,非包含点的字段的值都是string,包含点的字段是一个Object,比如刚才的form序列化之后结果就是 { user: {id :’’ , name: ‘’}, score: {id: ‘’, point: ‘’}}

    同理在MVVM实现时,也是一样,认为点是分割对象的关键字,这样我们就可以实现把多个对象嵌套到View模板里面,实现复合Object的双向映射

    最后一个问题,也就是高级MVVM编程里面必须要面对的问题,就是自定义事件的广播和冒泡,我看过大多数的MVVM框架,对于广播,这块有部分实现了,但是对于冒泡一个都没实现

    其实这个真的不是很复杂的问题,事件广播,这个最简单,三岁小孩都能写,我们在注册回调时候,不是有一个事件队列吗,在回调时候,通过特殊标记位,控制是否继续扩散广播,还是执行完毕终止即可

    而自定义事件的冒泡要骚骚复杂一些,他是由于OOP编程里面的继承和包含关系引申而来的,我们先说包含关系,前面说了MVVM框架里面,都会声明一块地方为VM控制区域,一般垃圾的框架都不会考虑,VM嵌套的情况,因为图简单吗

    但是实际开发过程中,你会遇到很多这种情况,就是VM复用的问题,一般都是发现使用了MVVM框架之后,发现VM定义的太大,没法复用,如果要复用VM就又发现VM定义的太小,出现需要VM嵌套的情况没法用

    其实简单,我们知道DOM事件是有冒泡的,VM同理,只要在自定义事件模型里面定义了VM的父子关系,或者同级关联关系,即可实现VM的自定义事件的广播和冒泡,另外也解决了VM复用的问题,可以让代码颗粒度更小

    另外那种,声明式编程这种老掉牙的概念就真的别在吵了,还记得10几年前的structs的tag吗,js圈子里面这种通过自定义tag,自定义className,自定义属性,挂载js来自定识别执行逻辑的例子大把皆是,还是建议广大前端开发,不要浮躁,多像java社区学习,多多从根本上了解分层理念的精髓,不要听了吹牛逼,听风就是雨,还是多了解原理才是真理啊

    最近心情很不好,股票大跌,公司的事情你懂的,写这篇文档纯属没事找事,欢迎广大道友开骂,来陪我大战三百回合

  • 相关阅读:
    打造基于CentOS7的xfce最简工作环境
    Linux下C程序的编辑,编译和运行以及调试
    修正 XE6 TListView 上方 SearchBok 右边的清除钮显示
    TabControl 显示彩色的图示 (XE6 Firemonkey)
    TSwitch 中文简繁显示支持(XE6 Android)
    改变 TMemo 的背景颜色 (Firemonkey)
    修正 XE5 Android 键盘三个问题
    Delphi 收藏
    展示 Popup 的使用方法
    ListView 下拉更新 (支持 Android)
  • 原文地址:https://www.cnblogs.com/xueduanyang/p/3601471.html
Copyright © 2011-2022 走看看