一个只有十行的精简MVVM框架(下篇)
本文来自网易云社区。
让我们来加点互动
前面学生信息的身高的单位都是默认m,如果新增一个需求,要求学生的身高的单位可以在m和cm之间切换呢?
首先需要一个变量来保存度量单位,因此这里必须用一个新的Model:
const tk = {
'first-name': 'Jessica',
'last-name': 'Bre',
'height': 180,
'weight': 70,
}
const measurement = 'cm'
为了让tk更方便的被其他模块重用,这里选择增加一个measurement数据源,而不是直接修改tk。
在视图部分要增加一个radio单选表单,用来切换身高单位。
const createList = function(kvPairs){
const createListItem = function (label, content) {
const li = document.createElement('li')
const labelSpan = document.createElement('span')
labelSpan.textContent = label
const contentSpan = document.createElement('span')
contentSpan.textContent = content
li.appendChild(labelSpan)
li.appendChild(contentSpan)
return li
}
const root = document.createElement('ul')
kvPairs.forEach(function (x) {
root.appendChild(createListItem(x.key, x.value))
})
return root
}
const createToggle = function (options) {
const createRadio = function (name, opt){
const radio = document.createElement('input')
radio.name = name
radio.value = opt.value
radio.type = 'radio'
radio.textContent = opt.value
radio.addEventListener('click', opt.onclick)
radio.checked = opt.checked
return radio
}
const root = document.createElement('form')
options.opts.forEach(function (x) {
root.appendChild(createRadio(options.name, x))
root.appendChild(document.createTextNode(x.value))
})
return root
}
const createToggleableList = function(vm){
const listView = createList(vm.kvPairs)
const toggle = createToggle(vm.options)
const root = document.createElement('div')
root.appendChild(toggle)
root.appendChild(listView)
return root
}
接下来是ViewModel部分,createToggleableList函数需要与之前的createList函数不同的参数。因此,对View-Model结构重构是有必要的:
const createVm = function (model) {
const calcHeight = function (measurement, cms) {
if (measurement === 'm'){
return cms / 100 + 'm'
}else{
return cms + 'cm'
}
}
const options = {
name: 'measurement',
opts: [
{
value: 'cm',
checked: model.measurement === 'cm',
onclick: () => model.measurement = 'cm'
},
{
value: 'm',
checked: model.measurement === 'm',
onclick: () => model.measurement = 'm'
}
]
}
const kvPairs = [
{
key: 'Name: ',
value: model.student['first-name'] + ' ' + model.student['last-name']
},
{
key: 'Height: ',
value: calcHeight(model.measurement, model.student['height'])
},
{
key: 'Weight: ',
value: model.student['weight'] + 'kg'
},
{
key: 'BMI: ',
value: model.student['weight'] / (model.student['height'] * model.student['height'] / 10000)
}]
return {kvPairs, options}
}
这里为createToggle添加了ops,并且将ops封装成了一个对象。根据度量单位,使用不同的方式去计算身高。当任何一个radio被点击,数据的度量单位将会改变。
看上去很完美,但是当你点击radio标签的时候,视图不会有任何改变。因为这里还没有为视图做更新算法。有关MVVM如何处理视图更新,那是一个比较大的课题,需要另辟一个博文来讲,由于本文写的是一个精简的MVVM框架,这里就不再赘述,并用最简单的方式实现视图更新:
const smvvm = function (root, {model, view, vm}) {
let m = {...model}
let m_old = {}
setInterval( function (){
if(!_.isEqual(m, m_old)){
const rendered = view(vm(m))
root.innerHTML = ''
root.appendChild(rendered)
m_old = {...m}
}
},1000)
}
smvvm(document.body, {
model: {student:tk, measurement},
view: createToggleableList,
vm: createVm
})
上述代码引用了一个外部库lodash的isEqual方法来比较数据模型是否有更新。此段代码应用了轮询,每秒都会检测数据是否发生变化,有变化了再更新视图。这是最笨的方法,并且在DOM结构比较复杂时,性能也会受到很大的影响。还是同样的话,本文的主题是一个精简的MVVM框架,因此略去了很多细节性的东西,只把主要的东西提炼出来,以达到更好的理解MVVM模式的目的。
MVVM框架的诞生
以上便是一个简短精简的MVVM风格的学生信息的示例。至此,一个精简的MVVM框架其实已经出来了:
/**
* @param {Node} root
* @param {Object} model
* @param {Function} view
* @param {Function} vm
*/
const smvvm = function (root, {model, view, vm}) {
let m = {...model}
let m_old = {}
setInterval( function (){
if(!_.isEqual(m, m_old)){
const rendered = view(vm(m))
root.innerHTML = ''
root.appendChild(rendered)
m_old = {...m}
}
},1000)
}
什么?你确定不是在开玩笑?一个只有十行的框架?
请记住: 框架是对如何组织代码和整个项目如何通用运作的抽象。
这并不意味着你应该有一堆代码或混乱的类,尽管企业可用的API列表经常都很可怕的长。但是如果你研读一个框架仓库的核心文件夹,你可能发现它会出乎意料的小(相比于整个项目来说)。其核心代码包含主要工作进程,而其他部分只是帮助开发人员以更加舒适的方式构建应用程序的附件。有兴趣的同学可以去看看cycle.js,这个框架只有124行(包含注释和空格)。
总结
此时用一张图来作为总结再好不过了!

本文来自网易云社区,经作者顾静授权发布。
了解网易云 :
网易云官网:https://www.163yun.com
网易云社区:https://sq.163yun.com/blog
网易云新用户大礼包:https://www.163yun.com/gift
更多网易研发、产品、运营经验分享请访问网易云社区。
一个只有十行的精简MVVM框架(下篇)的更多相关文章
- 一个只有十行的精简MVVM框架(上篇)
本文来自网易云社区. 前言 MVVM模式相信做前端的人都不陌生,去网上搜MVVM,会出现一大堆关于MVVM模式的博文,但是这些博文大多都只是用图片和文字来进行抽象的概念讲解,对于刚接触MVVM模式的新 ...
- 一个只有十行的精简MVVM框架
本文来自网易云社区. 前言 MVVM模式相信做前端的人都不陌生,去网上搜MVVM,会出现一大堆关于MVVM模式的博文,但是这些博文大多都只是用图片和文字来进行抽象的概念讲解,对于刚接触MVVM模式的新 ...
- ViewModel从未如此清爽 - 轻量级WPF MVVM框架Stylet
Stylet是我最近发现的一个WPF MVVM框架, 在博客园上搜了一下, 相关的文章基本没有, 所以写了这个入门的文章推荐给大家. Stylet是受Caliburn Micro项目的启发, 所以借鉴 ...
- 实现一个类 Vue 的 MVVM 框架
Vue 一个 MVVM 框架.一个响应式的组件系统,通过把页面抽象成一个个组件来增加复用性.降低复杂性 主要特色就是数据操纵视图变化,一旦数据变化自动更新所有关联组件~ 所以它的一大特性就是一个数据响 ...
- 依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...
- 迷你MVVM框架 avalonjs 学习教程18、一步步做一个todoMVC
大凡出名的MVC,MVVM框架都有todo例子,我们也搞一下看看avalon是否这么便宜. 我们先从react的todo例子中扒一下HTML与CSS用用. <!doctype html> ...
- 如何实现一个简单的MVVM框架
接触过web开发的同学想必都接触过MVVM,业界著名的MVVM框架就有AngelaJS.今天闲来无事,决定自己实现一个简单的MVVM框架玩一玩.所谓简单,就是仅仅实现一个骨架,仅表其意,不摹其形. 分 ...
- 剖析手写Vue,你也可以手写一个MVVM框架
剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...
- .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]
为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...
随机推荐
- 8.spring:事务管理(上):Spring的数据库编程、编程式事务管理
Spring的数据库编程 Spring框架提供了JDBC模板模式------>JdbcTemplate 简化了开发,在开发中并不经常是使用 实际开发更多使用的是Hibernate和MyBatis ...
- vue.js加入购物车小球动画
生成一个动画小球的div,并且生成五个小球,五个是为了生成一定数量的小球来作为操作使用,按照小球动画的速度,一般来说五个也可以保证有足够的小球数量来运行动画 动画的内容分别是外层和内层,外层控制动画小 ...
- 下载安装Redis+使用
Window 下安装 第一步:安装 下载地址:https://github.com/MSOpenTech/redis/releases 第二步:解压(盘符) 第三步:打开一个 cmd 窗口 使用 cd ...
- ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现
ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现 承接 http://www.wowotech.net/pm_subsystem/suspend_and_re ...
- Etherlab debian安装记录
debian wheezy 7.11(虚拟机安装选择桥接网卡) #set ustc source #apt-get install sudo #nano /etc/sudoers;add userNa ...
- qt+vs2005新建配置不自动加载Generated Files进工程(个人备份)
工程右键Qt Project Settings 的Moc Directory路径删除 确定,再进入将删除路径加上
- Gradle Goodness: Set Java Compiler Encoding
If we want to set an explicit encoding for the Java compiler in Gradle we can use the options.encodi ...
- Mybatis ,框架
什么是mybatis MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis使用简单的XML ...
- 关于session序列化和session钝化和活化
在第一次启动服务器后,在session中放入一个对象.在页面可以获得,当重启服务器,但是没有关闭浏览器的情况下刷新页面仍然能够获得这个对象,前提是这个对象必须实现了java.io.Serializab ...
- Matplotlib——中级
关于Matplotlib的愚见 初级中,我只是简单介绍了Matplotlib的使用方法,在中级部分,我系统地说一下我总结的内容. 上图是我画的关于Matplotlib几个对象之间的关系图.它们都来自于 ...