Vue面试题

241 阅读13分钟

vue

手写代码题
JavaScript面试题

vue基础

Vue的生命周期有哪些及每个生命周期做了什么?

  • Vue的生命周期分为三个阶段:初始化阶段、数据更新阶段、销毁阶段
  • 初始化阶段
    • beforeCreate(页面创建前):此时实例还未完成初始化,是没有this的,所以无法访问到data、computed、watch、methods等属性和方法。
    • created(页面创建后):实例已经创建完成,有了this,可以访问data、methods、computed等;但还没挂载DOM
    • beforeMount(页面渲染前):在渲染前被调用,此时模板已经编译完成,但还是获取不到dom节点,但有this,这个阶段很少用。
    • mounted(页面渲染后):在实例挂载到页面之后调用。此时真实DOM已经渲染完成,可以进行DOM操作。
  • 数据更新阶段
    • beforeUpdate(更新前):在数据更新之前被调用,该方法可用于在更新之前访问现有的DOM
    • updated(更新完成):在数据更新之后被调用,该方法还会在组件的子组件更新之后被调用。
  • 销毁阶段
    • beforeDestroy(销毁前):此时实例仍然可以使用。
    • destroyed(销毁完成):此时实例所有的指令和事件都已经卸除,所有的子实例都已经被销毁。

Vue3和Vue2的区别?

  1. 双向数据绑定原理:Vue2使用Object.defineProperty()对数据进行劫持,结合发布订阅者模式实现双向数据绑定。而Vue3是使用Proxy对数据进行处理,可以监听整个对象的变化。
  2. Props 的使用变化:vue2 通过 this 获取 props 里面的内容,vue3 直接通过 props
  3. Vue3是组合式API,使用生命周期钩子需要引入再使用,Vue2是选项API,可以直接调用生命周期钩子
  4. 生命周期的变化:使用setup代替了之前的beforeCreate和created
  5. ref和reactive,vue2没有这两个东西,vue3有,且用来创建响应式变量
  6. Route 获取页面实例与路由信息:vue2通过this获取router实例,vue3通过使用 getCurrentInstance/ userRoute和userRouter方法获取当前组件实例

Vue2的响应式原理是什么,Vue3的响应式原理是什么?

Vue2原理

  • 在Vue 2中,响应式是通过使用Object.defineProperty()方法来实现的。在组件实例化过程中,Vue会对数据对象(data)进行递归地遍历,将每个属性都转换为getter/setter,并且为每个属性创建一个依赖追踪的系统。当属性被访问或修改时,getter/setter会触发依赖追踪系统,从而进行依赖收集和派发更新,以保证数据和视图的同步。

Vue3原理

对于基本数据类型的数据

  • 响应式依然是靠Object.defineProperty()的get和set来完成的

对于对象类型的数据

  • 通过Proxy代理:拦截对象中任意属性的变化,包括属性值得读写、添加、删除等操作等
  • 通过Reflect反射函数进行操作

谈谈对MVVM的理解?

  • MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。

v-model实现原理?

  • 通过绑定变量,再监听事件对象,触发$event.target.value,再将值赋给变量

vue组件通信方式有哪些?

  1. props / $emit
    • 父组件通过v-bind向子组件传递数据,子组件通过props去接收父组件传递过来的数据。然后子组件通过$emit将数据派发到父组件
  2. 插槽 => 可以显示父组件中传递的内容
  • 默认插槽(父向子传递)、具名插槽(父向子传递)、作用域插槽(子向父传递)
    • 默认插槽:默认情况下组件的内容都在slot中显示
    • 具名插槽:允许父组件通过带有v-slot指令的<template>标签向子组件的指定名称区域分发内容
    • 作用域插槽:数据反向传递,允许子组件向父组件传递数据
  1. 依赖注入
    • 前提:一定是嵌套的,不管多深都可以
    • 在父组件调用provide()方法,将数据传递给子组件。子组件通过调用inject()方法来获取父组件传递过来的数据和方法
  2. 模板引用(ref与$refs)
    • 在父组件中,使用<template>标签定义子组件,并在<template>标签中使用ref属性为子组件指定一个引用名
    • 在父组件中,可以使用$refs属性来获取子组件的实例

如何传递多个插槽?

  • 多个<template>分别指定插槽名

动态插槽的应用场景?

  • 根据状态动态切换插槽内容,比如表格组件根据数据类型渲染不同列

说一下v-if与v-show的区别?

  • v-if是操作DOM元素的,v-show是操作样式的
  • v-if是惰性的,当条件不成立时,v-if不会渲染DOM元素;v-show无论条件成不成立,都能被编译,而且DOM元素保留

Vue2中,data为什么是函数?

  • 在Vue 2中,data 是一个函数,这是因为Vue需要确保每个组件实例都有独立的响应式数据。如果data 直接是一个对象,那么在多个组件实例中,它们可能会共享同一个数据,这将导致组件之间的状态互相影响,不符合预期。
  • 通过将 data 设为一个函数,每次当一个组件实例被创建时,这个函数都会返回一个新的对象,从而确保每个组件实例都有自己的数据

computed和watch的区别?

相同:都能监听data的数据变化
区别

  • 写法的不同,watch不需要返回值
  • compute是处理同步的,watch是处理异步的
  • 使用场景不同:watch监听一个数据变化,影响其他N个数据;computed监听N个数据,只影响一个数据

watch和watchEffect的区别?

  • 都能监听响应式数据变化,但监听数据变化的方式是不同得
  • watch要明确指出监听的数据,watchEffect不用明确指出监听的数据
  • watchEffect是立即执行的,在页面加载时会主动执行;watch是惰性的,不会立即执行

Vue中key值的作用?

  • key作用:用来作为节点的唯一标识
  1. 当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
  2. 为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

Vue3中ref和reactive有什么区别?

  • ref和reactive都是vue3中用于创建响应式数据的方法。
    两者的区别
    • 数据类型不同:ref用于包裹简单数据类型的数据,reactive用于包裹复杂数据类型的数据
    • 创建和访问方式不同:ref创建出来的响应式数据,想要通过.value去访问,而reactive创建出来的可以直接访问其属性或调用其方法

怎么用交叉观察者实现图片懒加载?

  • 图片懒加载的实现原理是:将图片以自定义属性的方式存储,然后通过交叉观察者确定可视区是否需要渲染,再根据交叉观察者去动态将自定义属性存储的图片放到渲染属性上。

有没有了解过组件初始化?

  • 组件初始化是指当组件被创建准备进行渲染时,所经历的一系列生命周期和内部状态设置的过程

beforeCreate

  • 在beforeCreate阶段,组件已被创建,但数据、方法等还未被设置,还没有this

created

  • 在created阶段,组件创建完成后立即调用,此时组件的数据、方法等已被设置,可以通过this访问

beforeMount

  • 这个生命周期也是只有this,还没有dom,比较少用

mounted

  • 在mounted中,组件已被渲染到页面上,在这个生命周期就可以操作dom了

v-html和v-text的区别?

  • v-text和插值表达式渲染数据,不解析标签
  • v-html不仅可以渲染数据,而且可以解析标签

setup在Vue3中是什么意思?

  • setup是Vue3新增的生命周期函数,setup的加入就是为了让Vue3使用组合式API
  • 代替了Vue2 中的 beforeCreate 和 created 钩子函数

get和post请求的区别?

  1. get请求用于从服务器获取数据,一般用于获取资源或查询数据,它将请求参数附加在url的后面,以键值对的形式传递给服务器,post请求用于向服务器提交数据,一般用于创建、更新或删除资源,它将请求参数放在请求体中等等。
  2. get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的;post请求是没有的长度限制,请求数据是放在body中
  3. get请求刷新服务器或者回退没有影响,post请求回退时会重新提交数据请求
  4. get请求可以被缓存,post请求不会被缓存
  5. get请求会被保存在浏览器历史记录当中,post不会。get请求可以被收藏为书签,因为参数就是url中,但post不能。它的参数不在url中

vue父子组件的生命周期执行顺序?

加载渲染阶段

  • 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

更新阶段

  • 父beforeUpdate->子beforeUpdate->子updated->父updated

销毁阶段

  • 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

在setup()中如何访问this?

  • setup()中没有this,响应式数据通过ref/reactive定义,方法直接申明

异步请求放在哪个钩子?

  • 客户端渲染:onMounted => 确保DOM可用

说说你对 Vue 中异步组件的理解?

  • 异步组件是指那些在需要时才加载的组件,而不是在应用初始化时就立即加载。这种机制可以显著提升页面加载速度和用户体验,尤其是在大型单页应用(SPA)中,通过懒加载的方式按需加载组件,避免不必要的资源浪费。

vue路由

如何实现路由页面鉴权?

分为两个层面:登录的情况、没登陆的情况

  • 可以用router.beforeEach去实现。
  • 用户还没登录的情况,设置白名单,如果用户需要跳转的页面不在白名单内,就强制用户跳转到登录页,如果在白名单内就直接放行
  • 登录的情况,如果用户想要跳转到登录界面,就强制跳回首页

导航守卫beforeEach这些有多少个参数?

  • 都有3个参数,分别是to:要进入的目标路由,from:要离开当前的路由,next:控制路由执行

Vue-router导航守卫有哪些?

  • 全局前置钩子:beforeEach、beforeResolve、afterEach
  • 路由独享的守卫:beforeEnter
  • 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

Vue的路由模式有哪些?

  • 哈希模式和历史模式

哈希路由

  • 使用场景:通常用在B端,business;云服务或管理台
  • 标志是不刷新页面,并且带#号,只是模块的切换
  • 底层实现:通过hashChange事件监听hash值的变化实现切换 => localtion

history路由

  • 使用场景:通常用在C端,client;商城
  • 标志是刷新页面,并且不带#号,会请求服务器资源;
  • 为什么能请求服务器资源,因为webpack开启了server服务;如果发布到线上的话,需要后端的配合才能成功跳转
  • 底层实现:通过history.pushstate 和 history.change()实现的 => history

Vue路由之间的跳转方式有哪些?

声明式跳转

  • router-link

编程式跳转

  • query带?
  • params跳转
  • 动态路由

Vue-Router的懒加载如何实现?

  1. 使用箭头函数 + import动态加载
const List = () => import('@/components/list.vue')
const router = new VueRouter({
  routes:[
    {path:'/list',component:List}
  ]
})
  1. 使用箭头函数 + require动态加载
const router = new Router({
  routes:[
    {
      path:'/list',
      component:resolve => require(['@/component/list'],resolve)
    }
  ]
})

route和router的区别?

  • route是路由对象,提供关于当前路由的信息 => 包括path、params、hash、query等路由信息参数
  • router是路由实例对象,提供操作路由的方法,控制路由导航 => 包括了路由的跳转方法,钩子函数等

如何定义动态路由?如何获取传过来的动态参数?

  1. param方式
  • 配置路由格式:/router/:id
  • 传递的方式:在path后面跟上对应的值
  • 传递后形成的路径:/router/123
  1. query方式
  • 配置路由格式:/router
  • 传递的方式:对象中使用query的key作为传递方式
  • 传递后形成的路径:/route?id=123

Vue-router跳转和location.href有什么区别?

  • 使用location.href更简单,但刷新了页面。
  • 使用router.push跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。

params和query的区别?

  1. 用法:query要用path来引入,params要用name来引入,接受参数都是类似的,分别是route.query.name和route.params.name
  2. query在浏览器地址栏中显示参数,params则不显示

谈谈你对vue中keep-alive的理解?

  • keep-alive是Vue中的内置组件,它不会渲染到dom树中,普通的组件在被替换之后,会销毁组件,组件中的一些状态都会被销毁,当这个组件再被创建时,组件内的所有属性和方法都是初始化状态的。而keep-alive的作用是,用keep-alive包裹某个组件,在这个组件被替换时,保存当前组件的状态,就是所谓的缓存

  • 参数:include、exclude => 指定是否缓存某些组件

    • include指定哪些被缓存,可以指定多个被缓存
    • exclude指定哪些组件不被缓存

Pinia和Vuex

Pinia有哪些使用场景?

  1. 共享状态管理

    • 多个组件可能需要访问和修改相同的状态、甚至不同页面间访问的数据。例如:用户登录信息、主题设置、购物车内容、全局配置等。
  2. 持久化数据存储

    • Pinia 可以结合插件实现状态的持久化存储,例如将用户偏好设置保存在本地存储中。这样即使用户刷新页面或者重新打开应用,仍然可以恢复之前的状态,提供更好的用户体验。
  3. 替代 Vuex 的现代方案

    • Pinia 被设计为 Vuex 的轻量级替代品,提供了更简洁的 API 和更直观的模块化结构。相比 Vuex,Pinia 减少了不必要的复杂性,例如不再需要 mutations,而是直接通过 actions 修改状态。
  4. 在组件外访问/修改状态

    • 需要在 Vue 组件之外(例如路由守卫、Axios)读取或更新应用状态时,Pinia Store 提供了方便的访问点。

说说Pinia和Vuex的区别?

Vuex

  1. Vuex一共有五个属性state、getter、mutation、action、module。
  • state:主要是用于管理store的一个容易,可以在这里面定义一些公用属性
  • getter:主要用于做一些计算,也可以用于访问state中的属性
  • mutation:主要用于对state的内容进行同步修改
  • action:主要进行一些异步操作,然后通过mutation来该变state的内容,调用action的方法时使用dispatch;
  • module:用于将store分模块,否则所有属性存在一个store中时会造成冗余

Pinia

  1. pinia在Vuex的基础上去掉了mutation,将action作为同步和异步共用的操作方法,并且去掉了module属性,因为每定义一个store就相当于一个模块。因此它一共有三个属性:state、getter、action。

区别

  • 使用方式不同,pinia和vuex是两个不同的库,因此在使用方式上有些细微差别
  • pinia支持compositionApi的格式,更加贴合Vue3
  • pinia的语法和使用方式更加简洁,调用action的方法时无需使用dispatch