Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
V

vue

> 编程语言
Open source

vue源码逐行注释分析+40多m的vue源码程序流程图思维导图(vue source code line by line annotation analysis +40 + m vue source code process flow chart mind map)

7.3K stars0 likes0 views
WebsiteGitHub

About

vue源码逐行注释分析+40多m的vue源码程序流程图思维导图(vue source code line by line annotation analysis +40 + m vue source code process flow chart mind map)

English document: https://github.com/ygs-code/vue/blob/master/README_EN.md

开始

vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了 。这个vue源码逐行分析,我基本每一行都打上注释,加上整个框架的流程思维导图,基本上是小白也能看懂的vue源码了。

说的非常的详细,里面的源码注释,有些是自己多年开发vue经验而获得的,有些是自己跑上下文程序知道的, 如果有不足的地方可以联系我QQ群 :302817612 修改,或者发邮件给我[email protected] 谢谢。 如果大家觉得不错请动动小手指,帮我点一个satr,你们的支持就是我的动力。

vue 如何去看vue源码呢?其实mvvm源码并没有想象中那么神秘,从12年开始到至今mvvm发展已经有了十几年历史了,从以前直接操作dom的jq发展有十几年历史,但是这十几年历史发展,并没有多大的改变,思想还是那些,模块还是分为几大块:

1.模板转换:

就是我们写的 vue 模板 或者是 react jsx 我们都可以理解是模板,然后他会经过 模板编译转换,像vue的话是进过一个方法paseHTML方法转换成ast树,里面的paseHTML用while 循环模板,然后经过正则 匹配到vue指令,还有vue的属性,事件方法等,收集到一个ast树中。

2.数据相应:

vue是一个双数据相应的框架,底层用的是Object.defineProperty 监听和挟持数据改变,然后调用回调方法更新视图更新。双数据绑定原理是:obersve()方法判断value没有没有__ob___属性并且是不是Obersve实例化的, value是不是Vonde实例化的,如果不是则调用Obersve 去把数据添加到观察者中,为数据添加__ob__属性, Obersve 则调用defineReactive方法,该方法是连接Dep和wacther方法的一个通道,利用Object.definpropty() 中的get和set方法 监听数据。get方法中是new Dep调用depend()。为dep添加一个wacther类,watcher中有个方法是更新视图的是run调用update去更新vonde 然后更新视图。 然后set方法就是调用dep中的notify 方法调用wacther中的run 更新视图

3.虚拟dom:

vnode,在vue用vnode是通过 ast对象,在转义成vonde 需要渲染的函数,比如_c('div' s('')) 等这类的函数,编译成vonde 虚拟dom。然后到updata更新数据 调用__patch__ 把vonde 通过diff算法变成正真正的dom元素。

4.diif算法:

​ vue2 的diff 算法是深度优先算法遍历,然后对比算法是通过 新旧的vnode对比先对比他们的基本属性,比如key 标签等,如果是相同则通过diff算法对比然后diff算法是新旧的vnode对比,然后有四个指针索引,两个新的vnode开始指针和新的 vnode 结束指针,两个旧的vnode开始指针和旧的 vnode 结束指针。然后先判断vnode是否为空,如果为空就往中间靠拢 开始的指针++ 结束的指针 --。然后两头对比之后,在交叉对比,直到找不到相同的vnode之后如果多出的就删除,如果少的话就新增,然后对比完之后在更新到真实dom。

源码入口流程 vue源码解读流程 1.new Vue 调用的是 Vue.prototype._init 从该函数开始 经过 $options 参数合并之后 initLifecycle 初始化生命周期标志 初始化事件,初始化渲染函数。初始化状态就是数据。把数据添加到观察者中实现双数据绑定。

new Vue实例化程序入口

…

查找和挂载模板

​ vm.$mount 进入这个挂载模板方法,判断是否有 render 函数 或者是template,如果没有则使用el.outerHTML , 实际上这里就是要拿到模板的html内容

…

编译AST和render函数

调用 Vue.prototype.$mount 方法之后 拿到模板之后 就会进入以下这几个方法,这几个方法用了很多函数式编程

compileToFunctions

createCompiler

createCompilerCreator

baseCompile

parse

parseHTML

这里比较重点的是parseHTML 他是 while (html) { //循环html 然后 然后经过正则 匹配到vue指令,还有vue的属性,事件方法等,收集到一个ast树中。

…

一些匹配模板正则

…

双数据响应

双数据绑定 入口 方法在defineReactive函数中 ,不管是 prop 还是 state 还是 属性监听方法 set 方法,还是initInjections 入口都是这里。

首先他会实例化 var dep = new Dep(); 依赖收集 Dep,get方法会添加一个

​ //添加一个dep ​ dep.depend();

​ if (childOb) { //如果子节点存在也添加一个dep ​ childOb.dep.depend(); ​ if (Array.isArray(value)) { //判断是否是数组 如果是数组 ​ dependArray(value); //则数组也添加dep ​ } ​ }

set 方法是触发更新视图的

//observe 添加 观察者

// 然后在添加依赖

childOb = !shallow && observe(newVal); //更新数据 dep.notify();

…

依赖收集 Dep

在vue数据get获取中,谁读取了该数据,就把它收集起来,所以dep是一个集合,在数据set时,通过遍历dep去触发每个dep的notify方法通过视图更新 dep的主要功能是只作为收集,那在收集了依赖后,如何使视图更新呢 所以需要定义一个新的Watcher类,改类是会实现对视图的更新 dep每收集的一个依赖实际就是一个Watcher

…

数据检测 Watcher

Watcher的功能主要是接口到Dep的通知,然后调用update方法更新视图 在update方法中会触发回调,回调函数实际就是已生成render函数

在调用render函数是,函数里的值就会获取到已经更改后值,所以就会生成新的vnode 新的vnode生成后,就是patch的过程,用新的vnode与旧的vnode进行比对,最终将比对后的vnode转换为实际的dom添加到模板挂载节点上 新的模板挂载后,将旧的模板删除,这样视图就更新完成

…

在Watcher实例构造函数执行时,会触发get 触发了get后就会该Watcher实例进行收集 update为接到Dep通知时触发的方法 update内会调用run方法 在run方法内会调用cb回调方法 cb回到方法实际就是模板编译时render方法

虚拟DOM

vue中的虚拟DOM,实际就是通过定义一个Vnode类,在该类上添加了dom的一些属性来标识一个dom

主要的作用是降低对实际dom的操作,来减轻对浏览器性能的耗费

…

diff算法

patch ,sameVnode, patchVnode ,updateChildren 这几个方法

入口是patch 然后调用sameVnode

…

如果调用sameVnode 条件成立 则进入patchVnode 方法,

patchVnode 方法主要是对vnode 进行增加和删除,主要还有key更新等。然后 判断 两个虚拟dom都不为空,并且他们不相等的时候oldCh !== ch 就进入updateChildren diff更新算法。

…

ddif 算法updateChildren

diif算法,vue2 的diff 算法是深度优先算法遍历,然后对比算法是通过 新旧的vnode对比先对比他们的基本属性,比如key 标签等,如果是相同则通过diff算法对比然后diff算法是新旧的vnode对比,然后有四个指针索引,两个新的vnode开始指针和新的 vnode 结束指针,两个旧的vnode开始指针和旧的 vnode 结束指针。然后先判断vnode是否为空,如果为空就往中间靠拢 开始的指针++ 结束的指针 --。然后两头对比之后,在交叉对比,直到找不到相同的vnode之后如果多出的就删除,如果少的话就新增,然后对比完之后 在调用patchVnode去增删虚拟dom。然后如果有vnode不相同在调用updateChildren,这样就做到深层递归,也叫深度优先搜索,然后子vnode没有了在更新到真实dom。

…

具体看我源码和流程图,这里文字就不描述这么多了,流程图是下面这中的网盘,源码是vue.js,基本每一行都有注释

链接:https://pan.baidu.com/s/10IxV6mQ2TIwkRACKu2T0ng 提取码:1fnu

上面的vue.js 就是我基于vue源码中每行加有注释的vue.js, 其他文件就是我看vue.js源码的时候抽出来的vue.js 源码小demo。如果大家觉得不错请动动小手指,帮我点一个satr,你们的支持就是我的动力

作者:姚观寿

最近失业了,想找一份前端开发工作,希望有朋友公司招聘的可以联系下我,谢谢你们,地点 深圳,或者远程都可以,前端构架,前端高级开发,组长职位都行。 我微信:18529531779 , helloTalk 号@18529531779,邮箱:[email protected] 谢谢了。

GitHub Issues· 0 open

View all on GitHub

No open issues yet, or sync has not completed.

Highlights

  • •JavaScript

> Tags

JavaScript

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言