vue面试题
1、说说你对SPA 单⻚⾯的理解,它的优缺点分别是什么?
SPA(single-page application )仅在Web ⻚⾯初始化时加载相应的HTML、JavaScript 和CSS。⼀旦⻚⾯加载完成,SPA 不会因为⽤户的操作⽽进⾏⻚⾯的重新加载或跳转;取⽽代之的是利⽤路由机制实现HTML 内容的变换,UI 与⽤户的交互,避免⻚⾯的重新加载。
优点:
⽤户体验好、快,内容的改变不需要重新加载整个⻚⾯,避免了不必要的跳转和重复渲染;基于上⾯⼀点,SPA 相对对服务器压⼒⼩;
前后端职责分离,架构清晰,前端进⾏交互逻辑,后端负责数据处理;
缺点:
初次加载耗时多:为实现单⻚Web 应⽤功能及显示效果,需要在加载⻚⾯的时候将JavaScript、CSS 统
⼀加载,部分⻚⾯按需加载;
前进后退路由管理:由于单⻚应⽤在⼀个⻚⾯中显示所有的内容,所以不能使⽤浏览器的前进后退功能,所有的⻚⾯切换需要⾃⼰建⽴堆栈管理;
SEO 难度较⼤:由于所有的内容都在⼀个⻚⾯中动态替换显示,所以在SEO 上其有着天然的弱势。
2、v-show 与v-if 有什么区别?
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和⼦组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第⼀次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS 的“display” 属性进⾏切换。
所以,v-if 适⽤于在运⾏时很少改变条件,不需要频繁切换条件的场景;v-show 则适⽤于需要⾮常频繁切换条件的场景。
3、Class 与Style 如何动态绑定?
Class 可以通过对象语法和数组语法进⾏动态绑定:对象语法:
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
isActive: true, hasError: false
}
复制代码
数组语法:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
data: {
activeClass: 'active', errorClass: 'text-danger'
}
复制代码
Style 也可以通过对象语法和数组语法进⾏动态绑定:
对象语法:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red', fontSize: 30
}
数组语法:
<div v-bind:style="[styleColor, styleSize]"></div>
data: { styleColor: {
color: 'red'
},
styleSize:{ fontSize:'23px'
}
}
4、怎样理解Vue 的单向数据流?
所有的prop 都使得其⽗⼦prop 之间形成了⼀个单向下⾏绑定:⽗级prop 的更新会向下流动到⼦组件中,但是反过来则不⾏。这样会防⽌从⼦组件意外改变⽗级组件的状态,从⽽导致你的应⽤的数据流向难以理解。额外的,每次⽗级组件发⽣更新时,⼦组件中所有的prop 都将会刷新为最新的值。这意味着你不应该在⼀个⼦组件内部改变prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。⼦组件想修改时,只能通过
$emit 派发⼀个⾃定义事件,⽗组件接收到后,由⽗组件修改。有两种常⻅的试图改变⼀个prop 的情形:
这个prop ⽤来传递⼀个初始值;这个⼦组件接下来希望将其作为⼀个本地的prop 数据来使⽤。在这种情况下,最好定义⼀个本地的data 属性并将这个prop ⽤作其初始值:
props: ['initialCounter'], data: function () {
return {
counter: this.initialCounter
}
}
这个prop 以⼀种原始的值传⼊且需要进⾏转换。在这种情况下,最好使⽤这个prop 的值来定义⼀个计算属性
props: ['size'], computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
5、computed 和watch 的区别和运⽤的场景?
computed:是计算属性,依赖其它属性值,并且computed 的值有缓存,只有它依赖的属性值发⽣改变,下
⼀次获取computed 的值时才会重新计算computed 的值;
watch:更多的是「观察」的作⽤,类似于某些数据的监听回调 ,每当监听的数据变化时都会执⾏回调进⾏后续操作;
运⽤场景:
当我们需要进⾏数值计算,并且依赖于其它数据时,应该使⽤computed,因为可以利⽤computed 的缓存特性,避免每次获取值时,都要重新计算;
当我们需要在数据变化时执⾏异步或开销较⼤的操作时,应该使⽤watch,使⽤watch 选项允许我们执
⾏异步操作( 访问⼀个API ),限制我们执⾏该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性⽆法做到的。
6、直接给⼀个数组项赋值,Vue 能检测到变化吗?
由于JavaScript 的限制,Vue 不能检测到以下数组的变动:
当你利⽤索引直接设置⼀个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的⻓度时,例如:vm.items.length = newLength
为了解决第⼀个问题,Vue 提供了以下操作⽅法:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的⼀个别名vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)
复制代码
为了解决第⼆个问题,Vue 提供了以下操作⽅法:
// Array.prototype.splice vm.items.splice(newLength)
7、谈谈你对Vue ⽣命周期的理解?
[if !supportLists](1) [endif]⽣命周期是什么?
Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新-> 渲染、卸载等⼀系列过程,我们称这是Vue 的⽣命周期。
[if !supportLists](2) [endif]各个⽣命周期的作⽤
⽣命周期描述
beforeCreate组件实例被创建之初,组件的属性⽣效之前
created组件实例已经完全创建,属性也绑定,但真实dom 还没有⽣成,$el 还不可⽤
beforeMount在挂载开始之前被调⽤:相关的render 函数⾸次被调⽤
mountedel 被新创建的vm.$el 替换,并挂载到实例上去之后调⽤该钩⼦
beforeUpdate组件数据更新之前调⽤,发⽣在虚拟DOM 打补丁之前
update组件数据更新之后
activitedkeep-alive 专属,组件被激活时调⽤
deadctivatedkeep-alive 专属,组件被销毁时调⽤
beforeDestory组件销毁前调⽤
destoryed组件销毁后调⽤
[if !supportLists](3) [endif]⽣命周期示意图
https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B
%BE%E7%A4%BA
8、Vue 的⽗组件和⼦组件⽣命周期钩⼦函数执⾏顺序?
Vue 的⽗组件和⼦组件⽣命周期钩⼦函数执⾏顺序可以归类为以下4 部分:加载渲染过程
⽗beforeCreate -> ⽗created -> ⽗beforeMount -> ⼦beforeCreate -> ⼦created -> ⼦beforeMount -> ⼦
mounted -> ⽗mounted
⼦组件更新过程
⽗beforeUpdate -> ⼦beforeUpdate -> ⼦updated -> ⽗updated
⽗组件更新过程
⽗beforeUpdate -> ⽗updated
销毁过程
⽗beforeDestroy -> ⼦beforeDestroy -> ⼦destroyed -> ⽗destroyed
9、在哪个⽣命周期内调⽤异步请求?
可以在钩⼦函数created、beforeMount、mounted 中进⾏调⽤,因为在这三个钩⼦函数中,data 已经创建,可以将服务端端返回的数据进⾏赋值。但是本⼈推荐在created 钩⼦函数中调⽤异步请求,因为在created 钩
⼦函数中调⽤异步请求有以下优点:
能更快获取到服务端数据,减少⻚⾯loading 时间;
ssr 不⽀持beforeMount 、mounted 钩⼦函数,所以放在created 中有助于⼀致性;
10、在什么阶段才能访问操作DOM?
在钩⼦函数mounted 被调⽤前,Vue 已经将编译好的模板挂载到⻚⾯上,所以在mounted 中可以访问操作
DOM。vue 具体的⽣命周期示意图可以参⻅如下,理解了整个⽣命周期各个阶段的操作,关于⽣命周期相关的
⾯试题就难不倒你了。
11、⽗组件可以监听到⼦组件的⽣命周期吗?
⽐如有⽗组件Parent 和⼦组件Child,如果⽗组件监听到⼦组件挂载mounted 就做⼀些逻辑处理,可以通过以下写法实现:
// Parent.vue
<Child @mounted="doSomething"/>
//
Child.vue mounted() {
this.$emit("mounted");
}
复制代码
以上需要⼿动通过$emit 触发⽗组件的事件,更简单的⽅式可以在⽗组件引⽤⼦组件时通过@hook 来监听即可,如下所示:
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('⽗组件监听到mounted 钩⼦函数...');
},//
Child.vue mounted(){
console.log('⼦组件触发mounted 钩⼦函数...');
},
// 以上输出顺序为:
// ⼦组件触发mounted 钩⼦函数...
// ⽗组件监听到mounted 钩⼦函数...
当然@hook ⽅法不仅仅是可以监听mounted,其它的⽣命周期事件,例如:created,updated 等都可以监听。
12、谈谈你对keep-alive 的了解?
keep-alive 是Vue 内置的⼀个组件,可以使被包含的组件保留状态,避免重新渲染,其有以下特性:
⼀般结合路由和动态组件⼀起使⽤,⽤于缓存组件;
提供include 和exclude 属性,两者都⽀持字符串或正则表达式,include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存,其中exclude 的优先级⽐include ⾼;
对应两个钩⼦函数activated 和deactivated ,当组件被激活时,触发钩⼦函数activated,当组件被移