vue生命周期相关的面试题
1.vue生命周期都有哪些?
beforeCreate:function () {
/*实例创建之前调用,表示Vue刚刚出生,data/methods都没有初始化,不能访问data和methods*/
},
created:function () {
/*实例创建之后调用,data和methods已经初始化好了,此时还没有开始编译模板
*/
},
//这个阶段完成后,vue会开始编译模板,根据data中的数据生成html,但是还没有渲染到页面上,仅存在于内存中
beforeMount:function () {
/*页面挂载之前调用,完成了模板的编译,用编译好的模板替换el属性指向的dom对象中的内容,但是还没有挂载到页面上*/
},
mounted:function () {
/*页面挂载之后调用,此时可以操作dom元素*/
},
beforeUpdate:function(){
/*数据更新之前调用,此时data中的值是最新的,页面上的数据依然是旧的。
*
* */
},
//这个阶段执行完后,虚拟dom会根据最新的数据生成最新的模板,然后替换之前的内容。
updated:function () {
/*数据更新完成之后调用,此时data中的数据和页面上的数据都是最新的
* */
},
beforeDestroy:function(){
/*实例销毁之前调用,一些实例的属性和方法还是可以使用。
* */
},
destroyed:function () {
/*
* 实例销毁之后调用,此时所有的属性和方法都不能使用。
* */
}
2.进入页面会执行哪些生命周期函数
beforeCreate、created、beforeMounted、mounted
3.在哪里可以访问data
beforeCreate中不可以访问
created中有el
beforeMounte中有el
mouted中都有,包括之后的生命周期钩子函数都有
4、如果加入了keep-alive会增加两个生命周期函数
activated和deactivated
进入页面的时候触发activated,离开页面触发 deactivated
5.如果加入keep-alive组件,第一次进入页面会触发哪些生命周期
beforeCreate、created、beforeMounted、mounted、activated
6、如果加入了keep-alive组件后,第二次或第n次进入页面会触发哪些生命周期?
只触发一个生命周期:activated(因为该页面已经被缓存起来了)
谈谈你对keep-alive组件的了解
1.是什么
vue自带的一个组件,用来缓存组件,提升性能,keep-alive可以在组件切换时,保存其包裹组件的状态,使其不被销毁。
2、参数
include:表示只有匹配的组件才会被缓存;
exclude:表示匹配到的组件不会被缓存;
3、生命周期
有两个生命周期函数,同上
4.使用场景
-列表页面跳转详情页的时候,用户通过点击跳转,那么详情页每次都要去请求数据,如果用户每次点击的都是同一个,那么详情页就没必要去重新请求,直接缓存起来就行了,如果点击的不是同一个再重新发起请求;
-在router-view上使用可以缓存路由组件;
v-if和v-show的区别
1.相同点
都可以控制元素的显示隐藏
2.区别
v-if通过创建/销毁dom元素来控制元素的显示隐藏,v-show通过css属性的display:none来控制元素的显示隐藏
3.场景
频繁切换使用v-show,会节省性能,反之使用v-if
说一下vue组件中的name的作用
1、当项目使用keep-alive时,可搭配组件name进行缓存过滤
当我们使用keep-alive缓存组件时,被缓存组件中的mounted函数只会执行一次,第二次进入页面不会重新触发,有两种解决方法,一种是使用activated(),在里面进行mounted中的操作;另一种就是在keep-alive中增加一个过滤,如下所示:
<div id="app">
<keep-alive exclude="Home">
<router-view/>
</keep-alive>
</div>
exclude属性就是要忽略匹配到的组件。
2、DOM做递归组件时;
当组件需要自己调用自己的时候
//父组件List.vue
<template>
<div class="list">
<Tree :list="list"/>
</div>
</template>
<script>
import Tree from './Tree.vue';
export default {
name: "List",
components: {Tree},
data() {
return {
list: [
{
title: "A",
children: [
{
title: "A-A",
children: [
{
title: "A-A-A",
},
],
},
{
title: "A-B",
},
],
},
{
title: "B",
},
{
title: "C",
},
{
title: "D",
},
],
};
},
};
</script>
//子组件Tree.vue
<template>
<div class="tree">
<div v-for="(item, index) of list" :key="index">
<div>
<span class="item-title-icon"></span>
{{ item.title }}
</div>
<div v-if="item.children">
<Tree :list="item.children" /> //递归组件是指组件自身调用自身
</div>
</div>
</div>
</template>
<script>
export default {
name: "Tree",
components: {},
props: ["list"],
};
</script>
3、使用vue-tools时;
vue-devtools调试工具里显示的组件名称是由vue中组件name决定的
v-if和v-for的优先级
v-for的优先级比v-if的优先级高,这是在源码中规定好的,并且v-for和v-if不可以同时使用,同时使用会很浪费性能,比如明知判断条件是false的情况下,还需要去遍历一下数据,所以通常我们会把v-if放在v-for的外面。
nextTick的原理是什么
是用来获取更新后的dom内容,并且该方法是异步的
created() {
console.log(111)
},
methods: {
btn(){
console.log(333)
this.$nextTick(()=>{
console.log(222)
})
},
},
作用是将回调函数延迟到下次dom更新循环之后执行因为vue更新数据是异步的,修改data中的数据,视图不会立刻更新,vue会将你对data的修改放到一个watch队列中,当同一事件循环中的所有数据更新完以后,再进行试图更新,所以会产生延迟。
最常见的使用场景就是,在created中获取dom元素的时候需要使用$nextTick获取
组件中的data为什么必须是一个函数?
组件中的data
写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data
,相当于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data
,就会造成一个变了全都会变的结果。
怎么理解vue中的单向数据流?
当父组件给子组件传递数据的时候,子组件只允许对数据进行读取,不允许修改数据,因为当子组件修改了父组件传过来的数据时,其他引用父组件数据的组件也会被修改,从而导致报错,然而也不知道是当前组件报错还是父组件报错还是修改父组件信息的子组件的错误;
如果要修改可以通过this.$emit方法派发自定义事件,在父组件中修改;
vue路由有几种模式?
hash模式和history模式,默认是hash模式
区别如下:
1、表现形式不同,hash使用#表示,history用/表示;
2、hash值不会发送到服务端,history会发送到服务端 ,如果没有匹配到对应的路由,需要配置对应的页面;
3、获取方式不同,hash值可以通过location.path获取,history通过location.pathname获取;
4、hash可以通过window.onhashchange监听hash值的改变 ,history
可以通过onpopstate监听变化;
谈一谈对数据双向绑定的原理?
实现一个简单的数据双向绑定,说一下基本的思路
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实现一个简单的双向数据绑定</title>
</head>
<body>
//在输入框中输入内容会同步到p标签中
<input type="text" id="ipt" value="">
<p class="pp"></p>
</body>
<script>
const ipt=document.querySelector('#ipt'),
pp=document.querySelector('.pp');
let obj={
name:''
};
Object.defineProperty(obj,'name',{
get(){
console.log('get')
},
set(newVal){
pp.innerHTML=newVal;
}
})
ipt.addEventListener('keyup',function(e){
obj.name=e.target.value;
})
</script>
</html>
vue的渲染流程
组建中的template标签会编译为render函数,通过render函数创建出dom元素,然后转化为虚拟dom最终转化为真实dom
虚拟dom是什么?在vue中做了什么?是如何提升渲染效率的?
1、虚拟dom是一个js对象,用对象属性来描述节点,是一层对真实dom的抽象
<ul class="ul">
<li></li>
</ul>
//转化为虚拟dom
{
ele:'ul' //目标元素 必需
attr:'ul' //属性
children:[] //子元素
}
2、因为dom的执行速度远不如js执行速度快,因此将真实的dom抽象成js对象,然后通过算法计算出真正需要更新的节点,从而减少了大量的dom操作。
3、将直接操作dom转换成了两个js对象中去比较,找出差异项,做局部更新,提高了执行效率。
未完待续...