- 1. diff算法
- 2. vue中key的作用和原理
- 3. Vue.use是干什么的
- 4. vue.extend作用
- 5. vue组件data为什么必须是个函数
- 6. 函数组件的优势
- 7. vue中的过滤器
- 8. v-once的使用场景
- 9. Vue.mixin的使用场景和原理
- 10. Vue中slot如何实现
- 11. 对双向绑定的理解
- 12. vue中.sync修饰符的作用
- 13. vue中递归组件理解
- 14. 组件中的name属性
- 15. vue中的修饰符
- 16. vue中异步组件作用及其原理
- 17. 对nextTick的理解
- 18. keep-alive组件平时在哪里使用
- 19. 自定义指令的应用场景
- 20. vue中使用了哪些设计模式
- 21. vue中的性能优化有哪些
diff算法
diff概念
vue 基于虚拟 DOM 做更新 。diff 的核心就是比较两个虚拟节点的差异。Vue 的 diff 算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式+双指针的方式进行比较。
源码 core/vdom/patch.ts
diff比较流程
先比较是否相同节点key tag
相同节点比较属性,并复用老节点(将老的虚拟dom复用给新的虚拟节点DOM)
比较儿子节点,考虑老节点和新节点儿子的情况
- 老的没儿子,现在有儿子。直接插入新的儿子
- 老的有儿子,新的没儿子。直接删除页面节点
- 老的儿子是文本,新的儿子是文本,直接更新文本节点即可
- 老的儿子是一个列表,新的儿子也是一个列表 updateChildren
优化比较:头头、尾尾、头尾、尾头
比对查找进行复用
vue3中采用最长递增子序列来实现diff优化
听完了,理解并不透彻,仍需加强
vue中key的作用和原理
key的概念
- key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧nodes 对比时辨识 VNodes。如果不使用key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。
- 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染
key的作用
- Vue 在 patch 过程中通过 key 可以判断两个虚拟节点是否是相同节点。(可以复用老节点)
- 无 key 会导致更新的时候出问题
- 尽量不要采用索引作为 key
Vue.use是干什么的
use概念
安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install方法。install 方法调用时,会将 Vue 作为参数传入,这样插件中就不在需要依赖 Vue 了。
插件的功能
- 添加全局指令、全局过滤器、全局组件
- 通过全局混入来添加一些组件选项
- 添加vue实例方法,通过把他们添加到vue.prototype上实现
实现原理
1 | Vue.use =function(pugin:Functionobject{ |
vue.extend作用
extend概念
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
data 选项是特例,需要注意-在 vue.extend()中它必须是函数。
1 | var Profile =Vue.extend({ |
在底层是构造一个sub(VueComponent实例),这个sub是继承了vue的构造函数
分析
- 所有的组件创建时都会调用vue.extend方法进行创建
- 有了此方法我们可以手动挂载组件
- 后端存储的字符串模板我们可以通过Vue.exntend方法将其进行渲染,但是需要引入编译时。
vue组件data为什么必须是个函数
- 根实例对象data可以时对象也可以是函数“单例”,不会产生数据污染情况
- 组件实例对象data必须为函数,目的是防止多个组件实例对象之间共用一个data,产生数据污染。所以需要通过工厂函数返回全新的data作为组件数据源。
1 | function vue(){} |
函数组件的优势
函数式组件的特性:无状态、无生命周期、无this,但是性能高。 正常组件是一个类继承了 Vue, 函数式组件就是普通的函数,没有 new 的过程。最终就是将返回的虚拟 DOM 变成真实 DOM 替换对应的组件。
底层方法:在createComponent中会判断有没有一个ctor.options.funcitonal,如果存在则直接调用createFunctionalComponent创建函数式组件
函数式组件不会被记录在组件的父子关系中,在Vue3 中因为所有的组件都不用 new 了,所以在性能上没有了优势~。
vue中的过滤器
过滤器是指不改变原始数组,只是对数据进行加工处理后返回过滤后的数据再进行第哦啊用处理,我们也可以理解成纯函数。
常见场景:单位转换、千分符、文本格式化、时间格式化等操作。
写个方法不香吗,vue3中果断放弃了过滤器
1 | vue.filter('filerA',funciton(value){ |
v-once的使用场景
v-once概念
v-once是vue中的内置指令,只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化性能。
v-for中使用v-once
vue3.2之后,增加了v-memo指令,通过依赖列表的方式控制页面渲染。
Vue.mixin的使用场景和原理
Vue.mixin概念
mixin可以用来扩展组件,将公共逻辑进行抽离。在需要该逻辑时进行“混入”,采用册罗模式针对不同的属性进行合并。如果混入的数据和本身组件中的数据冲突,会采用“就近原则”以组件数据为准。
mixin中有很多缺陷:”命名冲突问题“、”数据来源问题“,vue3采用compositionAPI提取公共逻辑非常方便
混入方式
在vue中我们可以局部混入和全局混入。一般情况下全局混入用于编写插件。局部混入用于复用逻辑。
mixin合并策略
核心就是:对象的合并处理
- props、methods、inject、computed同名时会被替换
- data会被合并
- 生命周期和watch方法会被合并成队列
- components、directives、filters会在原型链上叠加
组件的扩展除了mixin只歪还有一个属性叫extends,但是不怎么常用
Vue中slot如何实现
什么是插槽
插槽设计来源于 Web Components 规范草案,利用s1ot进行占位,在使用组件时,组件标签内部内容会分发到对应的 slot 中。
何时使用
通过插槽可以让用户更好的对组件进行扩展和定制化。可以通过具名插槽指定染的位置。常用的组件例如:弹框组件、布局组件、表格组件、树组件…
对双向绑定的理解
概念
vue中双向绑定靠的是指令vodel,可以绑定一个动态值到视图上,同时修改视图能改变数据对应的值(能修改的视图就是表单组件)经常会听到一句话:v-model是value+input 的语法糖。
表单元素中的v-model
内部会根据标签的不同解析出不同的语法。并且这里有“额外“的处理逻辑
例如 文本框会被解析成 value +input事件
例如 复选框会被解析成 checked+change事件
……
底层是将v-model编译为一个directive指令
组件中的v-model
组件上的 v-mode1 默认会利用名为 va1ue 的 prop和名为 input 的事件。对于组件而言 v-model 就是value +input 的语法糖。可用于组件中数据的双向绑定。
名字也可以修改:
1 | Vue.component('base-checkbox',{ |
那组件中如果有多个数据想做双向数据绑定怎么办?很遗憾在vue2中不支持使用多个v-model的。vue3中可以通过以下方法进行绑定。
1 | <my v-model:a="a" v-model:b="b" v-model :c="c"></my> |
vue中.sync修饰符的作用
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”,这时可以使用.sync来实现。`v-model默认只能双向绑定一个属性,这里就可以通过.sync修饰符绑定多个属性。
vue3中.sync语法被移除
vue中递归组件理解
菜单组件:
1 | <el-menu> |
模板递归
1 | <e]-menu> |
编写递归组件resub,在组件中调用自己
1 | <e1-submenu :key="data.id" v-if="data.children"> |
组件中的name属性
- 增加 name 选项会在components属性中增加组件本身,实现组件的递归调用。
- 可以标识组件的具体名称方便调试(devtools)和查找对应组件。
- $children.filter(item=>item.$options.name === ‘xxx’) 查找
1 | Sub.options.components[name]=sub;//子组件会通过name属性,将自己也注册到组件中 |
vue中的修饰符
- 表单修饰符iazy、trim、number
- 事件修饰符stop、prevent、self、once、capture、passive、native
- 鼠标按键修饰符 left、right、middle
- 键值修饰符 对 keyCode 处理
- .sync 修饰符
vue中异步组件作用及其原理
异步组件概念
Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。推荐的做法是将异步组件和 webpack的 code-splitting 功能一起配合使用。
异步组件写法
回调写法
1 | { |
promise写法
1 | { |
对象写法
1 | const Asynccomponent= ()=>({ |
异步组件原理
- 默认渲染异步占位符节点
- 组件加载完毕后调用$forceUpdate强制更新,渲染加载完毕后的组件
对nextTick的理解
nextTick概念
- Vue 中视图更新是异步的,使用 nextTick 方法可以保证用户定义的逻辑在更新之后执行。
- 可用于获取更新后的 DOM,多次调用 nextTick 会被合并。
keep-alive组件平时在哪里使用
keep-alive 是 vue 中的内置组件,能在组件切换过程会缓存组件的实例,而不是销毁它们。在组件再次重新激活时可以通过缓存的实例拿到之前渲染的 DOM 进行渲染,无需重新生成节点。
使用场景
动态组件可以使用keep-alive进行缓存
1 | <keep-alive :include="whiteList" :exclude="blackList":max="count"> |
在路由中使用keep-alive
1 | <keep-alive :include="whiteList" :exclude="blackList":max="count"> |
也可以指定meta属性指定哪些页面需要缓存,哪些不需要
1 | <div id="app"> |
原理
……有待深化
自定义指令的应用场景
Vue 除了内置指令之外,同时 Vue 也允许用户注册自定义指令来对 Vue 进行扩展。指令的目的在于可以将操作 DOM 的逻辑进行复用。
指令的生命周期
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
- componentupdated:指令所在组件的VNode 及其子VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
常见的指令编写
- 图片懒加载v-lazy
- 防抖v-debounce
- 按钮权限v-has
- 拖拽指令v-draggable、mousemove、mouseup、dragenter、drop、可视化拖拽编辑器
- 点击事件处理v-click-outside
1 | <div v-click-outside="hide"><input type="text" @focus="'show" /><div v-if="isshow">显示面板</div></div> |
1 | Vue.directive(clickOutside,{ |
vue中使用了哪些设计模式
- 单例模式:单例模式就是整个程序中有且金瓯一个实例,vuex中的store
- 工厂模式:传入参数即可创建实例(createElment)
- 发布订阅者模式:订阅者吧自己想订阅的事件注册到调度中心,当该事件触发时,发布者发布该事件到调度中心,有调度中心统一调度订阅者注册到调度中心的处理代码
- 观察者模式:watcher和dep的关系
- 代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用
- 装饰模式:vue2装饰器的用法(对功能进行增强@)
- 中介者模式:中介者是一个行为设计模式,通过提供一个统一的接口让胸痛的不同部分进行通信。
- 策略模式:指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案
- 外观模式:提供了统一的接口,用来访问子系统中的一群接口
- ……
vue中的性能优化有哪些
- 数据层级不易过深,合理设置响应式数据
- 通过Object.freeze()方法冻结属性
- 使用数据时缓存值的结果,不频繁取值
- 合理设置key属性
- v-show和v-if的选取
- 控制组件粒度->vue采用组件级更新
- 采用函数式组件->函数式组件开销低
- 采用异步组件->借助webpack分包的能力
- 使用keep-alive缓存组件、v-once
- 分页、虚拟滚动、时间分片等策略