js架构设计模式——前端MVVM框架设计及实现(一)
前端MVVM框架设计及实现(一)
最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了
借鉴的自然还是从正美的avalon开始了,我记得还是去年6月写过一个系列的avalon源码分析的,不过那时候0.7版本,不够健全,现在已经好太多了
框架是面向一个领域,提供一套解决方案,那么我们用前端的MVVM能为我们带来什么便利?
- 关注点分离
- 操作数据即操作DOM
- 动态模板
关注点分离是MVVM与身俱来的,操作数据即操作DOM,是VM中的访问器带来的,动态模板是流程绑定实现的。
关于MV*的讨论太多了,这里不在讨论,我们重点就是分析如何实现前端MVMM框架
Avalon 地址 https://github.com/RubyLouvre/avalon
学会MVVM需要先会哪些东西?
1. javascript语言基础(作用域,原型链,闭包等等)
2. 简单设计模式,基本的数据结构
3. 阅读或者写过jQuery源码
为什么要这样说呢,因为avalon就是这些东东的综合体!
我是以avalon为蓝本,按照作者是思路模仿实现的,当然avalon的代码有4000多行,新手如果去学习的话估计无从下手,也力不从心
为什么呢?简单的说实现的手段有点另类,写的代码有点狂野(请原谅我不知道如何形容),不过用户体验倒是不错!
简单的看下代码结构

<div ms-controller="box">
<div style=" background: #a9ea00;" ms-css-width="w" ms-click="click"></div>
<p>{{ w }}p>
</div>
<script>
avalon.define("box", function(vm) {
vm.w = 100;
vm.click = function() {
vm.w = parseFloat(vm.w) + 10;
}
})
</script>

针对这个代码结构,我们要明白:
1:为什么要自定义大量标记(声明式绑定)
这就是MVVM 最原始的意义,数据逻辑展现分离。表现就是 数据 js逻辑代码 htmlcss展现
所以再HTML里加结构是自然而然的事情,如果html都用js生成,那就跟mvvm搭不上边
2:avalon.define里面为什么不需要操作dom?
在MVVM中,数据是核心,由于VM与V之间的双向绑定,操作了VM中的数据(当然只能是监控属性),就会同步到DOM,我们透过DOM事件监控用户对DOM的改动,也会同步到VM。
本章我们就实现第一步:搭建基本的分层结构,实现双向通知机制
第一版实现:300行代码,请对照分析看源码 https://github.com/JsAaron/aaMVVM
针对上面2个问题,我们看看如何才能做到操作数据即操作dom呢?
简单的说一下实现是思路:大家可以down下git的aaMVVM对照下,比原版的4000行代码友爱多了!
我们知道在MVVM中,M只是一个过客,它与其他表示业务状态的东西融入VM(ViewModel)中。ViewModel是一个状态的集合,当然还拖家带口监控着大量的回调
所以ViewModel就承载的几乎所有的功能,在avalon中ViewModel就包含所有的数据与方法的定义,沟通着V与M,起到承上启下的作用~
视图模型如何与数据跟视图关联起来?
通过avalon.define定义的vm中的属性与方法都与对应的html结构中的标记有映射关系,所以改变vm中的数据与之关联的dom就会自动刷新
分析下
vm.w = 100
当模型的数据改变为100时,对应的视图中div的宽度为100, 文本<p>100</p> ,可见修改一个数据在同一个控制器内与之关联的2个映射动作都将会修改
一个是css操作,一个是text赋值
从这个操作我们可以大胆推测下vm.v中应该有一个列表,记录了当前控制器下对应的映射操作(多个)
为了实现set与get方法,avalon也类似emberjs,采用了Object.defineProperty
我用最简单的代码模拟下实现
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>测试VM</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
</head>
<body>
<div id='box' ao-controller="box">
<div id='aa-attr' style="background: #a9ea00;width:100px;height:100px;" ao-css-width="w" ao-click='click' ></div>
<p id='aa-text'>{{ w }}</p>
</div>
<script>
var vm = {}
var bindings = {
w: function(value) {
if (value) {
document.getElementById('aa-attr').style.width = value + 'px';
} else {
return document.getElementById('aa-attr').style.width;
}
}
}
var access = function(newValue){
if (newValue) { //set
bindings['w'](newValue);
} else { //get
return bindings['w']();
}
}
Object.defineProperty(vm, 'w', {
get : access,
set : access,
enumerable : true,
configurable : true
})
vm.w = 300 //设置element.style.width == 300
alert(vm.w)
</script>
</body>
</html>
也就是说
vm.w = 100 即要修改style也要修改p,就是一对多的关联方式
所以在avalon中针对每一个监控属性,都会生成set与get的访问控制器,那么在每一个监控属性的访问控制器里面都会有一个
accessor[subscribers] = [] //订阅者数组,这样的东东来存放与之相关的依赖

当我们触发 vm.w = 100时,就会触发w:set方法,取出accessor[subscribers]中的依赖,从而各执执行,这样就实现了依赖执行了
对应的方法:自动更新自身的依赖

//通知依赖于这个访问器的订阅者更新自身
function notifySubscribers(accessor) {
var list = accessor[subscribers]
if (list && list.length) {
var args = [].slice.call(arguments, 1)
for (var i = list.length, fn; fn = list[--i];) {
var el = fn.element
fn.handler(fn.evaluator.apply(0, fn.args || []), el, fn)
}
}
}

上面只是简单的思路,真正实现的时候真要做到大而全的框架,考虑的问题可不是那么简单的事
1 框架是怎么解释声明式绑定的语法
2 如何把解析后的语法生成对应的处理句柄
3 用户的定义如何生成vm模型
4 如何收集这些依赖
5 如何自动更新依赖映射
js架构设计模式——前端MVVM框架设计及实现(一)的更多相关文章
- js架构设计模式——前端MVVM框架设计及实现(二)
前端MVVM框架设计及实现(二) 在前端MVVM框架设计及实现(一)中有一个博友提出一个看法: “html中使用mvvm徒增开发成本” 我想这位朋友要表达的意思应该是HTML定义了大量的语法标记,HT ...
- 前端MVVM框架设计及实现(二)
在前端MVVM框架设计及实现(一)中有一个博友提出一个看法: “html中使用mvvm徒增开发成本” 我想这位朋友要表达的意思应该是HTML定义了大量的语法标记,HTML中放入了太多的逻辑,从而增加了 ...
- 前端MVVM框架设计及实现
最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的Avalon开始了,我2013年写过一个关于MVC MV ...
- 前端MVVM框架设计及实现(一)
最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的avalon开始了,我记得还是去年6月写过一个系列的av ...
- 前端MVVM框架:Knockout.JS(一)
前言 在我们平时开发 Web 应用程序的时候,如果项目不算特别大的话,一般都是拿 jQuery 再配合一些前端 UI 框架就在项目上面应用了.如果页面逻辑稍微复杂的话,那个在写前端 JavaScrip ...
- 轻量级前端MVVM框架avalon - 初步接触
迷你简单易用的MVVM框架 avalon的介绍http://rubylouvre.github.io/mvvm/ 按照作者的介绍,在HTML中添加绑定,在JS中用avalon.define定义View ...
- 前端MVVM框架avalon - 模型转换1
轻量级前端MVVM框架avalon - 模型转换(一) 接上一章 ViewModel modelFactory工厂是如何加工用户定义的VM? 附源码 洋洋洒洒100多行内部是魔幻般的实现 1: fun ...
- js架构设计模式——你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解?
你对MVC.MVP.MVVM 三种组合模式分别有什么样的理解? MVC(Model-View-Controller)MVP(Model-View-Presenter)MVVM(Model-View-V ...
- 不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端MVVM的本质
最近前端圈子里面,发现大家都在热炒概念,什么knockout,angularJs,都被捧成神了,鄙人不才,最近心情也不好,特地写这篇文章来找骂 写代码的码农都知道,Java社区虽然不是一个提出分层思想 ...
随机推荐
- Fragment和Activity(转)
Android Fragment和Activity Fragment和Activity Fragment和Activity的交互 一个Fragment的实例总是和包含它的Activity直接相关. f ...
- 快速搭建本地HTTP服务器
我们都知道,可以通过浏览器直接打开HTML文件来查看可视化的效果,但这种方式有一些局限性.比如我们在做手机端适配的时候,无法直接查看手机端的效果等.为了不受此类限制,强烈建议搭建一个本地的HTTP服务 ...
- 如何把一个TXT文本文件按行数分割成多个文本文件
2011-04-27 12:00:24| 分类: 默认分类 |字号 订阅 网上有很多文本分割软件都是按字节大小来分割的,主要用于小说类的文本分割,对于比较有规则的内容按行数进行分割非常不方便 ...
- 更少的直接百度,更多的取看API
很多时候我们会对于一个jar包中的一个类的某个方法犯迷糊 我们不知道传进去什么样子的参数,这个方法的返回值到底是什么样的. 更多的时候我们不知道这个jar中有没有我们想要的这个方法. 很多时候以前我都 ...
- 关于flex4 list 高度适应内容
Flex 4: Setting Spark List height to its content height How to set a Spark List height to the height ...
- POJ 3186 Treats for the Cows
简单DP dp[i][j]表示的是i到j这段区间获得的a[i]*(j-i)+... ...+a[j-1]*(n-1)+a[j]*n最大值 那么[i,j]这个区间的最大值肯定是由[i+1,j]与[i,j ...
- SQL复习三(子查询)
子查询 子查询就是嵌套查询,即select中包含这select,如果一条语句中存在着两个,或者两个以上的select,那么就是子查询语句了. 子查询出现的位置 where后,作为条件的一部分: fro ...
- MRC的下setter访问器的两种形式
// Person复合了Phone和Room // 第一种:比较合理 先判断对象形参传递的对象和原属性是否一致,不一致在释放旧值,给形参传递的值retain,因为retain方法会返回该对象,因此可以 ...
- Oracle教程-安装、结构(一)
本文安装的是Oracle中的11G版本 一. 将文件win32_11gR2_database_1of2.zip和win32_11gR2_database_2of2.zip解压. 注意:这两个文件解压到 ...
- eazasyui树形菜单
//此处是easyui的json格式 var tree = { id:'', text:'', state:'', checked:'', attributes:'', children:'' } / ...