当前位置: 首页 > news >正文

前端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

我用最简单的代码模拟下实现

测试VM

{{ w }}

也就是说

vm.w = 100  即要修改style也要修改p,就是一对多的关联方式

所以在avalon中针对每一个监控属性,都会生成set与get的访问控制器,那么在每一个监控属性的访问控制器里面都会有一个

accessor[subscribers] = [] //订阅者数组,这样的东东来存放与之相关的依赖

image

当我们触发  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 如何自动更新依赖映射

 

GitHub上会同步更新最新的实现,。。。敬请关注~

Fork https://github.com/JsAaron/aaMVVM

相关文章:

  • python的不定时更新
  • LumiSoft收取邮件(含邮件附件)
  • Frost Sullivan权威报告:阿里云再次领跑云WAF大中华区市场
  • Yii框架官方指南系列28——缓存:概览
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • 一个表单对应多个提交按钮,每个提交按钮对应不同的行为
  • MySQL用户中的%到底包不包括localhost?
  • tomcat集群时统计session与在线人数
  • 初探G6, 切换数据时保证图位置不变
  • 常见div+css网页布局(float,absolute)
  • 用PyTorch创建一个图像分类器?So easy!(Part 1)
  • 【Leetcode】Path Sum II
  • docker学习笔记
  • 3、开启debug调试模式
  • 为什么BAT公司使用微服务架构,资深架构师来告诉你原因!
  • 〔开发系列〕一次关于小程序开发的深度总结
  • 4个实用的微服务测试策略
  • Electron入门介绍
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • MySQL主从复制读写分离及奇怪的问题
  • Unix命令
  • 解决iview多表头动态更改列元素发生的错误
  • 聊一聊前端的监控
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 新手搭建网站的主要流程
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 数据库巡检项
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • #FPGA(基础知识)
  • #Spring-boot高级
  • #Ubuntu(修改root信息)
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (原)本想说脏话,奈何已放下
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)winform之ListView
  • (转)平衡树
  • (转)原始图像数据和PDF中的图像数据
  • .net 生成二级域名
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • /bin/rm: 参数列表过长"的解决办法
  • @基于大模型的旅游路线推荐方案
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [2016.7.Test1] T1 三进制异或
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [Android] 240204批量生成联系人,短信,通话记录的APK
  • [Android]如何调试Native memory crash issue
  • [AutoSar]工程中的cpuload陷阱(三)测试
  • [BT]BUUCTF刷题第9天(3.27)