不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端MVVM的本质
最近前端圈子里面,发现大家都在热炒概念,什么knockout,angularJs,都被捧成神了,鄙人不才,最近心情也不好,特地写这篇文章来找骂
写代码的码农都知道,Java社区虽然不是一个提出分层思想的,确实贯彻的最好的,如今是个Java开发都不会不知道SSH的开发模式,从MVC到MVVM的概念的热炒,其实真没什么技术进步
(如果你觉得本文言辞激烈,过于愤世嫉俗,实在看不下去,欢迎移步另一位园友的分层进化史科普文章http://www.cnblogs.com/indream/p/3602348.html)
先看什么是MVVM
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社区对于软件开发分层理解的精髓
标准的数据驱动开发,应该如上图所示,在一个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社区学习,多多从根本上了解分层理念的精髓,不要听了吹牛逼,听风就是雨,还是多了解原理才是真理啊
最近心情很不好,股票大跌,公司的事情你懂的,写这篇文档纯属没事找事,欢迎广大道友开骂,来陪我大战三百回合
不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端MVVM的本质的更多相关文章
- 前端MVVM框架设计及实现
最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的Avalon开始了,我2013年写过一个关于MVC MV ...
- MVVM框架avalon在兼容旧式IE
迷你MVVM框架avalon在兼容旧式IE做的努力 当前标签: avalon 共3页: 1 2 3 下一页 迷你MVVM框架avalon在兼容旧式IE做的努力 司徒正美 2014-03-13 11: ...
- Web前端MVC框架的意义分析
前言: Web前端开发是Web技术发展中的一个重要组成部分,在传统的前端开发中由于外界因素的影响导致其开发形式呈现出简单化的特点,即以页面为主体来展示界面中的信息.然而随着科学技术的不断进步,Web前 ...
- 轻量级前端MVVM框架avalon - 初步接触
迷你简单易用的MVVM框架 avalon的介绍http://rubylouvre.github.io/mvvm/ 按照作者的介绍,在HTML中添加绑定,在JS中用avalon.define定义View ...
- 前端MVVM框架设计及实现(一)
最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的avalon开始了,我记得还是去年6月写过一个系列的av ...
- 前端MVVM框架设计及实现(二)
在前端MVVM框架设计及实现(一)中有一个博友提出一个看法: “html中使用mvvm徒增开发成本” 我想这位朋友要表达的意思应该是HTML定义了大量的语法标记,HTML中放入了太多的逻辑,从而增加了 ...
- 轻量级前端MVVM框架avalon - 执行流程2
接上一章 执行流程1 在这一大堆扫描绑定方法中应该会哪些实现? 首先我们看avalon能帮你做什么? 数据填充,比如表单的一些初始值,切换卡的各个面板的内容({{xxx}},{{xxx|html}}, ...
- 前端MVVM框架avalon - 模型转换1
轻量级前端MVVM框架avalon - 模型转换(一) 接上一章 ViewModel modelFactory工厂是如何加工用户定义的VM? 附源码 洋洋洒洒100多行内部是魔幻般的实现 1: fun ...
- 前端MVVM框架:Knockout.JS(一)
前言 在我们平时开发 Web 应用程序的时候,如果项目不算特别大的话,一般都是拿 jQuery 再配合一些前端 UI 框架就在项目上面应用了.如果页面逻辑稍微复杂的话,那个在写前端 JavaScrip ...
随机推荐
- shell运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用. expr 是一款表达式计算工具,使用它能完成表达式的求值操作. #!/bin/bash v ...
- Apache Ignite高性能分布式网格框架-初探
Apache Ignite初步认识 今年4月开始倒腾openfire,过程中经历了许多,更学到了许多.特别是在集群方面有了很多的认识,真正开始认识到集群的概念及应用方法. 在openfire中使用的集 ...
- pt-table-checksum
pt-table-checksum是percona公司提供的一个用于在线比对主从数据一致性的工具. 实现原理 将一张大表分成多个chunk,每次针对一个chunk进行校验,同时将校验的结果通过REPL ...
- Intellij idea添加单元测试工具
1.idea 版本是14.0.0 ,默认带有Junit,但是不能自动生成单元测试,需要下载JunitGererator2.0插件 2.Settings -Plugins,下载 JunitGenerat ...
- 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...
- potrace源码分析一
1 简介 potrace是由Dalhousie University的Peter Selinger开发一款位图轮廓矢量化软件,该软件源码是可以公开下载的,详细见项目主页:http://potrace. ...
- 一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)
在目前的软件项目中,都会较多的使用到对文档的操作,用于记录和统计相关业务信息.由于系统自身提供了对文档的相关操作,所以在一定程度上极大的简化了软件使用者的工作量. 在.NET项目中如果用户提出了相关文 ...
- 基于SignalR的消息推送与二维码描登录实现
1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...
- 企业做数据缓存是使用Memcached还是选Redis?
企业是使用Memcached还是选Redis? 在构建一款现代且由数据库驱动的Web应用程序并希望使其拥有更为出色的性能表现时,这个问题总会时不时出现.并给每一位开发人员带来困扰.在考虑对应用程序的性 ...
- RabbitMQ + PHP (三)案例演示
今天用一个简单的案例来实现 RabbitMQ + PHP 这个消息队列的运行机制. 主要分为两个部分: 第一:发送者(publisher) 第二:消费者(consumer) (一)生产者 (创建一个r ...