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

kidney kidney     2022-10-04     468

关键词:

源码阅读:究竟怎样才算是读懂了?

市面上有很多源码分析的文章,就我看到的而言,基本的套路就是梳理流程,讲一讲每个模块的功能,整篇文章有一大半都是直接挂源码。我不禁怀疑,作者真的看懂了吗?为什么我看完后还是什么都不懂呢?

事实上一个经过无数次版本迭代的框架源码并不适合初学者直接阅读,因为里面有太多细节,太多噪点,太多枝枝蔓蔓。要想真正理解框架的核心逻辑,必须剥茧抽丝,还原出一个纯净的雏形。如同 jQuery 最早的版本只有六百多行,我相信 Vue 的核心功能也只需要几百行就能实现。所以,读懂源码的标志就是还原,码越薄,真相就越清晰。

 

如何还原雏形?

一开始我设想的还原过程就是先删后拆。什么报错信息、参数校验、非核心功能全部砍掉,八千行变成了五千行。然后再拆,按功能模块将一个 Vue.js 拆分成 util.js, observer.js, watcher.js …

理想状态下,我应该能够理解源码了吧,可做完解剖手术后,我发现里面的逻辑依然纷繁复杂,剪不断,理还乱,草蛇灰线,伏脉千里,即便换了一个更早期更简短的版本,仍然很快又陷入了永无止境的细节中。

最终我得出结论:与其根据源码还原雏形,不如参考源码自己从头实现一个雏形。

 

定义核心

Version:2.0.4

只考虑 runtime 版本,不考虑模板编译,不考虑服务端渲染。

核心功能:响应式的数据绑定、虚拟 DOM、diff 算法、patch 方法(用于更新真实 DOM)

如果你对上述基础概念完全不熟,建议先积累一些背景知识:关于响应式绑定参考这篇文章,关于 virtual dom 和 diff 算法参考这个视频。当然,这些并不是必须的。

 

目标

事实上,Vue-cli 生成的项目中,<template> 标签中的内容都会被编译为 render 函数,render 函数返回整棵虚拟节点树。我们最终要实现一个 Vue,来完成上面的示例。

 

当 new Vue() 的时候发生了什么?

我们的实现会参考源码的套路,但会大量的简化其中的细节。为了理解源码的结构,最好的突破口就是了解程序的起点 new Vue() 的背后究竟发生了什么。

简单梳理下源码的执行流:

=> 初始化生命周期

=> 初始化事件系统

=> 初始化state,依次处理 props、data、computed …

=> 开始渲染 _mount() => _render() 返回 vdom=> _update() => __patch__() 更新真实DOM

更详细的说明可以参考这篇文章,我们只会实现其中最核心的部分

 

第一步:将虚拟 DOM 树渲染到真实的 DOM

每一个 DOM 节点都是一个 node 对象,这个对象含有大量的属性与方法,虚拟 DOM 其实就是超轻量版的 node 对象。

 

我们要生成的 DOM 树看上去是这样的:

关于 data 参数的属性,请参考官方文档

随后我们会通过 createElm 方法和 createChildren 方法的相互调用,遍历整棵虚拟节点树,生成真实的 DOM 节点树,最后替换到挂载点。

完整代码

 

第二步:修改数据,执行 diff 算法,并将变化的部分 patch 到真实 DOM

diff 算法的逻辑比较复杂,可以单独摘出来研究,由于我们的目的是理解框架的核心逻辑,因此代码实现里只考虑了最简单的情形。

完整代码

 

第三步:对数据做响应式处理,当数据变化时,自动执行更新方法

data 中的每一个属性都会被处理为存取器属性,同时每一个属性都会在闭包中维护一个属于自己的 dep 对象,用于存放该属性的依赖项。当属性被赋予新的值时,就会触发 set 方法,并通知所有依赖项进行更新。

完整代码

 

Vue 渐进式的特点,使其上手极其容易,我相信,渐进式的展现框架逻辑的实现过程,也会使理解变得更容易。

 

vue双向绑定原理,教你一步一步实现双向绑定(代码片段)

当今前端天下以Angular、React、vue三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或者三个阵营都要选择,大势所趋。所以我们要时刻保持好奇心,拥抱变化,只有在不断的变化中你才能利于不败之地,保... 查看详情

recyclerview源码学习:一步一步自定义layoutmanager

前言这篇文章实现了一个简单的LayoutManager,重点在于从原理方面一步一步去了解如何自定义一个LayoutManager。麻雀虽小,但五脏俱全。从自定义LayoutManager的layout布局,到scroll滑动,再到添加简单的动画效果。其实&... 查看详情

一步一步学vue

...不同,我们会对其进行增删改查的基本操作,之后进行进一步的完善,按照常规的系统使用经验,一般我们新增和编辑都是在模态框中处理,这里我们不会去构建复杂的模态框,只用一个简单的div层来代替,后期接下来的文章中... 查看详情

mybatis源码解析,一步一步从浅入深:映射代理类的获取

在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题:  1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper?  2,UserDao明明是我们定义的一个接口类,根本没有定义... 查看详情

一步一步学vue

本篇是是vue路由的开篇,会以一个简单的demo对vue-router进行一个介绍,主要覆盖以下几个常用场景:1、路由跳转2、嵌套路由3、路由参数 1、Vue-Router  一般来说,路由定义就是定义地址访问规则,然后由路由引擎根据这些... 查看详情

一步一步学习vue

本篇继续介绍vue-router,我们需要要完成这样个demo:《分页显示文章列表》;这里我们以博客园首页列表为例简化处理:按照上图框选所示,简单分为蓝色部分文章组件(ArticleItemComponent),橙色框选部分列表组件(ArticleListCompon... 查看详情

一步一步学vue

接上篇,这次是真的接上篇,针对上篇未完成的部分,增加鉴权功能,开始之前,我们先要介绍一个新的知识,路由元数据。 在vue-router中,定义元数据的方式:constrouter=newVueRouter({routes:[{path:‘/foo‘,component:Foo,children:[{path:... 查看详情

一步一步实现一个promisea+规范的promise

...分为三个部分,每个部分实现Promise的一部分特性,最终一步一步的实现一个完整的、遵循promiseA 查看详情

一步一步copy163:网易严选----vue-cli(代码片段)

...栈开发,域名备案中近期上线(mpvue+koa2+mysql)小程序服务端源码地址 小程序源码地址 功能实现api:           ------------致谢heyushuo点这儿给个star吧~首页  https://www.heyuhsuo.xyz/heyushuo... 查看详情

一步一步搭建vue

一步一步搭建自己搭建类似与vue-cli的框架第一步:搭建项目目录结构进入项目目录1.vue_demo>npminit-y(如果没有y则需要自己去写配置信息)2.安装依赖包vuedemo>npminstallvuewebpackwebpack-dev-servervue-loadervue-html-loadercss-loadervue-style-loadervue... 查看详情

一步一步学习vue

本篇继续学习vuex,还是以实例为主;我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码:todolist.js;(function(){varlist=[];varTodo=(function(){varid=1;returnfunction(title,desc){this.title=title;this.desc=desc... 查看详情

一步一步实现读写锁

多线程编程中,需要对共享变量进行加锁。但是频繁地加锁,会对程序效率有很大影响。在某些读多写少的场景下,多个线程进行读数据时,如果都加互斥锁,这显然是不必须的。于是读写锁便应运而生。读写锁的加锁规则:1... 查看详情

recyclerview源码学习:一步一步自定义layoutmanager

前言这篇文章实现了一个简单的LayoutManager,重点在于从原理方面一步一步去了解如何自定义一个LayoutManager。麻雀虽小,但五脏俱全。从自定义LayoutManager的layout布局,到scroll滑动,再到添加简单的动画效果。其实&... 查看详情

一步一步学vue

为了提升代码的逼格,之后代码改为Vue文件组件,之前代码虽然读起来容易理解,而且适合在小的项目中使用,但是有如下缺点:全局定义(Globaldefinitions) 强制要求每个component中的命名不得重复字符串模板(Stringtemplates) 缺... 查看详情

一步一步实现混合驱动自动化测试框架的搭建(代码片段)

一步一步实现混合驱动自动化测试框架的搭建实现功能:登录126邮箱,添加联系人,然后发送邮件,带附件 数据驱动框架结构:Action:   封装的操作元素的函数,如login,添加联系人。。。conf:日志配置文件定位... 查看详情

一步一步解读refresh源码(代码片段)

解读refreshrefresh()1.prepareRefresh2.obtainFreshBeanFactoryBeanDefinition测试(读取Bean方式)1.xml方式读取2.组件扫描4.编程方式(Bean构建器)3.prepareBeanFactory4.postProcessBeanFactory5.invokeBeanFa 查看详情

一步一步学vue

  前言:我以后在文章最后再也不说我下篇博文要写什么,之前说的大家也可以忽略,如果你不忽略,会失望的??,不过说出去的话还是要表示一下的,简单介绍一下路由钩子:  正如其名,vue-router 提供的导航钩子主要... 查看详情

我是如何一步一步实现网页离线缓存的?

问题一个HybridAPP,如何做离线缓存策略?也可以简单来说,你的APP只是一个壳,里面真正加载的内容是H5,如果优化加载内容的速度?先了解一下NSURLProtocol从字面意思看它是一个协议,但是它其实是一个类,而且继承自NSObject。... 查看详情