TNTWeb - 全称腾讯新闻前端团队,组内小伙伴在Web前端、NodeJS开发、UI设计、挪动APP等大前端畛域都有所实际和积攒。

目前团队次要反对腾讯新闻各业务的前端开发,业务开发之余也积攒积淀了一些前端基础设施,赋能业务提效和产品翻新。

团队提倡开源共建,领有各种技术大牛,团队Github地址:https://github.com/tnfe

本文作者ancai,我的项目地址:https://github.com/ancai/nvm

一、前言

本文是本人在之前的业余时间做过的一个小我的项目的实际总结,次要是介绍对于古代Web前端框架的设计实现思路,参考了Vue2.x版本的设计思维。

二、MVVM模式

web开发的程序员对于MVC的设计思维应该并不生疏,网上相干的文章也有很多。M(model)-V(view)-C(Controller)代表了一种程序组织架构的模式,实现了数据、视图和逻辑的无效解耦。M,示意数据状态,V代表视图界面,Controller用于解决数据和视图之间的交互逻辑。后端的web框架(如Java中的springMVC、Struts2;nodejs中的express、koa等)仍然沿用此设计模式至今。
不过在前端畛域,波及到用户界面的编程,MVC的架构模式当初曾经不是支流了。究其原因,次要有几方面:

  • 业务逻辑和UI混合在一起
  • 不利于扩大和复用
  • 无奈验证测试
  • 减少数据的复杂性

起初微软提出了MVVM的架构模式,其中和MVC的区别之处是VM取代了C,即ViewModel(视图模型)替换了控制器。次要利用在用户界面编程的畛域,提供了双向的数据绑定性能。View的变动会主动反映在ViewModel上,通过ViewModel来告诉模型,数据模型Model变动时同样通过VM来关联到视图。MVVM架构模式的呈现给前端的开发带来了新的活力,使得前端开发更容易编写单元测试。同时借助于ViewModel的两头桥梁,开发人员不必再关注一些DOM操作的交互细节,程序更简洁和优雅,联合组件化的编程设计思维,前端模块更易复用和拓展。
ViewModel,个别由框架来实现,次要是提供了双向数据绑定性能。
更多对于的比拟举荐两篇文章:什么是MVVM框架?|MVC vs MVVM: Key Differences with Examples

三、流程架构

我的项目外面波及到对模板、视图、数据、指令以及依赖的治理。


从大的方面看,框架次要实现了模板和数据之间的双向绑定。应用数据劫持的相干技术,对数据的变动的进行追踪,同时引入公布订阅模式实现对属性的依赖治理。另一方面则波及模板的解析,提取模板中的指令和表达式,关联到数据,来初始化视图。模板和数据通过watcher衔接起来,这样数据的变动间接映射到视图;同时须要监听视图上的输出相干的事件,这样当输出变动时间接映射到数据模型。


从工程解决的角度上看,能够分成四个步骤:初始化、数据监测、模板编译和框架性能。初始化的过程次要是取得调用方传递的配置信息,模型数据和模板的预处理,某些要害属性代理到下层。数据监测的环节,波及对一般JavaScript对象的劫持解决,针对数组的加强解决,通过一个公布-订阅模式实现对数据属性的依赖注入,同时关联到watcher。模板编译环节,解析一个相似HTML的模板,提取外面的变量表达式和相干指令,通过watcher关联到数据模型。


下面给出了我的项目中的外围类图,Observer实现对数据的劫持,Dep相当于是一个公布-订阅器同时关联到Watcher和Observer,Compile负责解析模板,进一步提取取得Directives类同时关联到Parser和Watcher,Parser用于解析指令生产视图UI,Watcher应用到一个Batcher来批量解决更新变动。


我的项目代码的目录构造比较简单,src目录下总共有14个代码文件,总代码行数在千行左右,了解起来不是很艰难。index.js为入口文件,模板编译相干的解决逻辑均放在compile文件夹下,observer.js文件搁置数据劫持相干的解决逻辑,value.js外面是字符串类型的属性表达式转化为对象数据的解决逻辑,dep.js实现了一个简略的公布-订阅模式来关联数据状态的变动以及watcher实例,watcher.js外面有具体的正文阐明在哪个环节被调用。另外,整个我的项目应用webpack简略构建,打包后的体积也很小。

四、数据劫持实现


利用ES5中提供的object.defineProperty 这一API,从新定义get和set属性拜访器实现对数据的劫持。次要是对一般对象和数组的加强解决,监测数据的变动,告诉依赖。在首次拜访属性时注入依赖,通常产生在首次初始化模板时,取得状态属性的表达式,在此时注入状态属性的依赖,这里的依赖就是watcher实例;当数据发生变化时,通过dep的公布-订阅模式告诉watcher实例,进而更新视图状态。

五、模板编译实现


模板的编译,没有应用虚构DOM结点,间接从原始的html模板动手,遍历字符串模板,收集外面的指令。同时解析表达式,取得对模型数据的依赖注入,在首次加载时,会关联到watcher上。外面针对不同类型的指令,对应不同的解析处理器,分为一般指令、事件指令、双向绑定指令、if/for指令等。其中波及到if/for的指令,须要创立新的执行上下文,关联子级的环境数据。

六、要害代码实现

下面两张图时对于依赖管理器和watcher的简略实现,依赖管理器能够视作一个公布-订阅模式的设计,即通过Dep类 watcher订阅了模型数据,当模型数据变动时,watcher就晓得了。有面图时watcher的简略解决逻辑,当模版编译解析出表达式时,就会创立watcher的实例,同时拜访模型数据的值时,将该新建的watcher实例注入进去。就这样,watcher实例充当了模版编译和模型数据的桥梁。

七、总结

本我的项目没有应用到virtual node(虚构DOM结点),间接由字符串模板编译成了视图局部。其中略微有点难了解的局部:属性表达式的提取解析、依赖的注入、if和for指令的解决、watcher的实现。
作为一个能力较弱的程序员,还无奈像前端技术大牛那样发明出一个成熟的前端框架。通过本文的简略论述,心愿能帮忙到有雷同困惑的小伙伴加深对MVVM以及前端框架原理的了解,大牛请主动疏忽。本我的项目的残缺源码参见最初局部,给出了具体的示例。

八、代码示例

源码

示例

九、团队

TNTWeb - 腾讯新闻前端团队,TNTWeb致力于行业前沿技术摸索和团队成员集体能力晋升。为前端开发人员整顿出了小程序以及web前端技术畛域的最新优质内容,每周更新✨,欢送star,github地址:https://github.com/tnfe/TNT-Weekly