文章目录
1 MVVM
MVVM 是Model-View-ViewModel
缩写。Model
层代表数据模型,View
层代表用户视图,ViewModel
是View
层和Model
层之间的桥梁,负责把Model
层数据同步到视图,视图变化的时候会更新Model
层的数据。
2 Vue 生命周期
Vue 的生命周期有四个关键节点,分别是:创建、渲染、更新、销毁。
Vue3.x | Vue2.x | 使用场景 |
---|---|---|
setup() | beforeCreate | 在实例生成之前执行,可以在这加 loading 事件 |
setup() | Created | 在实例生成之后执行,常用于异步获取数据 |
onBeforeMount | beforeMount | 在模板渲染完成之前执行 |
onMounted | mounted | 在模板渲染完成之后执行,可获取 DOM 元素 |
onBeforeUpdate | beforeUpdate | 在data中的数据变化之前执行,可用于获取更新前各种状态 |
onUpdated | updated | 当data中的数据发生变化,页面重新渲染完后执行 |
onBeforeUnmount | beforeDestroy | 在组件销毁之前执行,可用于一些定时器的取消 |
onUnmount | destroyed | 当组件销毁之后执行 |
『第一次加载页面会触发哪些钩子函数』
会触发 beforeCreate
、created
、beforeMount
、mounted
。
3 v-show VS v-if
『v-show』
不管初始条件是什么,元素总是会被渲染,它是基于display
属性进行切换。
『v-if』
只有当条件为true
时才会渲染元素。
『v-show VS v-if』
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
4 computed VS watch
『computed』
computed
是计算属性,它会根据所依赖的数据动态计算出结果。计算出的结果会被缓存,只有当所依赖的数据发生改变时,才会重新计算结果,否则返回之前的计算结果。
『watch』
watch
是侦听属性,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。它的结果是不会被缓存的,当被侦听的数据发生变化时,每次都会执行对应的函数。
『computed VS watch』
如果一个数据依赖于其它数据,可以使用 computed
。
如果需要在某个数据变化时执行某些操作,可以使用 watch
。
5 组件间的传值方式
![](https://i-blog.csdnimg.cn/blog_migrate/b567e5e98a563ee084c95e5d1fa856fa.png)
6 组件中的 data 为什么是函数
为什么组件中的 data
必须是一个函数,然后 return
一个对象,而 new Vue
实例里,data
可以直接是一个对象?
因为在 Vue 中组件是可以复用的,并且对象是引用数据类型,如果组件中的data
采用对象的形式,那么组件之间的数据就会互相影响。而通过 new Vue
出来的实例,只有一个,它不会被复用的,因此数据不会互相影响。
使用场景:如果想要在修改数据后立刻得到更新后的 DOM 结构,可以使用nextTick()
。
7 nextTick()
官方对其的定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
nextTick
是 Vue 中的性能优化手段,基于 JS 执行机制实现。它的执行时机是在下次 DOM 更新循环结束之后执行,所以如果需要在修改数据后立刻得到更新后的 DOM 结构,可以使用nextTick()
。
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const { createApp, components, nextTick } = Vue;
// 子孙组件
const childrenComponent = {
template:
"<div id='des'>{{ name }}<button @click='change'>click</button></div>",
data() {
return {
name: "小鱼",
};
},
methods: {
change() {
this.name = "小熊";
const el = document.getElementById("des");
console.log(`DOM 未更新:${el.innerText}`);
nextTick(() => {
console.log(`DOM 已更新:${el.innerText}`);
});
},
},
};
const Root = {
template: "<children-component></children-component>",
components: {
childrenComponent,
},
};
const app = createApp(Root);
app.mount("#app");
</script>
</body>
8 v-model 的原理
v-model
本质上是语法糖,在内部为不同的元素使用不同的属性和监听不同的事件来实现。
text
和textarea
元素使用value
属性和input
事件checkbox
和radio
使用checked
属性和change
事件select
元素使用value
属性和change
事件。
1️⃣ 在元素上使用 v-model
<input type='text' v-model='userName' />
// 等同于
<input type='text' :value='userName' @input='userName = $event.target.value' />
<textarea v-model='des' />
// 等同于
<textarea :value='des' @input='des = $event.target.value' />
<input type='checkbox' v-model='flag' />
// 等同于
<input type='checkbox' :checked='flag' @change='flag = $event.target.checked' />
<input type='radio' value='1' name='sex' v-model='sexVal' />
<input type='radio' vlaue='0' name='sex' v-model='sexVal' />
// 等同于
<input type='radio' value='1' name='sex' :checked='sexVal === 1' @change='sex = $event.target.value' />
<input type='radio' value='0' name='sex' :checked='sexVal === 0' @change='sex = $event.target.value' />
<select v-model='sex'>
<option :value='1'>男</option>
<option :value='0'>女</option>
</select>
// 等同于
<select :value='sex' @change='sex = $event.target.value'>
<option :value='1'>男</option>
<option :value='0'>女</option>
</select>
2️⃣ 在组件上使用 v-model
在组件上使用 v-model
,本质上是父子组件之间的通信,是通过 props/$emit()
来实现的。
// 父组件
<children-component v-model='des'></children-component>
// 等同于
<children-component :model-value='des' @update:model-value='des = $event'></children-component>
// 子组件
<input type='text' :value='modelValue' @input='$emit("update:modelValue", $event.target.value)' />
props: ['modelValue']
9 单向数据流
单向数据流是指只能从一个方向来修改数据状态。比如父级组件 prop
的更新会向下流动到子级组件中,但是子级组件不能直接修改父级组件的数据,否则会导致应用中的数据流向不好理解。
如果,子级组件需要操作这个数据,有两种方法:
1️⃣ 在子级组件中定义一个局部变量,并用prop
的值初始化它:
props: ['userName'],
data: function () {
return {
localUserName: this.userName
}
}
2️⃣ 定义一个计算属性,处理prop
的值并返回:
props: ['userName'],
computed: {
localUserName: function () {
return this.userName.trim().toLowerCase()
}
}
之后如果父级组件需要用到这个处理后的值,子级组件可以通过$emit
的方式传给父级组件。
10 v-for 中 key 的作用
当 Vue 更新使用 v-for
渲染的元素列表时,它默认使用“就地更新”的策略。也就是说,如果数据项的顺序发生改变,Vue 不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素。
当使用 key
时,Vue 能跟踪每个节点的身份,从而重用和重新排序元素。
11 v-if 和 v-for 的优先级
2.x 语法中,v-for
会优先生效。
3.x 语法中,v-if
会优先生效。
12 单页面应用
1️⃣ 什么是单页面应用?
就是只有一个主页面,有多个页面片段的应用,页面片段都包含在主页面中,在交互的时候页面片段由路由动态载入,页面跳转时是局部刷新。
2️⃣ 单页面应用和多页面应用区别?
单页面应用(SPA) | 多页面应用(MPA) | |
---|---|---|
组成 | 一个主页面和多个页面片段 | 多个主页面 |
刷新方式 | 局部刷新 | 整页刷新 |
url 模式 | 哈希模式 | 历史模式 |
SEO 搜索引擎优化 | 难实现,可使用 SSR 方式实现 | 容易实现 |
数据传递 | 容易 | 通过 url、cookie、localStorage 等传递 |
页面切换 | 速度快、用户体验好 | 切换加载资源、速度慢、用户体验差 |
维护成本 | 相对低 | 相对高 |
优点:
- 用户体验好、内容的改变不需要重新加载整个页面。
- 维护成本 相对低。
缺点:
- 不利于搜索引擎的抓取。
- 首次渲染速度相对较慢(浏览器一开始会加载所有必要的
html
、css
和js
文件。)
13 Vue 的性能优化
v-if
和v-for
尽量不在同一个标签中使用。- 如果需要使用
v-for
给每项元素绑定事件时使用事件代理来完成。 - 使用
v-for
时,保证key
唯一。 - 采用
keep-alive
缓存组件,主要用于保留组件状态或避免重新渲染。 - 正确使用
v-if
和v-show
。 - 使用路由懒加载、异步组件。
- 第三方模块按需导入
- 防抖、节流
- 图片懒加载
- 长列表滚动到可视区域动态加载
- 打包优化
- 压缩代码
- 使用 CDN 加载第三方模块。
14 事件修饰符及其作用
.stop
:阻止单击事件继续传播.prevent
:阻止了事件的默认行为.capture
:添加事件监听器时使用事件捕获模式.self
:只当在event.target
是当前元素自身时才会触发处理函数.once
:点击事件将只会触发一次.passive
这个.passive
修饰符尤其能够提升移动端的性能。
请记住,.passive
会告诉浏览器你不想阻止事件的默认行为。
15 v-for 与 v-if 不能在同一标签使用
在 Vue3 中,由于v-if
比v-for
具有更高的优先级,所以v-if
在进行判断时,会因为无法读取到列表中的项目而报错。
这种情况一般有2种解决方法:
- 如果判断条件是存在列表项目中,可以将列表声明为一个计算属性,使其返回过滤后的列表。
- 如果判断条件不存在列表项目中,可以将
v-if
移动到外层元素上,这样就可以实现整个列表的显示或隐藏。
16 路由跳转方式
路由跳转方式主要分为两种:第一种是通过 <router-link>
标签来进行跳转,第二种方式是借助router
的实例方法来实现跳转。
实例方法有三个:
router.push(...)
router.replace(...)
router.go(n)
它们三者区别如下:
router.push()
:跳转到指定的url
,并在history
栈中添加一条记录,点击后退会返回到上一个页面。router.replace()
:跳转到指定的url
,但是不会在history
栈中添加一条记录,点击后退会返回到上上个页面。router.go(n)
:向前或者向后跳转n
个页面,n
可为正整数或负整数。
17 简要概述 Vuex
Vuex 是为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储方式来管理所有组件的状态,并保证状态以一种可预测的方式发生变化。
Vuex 有5种属性:分别是State
、Getter
、Mutation
、Action
、Module
。
- State:类似组件中的
data
,用来存放数据。 - Getter:类似组件中的计算属性,
getter
的返回值会被缓存起来,且只有当它的依赖值发生改变时才会重新计算。 - Mutation:类似组件中的
methods
,里面存放的操作可以修改state
中的数据。也是修改state
数据的唯一方式。 - Action:Action 类似于
mutation
,不同之处在于 Action 提交的是mutation
,而不是直接修改state
中的数据,并且 Action 可以包含异步操作。
18 Vue 首屏性能优化,解决页面加载时间过长方法
VUE首页加载过慢,其原因是因为它是一个单页应用,需要将所有需要的资源都下载到浏览器端并解析。
考虑解决方法:
- 路由懒加载
- UI 框架按需加载
- 启用Gzip压缩
- 静态资源本地缓存
- 使用Quicklink,在网速好的时候可以帮助预加载页面资源
19 简要概述 < keep-alive >
<keep-alive>
是 Vue 中的内置组件,能在组件切换过程中保存组件的状态,防止重复渲染。
设置了<keep-alive>
缓存的组件,会多出两个生命周期函数(activated
与deactivated
)。
如果组件缓存后,需要获取数据,有 2 种方法:
beforeRouteEnter
actived
beforeRouteEnter:
每次组件渲染的时候,都会执行beforeRouteEnter
(导航守卫)。
beforeRouteEnter(to, from, next) {
next(vm => {
vm.getData(); // 获取数据
})
}
activated:
在<keep-alive>
缓存的组件被激活时,都会执行actived
activated() {
this.getData();
}
注意:服务器端渲染期间avtived
不被调用。
20 简要概述虚拟 DOM
虚拟 DOM 它只是对真实 DOM 的抽象,以对象作为基础,用对象的属性来描述节点,最终可以通过操作使虚拟 DOM 映射到真实 DOM 上。
Vue 可以对虚拟 DOM 进行创建节点、删除节点以及修改节点等操作,然后经过diff
算法得出需要修改的最小单位,再更新真实的 DOM,这样可以减少了 DOM 的操作,提高了性能。