1. 生命周期
vue 的生命周期就是 vue 实例创建到实例销毁的过程,期间会有 8 个生命周期钩子函数的调用: 创建前/后,加载前/后,更新前/后,销毁前/后;
Vue 生命周期的作用:给了用户在不同阶段添加自己的代码的机会;
- beforeCreate(创建前)
data 和 methods 这些方法和数据都为undefined,还未初始化;
可以在这加loading事件,在加载实例时触发 - created(创建后)
进行挂载数据,绑定事件(项目中用的最多),主要进行一系列的数据操作
取消loading事件、发起Ajax 请求,从而初始化 data 数据
(异步请求数据) - beforeMount(加载前)
编译模板为虚拟 dom 放入到render函数中准备渲染,此时DOM还是无法操作 - mounted(加载后)
钩子调用时,开始执行render ,渲染出真实dom,这里操作真实dom
关于dom的操作要放在mounted里面(DOM 渲染在 mounted 周期中就已经完成) - beforeUpdate(更新前)
- updated(更新后)
- beforeDestroy(销毁前)
- destroyed(销毁后)
常用于销毁程序运行之前留下的定时器,或其他组件销毁后还在执行的程序.
1.1 父子组件生命周期调用顺序
beforeCreate、created 先父后子
beforeMount 先父后子、 mounted 先子后父
beforeUpdate先父后子、 updated先子后父
beforeDestroy先父后子、 destroyed先子后父
渲染顺序:先父后子,完成顺序:先子后父
更新顺序:父更新导致子更新,子更新完成后父
销毁顺序:先父后子,完成顺序:先子后父
1.2 created和mounted的区别
- created: 在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
- mounted: 在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
1.3 keep-alive 生命周期
概念:keep-alive 是 vue 的内置组件,用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中。 主要用于保留组件状态或避免重新渲染。
作用:在组件切换过程中将状态保留在内存中,防止重复渲染 DOM,减少加载时间以及性能消耗,提高用户体验。
生命周期函数:activated 在 keep-alive 组件激活时调用,deactivated 在 keep-alive 组件停用时调用。
2. 组件通信
2.1 父子组件通信
-
父组件向子组件传值
父传子使用props
属性
父组件访问子组件:使用$children
(所有子组件)或$refs
(某个确切子组件) -
子组件向父组件传值
子传父使用$emit
自定义事件
子组件访问父组件:使用$parent
v-model //父子组件数据双向同步
props + $emit (最常用的父子通讯方式)
$refs / $children + $parent
//解决多层嵌套情况下,父组件A下面有子组件B,组件B下面有组件C,组件A传递数据给组件C的问题
$attrs + $listeners(爷孙) //Vue 2.4提出, 组件之间的跨代通信
provider/inject (依赖注入) 不论子组件嵌套有多深
2.2 兄弟组件通信
- EventBus(事件总线)(常用任意两个组件之间通讯)
- Vuex 状态管理(用于任意组件的任意通讯)
跨级通信: eventBus、 Vuex、 provide / inject 、 $attrs / $listeners
3. 路由
3.1 前端路由理解
在SPA项目中,不同组件(功能)之间的切换,要依赖前端路由来完成!
前端路由就是更新视图但不请求页面, 利用锚点完成切换,页面不会刷新,官网推荐用 vue-router.js 来引入路由模块。
前端路由:Hash地址与组件之间的对应关系
核心:监听hash地址变化,动态切换组件
3.2 Vue 路由模式 hash 和 history
Vue-Router有两种模式:hash模式
和history模式
。默认的路由模式是hash模式,hash路由被称为前端路由,已经成为SPA单页面应用的标配。
-
Hash 模式: URL中有#
后面的 hash 值的变化,浏览器既不会向服务器发出请求,浏览器也不会刷新,每次 hash 值的变化会触发hashchange
事件 -
history模式: URL中没有#
history 模式下刷新,会出现 404 情况,需要后台配置支持
利用了 HTML5 中新增的 pushState() 和 replaceState() 方法
这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
3.3 Vue 的路由钩子函数/路由守卫
导航守卫主要用来通过跳转或取消的方式守卫导航
,导航守卫就是路由跳转过程中的一些钩子函数。
有的时候,需要通过路由来进行一些操作,比如最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录页面让其登录。 为此有很多种方法可以植入路由的导航过程:全局的,单个路由独享的,或者组件级的
- 全局守卫
全局前置守卫:beforeEach(to,from,next)
全局后置钩子:afterEach(to,from) - 路由独享守卫:beforeEnter
- 组件内守卫:beforeRouteEnter / beforeRouteUpdate / beforeRouteLeave(路由进入 / 更新 / 离开之前 )
vue-router有哪几种导航钩子?
全局路由钩子:beforeEach全局前置守卫,跳转前进行判断拦截、beforeResolve 全局解析守卫、afterEach 全局后置钩子
单个路由独享钩子: beforeEnter/ beforeLeave
组件内钩子:beforeRouteEnter/ beforeRouteUpdate/ beforeRouteLeave
3.4 如何定义动态路由?如何获取传过来的动态参数?
动态路由也可以叫路由传参
动态路由有 query 和 param
两种方式传参
- query用 path来引入,params用 name来引入, 接收参数类似,分别是 $route.query.name 和 $route.params.name
- query更加类似于ajax中get传参,params则类似于post,前者在浏览器地址栏中显示参数,后者不显示
- query与param两种传参,最大区别是传参方式不一样,传的参数是否能在路由中显示,能否刷新后仍然传参
3.5 $route 和 $router 区别
- $route 是路由信息对象,每个路由都会有一个 route 对象,是局部对象,包括 path,params,hash,query,name 等路由信息参数
- $router 是 路由实例对象,是全局对象,包括了路由的跳转方法,钩子函数等。
3.6 Vue-router跳转和location.href区别
- 使用 location.href= /url 来跳转,简单方便,但是刷新了页面
- 使用 history.pushState( /url ) ,无刷新页面,静态跳转
- 引进 router ,然后使用 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少 dom的消耗。
3.7 Vue 路由懒加载(按需加载路由)
- 使用箭头函数+import动态加载
- 使用箭头函数+require动态加载
- 使用webpack的require.ensure技术,也可以实现按需加载
3.8 路由跳转方式
Vue 中路由跳转有两种,分别是声明式和编程式
用 js 方式进行跳转的叫编程式导航 this.$router.push()
用 router-link 进行跳转的叫声明式, router-view 路由模板显示的位置
路由中 name 属性有什么作用?
在 router-link 中使用 name 导航到对应路由
使用 name 导航的同时,给子路由传递参数
4. Vuex
4.1 Vuex 的原理
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
。vuex是终极的组件之间的数据共享方案,在企业级的vue项目开发中,vuex可以让组件之间的数据共享变得高效、清晰、易于维护
。Vuex 应用的核心就是 store(仓库)。store基本上就是一个容器,它包含着应用中大部分的状态 ( state )。
vuex适合大范围、频繁的数据共享,,简单来说 vuex 就是 vue 的状态管理工具。
Vuex 有五个属性 state getters mutations actions modules
- State:类似组件中的data,数据源存放地,存放的数据是响应式的,state 中数据改变,对应这个数据的组件也会发生改变
- Getter:是 store 的计算属性,可以对 state 进行计算操作,Getter 可以在多组件之间复用
- Mutation:类似于组件中的methods,处理数据逻辑,该方法只能进行同步执行;更改vuex store 中修改状态的唯一办法就是提交 mutation
- Action:异步操作数据 ,但是是通过 mutation 来操作;Action提交的是mutation,而不是直接变更状态
- Module:把以上四个属性再细分,让仓库更好管理,模块化vuex
vuex使用场景:组件之间的状态,登录状态,加入购物车,音乐播放
Vuex 使用流程:
下载 vuex
在 src 下创建 store 以及 index.js
引入 vue 和 vuex, 使用 vuex ,导出实例对象
在 main.js 中引入,在.vue 文件中使用
4.2 Vuex中action和mutation的区别
action类似mutation
- mutation中的操作是一系列的同步函数,用于修改state中的变量的的状态
- action 可以包含任意异步操作;action 提交的是 mutation,而不是直接变更状态
4.3 Vuex流程
- 在 vue 组件里面,通过 dispatch 来触发 actions 提交修改数据的操作
- 然后通过 actions 的 commit 触发 mutations 来修改数据
- mutations 接收到 commit 的请求,就会自动通过 mutate 来修改 state
- 最后由 store 触发每一个调用它的组件的更新
4.4 vuex 的优势
优点:解决了非父子组件的通信,减少了 ajax 请求次数,有些可以直接 从 state 中获取
缺点:刷新浏览器,vuex 中的 state 会重新变为初始状态,解决办法是 vuex-along,得配合计算属性和 sessionstorage 来实现
5. Vue 3.0
Vue3.0有什么更新
(1)监测机制的改变
vue3带来基于代理 Proxy的 observer 实现,消除了Vue 2 基于Object.defineProperty 的实现所存在的限制
(2)只能监测属性,不能监测对象
检测属性的添加和删除;
检测数组索引和长度的变更;
支持 Map、Set、WeakMap 和 WeakSet。
(3)模板
3.0 把作用域插槽改成了函数的方式,提升了渲染的性能
(4)对象式的组件声明方式
vue2中的组件是通过声明的方式传入,和 TypeScript 的结合麻烦
Vue3 组件声明方式,改成了类式的写法,这样和 TypeScript 的结合变得很易
(5)其它方面的更改
支持自定义渲染器
支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件
Vue3.0 是如何变得更快的?(底层,源码)
- diff 方法优化
Vue2 中的虚拟 dom 是进行全量的对比 - Vue3.0 中新增了静态标记(PatchFlag)
在与上次虚拟结点进行对 比的时候,值对比带有 patch flag 的节点,并且可以通过 flag 的信息 得知当前节点要对比的具体内容化。
hoistStatic 静态提升
Vue2 : 无论元素是否参与更新,每次都会重新创建。 Vue3.0 : 对不参与更新的元素,只会被创建一次,之后会在每次渲染时候被不停的复用 - cacheHandlers 事件侦听器缓存
默认情况下 onClick 会被视为动态绑定,所以每次都会去追踪它的 变化但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用
Vue3.0 为什么要用 proxy
vue 的数据劫持有两个缺点:
1、无法监听通过索引修改数组的值变化
2、无法监听 object 对象的值变化,所以 vue2.x 中才会有 $set 属性的存在
proxy 是 es6 中推出的新 api,可以弥补以上两个缺点,所以 vue3.x 版本用 proxy 替换 object.defineproperty
defineProperty和proxy的区别
defineProperty 只能劫持对象的属性,不能监听属性的添加和删除;
defineProperty 需要遍历对象的每一个属性,对于性能会有一定的影响;
Proxy 直接代理整个对象而非对象属性,可以监听属性的添加和删除;
Proxy 可以监听数组的变化。
6. 虚拟DOM
6.1 简述虚拟 dom 与 diff 算法
什么是虚拟DOM
- 虚拟DOM也就是常说的虚拟节点,是用JS的object对象来模拟真实DOM 中的节点(虚拟DOM是一个用来描述真实dom结构的普通JS对象)
- 该对象包含了真实DOM的结构及属性,用于对比虚拟DOM和真实DOM的差异,从而进行局部渲染来达到优化性能的目的。
为什么使用虚拟DOM
- 为了减少频繁操作DOM而引起回流重绘所引发的性能问题!!
虚拟DOM的作用是什么
- 跨平台: Virtual DOM本质上是JavaScript的对象,它可以很方便的跨平台操作,比如服务端渲染、uniapp等
- 减少了对Dom的操作:虚拟dom可以很好的跟踪当前dom状态,然后通过diff算法,计算出前后两个虚拟dom之间的差异,得出一个更新的最优方法,可以很明显的提升渲染效率以及用户体验
Diff 算法
- 就是用于比较新旧两个虚拟dom之间差异的一种算法;
- 把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的 key 值,方便比较
- diff过程就是调用patch函数,比较新老节点,一边比较一边给真实DOM打补丁(patch)
6.2 为什么虚拟 dom 会提高性能(必考)
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能
6.3 Vue中key的作用
- v-if 中使用 key: key 的作用是用来标识一个独立的元素
- v-for 中使用 key: key 的作用是为了
高效的更新渲染虚拟 DOM
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,diff 操作可以更准确、更快速
Vue 列表为什么加 key?
vue中列表循环需加 :key=“唯一标识” 唯一标识且最好是静态的,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件, key的作用主要是为了高效的更新渲染虚拟DOM