当前位置: 首页 > Web前端 > vue.js

[fed-task-03-02]Vue源码-响应式、虚拟DOM、模板编译和组件化

时间:2023-03-31 17:08:09 vue.js

文章内容输出来源:拉勾教育大前端高薪训练营文章内容包括:模块作业、学习笔记短篇回答问题1、请简要描述一下Vue第一次渲染的过程。Vue第一次渲染的过程:(1)Vue初始化:初始化vue的实例成员和静态成员;(2)newVue():初始化后,调用vue的构造函数。This._init()在构造函数中被调用。这个方法相当于vue的入口,最后调用vm.$mount();(3)调用入口文件的vm.$mount():该方法主要是将模板编译成render函数。首先判断是否传递了render选项,如果没有,将模板编译成render函数。这个过程就是通过compileToFunctions()生成render()渲染函数(newFunction)。最后,设置options.render=render;(4)在runtime版本中调用vm.$mount():在该方法中会重新获取el(5)在lifecycle.js中调用mountComponent(this,el):首先在方法中判断是否有render选项,如果不是但是传入模板,当前开发环境会发出警告;触发beforeMount;然后定义updateComponent,这个方法会调用vm._render()渲染虚拟dom,调用vm._update()将虚拟dom转换成真实dom;然后创建一个Watcher实例,创建过程中传入的updateComponent会在Watcher内部调用,然后调用get()方法;然后触发挂载,最后返回vm;(6)watcher.get():创建Watcher后会调用一次get,get会在内部调用updateComponent();调用vm._render()创建VNode:调用用户在实例化时传入的render或者模板编译生成的render,返回VNode;callvm._update():内部调用vm.__patch__(vm.$el,vnode)挂载真实dom并记录vm.$el。2、请简述Vue响应式的原理。Vue的响应式原理其实是在vm._init()中完成的,调用顺序是initState()-->initData()-->observe()。observe()是响应式入口函数。(1)observe(value):该方法接收一个参数值,需要处理成响应式对象;判断该值是否为对象,如果不是直接返回;判断值对象是否有__ob__属性,有则直接返回;如果否,则创建一个观察者对象;返回观察者对象;(2)观察者:为值对象定义不可枚举的__ob__属性,记录当前观察者对象;数组的响应式处理,涵盖了原有的push/splice/unshift等方法,它们会改变原有的数组,并在调用这些方法时发送通知;对象的响应式处理,调用walk方法,遍历对象的各个属性,调用defineReactive;(3)defineReactive:为每个属性创建一个dep对象,如果当前属性的值是一个对象,则调用observe;定义getter,收集依赖,返回属性值;定义setter,保存新值,如果新值是对象,则调用observe,dispatchupdate(发送通知),调用dep.notify();(4)依赖收集:在Watcher对象的get方法中调用pushTarget来记录Dep.target属性;访问data中成员时收集依赖,在defineReactive的getter中收集依赖;将属性对应的watcher对象添加到dep的subs数组中;为childOb收集依赖,目的是在子对象增删成员时发送通知;(5)Watcher:当dep.notify调用watcher对象的update()方法时,会调用queueWatcher()判断watcher是否处理完毕。如果没有,加入队列queue,调用flushSchedulerQueue():触发beforeUpdate钩子,调用watcher.run(),run()-->get()-->getter()-->updateComponent,清空lastDependency,触发活动挂钩,触发更新挂钩。3、请简要描述Key在虚拟DOM中的作用和好处。Key的作用:主要用在虚拟DOM的diff算法中,在比较新旧节点时区分vnode。在使用键的时候,Vue会根据键的变化重新排列元素的顺序,尽可能复用页面元素,只找到一个必须更新的DOM,最终减少DOM操作。常见的例子结合v-for进行列表渲染,或者强制替换元素/组件。设置Key的好处:(1)更新数据时,可以尽可能减少DOM操作;(2)列表渲染时,可以提高列表渲染的效率,提高页面的性能;4、请简述Vue中模板编译的过程。模板编译的过程:(1)compileToFunctions(template,...):模板编译的入口函数,首先从缓存中加载编译好的render函数,如果没有缓存,则调用compile(template,options)开始编译;(2)compile(template,options):先合并options选项,然后调用baseCompile(template.trim(),finalOptions);compile的核心是合并options,模板的实际处理是在baseCompile中完成的;(3)baseCompile(template.trim(),finalOptions):先调用parse()将模板转化为AST树;然后调用optimize()对AST进行优化,首先在AST树中标记静态子树,检测静态子树,设置为static,而不是每次重新渲染都需要重新生成节点,静态子树在补丁阶段被跳过;调用generate()从AST树生成js代码;(4)compileToFunctions(template,...):继续编译将上一步生成的字符串形式的js代码转化为函数,通过调用createFunction()将字符串转化为函数新功能(代码);render和staticRenderFns被初始化并挂载到Vue实例的options的相应属性中。学习笔记Vue.js源码分析-响应式原理准备工作Vue源码获取项目地址:https://github.com/vuejs/vueFork复制到自己的仓库,clone到本地,可以自己写评论提交到github为什么要分析Vue2.6到目前为止,Vue3.0的正式版还没有发布。新版本发布后,已有项目不会升级到3.0。2.x还有很长的过渡期。3.0项目地址:https://github.com/vuejs/vue-...了解Flow官网:https://flow.org/JavaScript的静态类型检查器Flow的静态类型检查错误是通过静态类型推断实现的。文件开头通过//@flow或/*@flow*/声明方式来设置打包打包工具RollupVue.js源码打包工具使用Rollup,比webpack更轻量。Webpack将所有文件都当作模块处理,而Rollup只处理js文件,更适合在Vue.js等库中使用。Rollup打包不会产生冗余代码在sourcemappackage.json文件中设置dev脚本添加参数--sourcemap"dev":"rollup-w-cscripts/config.js--sourcemap--environmentTARGET:web-full-dev",执行devnpmrundev进行打包,使用rollup,-w参数是监听文件变化,文件变化会自动重新打包不同build版本的vue编译器:用于编译模板字符串的代码称为JS渲染函数,体积大,效率低。Runtime:用于创建Vue实例,渲染处理虚拟DOM等的代码,体积小,效率高,基础以上是去除编译代码UMD:UMD版本是通用模板版本,支持a多种模块方法。vue.js默认文件为UMD版本的运行时+编译器CommonJS(cjs):CommonJS版本用于配合Browserify或webpack等旧的打包工具1ESModule:从2.6开始,Vue会提供两个ESModulebuildfilesformodern打包工具提供的版本ESM格式是为了静态分析而设计的,所以打包工具可以利用这个来进行tree-shaking,从最终打包中排除未使用的代码ES6模块和CommonJS模块的区别,参考https://es6.ruanyifeng.com/?s...寻找入口文件查看dist/vue.js的构建过程执行npmrundevscript/config.js的执行过程功能:生成rollup构建的配置文件使用环境变量TARGET=web-full-dev从入口srcplatformswebentry-runtime-with-compiler.js开始读取源码记录el不能是body或者html标签如果没有render,如果有则转换template为renderfunction是render方法,直接调用mount挂载DOMVue初始化过程导出Vue的四个模块srcplatformswebentry-runtime-with-compiler.jsweb平台相关入口重写平台相关$mount()方法注册Vue.compile()方法,传递一个HTML字符串并返回render函数srcplatformswebruntimeindex.jsweb平台相关的注册和平台相关的全局指令:v-modelv-show注册和平台相关的全局组件:v-transitionv-transition-group全局方法:__patch__:将虚拟dom转换为真实DOM;$mount:mount方法srccoreindex.js与平台无关。Vue的静态方法就设置好了。initGlobalAPI(Vue)srccoreinstanceindex.js与平台无关。定义paparazzi函数,调用this._init(options)方法将普通实例成员数据混入Vue。原来的查看源码解决如下问题vm.msg={count:0},重新赋值属性,是否对应?vm.arr[0]=4,给数组元素赋值,视图会更新吗?vm.arr.length=0,修改数组长度,视图是否会更新vm.arr.push(4),视图是否会更新对应的处理入口src/core/instance/init.jsinitState(vm)vmstateInitialization初始化_data、_props、methods等src/core/instance/state.jsWatcherClassWatcher分为三种,ComputedWatcher、UserWatcher(监听器)、RenderingWatcherRenderingWatcher创建时机:/src/core/instance/lifecycle.jsset方法源码Vue.set()global-api/index.jsvm.$set()instance/index.jsdelete方法源码Vue.delete()global-api/index.jsvm.$delete()instance/index.js删除对象的属性如果对象是反应性的,请确保删除会触发视图的更新。该方法主要用于避免Vue无法检测到属性被删除的限制,但应该很少使用。注意:目标对象不能是Vue实例,也不能是Vue实例的后续数据对象。vm.$watchvm.$watch(expOrFn,callback,[options])是一个表达式或计算属性函数,用于观察Vue实例中的变化。回调函数得到的参数是新值和旧值。表达式只接受受监督的关键路径。对于更复杂的表达式,请改用函数。expOrFn:$data中要监听的属性,可以是表达式,也可以是函数callback:数据变化后执行的函数Function:回调函数对象:有handler属性(字符串或函数),如果属性为字符串,然后在methods中对应定义options:可选optionsdeep:布尔型,深度监控immediate:布尔型,是否立即执行回调函数这三种Watcher对象没有静态方法,因为$watch方法需要使用Vue实例Watcher分三种:计算属性Watcher、用户Watcher(监听器)、渲染Watcher创建顺序:计算属性Watcher、用户Watcher(监听器)、渲染Watchervm.$watch():src/core/instance/state.js异步更新队列-nextTick()Vue更新DOM异步执行,延迟回调在下一个DOM更新周期结束后批量执行。修改数据后立即使用该方法获取更新后的DOMvm.$nextTick(function(){/*operateDOM*/})或Vue.nextTick(function(){})源码位置:src/core/instance/的render.js源码在Watcher的queueWatcher中手动调用vm.$nextTick()执行nextTick()。src/core/util/next-tick.js的核心是timerFunc函数的处理,Promise->MutationObserver->setImmediate->setTimeoutVue。js源码分析-VirtualDOM什么是VirtualDOM?虚拟DOM(VirtualDOM)使用JavaScript对象来描述真实DOMVue.js中的虚拟DOM。它借鉴了Snabbdom并添加了Vue.js的特性。例如:为什么使用虚拟DOM进行指令和组件机制,避免直接操作DOM,提高开发效率作为中间件,跨平台的虚拟DOM不一定能提高性能在第一次渲染时,会增加开销,提高渲染效果复杂视图情况下的表现hfunctionvm.$createElement(tag,data,children,normalizeChildren)tag:标签名称或组件对象data:描述标签,可以设置DOM的属性或标签children的属性:标签中的文本内容或设置key的子节点设置Key的好处:(1)更新数据时,可以尽可能减少DOM操作;(2)列表渲染时,可以提高列表渲染的效率,提高页面的性能;Vue.js源码分析-模板编译和组件模板编译功能Vue2.x使用VNode来描述视图和各种交互。用户自己写VNode比较复杂。用户只需要编写类似HTML的代码——Vue.js模板,由编译器转换成返回VNode的渲染函数。在build过程中被webpack转换到render编译生成的函数的位置function_c()srccoreinstancerender.js_m()/_v()/_s()srccoreinstancerender-helpersindex.js抽象语法树什么是抽象语法树abstractsyntaxtree简称AST(AbstractSyntaxZTree),用对象的形式来描述树形代码结构。这里使用抽象语法树来描述树形的HTML字符串。为什么要使用抽象语法树模板?AST优化模板处理标签模板中的静态内容,在patch过程中直接跳过静态内容。静态内容不需要在补丁过程中进行比较和重新渲染。组件化Vue组件是一个带有预定义选项的Vue实例,一个组件可以在页面上形成一个功能齐全的区域。该组件可以包含脚本、样式和模板。第一个渲染过程Vue构造函数this._init()this.$mount()mountComponent()newWatcher()RenderWatcherupdateComponent()vm。_render()->createElement()vm._u日期()