Vue
篇
1.描述如何使用用户权限进行动态列表渲染?
通过请求获取到用户的权限列表,然后通过v-if/v-else-if/v-else
来判定需要显示哪些列表元素
2.Vue
使用的是哪种设计模式?
采用订阅发布模式 在Vue
中使用observer
与definereactive
两个方法结合对数据进行劫持 通过watch
类实现订阅,通过Dep
类进行解耦合 数据变更时首先触发set
方法,然后调用Dep.notify
通知视图进行更新
3.说明Vue
操作真实Dom
的性能瓶颈?
一次性渲染大量复杂类型数据时,会导致Vue
劫持数据和渲染时间过长,长时间执行js
代码会导致用户无法与页面进行交互
优化:使用requestAnimation
方法将数据进行分割,分批次渲染 页面中存在大量数据时,修改局部数据会导致整个页面的重新渲染,进而导致页面卡顿
4.Vue
中如何获取Dom
?
通过在元素上添加ref="refName"
属性对元素进行引用,在js
中,使用this.$refs.refName
来获取当前Dom
5.Vue
中的双向数据绑定的原理是什么?
在Vue2
中,通过数据劫持与订阅发布模式来实现,使用Object.defineProperty()
来实现对数据的劫持
只能监听object
对象,无法监听数组 需要遍历对象的每个属性 如果需要深度劫持对象,必须进行深度遍历 在vue3
中,通过Proxy
代理来劫持对象
可以监听数组 可以直接监听对象,不必遍历属性再依次监听 拦截方法更加丰富 返回一个新对象,操作这个对象可以就可以实现劫持 具有更好的性能红利
6.谈谈在Vue
中如何存储token
?
token
一般指的是加密后的用户身份信息当用户成功进行登录后,后端会将用户的身份信息进行加密,并包装成为一个token
信息返回前端 前端将token
信息存放在vuex
或者pinia
中,以及持久化到localStorage
中 每次跳转路由时,判断在localStorage
中是否存在token
信息,如果没有,返回登录;如果有,在前端向后端发送请求时,在请求头中携带token
信息 后端根据请求头中的token
信息来解密,如果解密成功,获取用户的信息,并且返回响应后的数据;如果解密失败或已过期,则返回错误提示
7.什么是nextTick
?它有什么作用?
在Vue
中,当Model
层数据更改后,它并不会立即重新渲染页面,它会在下一个事件循环tick
中进行更新 这意味着,如果我们希望在数据更改后基于更新后的Dom
来实现某些功能,可以在数据修改之后调用nextTick(callback)
达到效果,callback
回调函数将会在Dom
更新后立刻执行
8.nextTick
与setTimeout
有什么区别?
在Vue
中,修改Model
层的数据与View
层的更新是异步操作 当Model
层数据被修改后,会在下一个事件循环tick
中对Dom
更新,即通过nextTick
这个方法可以实现当Dom
更新之后进行的操作
在nextTick
源码中,会监听是否具有Promise.then
操作 如果不支持Promise.then
,会采用MutationObserver
如果不支持MutationObserver
,会采用setImmediate
如果不支持setImmediate
,会采用setTimeout
9.在Vue
中,如何实现组件间通信?
父与子
通过props
实现父组件向子组件传值,$emit
子组件向父组件传值 使用$attrs
与$listeners
使用组件层面的v-model
使用$parent
与$children
跨层级
使用全局事件总线bus.$emit
与bus.$on
使用provide
与inject
使用状态管理工具vuex
,pinia
10.说明Vue
中key
值的作用?
在Vue
中,key
值通常用来为v-for
添加唯一的标识符 当添加了key
后,可以提高渲染页面时新旧节点使用diff
算法对比的效率
diff
算法用来对比新旧虚拟Dom
,它会最大化地实现相同节点地复用在diff
算法中,会先进行新旧节点的首尾交叉对比,当无法对比时,使用新节点地key
与旧节点比较,找出差异
旧数据与新数据各有两个头尾的变量startIndex
与endIndex
,两者分别有四种对比方式:首与首,尾与尾,新首与旧尾,新尾与旧首.在比较的过程中,startIndex
与endIndex
会向中间靠,如果四种比较方式均未匹配,则会使用key
值进行比较,当startIndex>oldIndex
时,会结束比较 如果不添加key
值,Vue
的就地更新策略会导致代码出现bug
11.v-model
的原理是什么?
v-model
用于双向数据绑定,能够将data
中的数据渲染到页面,同时如果页面的对应值发生改变后会同步更新data
数据在Vue
中,利用数据劫持配合订阅发布模式进行实现
在Vue2
中,通过Object.defineProperty
来劫持对象属性的getter
与setter
操作 利用监听器Observer
监听对象中的所有属性,当属性发生变化后,需要通知订阅者Watcher
是否需要更新,利用消息订阅器Dep
来管理所有的订阅者,利用指令解析器Compile
对每个元素与节点进行扫描解析,将相关指令(v-model
,v-on
等)初始化成为一个订阅者,并替换模板数据或者绑定相应函数,当订阅者接收到相应属性发生变化后,就会调用更新函数更新视图
12.Vue
组件如何与iframe
通信?
在iframe
组件中要想获取父组件的数据,使用H5
的新特性postMessage
相关的Api
onMessage
监听消息postMessage
发送消息
13.Vue
中的自定义指令如何使用?
在Vue
中,指令分为全局指令与局部指令 创建自定义指令也可以创建为全局指令或者局部指令,全局指令在应用层级使用app.directive()
进行注册,局部组件在组件中注册 自定义指令也存在钩子函数,常用的bind
与update
两者可以进行简化
14.当修改组件data
中的数据时,重新渲染是同步还是异步进行的?
数据的更新是同步发生的 但是页面视图的更新是异步进行的,如果需要在数据更新后立刻操作更新后的Dom
元素,需要使用$nextTick(callback)
进行
15..sync
修饰符的作用是什么?
.sync
修饰符主要用来简化父子组件之间的数据通信在父组件向子组件传递数据时,使用.sync
修饰符,Vue
会自动为其创建一个更新数据的方法update:propName
,在子组件中使用时,利用this.$emit("update:propName",newValue)
来触发这个方法并向其传递新值,以此达到子组件向父组件传值
16.在Vue
中,如何实现多组件嵌套中的通信?
通过共同的祖先组件使用props
传值 通过provide/inject
方式传值 通过全局事件总线传值 使用状态管理工具vuex
或pinia
17.如何使得组件内部的CSS
只在组件内部生效?
18.keep-alive
有什么作用?
keep-alive
用来实现当切换组件时,原组件不会被卸载,进而不会清空原组件中的数据
19.使用keep-alive
时,组件中的生命周期会增多吗?
会增加两个新的生命周期:activated
与deactivated
activated
在组件被激活时会调用deactivated
在组件被缓存时会调用
20.Vue
创建项目的指令是什么?
使用@vue/cli
版本低于3.0
,使用npm init
版本高于3.0
,使用vue create
使用vite
21.Vue
中如何使用ref
绑定?
在元素标签或者组件标签中添加ref
属性,可以获取当前Dom
元素或者VueComponent
实例 在Composition API
中,使用ref
包装简单数据类型数据,使之成为响应式数据
22.介绍Vue
中的导航守卫?
全局导航守卫
全局前置守卫,使用router.beforeEach((to,from,next)=>{})
设置一个全局前置守卫 全局解析守卫,使用router.beforeResolve((to,from,next)=>{})
设置一个全局解析守卫 全局后置钩子,使用router.afterEach((to,from,next)=>{})
设置一个全局后置钩子 路由导航守卫
在路由中配置beforeEnter((to,from,next)=>{})
设置一个路由独享守卫 组件内导航守卫
路由前置守卫,使用beforeRouteEnter((to,from,next)=>{})
设置 路由更新守卫,使用beforeRouteUpdate((to,from,next)=>{})
设置 路由后置钩子,使用beforeRouteLeave((to,from,next)=>{})
设置 参数解释
to
代表将要到达的路由对象from
代表从某个路由对象跳转而来next
是一个回调函数,不论是否满足跳转逻辑,必须调用这个方法,否则路由不会被放行
23.在Vue
中,有哪些常用的指令?
v-bind
动态绑定元素属性,简写:
v-on
绑定元素触发的事件,简写@
v-if/v-else-if/v-else
条件渲染v-show
条件渲染v-for
列表渲染v-model
双向数据绑定v-slot
使用插槽,简写#
v-text/html
将内容作为文本或者html展示v-once
绑定事件且该事件仅生效一次
24.Vue
中的插槽共有几种?有什么作用?
三种插槽,分别是默认插槽
,具名插槽
,作用域插槽
默认插槽
默认插槽就是匿名插槽,其默认的插槽名为default
具名插槽
当存在多个插槽时,通过为插槽添加name
来区分插槽 作用域插槽
25.Vue
如何使用插件?
在Vue
中,插件通常是一个包含install(app,options)
方法的对象,该方法会在插件被使用时调用 使用Vue.use(pluginName)
来安装插件,当插件被安装好之后,可以进行使用
26.如何在Vue
中实现图片懒加载与组件懒加载?
组件懒加载
引入组件时,使用const comp=()=>import(path)
回调函数的方式 在路由中引入组件,配置路由规则时,使用component:()=>import(path)
的方式 图片懒加载
首先为所有图片设置一个统一的src
指向,可以是一个loading
图,将图片的真实地址赋值给一个自定义属性.监听滚动条的位置,当图片没有出现在可视区域时,不做任何改变;当图片到达可视区域时,使用真实地址替换原来的src
属性值 使用骨架屏 使用第三方库
27.使用Vue
封装过组件吗?讲一下是如何实现的?
网页中的header
,aside
,footer
部分通常不需要逻辑的改变,仅仅需要样式的改变,此时可以封装组件 在组件中预留插槽,用来实现定制化的需求,比如显示不同的文本信息 在组件中使用props
进行传值,组件接收到父组件的传值后,根据值实现不同的逻辑 不在组件中处理业务逻辑,通过$emit
触发父组件的方法,实现业务处理
28.描述Vuex
的工作流程(原理)?
在Vuex
中,共有state
,actions
,mutations
,getters
,modules
五个模块 所有的数据状态都定义在state
中,state
中的数据无法被直接修改,通常在组件中,绑定某个事件,通过dispatch
触发actions
中的某个方法,然后该方法使用commit
触发mutations
中的某个方法,通过mutations
中的这个方法才能够修改state
中的数据 actions
中可以执行异步操作,getters
可以用来包装state
中的数据并返回,相当于一个计算属性,modules
用来对Vuex
中的数据进行模块化管理
29.Vuex
在项目中如何使用?
对于中小型项目,在公共状态使用不多的情况下,不建议使用Vuex
进行状态管理 对于大型项目,如果各个组件之间共用的状态比较多,这时适合使用Vuex
30.Vuex
中模块中的某个state
发生了改变,其他模块如何获取?
在Vuex
中,利用modules
来实现状态的模块化管理 在模块化中,如果需要访问到根状态
在getters
中,函数getterFun(state,getters,rootState,rootGetters)
使用额外参数rootState
,rootGetters
访问,进而通过根访问到其他模块 在actions
中,函数actionFun({rootState,rootGetters},payload)
使用额外参数rootState``rootGetters
访问,进而通过根访问到其他模块
31.Vuex
的数据会丢失,应当如何解决?
当使用Vuex
时,如果将数据存储到了state
中,刷新页面时会出现数据丢失 一般将数据持久化到本地localStorage
进行存储,数据变更时,通过Vuex
存储到本地,当需要使用时再从本地进行读取
32.如何获取Vuex
的数据?
通过访问this.$store.state
直接获取 通过辅助函数mapState()
获取
33.如果Vuex
中的数据量很多,应当如何进行管理?
拆分成为单独的模块,分模块进行管理,在modules
中进行合并
34.在Vuex
中,actions
与mutations
分别是用来干什么的?为什么不能使用mutations
处理异步?
两者都是用来改变状态 区别在于:
actions
中可以存在异步代码,并且最终仍然会调用mutations
中的方法来更改state
;而mutations
是同步代码,直接修改state
中的状态,mutations
中如果存在异步代码,将无法被devtools
捕获状态变化actions
会默认将自身封装成为一个Promise
,而mutations
仅仅是一个单纯的函数
35.Vue
如何进行路由配置?
在Vue
中,使用vue-router
插件配置路由 在Vue2
中
import router from "@router/index.js"
const app= new Vue ( { router} ) . mount ( "#app" )
import VueRouter from "vue-router"
import Vue from "vue"
Vue. use ( VueRouter)
const routes= [ {
} ]
const mode= "history"
const router= new VueRouter ( {
routes,
mode
} )
import router from "router/index.js"
app. use ( router)
import { createRouter, createMemoryHistory} from "vue-router"
const routes= [ {
} ]
const router= createRouter ( {
routes,
history : createMemoryHistory ( )
} )
export default router
36.路由守卫可以用来实现什么功能?
执行页面权限管理操作
在进入每个页面之前,使用全局前置钩子beforeEach
,判断to
页面是否需要登录才能查看,并判断用户是否已经登录.如果页面不需要登录,直接next()
放行,如果需要登录,并且用于已经登录,直接next()
放行,否则引导至登陆页面 在页面跳转前处理
如在使用echarts
时,在路由跳转之前清除图标实例,防止后续出现渲染错误 提示用户跳转前执行数据保存操作
37.在vue-router
中,有哪些路由模式?
在vue-router
中,主要有history
模式与hash
模式 history
模式
该模式下,url
以/
分割,该模式需要后端配合,对于SEO
更加友好.存在兼容性问题 hash
模式
该模式下,url
中#
后面的部分是路由,hash
部分不会被发送给服务器,不需要后端进行额外的配置,但是不利于SEO
.兼容性更好
38.路由守卫有什么作用?全局路由守卫和局部路由守卫有什么区别?
路由守卫用来在路由变更时做出一些拦截操作 全局路由守卫
全局前置守卫:beforeEach
在进入所有路由之前触发该钩子 全局解析守卫:beforeResolve
在解析所有路由时,路由被确认之前触发该钩子 全局后置钩子:beforeAfter
在所有路由即将离开之前触发该钩子 路由独享守卫
beforeEnter
在进入到设置了该钩子的路由组件之前被触发 组件内守卫
beforeRouteEnter
在进入当前路由之前触发该钩子beforeRouteUpdate
在当前组件路由更新之前触发该钩子(当前路由改变,但是组件被复用时触发,比如商品详情页面跳转至另一个商品详情页面)beforeRouteLeave
在离开当前路由之前触发该钩子
39.路由如何传参?
在vue-router
中,可以通过query
与params
的方式传参 query
传参
声明式导航
query
传参直接在url
中以?
的形式对参数进行拼接静态字符串传参 使用<rouer-link to="/path?prop1=value1&prop2=value2">
在to
属性中进行传参动态字符串传参 使用<rouer-link :to="pathWithPropAndValue">
在to
属性中进行传参动态对象传参 使用<rouer-link :to="{name:'namedRoute',query:{prop:value}}">
在to
属性中进行传参使用this.$route.query.propName
获取传递的参数 函数式导航
使用this.$router.push("/path?prop=value")
的形式传参 使用this.$router.push({name:namedRoute,query:{prop:value}})
的形式传参 params
传参
声明式导航
params
传参以/
的形式进行参数传递,需要注意,在配置路由规则时,使用path:"/yourPath/:prop1/:prop2"
的形式静态字符串传参 使用<router-link to="/path/par1/par2">
在to
属性中进行传参动态字符串传参 使用<router-link :to="pathWithPropAndValue">
在to
属性中进行传参动态对象传参 使用<router-link :to="{name:namedRoute,params:{prop:value}}">
在to
属性中进行传参使用this.$route.params.propName
获取传递的参数 函数式导航
使用this.$router.push("/path/prop1/prop2")
的形式传参 使用this.$router.push({name:namedRoute,params:{prop:value}})
的形式传参
40.Vue
路由的函数式导航有哪几种?
this.$router.push
跳转至指定路由页面,操作后,会向history
栈中添加一条记录,可以追溯历史记录this.$router.replace
跳转至指定路由页面,操作后不会向history
栈中添加记录,无法追溯历史记录this.$router.go
指定向前(正整数)或者向后(负整数)跳转几个页面
41.vue-router
有几种导航方式?
声明式导航,使用<router-link to>
的方式跳转页面 编程式导航,使用this.$router.push
的方式跳转页面
42.使用query
传参与使用params
传参有什么区别?什么情况下params
传参会失效?
query
传参,参数会以?
的方式拼接在url
之后,可以用来传递非重要的参数params
传参,参数会直接在/
后传递,可以用来传递重要参数
如果使用params
传参,同时指定了跳转时的path
属性this.$router.push({path:yourPath,params:{prop:value}})
,那么params
传参会失效,应当使用命名路由的方式进行传参
43.vue-router
有哪些方法?
router.beforeEach
全局路由前置钩子router.push
指定路由跳转router.go
,router.back
,router.forward
前进与返回一页,在浏览器中前进router.addRoute
动态设置路由映射,添加一条新的路由规则
44.谈谈对MVVM
的理解?
它是一种软件架构设计模式,另外的设计模式还包括MVC
与MVP
不同于设计模式,架构模式往往采用了多种设计模式 MVVM
可以拆分成为Model
=>View
=>ViewModel
Model
层,数据模型层,对应项目开发时的数据包View
层,视图层,对应真实开发时的Dom
结构ViewModel
层,扮演View
至Model
的中间层,处理View
层的全部业务逻辑 通过使用MVVM
,避免了直接操作Dom
,当Model
层数据发生更改后,页面会自动进行渲染
45.vue-router
有什么组件?
<router-link>
组件,利用to
属性,可以实现在带有路由的组件之间跳转<router-view>
组件,路由出口,在这里展示路由组件
46.vue-router
与location.href
有什么区别?
vue-router
location.href
使用pushState
实现静态跳转,页面不会重新加载 触发浏览器重新加载 使用diff
算法,按需加载,减少Dom
操作 - 是路由跳转或同一个页面跳转 页面间的跳转 异步加载 同步加载
47.vue-cli
如何自定义组件?
新建.vue
文件 如果需要在部分组件中引入,直接使用import
导入该组件,并且在component
中进行注册后使用 如果需要在所有组件中实现,在main.js
中进行全局注册,使用import
引入组件后,设置Vue.component("customedName",ComponentName)
,在全局可以使用该组件
48.谈谈对vue-loader
的理解?它的原理是什么?
浏览器只能够解析.html
,.css
,.js
格式的文件 使用Vue
进行开发时,.vue
文件是无法直接被浏览器识别的,vue-loader
就是用来将.vue
文件转换成为浏览器可识别的文件 vue-loader
工作时,会将.vue
文件拆分成为三部分template
,script
,style
.
template
部分通过compile
生成render
,staticRenderFns
script
部分获取返回的配置项scriptExports
style
部分通过css-loader
,vue-style-loader
添加到head
中,或者通过css-loader
,MiniCssExtractPlugin
提取到一个公共的css
文件中通过vue-loader
提供的normalizeComponent
方法,将staticRenderFns
,render
,scriptExports
进行合并,返回构建vue
组件需要的配置项对象
49.Vue
实例中的data
数据在哪个声明周期能够获取到?
最早在created
生命周期中可以获取,后续的beforeMount
,mounted
,beforeUpdate
,updated
,beforeUnmount
,unmounted
均可以访问
50.完整的路由解析流程是什么?
导航被触发 在失活的组件中调用beforeRouteLeave
组件守卫 调用全局beforeEach
守卫 在重用的组件中调用beforeRouteUpdate
组件守卫 在路由配置里调用beforeEnter
路由守卫 解析异步路由组件 在被激活的组件中调用beforeRouteEnter
组件守卫 调用全局beforeResolve
守卫 导航被确认 调用全局afterEach
守卫 触发Dom
更新 调用beforeRouteEnter
中的next()
回调函数
51.计算属性通常用来做什么?
计算属性用来将数据按照定义的逻辑计算规则进行计算后返回一个包装后的值 计算属性与data
中的数据类似,可以直接在插值语法中使用 计算属性能够实时监听到源数据的变化,并且根据变化后的数据计算得出新的数据 计算属性具有缓存,在第一次计算之后,如果后续再次使用,将会使用缓存中的值
52.computed
与watch
有什么区别?
computed
watch
当源数据发生更改后会重新计算新值 当源数据发生更改后触发侦听 有返回值 没有返回值 有缓存 没有缓存 关注计算的结果 关注执行的过程 有一个getter
与setter
方法,默认使用getter
方法 -
53.状态管理的数据走向是什么?
状态管理指的是对于多个组件需要共用的数据,抽离出来,实现统一管理,让状态变化可以预测 使用vuex
来管理状态时
state
用来集中存储数据actions
用来存放多个异步请求处理的方法mutations
用来存放多个修改state
中数据的方法,这里不允许出现异步处理方法 在各个view
视图层中
初始化仓库中的数据:store
=>state
=>view
直接commit
一个mutations
中的方法更改state
时:view event
=>mutations
=>state
=>store
=>view update
通过异步操作更改state
时:view event
=>actions
=>mutations
=>state
=>store
=>view update
54.为什么Vuex
中存储的数据会丢失?如何解决?
Vuex
中的数据是存储在运行内存之中的,当页面刷新时,页面会重新被加载,Vue
实例也会重新被加载,Vuex
中的数据会被重新赋值成初始值将Vuex
中的数据存储到localStorage
或者sessionStorage
中
55.能不能自己实现v-model
功能?
v-model
双向数据绑定通常用于表单的input
输入功能在data
中定义一个用于为input
元素赋初值的value
,为input
绑定该值 监听input
元素的oninput
事件,当输入内容时,更新data
中的value
值
56.在Vue
中使用双向数据绑定,如何知道值的改变?
在Vue2
中,使用Object.defineProperty
实现对值的监控 在Vue3
中,使用Proxy
代理实现对值的监控
57.有时候当实现用户退出登录时,用户的头像仍然显示,是什么原因?
头像是否采用了应用缓存机制,需要清除H5
应用缓存 头像是否缓存在WebStorage
中,需要执行清除 头像是否缓存在Vuex
或者pinia
中,需要执行清除 头像是否缓存在cookie
或者浏览器缓存中,需要执行清除
58.Vue
中的双向数据绑定如何实现?
在Vue
中,为所有data
中的数据添加了getter
与setter
方法
getter
方法实现数据更新并发布回调setter
方法添加消息订阅 对作用域中的所有Dom
节点进行数据处理,根据不同的指令来实现消息订阅与发布回调方法绑定
在v-model
中,在oninput
事件中添加消息发布回调方法绑定 在v-text
中,添加value
数据更新消息订阅回调方法绑定 在输入框输入时,会触发oninput
事件,触发消息发布方法实现数据更新,之后再触发订阅方法,实现Dom
中的数据更新
59.Vue
如何实现响应式?它的响应式有什么缺点?
在Vue2
中,数据的响应式是通过Object.defineProperty
实现的
将所有的属性改写为getter
与setter
在每个.vue
组件中,有一个watcher
对象,当页面数据发生变更时,会通知页面调用render
方法渲染 缺点
它不能对对象的新增,删除属性实现响应式 它不能对数组的长度修改实现响应式 需要调用$set
,$delete
方法才能够实现
60.在<keep-alive>
中使用include
与exclude
有什么区别?
两者均可以使用字符串,正则表达式与数组的形式来指定组件的name
include
用来指定包含的组件会应用<keep-alive>
效果exclude
用来指定不包含的组件会应用<keep-alive>
效果
61.使用多个组件库,提取其中的公共代码进行压缩后发现js
代码过大,应当如何处理?
对组件不要进行全局引用,尽量采用动态引入或者局部引如 这样做可以减少页面首次加载时需要加载大量文件拖慢网页速度的问题,也可以解决文件打包时一次性将所有依赖全都打包造成的文件过大问题
62.Vue
如何配置多个代理?
在vue.config.js
中设置如下配置 在proxy
对象中的每个key
值,代表将该路径代理到target
中
module. exports= {
devServer : {
proxy : {
"/api1" : {
target : "targetURL" ,
ws : true ,
changeOrigin : true ,
reWrite : path => path. replace ( / ^\/api1 / , "" )
} ,
"/api2" : {
}
}
}
}
import { defineConfig } from 'vite'
export default defineConfig ( {
server : {
proxy : {
'/api1' : {
target : 'targetURL' ,
ws : true ,
changeOrigin : true ,
rewrite : ( path ) => path. replace ( / ^\/api1 / , '' ) ,
} ,
'/api2' : {
}
} ,
} ,
} )
63.为什么Vue3
中的双向数据绑定使用Proxy
?
在Object.defineProperty
中,如果需要实现完整的数据劫持,需要遍历其中的所有属性,如果是深层次数据,还需要递归来实现属性绑定 在Proxy
中,代理对象不需要遍历属性进行绑定,当有新属性被添加或是已有属性被删除,不需要在做额外的操作即可实现
64.封装一个组件会有哪些考虑?在使用组件时希望能够添加一些自定义的数据应当如何实现?
封装组件需要考虑到组件的复用性
使用组件时,为组件传递的props
参数,以及参数的默认值 组件中会触发的事件,定义事件处理函数及返回值 组件的内容应当遵循通用性与灵活性 要实现用户能够在组件中实现自定义样式或内容
使用v-slot
插槽 添加一个render
函数,允许用户自定义渲染内容或样式
65.Vue
组件中的data
选项为什么是函数,不能是对象?
如果data
是一个对象或者是一个数组等引用类型,那么在不同的组件中使用的data
将引自同一块内存,在任何组件中对其进行修改之后,都会影响其他组件 利用函数的返回值作为data
,当每次使用组件时,都会调用函数,创建一个新的对象,不同组件之间的数据才不会相互影响
66.在Vue
中,发送请求在哪个阶段进行?
建议将发送请求的执行时机安排在created
钩子函数中 在beforeCreate
钩子函数中,此时数据尚未挂载完成,不能使用this
将数据保存到组件的data
之中 在beforeMount
与mounted
钩子函数中发送请求的时机稍晚,会增加页面加载时间,并且Vue
的SSR
不支持beforeMount
与mounted
钩子函数
67.兄弟与父子组件通信,在不使用Vuex
的情况下有多少种方案?
兄弟之间
全局事件总线通信 通过props
与emit
寻找共同的父组件 父子之间
通过props
与emit
通信 通过provide
与inject
通信 通过$attrs
与$listners
通信 通过$ref
与$parent
通信 通过全局事件总线通信
68.v-if
与v-for
能够同时使用吗?
可以,如果在循环时,使用v-if
只能够获取少部分数据的情况下,不推荐使用 v-for
的优先级高于v-if
,当遍历的数据较多时,满足的条件却较少时,会浪费性能.解决办法是使用计算属性computed
,将需要使用的数据事先进行整理,最后直接使用v-for
渲染即可
69.v-bind
是用来做什么的?
v-bind
用来实现数据的动态绑定,在Vue
模板中,在HTML
元素中或者组件标签中的属性之前使用了v-bind
,那么它的属性值表示js
的区域
70.event-bus
是什么?
event-bus
是全局事件总线使用全局事件总线可以实现在任意的组件之间实现通信 在配置event-bus
时,只需要设置Vue.prototype.$bus=new Vue()
即可将$on
与$emit
方法在每个组件中使用
71.mounted
与created
有什么区别?
两者均是Vue
中的钩子函数 mounted
在组件渲染阶段,created
在数据挂载阶段created
在组件中的data
挂载到Vue
组件实例上时会执行,此时可以访问到this
实例,但是此时的页面Dom
尚未渲染,内容是最原始的数据mounted
在页面初次渲染完毕之后会触发,此时所有的数据都已经挂载完成,访问Dom
内容可以看到与页面相同的数据
72.Vue
中的生命周期有哪些?
阶段 Vue2
Vue3
初始化阶段 beforeCreate
与created
onBeforeCreate
与onCreated
挂载阶段 beforeMount
与Mounted
onBeforeMount
与onMounted
更新阶段 beforeUpdate
与updated
onBeforeUpdate
与onUpdated
卸载阶段 beforeDestroy
与destroyed
onBeforeUnmount
与onUnmounted
缓存组件 activated
与deactivated
onActivated
与onDeactivated
错误捕获 errorCaptured
onErrorCaptured
73.如何实现后台管理系统的用户权限验证?
在一般的流程之中,用户会首先进行登录操作,当用户输入账号密码成功登陆后,后端会返回给前端一个加密的token
信息,获取到的token
信息一般存放在vuex
中,然后保存到本地.利用该信息可以实现免密登录,获取到userinfo
通过路由拦截实现访问页面权限控制,在用户跳转到某些需要进行登录才能够查看的页面之前,检查用户是否已经登录,如果登录,执行下一步,否则将用户引导至登录页 根据用户权限动态生成导航列表,获取到已登录用户的权限列表后,在前端的路由表中,过滤出该用户能够访问的路由,实现页面级别的权限控制
如果后端会验证每一次用户的操作是否有权限,不论用户发送get
请求还是post
请求,都将会要求传入token
值,利用该token
验证用户是否有权限进行某些操作,失败会返回相应的状态码,前端利用该状态码实现另外的操作
74.如何处理token
过期?如何续期?
token
信息一般是一个加密后的用户信息,它包含了用户用户名,密码,过期时间等信息token
经常用于当用户成功登录后,后端会返回该值,在需要用户登录才能够查看的页面中,前端发送网络请求时需要携带token
当token
过期后
会引导用户至登录页重新登录 或者自动刷新token
信息,然后继续执行未执行完的操作
75.说说对Vue
的理解?
Vue
是一个基于MVVM
的数据驱动视图的框架,具有虚拟Dom
,当数据发生更改后,会利用diff
算法进行新旧虚拟Dom
对比,最大化地对Dom
节点进行复用,节省了Dom
操作地性能Vue
的单页面应用基于组件化封装,每个组件相当于是一个完善的模块,从而能够实现组件的复用,多个组件共同使用组成了一个完整的应用,组件结构清晰,方便维护Vue
有一套完善的指令系统,让开发者不必再操作Dom
,实现高效率的开发
76.说说对虚拟Dom
的理解?
虚拟Dom
是一个js
对象,用来模拟页面中的HTML
结构,并且使用flag
标记出动态的Dom
节点 虚拟Dom
的数据保存在应用程序的内存结构中,拥有更快的数据交换速度 每当有数据发生更改时,会生成一个新的虚拟Dom
,随后执行diff
运算,找出最小的数据更改节点,最大化地复用节点,减少不必要的Dom
操作,提高性能
77.说说provide
与inject
的用法?
在需要暴露数据的组件中使用provide
提供数据
在需要使用数据的组件中使用inject
接收数据
78.在vue-router
中,route
与router
有什么区别?
在使用vue-router
时
route
是当前组件的路由信息对象,包含了url
,路由参数等信息,通常用来获取路由参数router
是创建的路由实例,在路由实例上,通常使用编程式导航this.$router.push
来跳转页面
79.Vue
对比传统的前端开发,有什么优点?
组件化开发效率更高.在Vue
中,将应用分割成为一个个独立的组件,在组件中实现各自的功能,方便管理各个功能模块,组件之间也能够进行数据沟通,并且一个功能完整的组件可以实现复用,方便团队合作 使用虚拟Dom
对真实Dom
进行映射,当数据发生更改后,会调用diff
算法对新旧数据进行对比,找出最小的更改方式,最大化地复用Dom
,减少对Dom
的操作,提高了性能 实现数据与结构分离 双向数据绑定能够更快地在数据与Dom
之间建立联系 强大的周边生态支持,vuex
,vue-router
,pinia
等工具支持
80.浏览器是如何渲染页面的?Vue
中的虚拟Dom
是如何工作的?
浏览器渲染页面分为以下几个步骤
解析HTML
元素,构建Dom
树 解析CSS
,生成CSS
规则树 将Dom
树与CSS
规则树关联,生成渲染树 进行元素布局,浏览器按照渲染树设定每个节点在页面上的位置与尺寸 绘制渲染树,浏览器根据设定好的信息在页面上进行绘制呈现出内容 如果需要频繁操作Dom
节点,会不停地触发浏览器的重排与重绘,导致浏览器的性能降低 虚拟Dom
的工作流程
使用js
对象模拟出真实的Dom
结构 使用diff
算法对比新旧虚拟Dom
,找出差异 根据差异找到真实Dom
,并在真实Dom
中修改差异
81.双向数据绑定与单项数据流的优缺点有哪些?
特点 单向数据流 双向数据流 含义 通过Model
层可以修改View
层的数据,反之不行 Model
层与View
层可以互相修改数据优点 状态变化可以追溯,并且只能够手动更改 操作简单,可以减少不必要的事件监听 缺点 存在大量样板代码,代码量大 数据的更改是暗箱操作,不易追溯
82.既然Vue
能够监听数据的变化,为什么还要使用diff
算法?
diff
算法探讨的是如何才能最大化地减少对Dom
本身的操作diff
算法流程
根据真实Dom
生成虚拟Dom
,即一个js
对象 数据发生更改后,虚拟Dom
也会发生对应更改,对比新旧虚拟Dom
找出差异,根据差异生成patch
更新虚拟Dom
的时机发生在setState
与调用Hooks
等之后 采用深度优先遍历算法实现遍历 在树,组件,元素三个层面进行复杂度的优化 根据patch
更新真实Dom
,反馈到用户界面 忽略节点的跨层级操作场景,提升对比效率
对树进行分层对比 如果组件的层级一致,默认为相似的树结构,否则默认为不同的树结构 若组件是同一类型则进行树比对,如果不是则直接放入补丁中 同一层级的子节点,通过标记key
的方式进行列表对比 元素比对主要发生在同级别中,通过标记节点操作生成补丁
83.Vue
为什么没有React
的shouldComponentUpdate
生命周期?
Vue
的响应式系统在初次渲染时就收集了渲染依赖的数据项,通过自动的方式可以取得不错的性能
84.如何在Vue
中使用Jsx
语法?
Jsx
指的是javascript
与XML
结合的一种格式,React
发明了Jsx
,利用js
语法创建虚拟Dom
遇到<
时当作HTML
解析,遇到{
时,当作js
解析 在Vue
中,很少使用Jsx
85.在Vue
中,跳转至另外一个页面,再返回先前的页面,如何保持页面的状态不改变?
使用keep-alive
内置组件能够实现组件状态的缓存,当用户跳转至另外的页面时,再返回先前的页面,不会丢失数据 在keep-alive
中,有include
与exclude
属性可供选择
include
,接收一个字符串数组或正则表达式或一个字符串作为参数,可以用来设置需要缓存的组件exclude
,接收参数同上,可以用来设置不需要缓存的组件
86.beforeMount
与Mounted
生命周期的区别是什么?
beforeMount
Mounted
虚拟Dom
创建完成,尚未渲染到页面,更改数据时不会触发update
真实Dom
完成渲染,已经挂载到页面中,此时可以使用$ref
获取到Dom
对象
87.Vue
性能优化的方法有哪些?
使用路由懒加载 使用图片懒加载 使用keep-alive
缓存页面 使用v-show
替换v-if
避免在标签中国同时使用v-for
与v-if
长列表性能优化 事件的自动销毁,当组件被卸载时,会自动解绑它的全部事件监听及指令 使用第三方库时按需引入 无状态的组件标记为函数式组件
88.使用Vue
开发与使用原生开发项目有何不同?
数据与页面元素自动绑定 方便页面参数传递及状态管理 模块化开发,能够实现无刷新保留场景参数的更新 代码的可阅读性更好 丰富的生态圈 开发单页面应用更加友好 组件之间样式不会冲突
89.在Vue
中,从某个具有滚动条的页面跳到另外一个页面后,再从另外一个页面返回来,如何使得滚动条仍然在原位置?
使用keep-alive
将组件包裹 在deactivated
生命周期中记录滚动条的位置 在activated
生命周期中使页面的滚动条滚动到之前记录的位置
90.如何实现用户的权限分配?
权限分配指的是不同的用户能够访问不同级别的页面 在实际情况中,一般使用RBAC
模型,引入角色的概念,然后将不同的权限分配给不同的角色,再将不同的用户与角色关联,对应的用户就会继承角色的权限.角色与权限都是多对多的关系 优点
实现用户与权限的解耦 提高了权限配置的效率 方便后期的维护