1、vue 生命周期有哪些,以及对应的行为有哪些
1.1、生命周期共分为四个阶段
vue的生命周期,共分为四个阶段,创建实例、DOM渲染、数据更新、销毁实例,这四个段就是 Vue 的生命周期。
1.2、生命周期共有八个基本钩子函数
$el就是Vue实例关联的DOM元素
-
1、beforeCreate(
创建前
)
触发的行为:vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。
在此阶段可以做的事情:加loading事件 -
2、created(
创建后
)
触发的行为:vue实例的数据对象data有了,$el还没有
在此阶段可以做的事情:解决loading,请求ajax数据为mounted渲染做准备 -
3、beforeMount(
渲染前
)
触发的行为:此阶段,vue实例的挂载元素$el和data都初始化了,但还是虚拟的dom节点。页面还没挂载显示。 -
4、mounted(
渲染后
)
触发的行为:vue实例的$el挂载到页面上,页面渲染完成。
在此阶段可以做的事情:操作dom -
5、beforeUpdate(
更新前
)
触发的行为: 视图层数据被改变后,会触发beforeUpdate,此时数据已更新, 界面未更新
-
6、updated(
更新后
)
触发的行为:组件的数据、界面都已更新
-
7、beforeDestroy(
销毁前
)
触发的行为:组件销毁时触发
在此阶段可以做的事情:一般用于取消定时器, 解除监听
。 -
8、destroyed(
销毁后
)
触发的行为:组件销毁时触发,vue实例解除了事件监听以及和dom的绑定
在此阶段可以做的事情:组件销毁时进行提示
拓展 (keep-alive 专属)
- activited ( keep-alive 专属),组件激活时调用
- deactivated( keep-alive 专属),组件失活时调用
2、vue父子组件生命周期执行顺序
-
页面初始化渲染过程
父beforeCreate === 》 父created === 》 父beforeMount === 》子beforeCreate === 》子created=== 》子beforeMount === 》子mounted === 》父mounted父组件先执行到beforeMounted,随后执行子组件到mounted,最后再反过来执行你组件的mounted,开始渲染。
-
子组件更新过程
父beforeUpdate ===》子beforeUpdate ===》子updated ===》父updated注意:子组件的更新,首先是父组件的beforeUpdate,其次才是子组件的更新,最后是你组件的updated.(子组件的任何更新,都是从你组件的beforeUpdate开始的)
-
父组件更新过程
父beforeUpdate ===》 父updated -
销毁过程
父beforeDestroy ===》 子beforeDestroy ===》 子destroyed ===》 父destroyed
3、vue和react谈谈区别和选型考虑
3.1、React和Vue有许多相似之处,它们都有:
- 使用 Virtual DOM
- 提供了响应式(Reactive)和组件化(Composable)的视图组件。
- 将注意力集中保持在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库。
3.2、 性能:
- 个人感觉差别不大。
3.3、生态圈
Vue: Vue+vue-router+vuex+iVew/element-ui
React: React+React-router+Redux+ant-design
3.4、什么时候选择Vue/React
如果你喜欢用(或希望能够用)模板搭建应用,请使用Vue
如果你喜欢简单易上手的东西,请使用Vue
如果你的应用需要尽可能的小和快,请使用Vue
如果你计划构建一个大型应用程序,请使用React
如果你想要一个同时适用于Web端和原生App的框架,请选择React
如果你想要最大的生态圈,请使用React
4、vue-router如何做用户登录权限等
vu-router中提供了导航守卫的功能,
可以通过设置全局前置守卫或者路由独享守卫来做用户登陆权限的判别。
更多参考链接:https://blog.csdn.net/yiyueqinghui/article/details/107291509
5、vue2、vue3是怎么实现监听的
-
Vue2
我们知道Vue2的响应式的实现是通过ES5中的 Object.defineProperty() 劫持数据,并为其设置getter和setter来实现的。
var obj = {name:'Tony'};
Object.defineProperty(obj,'name',{
set:function(key,val){
},
get:function(){
}
})
缺点:
1、对于对象中不存在的属性则无法实现监听.
2、无法监听数组的变化
但是对于数组、对象等引用类型的数据来说,该类数据的变化,是无法触发setter方法的,也就无法触发页面响应
针对数组,vue通过重写数组的某些方法来监听数组变化,重写后的方法会手动触发该数组的所有依赖进行更新。比如说push、splice、pop、unshift、shift、sort、reverse方法。
针对对象,vue通过Vue.set(target,key,val) 方法来监听对象属性的变化,从而触发更新,或者可能通过Vue.$forceUpdate()强制更新的方式来实现页面的响应。
-
Vue3
Vue3监听对象属性变化则是通过ES6中的Proxy来实现,这样即使有些属性是后期新加的,也可以监听到。
var user = new Proxy({},{
set:function(target,key,value,receiver){
}
})
6、v-if和v-for一起使用(在同一个标签上使用)的弊端以及解决办法
- 问题: v-if失效
- 原因: 由于
v-for的优先级比v-if高
, - 造成的问题
所以导致每循环一次就会执行v-if一次,
而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。 - 解决办法:
1、如果想先执行v-if的话,在v-for的外层,嵌套一层template,在这一层内进行v-if的判断;
2、如果v-if出现在v-for内部,则可使用计算属性提前过滤掉那些不需要显示的项
7、beforeDestroy里面一般进行什么操作
beforedestoryed是组件销毁之前执行的一个生命周期,
在这个生命周期里,我们可以进行定时器的清除、不用的dom元素的清除
等
8、vue中的事件修饰符主要有哪些?分别是什么作用
.prevent
: 阻止默认事件,等同于 JavaScript中的 event. preventDefault()
.stop
: 阻止事件冒泡,等同于 JavaScript中的 event, stopPropagation(),.caption
: 用于事件捕获
.self
: 只会触发自己范围内的事件,不包含子元素
.native
: 绑定原生事件
.once
: 事件只执行一次
-
.passive
: 表示 addEventlistener函数不会调用 preventDefault()passive主要用在移动端的 scroll事件,来提高浏览器响应速度,提升用户体验。
因为passive=true等于提前告诉了浏览器,touchstart和 touchmove不会阻止默认事件,手刚开始触摸,浏览器就可以立刻给与响应;
否则,手触摸屏幕了,但要等待 touchstart和 touchmove的结果,多了这一步,响应时间就长了,用户体验也就差了
9、介绍下什么是keep-alive
keep-alive是用于做组件缓存的,用于保留组件状态,避免重复渲染,只会执行一次。
有以下特性:
-
结合路由一起使用,用于
缓存路由组件
; -
提供 include 和 exclude 属性,两者都支持字符串和正则表达式,include 表示只有
名称匹配的组件会被缓存
,exclude 表示任何名称匹配的组件都不会被缓存
,其中exclude 的优先级比 include 高
; -
对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件离开时,触发钩子函数 deactivated。
被keep-alive包裹的组件,**没有create和beforeDestroyed等方法,但是有activated和deactivated方法。
10、vue中如何解决页面不重新渲染问题
(1).修改对象属性后页面未重新渲染,可以使用 this.$set(对象名称, '属性名', '属性值')
来修改对象,触发更新。
(2). 强制更新,使用this.$forceUpdate()
11、active-class 是哪个组件的属性
vue-router 模块的 router-link 组件。
12、嵌套路由怎么定义
在 VueRouter 的参数中 使用children 配置
,这样就可以很好的实现路由嵌套。
const routes = [
{ path: "/", redirect: "/home" },//重定向,指向了home组件
{
path: "/home",
component: home,
children: [
{ path: "/home/game", component: game }
]
}
]
// home.vue
<template>
<div>
<h3>首页</h3>
<router-link to="/home/game">
<button>显示<tton>
</router-link>
<router-view></router-view>
</div>
</template>
13、路由之间跳转
-
声明式(通过点击router-link标签跳转)
<router-link to="/home">跳转</router-link>
-
编程式( js 跳转)
this.$router.push('/home') 或者 this.$router.go(-1) //后退、前进, 会向 history 添加新记录 或者 this.$router.replace('/my') // 不会向 history 添加新记录
14、说出至少 4 种 vue 当中的指令和它的用法
- v-if 、 v-else、v-else-if (判断是否加载DOM)
- v-show(判断是否隐藏)
- v-for(把数据遍历出来)
- v-bind(绑定属性)
- v-model(实现双向绑定)
- v-on (绑定事件)
- v-text (绑定文本)
- v-html (绑定html字符)
v-slot
(插槽,vue2.6版本之后引入的,取代了slot与slot-scope 属性)v-cloak
(功能:与CSS 规则 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的节点,直到实例准备完毕后才显示,这样的话就可以防止在页面加载时出现闪烁的现象)
v-cloak参考链接:https://www.cnblogs.com/chengfengchi/p/11336927.htmlv-pre
(功能:如果这个节点与它的子节点没有绑定的指令,可以使用v-pre来跳过该节点的编译,以便加快编译过程.
示例<span v-pre> this will not be compiled </span>
v-once
(功能:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。)
示例如下:<!-- 有子元素,只渲染一次 --> <div v-once> <h1>comment</h1> <p>{{msg}}</p> </div> <!-- 组件,只渲染一次 --> <my-component v-once :comment="msg"></my-component>
15、vuex 有哪几种属性
有 5 种,分别是 state、getter、mutation、action、module
16、vuex 的 store 特性是什么
- vuex 就是
一个仓库
,仓库里放了很多对象。其中state 就是源数据的存放地
,就像vue组件中的data - state 里面存放的
数据是响应式
的,若是 store 中的数据发生改变,依赖这数据的组件也会发生更新 - 通过当前组件的
computed 计算属性
获取store中存储的数据。
16、vuex 的 getter 特性是什么
- getter 可以
对 state 进行计算筛选的操作
- 虽然在组件内也可以做计算属性,但是 getters 可以在多个组件之间复用
17、vuex 的 action、mutation 特性是什么,区别是什么
-
更改 Vuex 的 store 中源数据
的唯一方法是通过mutation
中的方法进行修改state中的数据const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { state.count++ // 变更状态 } } }) store.commit('increment') //触发state修改
-
Action 类似于 mutation,不同在于:
-
Action
无法直接修改state中的数据
,它通过触发mutation的中方法,而修改状态。 -
Action 可以
包含任意异步操作
。const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
18、使用 Vuex 只需执行 Vue.use(Vuex),并在 Vue 的配置中传入一个 store 对象的示例,store 是如何实现注入的
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
首先,Vue.use会执行Vuex对象中的install方法
其次,在install方法中调用了applyMixin
方法
然后,在applyMixin方法中,对于vue2.x版本,使用全局混入vuexInit
方法。在之后的组件实例中,在其beforeCreate阶段就会执行vuexInit
方法。
new Vue({
router,
store, // 在/store/index.js文件中暴露出的:new Vuex.Store出来的对象
render: h => h(App),
}).$mount('#app');
当我们执行new Vue的时候,其中的参数会被合并到
o
p
t
i
o
n
s
中。此时存在
o
p
t
i
o
n
s
.
s
t
o
r
e
,就将实例的
options中。此时存在options.store,就将实例的
options中。此时存在options.store,就将实例的store指向Store实例对象。而在子组件中,
s
t
o
r
e
属性也会指向父组件的
store属性也会指向父组件的
store属性也会指向父组件的store属性。即在每个实例中this.$store都会指向我们在/store/index.js中new Vuex.Store实例化出来的对象。
以上就是为什么我们再组件中this.$store都能指向Vuex的Store实例对象。
19、Vuex 如何区分 state 是外部直接修改,还是通过 mutation 方法修改的
-
Vuex 中
修改 state 的唯一渠道就是执行 commit('xx', payload) 方法
,其底层通过执行 this._withCommit(fn) 设置_committing 标志变量为 true,然后才能修改 state,修改完毕还需要还原_committing 变量。 -
外部修改虽然能够直接修改 state
,但是并没有修改_committing 标志位,所以只要 watch 一下 state,state 修改时判断是否_committing 值为 true,即可判断修改的合法性。
20、sync有用过吗?它是怎么用的
- 是什么
.sync是子组件改变
父组件传递过来的props数据
后,通知父组件数据已改变
的的一种方法 - 用法如下:
father.vue
<Child :title.sync="title"></Child>
child.vue(子组件中,数据title被修改后,通过emit告诉父组件,其实也就是通过vue自定义的一个update方法,触发你组件更新数据)
this.$emit('update:title', newTitle)
22、作用域样式(scoped css)与深度作用选择器
22.1、作用域样式是什么?
1). <style scoped>
2). 让组件的样式限定在当前组件作用域(范围)内有效
, 对其它外部或内部组件无效
22.2、组件不加scoped声明的问题
一个组件的样式可以影响到外部或内部的所有任何组件, 如果不做限制就会出现样式效果相互影响的问题
22.3、组件声明使用scoped
1). 标签变化
: 组件内所有标签包括子组件的根标签都添加了自定义data属性来标识
,如: data-v-2e8d0da5
2). 选择器的变化
:组件内所有样式选择器的最右边都会添加上自定义data属性的标识
, 如: .test2 .t3[data-v-2e8d0da5]
3). 结果:一旦加上scoped后, 样式选择器不再能匹配上子、孙组件的标签(根标签除外)
22.4、深度作用选择器
-
作用
使用了scoped后, 还能修改子/孙组件的样式, 尤其是第三方UI组件库组件 -
语法
// 原生css: 使用 >>> .test2 >>> .t2 { color: red; } // 预编译器: 使用/deep/ .test2 { /deep/ .t2 { color: red; } }
-
原理
-
内部是
由vue-loader来进行编译处理
的 -
编译打包后
样式选择器上的data属性条件
加在了最左边第一层选择器上:
.test2[data-v-2e8d0da5] .t3
-
结果:这样的话,对子/孙组件标签就没有此属性的条件, 就可以匹配上子/孙组件内的标签, 进而达到改变其样式效果
23、 v-show 与 v-if 有什么区别?
-
控制显隐的方式
v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐; -
性能消耗
v-if有更高的切换消耗;v-show有更高的初始渲染消耗; -
使用场景
v-if
适用于在运行时很少改变条件,不需要频繁切换条件的场景
;
v-show
则更适用于需要非常频繁切换条件的场景
。 -
编译条件
v-if 如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译
v-show不论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留; -
编译过程
v-if 切换有一个局部编译/卸载的过程
v-show只是简单的基于css切换;
24、怎样理解 Vue 的单向数据流?
简单来说,就是父子组件之间的prop的数据传递,父传给子,子若想修改,只能通过$emit
触发自定义事件来通过父组件来修改。
详细如下:
-
所有
父子组件通过 prop 之间形成了一个单向向下的数据绑定:每次父级组件发生更新时,子组件中所有的 prop 都将会更新为最新的值,但是反过来如果你在子组件中修改了prop的值,Vue 会在浏览器的控制台中发出警告,这就是单向数据流
。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
-
那么子组件想修改时,可以
通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改
。
25、computed 和 watch 的区别和运用的场景
computed 本质上是一个具有缓存的watch
-
computed
: 是「计算属性」,依赖其它属性值,只有它依赖的属性值发生改变,它才会重新计算,并且 computed 的值有缓存。 -
watch
: 是「观察/监视」的作用,每当监听的数据变化时都会执行回调进行后续操作; -
运用场景:
1). 当我们需要进行数值计算,并且依赖于其它数据时,应该使用
computed
,因为可以利用 computed 的缓存特性
,避免每次获取值时,都要重新计算;2). 当我们需要在数据变化时执行执行相应操作时( 如发送ajax请求 ),应该使用
watch
。
26、直接给一个数组项赋值,Vue 能检测到变化吗?
26.1 问题分析
由于Vue并没有给每个对象的属性添加监视,所以Vue检测不到变化
26.2 解决办法
-
方法一,由于Vue重写了数组的某些方法,可以使用splice进行修改
this.list.splice(开始的下标,1, newValue)
-
方法二,使用vm.set()
vm.$set(对象, key, newValue)
27、在哪个生命周期内调用异步请求?
可以在钩子函数created、beforeMount、mounted
中进行调用,
因为在这三个钩子函数中,data 已经创建
,用得较多的是created与mounted
-
created() 是
发ajax请求最早的时机
, 但无法读取初始界面
-
mounted() 是
发ajax请求最晚的时机
, 但它可以发请求前读取初始界面内容
28、在什么阶段才能访问操作DOM?
在钩子函数 mounted 被调之后,这时Vue 已经将编译好的模板挂载到页面上,
所以在 mounted 中可以访问操作 DOM,一般通过ref
来得到DOM对象进而做相应操作
29、vue全家桶和react全家桶
-
vue全家桶:
vue(整体架构) + vuex(状态管理) + vue-router(路由) + axios(ajax请求) + mint-UI(移动端UI框架库) || antd-vue/element-ui(PC端UI框架库)
-
react全家桶:
react(整体架构) + redux || mobx(状态管理) + react-router(路由) + axios(ajax请求) + React-Bootstrap || Ant-design || material-ui (UI框架库)
30、v-model是什么?怎么使用?还有哪些指令,vue中标签怎么绑定事件
- v-model可以实现双向绑定,
- 如何使用:
<input v-model="message" placeholder="请输入">
- 指令
v-model、v-bind、v-for、v-if、v-show、v-on(@)
。 - 绑定事件:
<a v-on:click="do" >跳转</a>
缩写<a @click="do" >跳转</a>
31、双向绑定的原理
首先来说,什么是双向绑定?双向绑定总共包含两个方面:
一是数据变化视图更新,即响应式,实现的方式是:进行数据绑定(响应式)。
二是将视图变化数据修改,实现的方式是:DOM 事件监听。
这两个方面都实现的,我们称之为数据的双向绑定。
实现双向绑定,事件监听就不说了,难的是在于数据的绑定, vue数据绑定(响应式) 通过“数据劫持“ + 订阅发布模式
二者相结合实现的,而数据劫持则是通过 Object.defineProperty()来重写get、set方法来实现。
32、vue-loader是什么?使用它的用途有哪些
答案:解析.vue文件的一个加载器,把template/js/style转换成js模块。
用途:js可以写es6、style样式可以scss或less、template可以加jade等
34、dom是在哪一个生命周期完成渲染的?
答案:在 mounted 中就已经完成了
35、第一次页面加载会触发哪几个生命周期?
答案:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个生命周期。
36、如何解决vue修改数据不刷新页面这个问题?
第一种:this.$set
第二种:给数组、对象赋新值时使用vue重写的数组、对象的方法
第三种:使用this.$forceupdate强制刷新
37、为什么会出现vue修改数据后页面没有刷新这个问题?
Vue.js 不能检测到对象属性的添加或删除。
38、nextTick的实现原理是什么
-
nextTick的原理
Vue 的 nextTick 其本质是对 EventLoop(事件循环机制) 的一种应用
。nextTick 的 核 心 是
利 用 了 如 Promise 、 MutationObserver 、setImmediate、setTimeout 来模拟微/宏任务的实现,通过这些异步回调任务队列,来实现 Vue 框架中自己的异步回调队列
-
nextTick的作用
在DOM更新结束之后执行的回调 -
Vue中为什么要使用nextTick
由于 Vue 的 DOM 操作是异步的,但是在一些情况下,仍然需要操作最新的DOM,这里就可以通过nextTick实现异步回调,在nextTick中实现对dom的操作。
39、删除数组用 delete 和 Vue.delete 有什么区别?
- delete:只是被删除数组成员变为 empty / undefined,其他元素键值不变
- Vue.delete:直接删了数组成员,触发更新(对象是响应式的,确保 删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限 制)
40、vue 在 v-for 时给每项元素绑定事件需要用事件代 理吗?为什么?
不需要,在 vue 中, vue 做了处理。
如果我们自己在非 vue 中,需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点上,委托给父节点来触发处理函数。
41、slot 是什么?有什么作用?原理是什么?
slot 是什么
slot 又名插槽,是 Vue 的内容分发机制,组件内部的模板引擎使用slot 元素作为承载分发内容的出口。
slot 又分三类,默认插槽,具名插槽和作用域插槽。
- 默认插槽
又名匿名插槽,当 slot 没有指定 name 属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。 - 具名插槽
带有 name 属性的 slot,一个组件可以出现多个具名插槽 - 作用域插槽
该插槽的不同点是在子组件渲染时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
slot的实现原理
-
当子组件 vm 实例化时,获取到父组件传入的 slot 标签的内容,存放在 vm.$slot 中
-
默认插槽为 vm. s l o t . d e f a u l t ,具名插槽为 v m . slot.default,具名插槽为 vm. slot.default,具名插槽为vm.slot.xxx,xxx 为插槽名,
-
当组件执行渲染函数时候,遇到 slot 标签,使用vm.$slot 中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
42、对 Vue 组件化的理解
- 组件是独立和可复用的代码单元。组件系统是 Vue 核心特性之一,开发者使用小型、独立和通常可复用的组件构建大型应用;
- 组件使用按分类有:
页面组件、业务组件、通用组件
; - 我们通常编写的.vue组件,其实是组件配置option而非组件,框架后续会根据这些配置生成页面;
- vue 中常见组件化技术有:属性 prop,自定义事件,插槽等,它们主要用于组件通信、扩展等;
- 组件应该是高内聚、低耦合的;
- 遵循单向数据流的原则。
参考链接:https://blog.csdn.net/yiyueqinghui/article/details/108024094
作者:Aniugel
链接:https://www.jianshu.com/p/4db4b191de06
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。