Vue面试知识点记述
温故而知新
1.v-show 与v-if 的区别
v-show是CSS display用来控制显示与隐藏的,而v-if控制的是组件的渲染与销毁,而不是直接的显示与隐藏。
所以频繁切换显示的时候用v-show ,否则用v-if
常用的Vue指令:
v-for:循环指令,基于数组或者是对象渲染列表,必须有key
v-bind:动态绑定一个或多个特性
v-on:用来监听指定元素的DOM事件,比如点击事件
v-model:用于表单输入和应用状态之间的数据双向绑定
v-once:只渲染元素和组件一次,随后的重新渲染,可以优化性能
2.v-for 和 v-if哪个优先级更高,如果两个同时出现,应该怎么优化得到更好的性能
在源码中,v-for 的优先级是高于v-if 的
如果同时出现,每次渲染都会先执行循环再进行判断条件,无论如何循环都不可避免,浪费了性能,要避免这种情况的发生,则在外层嵌套template,在这一层进行v-if的判断,然后在内部进行v-for的循环。
3.Vue中data为什么必须是个函数,而VUE的根实例则没有此限制
Vue组件可能存在多个实例,如果采用对象的形式定义data,则会导致他们公用一个data对象,就像是多个人共同吃一碗饭一样,这样就会造成数据污染,如果状态变更,则会影响多个实例,这样是不合理的,想要解决这类问题就需要采用函数形式定义,在initData时会将其作为工厂函数返回全新的data对象,可以有效避免多个实例状态污染的问题。Vue根实例是通过new方式创建出来的,每次只能创建一个,是单例的,所以不会存在数据污染的问题。
4.Vue中key的用处和原理
(1)key是循环中的唯一标识,Vue组件高度复用,增加Key可以标识组件的唯一性。key的作用是为了高效的更新虚拟DOM,其原理是Vue在Patch过程中通过key可以精准的判断两个节点是否是同一个,从而避免频繁更新不同的元素,使得整个patch过程更加的高效,减少DOM操作量,提高性能。如果不设置Key,可能在列表更新时引发一些隐没的Bug。通过key,也会让diff操作更加准确,更快速。
(2)Vue中在使用相同标签名元素的过度切换时,会使用到key属性,其目的是为了能够让vue能够区分他们,否则vue只会替换其内部属性,而不会触发过度效果。
我们来看一下没有Key的时候实用的是“就地复用”策略,如图:将F循环插入到B和C之间
在不用Key的情况下,A与A比较,B与B比较,这个时候原来的C就会变成F,原来的D就会变成C,以此类推,最后的E没有找到对应的位置,相应的标签与对应的值不一样,最后多出来的一个就会被删掉,而且性能不高。所以我们需要用到key来做标记,将变化前和变化后做对比,从而精准的找到位置插入到新的节点。
5.如何理解Vue中的diff算法
diff算法是虚拟DOM技术的必然产物,就是通过新旧虚拟DOM进行比较(diff),将变化的地方更新在真实的DOM中,为了能够精准的找到变化发生的地方,我们需要diff算法,diff具有高效的对比过程,从而降低复杂度。
Vue中diff执行的时候,是组件实例执行更新函数时,它会对比上一次的渲染结果oldVnode和新的渲染结果newVnode,这个过程就叫做patch。
diff算法的过程遵循深度优先,同级对比的策略,比较两组子节点是算法的重点。
6.Vue页面跳转并传递参数
(1)router-link跳转
(2)this.$router.push()
query与params的区别在于,query传参时,就像是ajax的get传参,在地址栏中是可以看到传的参数信息的,params传值,就像是post传值,在地址栏中看不到所传的参数信息。
7.Vue父子组件传值
父传子是通过props传递的
父:
子:
子组件向父组件传值通过$emit
子:
父:
这里还涉及到兄弟组件之间的传值,可以实用两种方法 :
(1)新建eventBus.js文件,其实就是一个简单的Vue实例,自带有两个方法$on 和$emit
分别在两个兄弟组件之间引入这个文件,传值实用$emit,接受使用$on
(2)第二种方法就是让父组件作为中间传值的中介,子传父,再父传子
8. Promise
Promise是异步问题同步化的解决方案,同时解决了回调地狱的问题。
Promise有三种状态:
初始:padding
成功:fulfilled
失败:rejected
异步是否完成取决于Promise的状态,而且只有两种状态,一种是调用resolve(),从初始到成功,另一种就是调用reject()从初始到失败,当状态改变时就会交给.then()方法来完成后续操作,等所以操作都运行完之后,才会最后输出.then()方法的值。
Promise的四种方法:
Promise.resolve():返回一个成功状态态的Promise,通过.then()注册成功的回调函数。
Promse.reject():返回一个失败状态的Promise,通过.catch()注册失败的回调函数。
Promise.all([p1,p2,p3]):只有当中的Promise对象全部成功,才会返回一个结果且是个数组。
Promise.race([p1,p2,p3]):返回其中一个运行最快的结果。
Promise的特点:
1.Promise的状态不受外界的影响。
因为Promise代表的是异步操作,只有异步操作成功或者或者失败,才会改变 Promise的状态。
2.Promise的状态一旦改变就无法更改。
一旦状态固化,返回的结果在任何地方都调用的到。
9.Vue生命周期以及适应场景
创建前后 beforeCreate/created
在beforeCreate 阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象有了,el还没有。
载入前后 beforeMount/mounted
在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前未虚拟的DOM节点,data尚未替换。
在mounted阶段,vue实例挂载完成,data成功渲染。
更新前后 beforeUpdate/updated
当data变化时,会触发beforeUpdate和updated方法。这两个不常用,不推荐使用。
销毁前后beforeDestory/destoryed(Vue3中,beforeUnmount/Unmount)
beforeDestory是在vue实例销毁前触发,一般在这里要通过removeEventListener解除手动绑定的事件。实例销毁后,触发的destroyed。
应用场景:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom
10.Map 和 forEach区别
map()方法是通过遍历循环元素组然后返回一个新的数组,
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
forEach()方法对每一个元素执行一次给定的函数,返回值为undefined
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
// expected output: "a"
// expected output: "b"
// expected output: "c"
相同点是这两个方法都只是循环遍历数组,并且不会改变元素组,它们的参数都是(正在处理的元素,索引,原数组)。
11.关于Http请求
转载一篇文章,解释的很详细,可以细细琢磨
转载:
12. Vue插槽(slot)
13.计算属性
简单的理解就是,将原来在模版内复杂的计算放在计算属性computed里面计算,模版里直接用插值表达式来引用计算属性里返回的值,例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
这是一段在模版中的代码,可以看出我们要对message进行很复杂的计算,但是实用计算属性,可以实现:
<div id="example">
{{ message}}
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
message: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
我们在大多数情况下调用方法也可以简单的计算出结果,但是计算属性与方法的却别就在于,计算属性是基于它们的响应式依赖进行缓存的,与自己有关的值发生改变时,自己才会改变,与自己无关的值改变时,自己不会发生改变,相交于方法计算结果会更快。
当有一些数据需要随着另外一些数据变化时,建议使用computed。
当有一个通用的响应数据变化的时候,要执行一些业务逻辑或异步操作的时候建议使用watch。
14. Watch监听
Watch监听记住三种方法就可以了,转载一篇,简单明了:
15.Vue动态绑定Class和Style
16. Vue.nextTick()方法
// 修改数据
vm.msg = 'Hello'
// DOM 还未更新
Vue.nextTick(function () {
// DOM 更新
})
转载:https://blog.csdn.net/zhouzuoluo/article/details/84752280
17.动态组件
多个不同的组件使用一个挂载点,根据后台传回的数据进行动态切换,使用<component>标签的is属性
18. 异步组件
简单理解:什么时候调用,什么时候引入
转载:https://blog.csdn.net/zaoqinghuan/article/details/114754301
19.keep-alive,mixin
20.单项数据流
在组件通讯中,父组件给子组件传值是通过prop传递的,prop只能由父组件进行修改,子组件是不能修改的,否则会报错,子组件想要修改,也只能通过$emit给父组件发送自定义事件,让父组件修改。
21.对于Vue以及双向数据绑定的理解
22.Vue路由
传统的多页面应用,指的是打开一个功能,就跳转到一个页面,而单页面应用,就是一个页面,点击一个功能,不会跳转重新打开一个页面,而是用到哪一块直接加在,需要什么只需要将相应组件的内容渲染进去就可以了,这个时候就需要用到路由,其实就是指向的意思,<router-link to=''> to为需要跳转到的目标地址。
路由中有三个基本的概念 route, routes, router。
1, route,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。
2, routes 是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]
3, router 是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。
具体可以看一下转载:https://blog.csdn.net/qq_42043377/article/details/82894144
23.VueX
本文主要是自己学习,复习而记录的一些知识点,如有错误,请积极指正,谢谢!