大前端面试题集锦——Vue篇

Vue

1.描述如何使用用户权限进行动态列表渲染?

  • 通过请求获取到用户的权限列表,然后通过v-if/v-else-if/v-else来判定需要显示哪些列表元素

2.Vue使用的是哪种设计模式?

  • 采用订阅发布模式
  • Vue中使用observerdefinereactive两个方法结合对数据进行劫持
  • 通过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.nextTicksetTimeout有什么区别?

  • 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.$emitbus.$on
    • 使用provideinject
    • 使用状态管理工具vuex,pinia

10.说明Vuekey值的作用?

  • Vue中,key值通常用来为v-for添加唯一的标识符
  • 当添加了key后,可以提高渲染页面时新旧节点使用diff算法对比的效率
    • diff算法用来对比新旧虚拟Dom,它会最大化地实现相同节点地复用
    • diff算法中,会先进行新旧节点的首尾交叉对比,当无法对比时,使用新节点地key与旧节点比较,找出差异
      • 旧数据与新数据各有两个头尾的变量startIndexendIndex,两者分别有四种对比方式:首与首,尾与尾,新首与旧尾,新尾与旧首.在比较的过程中,startIndexendIndex会向中间靠,如果四种比较方式均未匹配,则会使用key值进行比较,当startIndex>oldIndex时,会结束比较
  • 如果不添加key值,Vue的就地更新策略会导致代码出现bug

11.v-model的原理是什么?

  • v-model用于双向数据绑定,能够将data中的数据渲染到页面,同时如果页面的对应值发生改变后会同步更新data数据
  • Vue中,利用数据劫持配合订阅发布模式进行实现
    • Vue2中,通过Object.defineProperty来劫持对象属性的gettersetter操作
    • 利用监听器Observer监听对象中的所有属性,当属性发生变化后,需要通知订阅者Watcher是否需要更新,利用消息订阅器Dep来管理所有的订阅者,利用指令解析器Compile对每个元素与节点进行扫描解析,将相关指令(v-model,v-on等)初始化成为一个订阅者,并替换模板数据或者绑定相应函数,当订阅者接收到相应属性发生变化后,就会调用更新函数更新视图

12.Vue组件如何与iframe通信?

  • iframe组件中要想获取父组件的数据,使用H5的新特性postMessage相关的Api
  • onMessage监听消息
  • postMessage发送消息

13.Vue中的自定义指令如何使用?

  • Vue中,指令分为全局指令与局部指令
  • 创建自定义指令也可以创建为全局指令或者局部指令,全局指令在应用层级使用app.directive()进行注册,局部组件在组件中注册
  • 自定义指令也存在钩子函数,常用的bindupdate两者可以进行简化

14.当修改组件data中的数据时,重新渲染是同步还是异步进行的?

  • 数据的更新是同步发生的
  • 但是页面视图的更新是异步进行的,如果需要在数据更新后立刻操作更新后的Dom元素,需要使用$nextTick(callback)进行

15..sync修饰符的作用是什么?

  • .sync修饰符主要用来简化父子组件之间的数据通信
  • 在父组件向子组件传递数据时,使用.sync修饰符,Vue会自动为其创建一个更新数据的方法update:propName,在子组件中使用时,利用this.$emit("update:propName",newValue)来触发这个方法并向其传递新值,以此达到子组件向父组件传值

16.在Vue中,如何实现多组件嵌套中的通信?

  • 通过共同的祖先组件使用props传值
  • 通过provide/inject方式传值
  • 通过全局事件总线传值
  • 使用状态管理工具vuexpinia

17.如何使得组件内部的CSS只在组件内部生效?

  • 在创建样式时添加属性scope

18.keep-alive有什么作用?

  • keep-alive用来实现当切换组件时,原组件不会被卸载,进而不会清空原组件中的数据

19.使用keep-alive时,组件中的生命周期会增多吗?

  • 会增加两个新的生命周期:activateddeactivated
    • activated在组件被激活时会调用
    • deactivated在组件被缓存时会调用

20.Vue创建项目的指令是什么?

  • 使用@vue/cli
    • 版本低于3.0,使用npm init
    • 版本高于3.0,使用vue create
  • 使用vite
    • 使用npm create vue@latest

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的工作流程图示

  • 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中,actionsmutations分别是用来干什么的?为什么不能使用mutations处理异步?

  • 两者都是用来改变状态
  • 区别在于:
    • actions中可以存在异步代码,并且最终仍然会调用mutations中的方法来更改state;而mutations是同步代码,直接修改state中的状态,mutations中如果存在异步代码,将无法被devtools捕获状态变化
    • actions会默认将自身封装成为一个Promise,而mutations仅仅是一个单纯的函数

35.Vue如何进行路由配置?

  • Vue中,使用vue-router插件配置路由
  • Vue2
// main.js
import router from "@router/index.js"
const app=new Vue({router}).mount("#app")
// index.js
import VueRouter from "vue-router"
import Vue from "vue"
Vue.use(VueRouter)
const routes=[{
	// your config...
}]
const mode="history"
const router=new VueRouter({
	routes,
	mode
})
  • Vue3
// main.js
import router from "router/index.js"
app.use(router)
// index.js
import {createRouter,createMemoryHistory} from "vue-router"
const routes=[{
	// your config...
}]
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中,可以通过queryparams的方式传参
  • 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的理解?

  • 它是一种软件架构设计模式,另外的设计模式还包括MVCMVP
  • 不同于设计模式,架构模式往往采用了多种设计模式
  • MVVM可以拆分成为Model=>View=>ViewModel
    • Model层,数据模型层,对应项目开发时的数据包
    • View层,视图层,对应真实开发时的Dom结构
    • ViewModel层,扮演ViewModel的中间层,处理View层的全部业务逻辑
  • 通过使用MVVM,避免了直接操作Dom,当Model层数据发生更改后,页面会自动进行渲染

45.vue-router有什么组件?

  • <router-link>组件,利用to属性,可以实现在带有路由的组件之间跳转
  • <router-view>组件,路由出口,在这里展示路由组件

46.vue-routerlocation.href有什么区别?

vue-routerlocation.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.computedwatch有什么区别?

computedwatch
当源数据发生更改后会重新计算新值当源数据发生更改后触发侦听
有返回值没有返回值
有缓存没有缓存
关注计算的结果关注执行的过程
有一个gettersetter方法,默认使用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中的数据添加了gettersetter方法
    • getter方法实现数据更新并发布回调
    • setter方法添加消息订阅
  • 对作用域中的所有Dom节点进行数据处理,根据不同的指令来实现消息订阅与发布回调方法绑定
    • v-model中,在oninput事件中添加消息发布回调方法绑定
    • v-text中,添加value数据更新消息订阅回调方法绑定
    • 在输入框输入时,会触发oninput事件,触发消息发布方法实现数据更新,之后再触发订阅方法,实现Dom中的数据更新

59.Vue如何实现响应式?它的响应式有什么缺点?

  • Vue2中,数据的响应式是通过Object.defineProperty实现的
    • 将所有的属性改写为gettersetter
    • 在每个.vue组件中,有一个watcher对象,当页面数据发生变更时,会通知页面调用render方法渲染
  • 缺点
    • 它不能对对象的新增,删除属性实现响应式
    • 它不能对数组的长度修改实现响应式
    • 需要调用$set,$delete方法才能够实现

60.在<keep-alive>中使用includeexclude有什么区别?

  • 两者均可以使用字符串,正则表达式与数组的形式来指定组件的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":{
				// your config...
			}
		}
	}
}
  • vite.config.js中设置如下配置
import { defineConfig } from 'vite'
export default defineConfig({
  server: {
    proxy: {
      '/api1': {
        target: 'targetURL',
        ws:true,
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api1/, ''),
      },
      '/api2':{
      	// your config...
      }
    },
  },
})

63.为什么Vue3中的双向数据绑定使用Proxy?

  • Object.defineProperty中,如果需要实现完整的数据劫持,需要遍历其中的所有属性,如果是深层次数据,还需要递归来实现属性绑定
  • Proxy中,代理对象不需要遍历属性进行绑定,当有新属性被添加或是已有属性被删除,不需要在做额外的操作即可实现

64.封装一个组件会有哪些考虑?在使用组件时希望能够添加一些自定义的数据应当如何实现?

  • 封装组件需要考虑到组件的复用性
    • 使用组件时,为组件传递的props参数,以及参数的默认值
    • 组件中会触发的事件,定义事件处理函数及返回值
    • 组件的内容应当遵循通用性与灵活性
  • 要实现用户能够在组件中实现自定义样式或内容
    • 使用v-slot插槽
    • 添加一个render函数,允许用户自定义渲染内容或样式

65.Vue组件中的data选项为什么是函数,不能是对象?

  • 如果data是一个对象或者是一个数组等引用类型,那么在不同的组件中使用的data将引自同一块内存,在任何组件中对其进行修改之后,都会影响其他组件
  • 利用函数的返回值作为data,当每次使用组件时,都会调用函数,创建一个新的对象,不同组件之间的数据才不会相互影响

66.在Vue中,发送请求在哪个阶段进行?

  • 建议将发送请求的执行时机安排在created钩子函数中
  • beforeCreate钩子函数中,此时数据尚未挂载完成,不能使用this将数据保存到组件的data之中
  • beforeMountmounted钩子函数中发送请求的时机稍晚,会增加页面加载时间,并且VueSSR不支持beforeMountmounted钩子函数

67.兄弟与父子组件通信,在不使用Vuex的情况下有多少种方案?

  • 兄弟之间
    • 全局事件总线通信
    • 通过propsemit寻找共同的父组件
  • 父子之间
    • 通过propsemit通信
    • 通过provideinject通信
    • 通过$attrs$listners通信
    • 通过$ref$parent通信
    • 通过全局事件总线通信

68.v-ifv-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.mountedcreated有什么区别?

  • 两者均是Vue中的钩子函数
  • mounted在组件渲染阶段,created在数据挂载阶段
  • created在组件中的data挂载到Vue组件实例上时会执行,此时可以访问到this实例,但是此时的页面Dom尚未渲染,内容是最原始的数据
  • mounted在页面初次渲染完毕之后会触发,此时所有的数据都已经挂载完成,访问Dom内容可以看到与页面相同的数据

72.Vue中的生命周期有哪些?

阶段Vue2Vue3
初始化阶段beforeCreatecreatedonBeforeCreateonCreated
挂载阶段beforeMountMountedonBeforeMountonMounted
更新阶段beforeUpdateupdatedonBeforeUpdateonUpdated
卸载阶段beforeDestroydestroyedonBeforeUnmountonUnmounted
缓存组件activateddeactivatedonActivatedonDeactivated
错误捕获errorCapturedonErrorCaptured

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.说说provideinject的用法?

  • 在需要暴露数据的组件中使用provide提供数据
    • 以普通对象的形式或函数的形式提供数据
  • 在需要使用数据的组件中使用inject接收数据
    • 以数组形式或对象形式接收提供的数据

78.在vue-router中,routerouter有什么区别?

  • 在使用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为什么没有ReactshouldComponentUpdate生命周期?

  • Vue的响应式系统在初次渲染时就收集了渲染依赖的数据项,通过自动的方式可以取得不错的性能

84.如何在Vue中使用Jsx语法?

  • Jsx指的是javascriptXML结合的一种格式,React发明了Jsx,利用js语法创建虚拟Dom
  • 遇到<时当作HTML解析,遇到{时,当作js解析
  • Vue中,很少使用Jsx

85.在Vue中,跳转至另外一个页面,再返回先前的页面,如何保持页面的状态不改变?

  • 使用keep-alive内置组件能够实现组件状态的缓存,当用户跳转至另外的页面时,再返回先前的页面,不会丢失数据
  • keep-alive中,有includeexclude属性可供选择
    • include,接收一个字符串数组或正则表达式或一个字符串作为参数,可以用来设置需要缓存的组件
    • exclude,接收参数同上,可以用来设置不需要缓存的组件

86.beforeMountMounted生命周期的区别是什么?

beforeMountMounted
虚拟Dom创建完成,尚未渲染到页面,更改数据时不会触发update真实Dom完成渲染,已经挂载到页面中,此时可以使用$ref获取到Dom对象

87.Vue性能优化的方法有哪些?

  • 使用路由懒加载
  • 使用图片懒加载
  • 使用keep-alive缓存页面
  • 使用v-show替换v-if
  • 避免在标签中国同时使用v-forv-if
  • 长列表性能优化
  • 事件的自动销毁,当组件被卸载时,会自动解绑它的全部事件监听及指令
  • 使用第三方库时按需引入
  • 无状态的组件标记为函数式组件

88.使用Vue开发与使用原生开发项目有何不同?

  • 数据与页面元素自动绑定
  • 方便页面参数传递及状态管理
  • 模块化开发,能够实现无刷新保留场景参数的更新
  • 代码的可阅读性更好
  • 丰富的生态圈
  • 开发单页面应用更加友好
  • 组件之间样式不会冲突

89.在Vue中,从某个具有滚动条的页面跳到另外一个页面后,再从另外一个页面返回来,如何使得滚动条仍然在原位置?

  • 使用keep-alive将组件包裹
  • deactivated生命周期中记录滚动条的位置
  • activated生命周期中使页面的滚动条滚动到之前记录的位置

90.如何实现用户的权限分配?

  • 权限分配指的是不同的用户能够访问不同级别的页面
  • 在实际情况中,一般使用RBAC模型,引入角色的概念,然后将不同的权限分配给不同的角色,再将不同的用户与角色关联,对应的用户就会继承角色的权限.角色与权限都是多对多的关系
  • 优点
    • 实现用户与权限的解耦
    • 提高了权限配置的效率
    • 方便后期的维护
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Midshar.top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值