Vue
v-if和v-for哪个优先级更高?如果两个同时出现,如何优化?
- v-for高于v-if。
-
①不同级:外层嵌套template并使用v-if先判断,然后在内部使用v-for。
②同级:使用计算属性进行数据过滤再使用v-for,从而避免同级使用v-if。
Vue组件data为什么必须是个函数而Vue的根实例则没有此限制?
- Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们公用一个data对象,那么状态变更就会影响其所有实例,采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。
- 在Vue创建根实例过程中,全局只创建一个Vue实例【单例】,所以无此限制。
Vue中key的作用和工作原理?
-
key的作用主要是为了高效的更新虚拟DOM,其原理是Vue在patch过程中通过key可以精准的判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少虚拟DOM操作,提高性能。
example:
Without Keys 【点到点顺序更新,没有则创建】
With Keys 【点对点更新,没有则创建】
-
不设置key还可能在列表更新时引发一些隐藏的bug。因为调试源码可以知道无key的情况下,执行过程中每个节点的key都为undefined。
-
Vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让Vue可以区分它们,否则Vue只会替换其内部属性而不会触发过渡效果。
为什么不能使用index作为key?
-
①性能问题
②在对数据进行操作的时候,可能会引发一些bug。例如,在对数据进行删除的时候,删除中间数据,触发数据更新,此时数组下标发生变化,要删除的数据就会被保留,实际删除的是原先最后面的数据。
怎么理解Vue中的diff算法?
-
diff算法是虚拟DOM技术的必然产物,通过新旧虚拟DOM做对比(即diff),将变化的地方更新在真实DOM上,因此需要diff高效的执行对比过程,从而降低时间复杂度。【概述】
By the way
①两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
②同一层级的一组节点,他们可以通过唯一的id进行区分。
基于以上这两点,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。 - Vue2.x中为了降低watcher粒度,每个组件只有一个watcher与之对应,只有引入diff才能精确找到发生变化的地方。【必要性】
- Vue中diff执行的时刻是组件实例执行其更新函数时,它会对上一次渲染结果oldNode和新的渲染结果newNode,此过程称为patch。【执行方式】
-
diff过程整体遵循深度优先,同级比较的策略;两个节点之间比较会根据它们是否拥有子节点或文本节点做不同操作;比较两组子节点是算法的重点,首先假设头尾节点可能相同做四次比对尝试,如果没有找到相同节点才按照通用方式遍历查找,查找结束再按照情况处理剩下的节点;借助key通常可以非常精准找到相同节点,因此整个patch过程非常高效。【高效性】
对Vue组件化的理解?
- 组件是独立和可复用的代码组织单元。组件系统是Vue核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用。组件使用按分类有:页面组件、业务组件、通用组件。
- 组件化开发能大幅度提高应用开发效率、测试率、复用性等。
- 合理的划分组件,有助于提升应用性能。
…
Vue设计理念?
- 渐进式JavaScript框架
与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。 -
易用性
vue提供数据响应式、声明式模板语法和基于配置的组件系统等核心特性。这些使我们只需要关注应用的核心业务即可,只要会写js、html和css就能轻松编写vue应用。 -
灵活性
渐进式框架的最大优点就是灵活性,如果应用足够小,我们可能仅需要vue核心特性即可完成功能;随着应用规模不断扩大,我们才可能逐渐引入路由、状态管理、vue-cli等库和工具,不管是应用体积还是学习难度都是一个逐渐增加的平和曲线。 - 高效性
超快的虚拟 DOM 和 diff 算法使我们的应用拥有最佳的性能表现。
追求高效的过程还在继续,vue3中引入Proxy对数据响应式改进以及编译器中对于静态内容编译的改进都会让vue更加高效。
谈谈对MVC、MVP和MVVM的理解?
- 这三者都是框架模式,它们设计的目标都是为了解决Model和View的耦合问题。
- MVC【Model-View-Controller】模式主要应用在后端,如Spring MVC、ASP.NET
MVC等,在前端领域早期也有应用,如Backbone.js。它的优点在于分层清晰,缺点是数据流混乱,灵活性带来的维护性问题。
-
MVP【Model-View-Presenter】模式是MVC的进化模式,Presenter作为中间层负责MV通信,解决了两者耦合问题,但P层过于臃肿也会导致维护问题。
-
MVVM【Model-View-ViewModel】模式在前端领域有广泛应用,它不仅解决了MV耦合问题,还同时解决了维护两者映射关系的大量繁杂代码和DOM操作代码,在提高开发效率、可读性的同时还保持了优越的性能。
Vue优化
-
路由懒加载
javascript1
2
3
4
5const router = new VueRouter({
routes: [
{ path: '/xx', component: () => import('./xx.vue') }
]
}) -
keep-alive缓存页面
html1
2
3
4
5
6
7<template>
<div id="app">
<keep-alive>
<router-view/>
keep-alive>
div>
template> -
合理使用v-if和v-show
html1
2
3
4
5
6
7
8
9
10
11<template>
<div class="cell">
<div v-show="value" class="on">
<Heavy :n="10000"/>
div>
<section v-show="!value" class="off">
<Heavy :n="10000"/>
section>
div>
template> -
v-for遍历避免同时使用v-if
html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<template>
<ul>
<li
v-for="user in activeUsers"
:key="user.id">
{{ user.name }}
li>
ul>
template>
<script>
export default {
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
}
script> -
纯数据展示采用Object.freeze()进行冻结数据对象
javascript1
2
3
4
5
6
7
8
9export default {
data: () => ({
users: []
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
}; -
采用异步操作、异步组件
html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 异步请求等操作参看 ⑤
<template>
<div>
<message>message>
div>
template>
<script>
import Message from "./Message";
export default {
components: {
Message: () => import("./Message")
}
};
script> -
采用虚拟滚动,只渲染可视区域的内容
-
事件的销毁
javascript1
2
3
4
5
6
7//Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。
created() {
this.timer = setInterval(this.refresh, 2000)
},
beforeDestroy() {
clearInterval(this.timer)
} -
图片懒加载
参考项目:vue-lazyload
-
第三方插件按需引入
javascript1
2
3
4
5import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select) -
无状态的组件标记为函数式组件
html1
2
3
4
5
6
7
8
9
10
11
12<template functional>
<div class="cell">
<div v-if="props.value" class="on">div>
<section v-else class="off">section>
div>
template>
<script>
export default {
props: ['value']
}
script> -
子组件分割【render函数】
html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<template>
<div>
<ChildComp/>
div>
template>
<script>
export default {
components: {
ChildComp: {
methods: {
heavy () { /* 耗时任务 */ }
},
render (h) {
return h('div', this.heavy())
}
}
}
}
script> -
变量本地化【静态化】
html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<template>
<div :style="{ opacity: start / 300 }">
{{ result }}
div>
template>
<script>
import { heavy } from '@/utils'
export default {
props: ['start'],
computed: {
base () { return 42 },
result () {
const base = this.base // 不要频繁引用this.base
let result = this.start
for (let i = 0; i < 1000; i++) {
result += heavy(base)
}
return result
}
}
}
script> -
静态资源使用CDN加速
-
SSR
…
Vue3特性
-
更快
- 虚拟DOM重写
- 优化slots的生成
- 静态树提升
- 静态属性提升
- 基于Proxy的响应式系统
-
更小
- 通过摇树优化核心库体积
-
更容易维护
- TypeScript + 模块化
-
更加友好
- 跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台(Web、Android、iOS)一起使用
-
更容易使用
- 改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告
- 更好的调试支持
- 独立的响应化模块
- Composition API