MVC是什么?MVVM是什么? 区别?

MVC是model-view-controller:

  • model层代表数据模型,负责业务逻辑和数据存取;
  • view代表ui组件,负责显示数据;
  • controller可以响应用户的操作,更新model,从而更新view,实现同步更新。

MVVM是model-view-viewModel的缩写,就是将MVC中的C(controller)换成VM(viewmodel)。

viewmodel就是view和model层的桥梁,最大的特点是做到了数据的双向绑定。数据会绑定到viewmodel层并自动将数据渲染到页面上,而视图变化时也会通知viewmodel层更新数据。

MVVM优点:

1、低耦合:简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作 DOM 元素。因为在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也观察不到 View。视图(View)可以独⽴于 Model 变化和修改,⼀个 ViewModel 可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

2、可重⽤性:可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多 view 重⽤这段视图逻辑。

3、独⽴开发:开发⼈员可以专注于业务逻辑和数据的开发(ViewModel),设计⼈员可以专注于⻚⾯设计。

参考资料

https://juejin.cn/post/6844903480126078989

https://juejin.cn/post/7014844340576976926

怎样理解 Vue 的单向数据流

数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父级组件的状态,从而导致应用的数据流向难以理解。

注意:在子组件直接用 v-model 绑定父组件传过来的 prop 这样是不规范的写法 开发环境会报警告

如果实在要改变父组件的 prop 值 可以再 data 里面定义一个变量 并用 prop 的值初始化它 之后用$emit 通知父组件去修改

vue的双向绑定是如何实现的?

Vue2使⽤的是Object.defineProperty()进⾏数据劫持,结合发布订阅的⽅式实现。

Vue3使⽤的是Proxy代理,使⽤ref或者reactive将数据转化为响应式数据

通过数据劫持和发布订阅。数据劫持就是设置数据的setter和getter属性来对数据进行一些操作。Vue2数据劫持用到的是Object.defineProperty,3用到的是Proxy。

Object.defineProperty和Proxy有什么区别?

Object.defineProperty监听对象属性。而Proxy监听的是整个对象

Vue2的响应式原理?

用了数据劫持、观察者模式以及发布订阅模式。(数据劫持在上面)

数据劫持与 Dep 对象创建

Vue 获取 data 后,将其传入 Observer 进行处理。Observer 会遍历 data 中的每个属性,为每个属性创建一个 Dep 对象(依赖收集器),这个 Dep 对象是发布 - 订阅模式中的发布者。并使用 Object.defineProperty 对属性进行数据劫持,将这些属性转换为响应式数据。当访问或修改这些属性时,会触发相应的 getter 和 setter 方法。

模板编译与 Watcher 创建(观察者模式体现)

在完成数据劫持后,Compiler 会对模板进行编译。在编译过程中,会为每个需要响应数据变化的地方创建一个 Watcher 对象。Watcher 对象负责监听数据的变化,并在数据变化时更新视图。

依赖收集(发布 - 订阅模式:订阅阶段)

Dep 对象内部维护有一个 subs 数组,用于收集 Watcher 订阅者。Dep 提供了 addSub 方法用于添加 Watcher(收集依赖),notify 方法用于通知所有 Watcher 数据发生了变化。
当组件视图刷新或者初始化时,组件对应的 Watcher 会被设置为 Dep.target。当访问响应式数据触发 getter 时,getter 会调用 Dep 的 addSub 方法,将 Dep.target(即当前 Watcher)添加到 dep.subs 数组中,完成依赖收集。收集完成后,Dep.target 会被清空。

数据更新与视图更新(发布 - 订阅模式:发布阶段)

当组件中的某个数据发生变化时,会触发相应属性的 setter 方法。setter 方法会调用 Dep 的 notify 方法,通知 dep.subs 数组中的所有 Watcher 数据已更新。
每个 Watcher 接收到通知后,会调用自身的 update 方法。update 方法会触发 vm.render 渲染函数,生成新的虚拟 DOM(VNode)。接着,update 方法会带着新的 VNode 调用 patch 方法,将新的 VNode 与旧的 VNode 进行对比,更新实际的 DOM 节点,从而实现视图的更新。

参考资料:

vue2简易手写
https://juejin.cn/post/6989106100582744072#heading-14

Vue3的响应式原理

Vue 3 的响应式原理基于 Proxy 对象和 Reflect 以及一套依赖收集与触发更新机制。

核心 API 基础

  • Proxy:Vue 3 用 Proxy 替代 Vue 2 的 Object.defineProperty,解决了后者无法监听数组索引和 length 属性变化等局限,还能默认监听动态添加属性和属性删除操作。
  • Reflect:ES6 引入的新特性,用于在代码运行时设置或获取对象成员,与 Object 相关方法功能类似但更具语义,和 Proxy 配合使用。

响应式对象创建

  • reactive 函数:用于创建响应式对象,会递归处理对象的嵌套属性,确保引用类型属性也是响应式的。其 handler 中的 get 方法在获取属性值时会调用 track 函数进行依赖收集;set 和 deleteProperty 方法在属性值变化或属性删除时会调用 trigger 函数触发更新。

依赖收集与触发更新机制

  • effect 函数:创建副作用函数,执行时会将当前副作用函数赋值给 activeEffect,执行完后置为 null。当依赖的数据变化时,副作用函数会重新执行。
  • track 函数:收集依赖,利用 WeakMap 类型的 targetMap 存储对象的依赖信息。每个对象对应一个 Map(depsMap),depsMap 中每个键对应一个 Set(dep),dep 存储依赖该属性的副作用函数。
  • trigger 函数:触发更新,当对象属性值变化时,从 targetMap 找到对应依赖集合,遍历执行其中的副作用函数。

不同类型数据响应式处理

  • ref 函数:将基础类型数据包装成响应式对象,通过 get/set 存取器进行依赖追踪和触发更新。若数据是对象则调用 reactive 处理。
  • toRef 函数:将对象中的某个属性转化为响应式数据,返回具有 value 属性的对象,对 value 的修改会影响原始对象属性值。
  • toRefs 函数:将 reactive 创建的对象解构为多个响应式属性,方便在模板中使用,内部调用 toRef 实现。

    参考资料:

    vue3简易手写
    https://juejin.cn/post/7134281691295645732

什么是虚拟DOM?有什么优点?

虚拟DOM是一颗用js对象作为基础的树,用对象属性来描述节点,有tagname、props、children这些属性,是对真实DOM的一种抽象,VirtualDOM映射到真实DOM要经历VNode的create、diff、patch等阶段。

操作原生DOM慢,而js的运行效率高。我们可以把DOM对比操作放在js层,提高效率。运用patch算法来找到真正需要更新的节点,最大限度的减少DOM操作,提高性能。同时因为是js对象不依赖真实平台环境,所以具有了跨平台的优势。虚拟DOM能提升渲染性能,优势不在于单次的操作,而是在大量、繁琐的操作下,对视图进行高效的刷新,从总体上来看,性能消耗有一个让人能接受的范围。

为什么 data 是一个函数

组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果

Vue 组件通讯有哪几种方式

  1. props 和$emit 父组件向子组件传递数据是通过 prop 传递的,子组件传递数据给父组件是通过$emit 触发事件来做到的

  2. $parent,$children 获取当前组件的父组件和当前组件的子组件

  3. $attrs 和$listeners

  4. 父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。

  5. $refs 获取组件实例

  6. eventBus 兄弟组件数据传递 事件总线

  7. vuex 状态管理

为什么v-for要加key?

Key的作用是尽可能复用DOM元素。这跟vue的虚拟DOM机制和diff算法有关系。Key是children的唯一标识。数据发生改变的时候不可能直接去生成全新 的虚拟DOM,这样违背了创造虚拟DOM的初衷,使性能开销更大。Diff算法要判断是否是同一个节点关键就是要根据key去判断。

为什么不能用index作为key?

Key的值对于节点来说必须是唯一的,能够标识出身份的。而index是会随着节点数目、位置不同发生改变的,这可能会导致diff算法过程中误将两个不相同的节点当成相同节点然后进行pathvnode,或者两个相同节点当成不相同节点,进行不必要的添加、删除DOM的操作,可能原本只需要进行移动子节点这种少量的操作变成了大量对DOM的操作,性能开销会变大。

v-if 和 v-show 的区别

v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。

v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)

使用场景

v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景

v-show 适用于需要非常频繁切换条件的场景

v-if 与 v-for 为什么不建议一起使用

v-for 和 v-if 不要在同一个标签中使用,因为解析时先解析 v-for 再解析 v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式。

vue 内置指令

内置指令.png

什么是diff算法?

Diff算法是一种对比算法。对比旧的虚拟DOM和新的虚拟DOM,判断是哪个虚拟节点变更了,找出并只更新这个虚拟节点所对应的真实节点。Vue里如果数据发生改变就会触发setter,通过dep.notify方法通知所有订阅者watcher,订阅者们就会调用patch方法给真实DOM打补丁,更新视图。Patch方法对比当前同层的虚拟节点是否为同一种类型的标签,是就继续执行patchVnode方法进行深层对比,不是就直接整个节点替换为新的节点。sameVnode方法判断是否为同一类型节点,patchVnode方法判断新旧节点文本是否一样,以及子节点的情况,决定添加、删除DOM节点或者是执行updateChildren函数去对比子节点,updatechildren采用首位指针法,判断新旧首位节点是否是同一节点,用新vnode的key去找出旧节点中可以复用的位置,主要是子节点的位置的移动,如果最后发现新旧节点的子节点数量不同,就执行插入和删除操作。

参考资料

https://juejin.cn/post/6994959998283907102

nextTick是什么?应用场景是?

用在DOM节点变化后立即调用以获取变化后的节点。因为vue中DOM更新是异步的,更新后可能不能及时获取到节点。浏览器的事件循环机制再细致一点是宏任务->微任务->UI渲染->宏任务。Vue为了防止重复渲染,会把宏任务、微任务的事件放到队列中,nextTick的回调函数设置成一个promise的形式放到微任务队列最后。如果浏览器兼容性不支持,就依次降级成mutationObserve、setInternal、setTimeout。

vue中数据频繁变化为什么只更新一次(vue的异步更新机制)

利用了浏览器的异步任务队列实现。首选微任务队列,宏任务次之。vue检测到数据变化会开启一个队列,在同一事件循环中会缓存所有的数据变化,如果同一个watcher被多次触发,只会被推到队列中一次。

生命周期钩子有哪些?一般在哪一步发请求?

分为创建、挂载、更新、销毁阶段

beforeCreate、created、 beforeMount、mounted、beforeUpdate、updated、beforeDestory、destoried、activated

  • beforeCreate:new Vue后触发第一个钩子
  • created:实例创建完成但还没有挂载到DOM,已经完成数据的检测,可以访问到data、methods、watch、computed,但是$el还不能访问。这时候可以进行一些初始化操作,发送简单的ajax请求。
  • beforeMount:vue实例已经挂载到el上,模板编译完成,虚拟DOM创建完成。
  • mounted:真实DOM挂载完毕,完成渲染,可以使用$ref访问到DOM节点。(:mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick。)
  • beforeUpdate:响应式数据更新时调用,发生在虚拟DOM打补丁之前。
  • updated:虚拟DOM打补丁完成,组件DOM已经更新。

可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。

如果异步请求不需要依赖 Dom 推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:

  • 能更快获取到服务端数据,减少页面 loading 时间;
  • ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;

Vue 的父子组件生命周期钩子函数执行顺序

  • 加载渲染过程

父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted

  • 子组件更新过程

父 beforeUpdate->子 beforeUpdate->子 updated->父 updated

  • 父组件更新过程

父 beforeUpdate->父 updated

  • 销毁过程

父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

路由钩子

全局守卫三个:

router.beforeEachrouter.afterEachrouter.beforeResolve(全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用)

to/from/next三个参数 路由对象是平时用this.$route获取到的对象

next() 进入该路由。

next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。

next 跳转新路由,当前的导航被中断,重新开始一个新的导航。

路由独享守卫beforeEnter(在全局前置守卫调用之后)

写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const router = new VueRouter({

routes: [

{

path: ‘/foo’,

component: Foo,

name:’aaa’,

beforeEnter: (to, from, next) => {
// 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖

// …

},

meta: {

keepAlive: true // 需要被缓存

}

},

{

path: ‘/foo2’,

component: Foo2,

beforeEnter: (to, from, next) => {

// 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖

// …

},

meta: {

keepAlive: false // 不需要被缓存

}

}

]

})

组件路由守卫

beforeRouteEnterbeforeRouteLeavebeforeRouteUpdate(路由复用同一个组件时调用)

  • beforeRouteEnter在组件实例还没创建时调用,不能获取this,next的回调执行时期在mounted后

  • beforeRouteLeave 阻止用户离开,比如未保存草稿

1
2
3
4
5
6
7
8
9
10
11
12
beforeRouteLeave (to, from , next) {
if (文章保存) {

next(); // 允许离开或者可以跳到别的路由 上面讲过了

} else {

next(false); // 取消离开

}
}

路由解析流程

beforeEach(->beforeRouteUpdate-)> beforeEnter(独享)->解析异步路由组件->beforeRouteEnter->beforeResolve->导航被确认->

afterEach->beforeCreate->created->beforeMount->mouted->activated->beforeRouteEnter中next的回调

完整的导航解析流程:

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

keep-alive组件

可以实现组件缓存。缓存组件内部状态避免重新渲染。缓存动态组件用的少,一般是缓存路由组件

  • 常用的两个属性 include/exclude,允许组件有条件的进行缓存。
  • 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。
  • keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。

2.1版本前做法:

<!–这里是会被缓存的路由–>

<!–因为用的是v-if 所以下面还要创建一个未缓存的路由视图出口–>

  • 2.1版本后做法:

新增include和exclude属性,支持逗号分割的字符串、正则表达式、数组

匹配规则:组件的name、组件的局部注册名称。不可匹配匿名,且不能匹配嵌套的组件,exclude优先级更大。

keep-alive包含的组件中会多出activated和deactivated

afterEach离开后执行deactivates 然后再进入另外的activated,有keep-alive的情况下不会触发beforeCreate、created 、beforeMount、 mountedbefore、destroy、destroyed。

route和router的区别

router是vueRouter的一个实例对象,是全局的,包含所有路由和许多关键的对象和属性。

每个路由都会有一个route对象,$route为当前router跳转对象。可以获取对应的name、path、params、query等

v-if和v-show的区别

v-show是单纯的css切换,相当于为元素添加display:none;v-if是将整个元素添加或删除,有一个编译和卸载的过程,会触发重建和销毁。v-if有更高的切换消耗,而v-show有更高的初始渲染消耗.

v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;

介绍vuex

是为vue.js提供的状态管理插件,多个组件依赖同一个状态的时候可以使用,避免繁杂的组件间传值操作。有state、getters、mutations、actions五个核心属性。

  • state可以存放公共状态;

  • getters可以对状态进行修饰;

  • mutations用来同步改变状态值,通过this.$store.commit()提交,接受两个参数,一个是方法名,一个是传入的payload对象,mutations里面的方法接受state参数和payload;

  • actions用来异步改变状态值,通过this.$store.dispatch()提交,actions里面的方法接受content参数和传过来的参数。content是对当前store对象的拷贝。方法里调用content.commit()改变状态,而不是直接改变状态;

  • modules将状态分成多个模块,以免状态太多导致store对象臃肿不好维护。module文件夹中新建moduleA.js moduleB.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56

    const state={

    //…

    }

    const getters={

    //…

    }

    const mutations={

    //…

    }

    const actions={

    //…

    }

    export default{

    state,

    getters,

    mutations,

    actions

    }

    在store/index.js引入模块

    import moduleA from ‘…..’

    import moduleB from ‘…..’

    const store = new Vuex.Store({

    modules:{

    moduleA,

    moduleB

    }

    })

    export default store
  • 组件中批量使用state状态(语法糖):引入mapState辅助函数,通过扩展运算符将state混入到computed对象中。

1
2
3
4
5
6
7
8
9
10
11
12
import {mapState} from ‘vuex’
export default{js

computed:{

mapState([‘price’,’number’])

}

}


Computed、watch的区别?如何实现的?

Computed具有缓存的功能,依赖的属性值发生变化就会更新视图。在模板中放入过多逻辑会让模板难以维护,而且过多的计算和频繁更新很消耗性能,所以在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。Watch更多的是观察的作用,可以监听数据执行回调,需要深度监听对象中的属性可以打开deep:true选项,对对象中的每一项进行监听。

Vue-router常用路由模式实现原理?

Hash、history。

  • Hash模式是把前端路由的路径用井号#拼接在真实url后面的模式。#后发生改变时浏览器不会重新发起请求而是触发hashchange事件。

  • History模式路径中不包含#,依赖于html5的history api中的pushState和replaceState方法。由于改变了地址,刷新时会按照修改后的地址请求后端,需要后端配置处理,对地址访问做映射,否则会404.

Vue2和vue3的区别

  • 性能提升:Vue3 在性能上进行了优化,虚拟dom算法优化比如静态提升、Patch Flag和基于 Proxy 的响应式系统,这些都让 Vue3 比 Vue2 更快 。

    (静态提升是指将模板中不会发生变化的节点提取出来,只在首次渲染时创建;Patch Flag 是为动态节点添加标记,在更新时只比较有标记的节点,提高了比较效率)

  • 响应式原理:Vue 2:基于 Object.defineProperty() 方法实现响应式。有一些局限性,比如无法检测对象属性的添加和删除,对于数组,通过索引直接修改元素时无法更新视图。
    Vue 3:使用Proxy 直接代理整个对象而非对象属性,就可以监听到新增属性和删除属性,并且可以监听数组的变化。

  • 定义响应式变量:vue2直接写在data,vue3则用ref和reactive定义变量

  • 组件选项式 API 与组合式 API:vue2是选项型API, 代码里分割了不同的属性(properties):data,computed属性,methods,等等。Vue3是组合型API,需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。可以根据逻辑功能来组织代码。

  • 生命周期钩子:vue3命名发生改变,并且可以在组合式 API 中使用。新增了 setup 函数,它在 beforeCreate 和 created 之前执行,同时,生命周期钩子可以在 setup 函数中使用。

  • Typescript类型支持:从设计上就对 TypeScript 有更好的支持,组合式 API 的函数式风格使得类型推导更加自然和准确。

  • 多根节点组件:Vue3 template下可以包含多个根节点。

  • 打包体积:Vue 3对Tree Shaking有天然支持。因为Vue 3 采用了 ES 模块(ESM)的方式进行代码组织,打包工具(如 Vite、Webpack 等)可以在编译阶段分析模块之间的依赖关系,准确识别出未使用的代码,并将其从最终的打包文件中移除,从而减小包的体积,提高应用的加载速度。

Vue和React的区别

设计理念:
Vue:推崇易用性和简洁性,提供了更多开箱即用的功能,比如模板语法、数据绑定等。
React:函数式编程。更注重灵活性和可扩展性,推崇”一切皆组件”的理念,开发者可以自由组合。

模板与JSX:
Vue:使用基于HTML的模板语法,易于理解和上手。
React:使用JSX语法,它是一种看起来像HTML的JavaScript语法扩展。

响应式系统:
Vue:使用依赖收集的机制,通过Object.defineProperty实现数据响应。
React:使用useState和useEffect钩子来处理状态和副作用,依赖于一个高效的虚拟DOM算法。

组件通信:
Vue:有props和events来实现父子通信,以及provide和inject来实现跨组件通信。
React:有props和context来实现通信,也支持自定义上下文。

构建工具:
Vue:通常与Vue CLI配合使用,提供一键式项目脚手架。
React:通常与Create React App配合使用,同样提供快速的项目启动。

生态系统:
Vue:有Vuex用于状态管理,Vue Router用于路由。
React:有Redux用于状态管理,React Router用于路由。

使用过 Vue SSR 吗?说说 SSR

SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。

优点:

SSR 有着更好的 SEO、并且首屏加载速度更快

缺点: 开发条件会受到限制,服务器端渲染只支持 beforeCreate 和 created 两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。

服务器会有更大的负载需求

vue 中使用了哪些设计模式

1.工厂模式 - 传入参数即可创建实例

虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode

2.单例模式 - 整个程序有且仅有一个实例

vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉

3.发布-订阅模式 (vue 事件机制)

4.观察者模式 (响应式数据原理)

5.装饰模式: (@装饰器的用法)

6.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略

你都做过哪些 Vue 的性能优化

这里只列举针对 Vue 的性能优化 整个项目的性能优化是一个大工程 可以另写一篇性能优化的文章 哈哈

  • 对象层级不要过深,否则性能就会差
  • 不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)
  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分使用场景
  • v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if
  • 大数据列表和表格性能优化-虚拟列表/虚拟表格
  • 防止内部泄漏,组件销毁后把全局变量和事件销毁
  • 图片懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 适当采用 keep-alive 缓存组件
  • 防抖、节流运用
  • 服务端渲染 SSR or 预渲染