【一套代码小程序&Native&Web阶段总结篇】可以这样阅读Vue源码

前言前面我们对微信小程序进行了研究:【微信小程序项目实践总结】30分钟从陌生到熟悉在实际代码过程中我们发现,我们可能又要做H5站又要做小程序同时还要做个APP,这里会造成很大的资源浪费,如果设定一个规则,让我们可以先写H5代码,然后将小程序以及APP的业务差异代码做掉,岂不快哉?但小程序的web框架并不开源,不然也用不着我们在此费力了,经过研究,小程序web端框架是一套自研的MVVM框架,于是我们...

【一套代码小程序&Native&Web阶段总结篇】可以这样阅读Vue源码

前言

前面我们对微信小程序进行了研究:【微信小程序项目实践总结】30分钟从陌生到熟悉

在实际代码过程中我们发现,我们可能又要做H5站又要做小程序同时还要做个APP,这里会造成很大的资源浪费,如果设定一个规则,让我们可以先写H5代码,然后将小程序以及APP的业务差异代码做掉,岂不快哉?但小程序的web框架并不开源,不然也用不着我们在此费力了,经过研究,小程序web端框架是一套自研的MVVM框架,于是我们马上想到了借助第三方框架:

一套代码小程序&Web&Native运行的探索01

经过简单的研究,我们发现无论React或者Vue都是可以一定程度适应小程序开发模式的,市面上也有了对应的框架:mpvue&wepy

在使用以上任何一套框架体系前,我们都需要对MVVM框架有最基础的了解,不然后面随便遇到点什么问题可能都会变得难以继续,负责人要对团队负责而不是单纯只是想技术尝鲜,所以生产项目一定要使用自己能完成hold住的技术

这段时间我们尝试着去阅读Vue的源码,但现在的Vue是一个工程化产物,我们要学习的核心代码可能不到其中的1/3,多出来的是各种特性以及细节处理,在不清楚代码意图(目标)的情况下,事实上很难搞懂这段代码是要干什么,很多代码的出现都是一些精妙的小优化,知道的就会觉得十分惊艳,不知道的就会一头雾水,一来就看Vue的源码反而不利于深入了解

出于这个原因在网上看了很多源码介绍的文章,出来就放一个Vue官方的流程图,然后一套组合模块套路,基本就把我给打晕了,查询了很多资料,还是发现一些写的比较清晰的(我感觉适合多数人的)文章:

读懂源码:一步一步实现一个 Vue

https://github.com/fastCreator/MVVM(特别推荐,非常不错)

这两篇文章都有一个主旨:

在没有相关框架经验的情况下,单单靠单步调试以及网上的源码介绍,想要读懂Vue源码是不太靠谱的做法,比较好的做法是自己照着Vue的源码写一套简单的,最基础的MVVM框架,在完成这个框架后再去阅读Vue或者React的代码要轻易的多,我这边是非常认可这个说法的,所以我们照着fastCreateor的代码(他应该是参考的Vue)也撸了一个:https://github.com/yexiaochai/wxdemo/tree/master/mvvm

这里与其说撸了一个MVVM框架,不如说给fastCreateor的代码加上了自我理解的注释,通过这个过程也对MVVM框架有了第一步的认识,之前的文章或者代码都有些散,这里将前面学习的内容再做一次汇总,多加一些图示,帮助自己也帮助读者更好的了解,于是让我们开始吧!

PS:下面说的MVVM框架,基本就是Vue框架,并且是自己的理解,有问题请大家拍砖

MVVM框架的流程

我们梳理了MVVM框架的基本流程,这里只看首次渲染的话:

① 解析html模板形成mvvm实例对象element(实例上的$node属性)② 处理element属性,这里包括属性处理、事件处理、指令处理③ 使用处理过的element对象,为每个实例创建render方法PS:new MVVM只会产生一个实例,每个html标签都会形成一个vnode,组件会形成独立的实例,与根实例以$parent与$children维护关系④ 使用render方法创建虚拟dom vnode,vm实例element已经具备所有创建虚拟dom的必要条件,render只是利用他们,如果代码组织得好,不使用render也行⑤ render执行后会生成虚拟dom vnode,借助另一个神器snabbdom开始对比新旧虚拟dom的结构,完成最终渲染PS:render执行时作用域在mvvm实例(vm)下

所以整个代码核心全部是围绕着HTML=>element($node中间项,桥梁)=>render函数(执行返回vnode)=>引用snabbdom patch渲染

而抓住几个点后,对应的几个核心技术点也就出来了:

① 模板解析这里对应着 HTMLParser,帮忙解决了很多问题② 形成vnode需要的render函数,并且调用后维护彼此关系,这个是框架做的最多的工作③ 生成真正的vnode,然后执行对比差异渲染patch操作,这块重要的工作由snabbdom接手了

我们再把这里的目标映射成过程,就得到了这张图了(来自https://github.com/fastCreator/MVVM):

上面一行就是首次渲染执行的流程,下面几个图就是实现数据变化时候更新试图的操作,分解到程序层面,核心就是:

① 实例化

② Parser => HTMLParser

③ codegen

在此基础上再包装出数据响应模型以及组件系统、指令系统,每个模块都很独立,但又互相关联,抓住这个主干看各个分支这样就会相对比较清晰。所以网上很多几百行代码实现MVVM框架核心的就是只做最核心这一块,比如这个学习材料:https://github.com/DMQ/mvvm,非常简单清晰,为了帮助更好的理解,我们这里也写了一段比较独立的代码,包括了核心流程:

  1 <div id="app">  2<input type="text" v-model="name">  3   {{name}}  4 </div>  5   6 <script type="text/javascript" >  7   8function getElById(id) {  9  return document.getElementById(id); 10   } 11  12//主体对象,存储所有的订阅者 13function Dep () { 14  this.subs = []; 15   } 16  17//通知所有订阅者数据变化 18   Dep.prototype.notify = function () { 19  for(let i = 0, l = this.subs.length; i < l; i  ) { 20 this.subs[i].update(); 21  } 22   } 23  24//添加订阅者 25   Dep.prototype.addSub = function (sub) { 26  this.subs.push(sub); 27   } 28  29   let globalDataDep = new Dep(); 30  31//观察者,框架会接触data的每一个与node相关的属性, 32//如果data没有与任何节点产生关联,则不予理睬 33//实际的订阅者对象 34//注意,只要一个数据对象对应了一个node对象就会生成一个订阅者,所以真实通知的时候应该需要做到通知到对应数据的dom,这里不予关注 35function Watcher(vm, node, name) { 36  this.name = name; 37  this.node = node; 38  this.vm = vm; 39  if(node.nodeType === 1) { 40 this.node.value = this.vm.data[name]; 41  } else if(node.nodeType === 3) { 42 this.node.nodeValue = this.vm.data[name] || ''; 43  } 44  globalDataDep.addSub(this); 45  46   } 47  48   Watcher.prototype.update = function () { 49  if(this.node.nodeType === 1) { 50 this.node.value = this.vm.data[this.name ]; 51  } else if(this.node.nodeType === 3) { 52 this.node.nodeValue = this.vm.data[this.name ] || ''; 53  } 54   } 55  56//这块代码仅做功能说明,不用当真 57function compile(node, vm) { 58  let reg = /\{\{(.*)\}\}/; 59  60  
源文地址:https://www.guoxiongfei.cn/cntech/2193.html