首页 前端知识 前端面试题 — — vue篇

前端面试题 — — vue篇

2024-06-07 12:06:20 前端知识 前端哥 394 406 我要收藏

前端面试笔记之vue篇

  • 前言
    • 1.数据双向绑定原理⭐⭐⭐
    • 2. VUE生命周期⭐⭐⭐
    • 3.组件之间如何传值⭐⭐⭐
    • 4.v-model 的作用以及实现原理⭐⭐
    • 5.谈一谈VUEX⭐⭐
    • 6.如何解决VUEX页面刷新数据丢失问题?⭐⭐
    • 7.computed和watch的区别?⭐⭐⭐
    • 8.如何封装axios?⭐
    • 9.Route和router的区别⭐
    • 10.v-show和v-if的区别⭐⭐
    • 11.vue中数据变了但是视图不跟新怎么解决?⭐
    • 12.vue中data为什么是函数而不是对象?⭐⭐
    • 13.VUE中父子组件传值,父组件异步请求,子组件不能实时更新怎么解决?(VUE中数据不能实时更新怎么解决?)⭐⭐⭐
    • 14.父子组件传参emit如何传多个参数?⭐
    • 15.VUE路由跳转方式⭐⭐
    • 16.条件渲染v-if 与 v-for 优先级⭐
    • 17.VUE 中 $nextTick 作用与原理?⭐⭐⭐
    • 18.VUE中 for循环为什么加 key?⭐⭐
    • 19.VUE2和VUE3的区别?⭐⭐⭐
    • 20.为什么VUE3不继续用$set?⭐
    • 21.VUE路由中的history和hash的区别⭐⭐
    • 22.Pinia和Vuex的区别⭐
    • 23.Vue Diff算法⭐
    • 24. 动态组件 & 异步组件⭐
    • 25. 事件修饰符⭐
    • 26.路由之间如何传参⭐
    • 27.页面在编译时发生闪烁怎么解决?⭐
  • 其他

前言

这里是关于 vue面试的一些题,我整理了一些经常被问到的问题,出现频率比较高的问题,以及个人经历过的问题。如有不足之处,麻烦大家指出,持续更新中…(ps:一到三颗⭐代表重要性,⭐选择性了解,⭐⭐掌握,⭐⭐⭐前端需要知道的知识)
在这里插入图片描述

1.数据双向绑定原理⭐⭐⭐

答:通过数据劫持结合发布—订阅模式,通过Object.defineProperty()为各个属性定义get、set方法,在数据发生改变时给订阅者发布消息,触发相应的事件回调。

2. VUE生命周期⭐⭐⭐

概念:从创建、初始化数据、编译模板、挂载DOM、渲染-更新-渲染、卸载等一系列过程,称为为Vue 实例的生命周期。

vue2.0

  • beforeCreate:创建前。此时,组件实例刚刚创建,还未进行数据观测和事件配置,拿不到任何数据。
  • created:创建完成。vue 实例已经完成了数据观测,属性和方法的计算(比如props、methods、data、computed和watch此时已经拿得到),未挂载到DOM,不能访问到el属性,el属性,ref属性内容为空数组常用于简单的ajax请求,页面的初始化。
  • beforeMount:挂载前。挂在开始之前被调用,相关的render函数首次被调用(虚拟DOM)。编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,注意此时还没有挂在html到页面上
  • mounted:挂载完成。也就是模板中的HTML渲染到HTML页面中,此时可以通过DOM API获取到DOM节点,$ref属性可以访问常用于获取VNode信息和操作,ajax请求,mounted只会执行一次。
  • beforeUpdate:在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前,不会触发附加地重渲染过程。
  • updated:更新后。在由于数据更改导致地虚拟DOM重新渲染和打补丁之后调用,
  • beforeDestroy;销毁前。在实例销毁之前调用,实例仍然完全可用。(一般在这一步做一些重置的操作,比如清除掉组件中的定时器 和 监听的dom事件)
  • destroyed:销毁后。在实例销毁之后调用,调用后,vue实列指示的所有东西都会解绑,所有的事件监听器会被移除。
    其他:
    activated:在keep-alive组件激活时调用
    deactivated:在keep-alive组件停用时调用
    详情可看vue2.0官网生命周期钩子

vue3.0

  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeUnmount
  • onUnmounted

请添加图片描述
详情可看vue3.0官网生命周期钩子

3.组件之间如何传值⭐⭐⭐

一、Vue父子 组件之间传值

  • 子组件通过props来接受数据和通过$emit来触发父组件的自定义事件;

二、兄弟组件之间的传值

  • 建一个公共组件bus.js.。传递方通过事件触发bus.$emit。接收方通过在mounted(){}生命周期里触发bus.$on

三、可以通过VUEX 来跨组件传参。

四、父孙传值 $attrs(向下)$listeners(向上)

五、 祖先和子孙传值provide/inject

六、获取父组件实例this.$parent
详情可看vue之组件的传参方式

4.v-model 的作用以及实现原理⭐⭐

作用:v-model本质上不过是语法糖,可以用 v-model 指令在表单及元素上创建双向数据绑定。

实现原理:
v-bind:绑定响应式数据
触发oninput 事件并传递数据

5.谈一谈VUEX⭐⭐

原理:Vuex是专门为vue.js应用程序设计的状态管理工具。
构成:

  • state:vuex的基本数据,用来存储变量,存放的数据是响应式的。
  • mutations:提交更改数据,同步更新状态。
  • actions:提交mutations,可异步操作。
  • getters:是store的计算属性。
  • modules:模块,每个模块里面有四个属性。
    关于VUEX如何使用可以看VUE的传值问题

6.如何解决VUEX页面刷新数据丢失问题?⭐⭐

原因:因为vuex里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,vuex里面的数据就会被清空。

解决方法:将vuex中的数据直接保存到浏览器缓存中。

另一种方法:使用插件vuex-persistedstate
vuex-persistedstate可以将Vuex store的状态持久化存储到浏览器的localStorage或sessionStorage中,使得用户下次打开页面时能够继续使用之前的应用状态。

7.computed和watch的区别?⭐⭐⭐

computed值有缓存、触发条件是依赖值发生更改、 watch无缓存支持异步、监听数据变化

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是观察的作用,支持异步,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

computed应用场景:需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch应用场景:需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

详情请看Vue的计算属性与methods、watch的区别

8.如何封装axios?⭐

这个根据自己项目实际情况来说,这篇文章写的不错可以看看Vue的axios的简单封装

9.Route和router的区别⭐

  • route:是路由信息对象,包括“path,parms,hash,name“等路由信息参数。
  • Router:是路由实例对象,包括了路由跳转方法,钩子函数等。

10.v-show和v-if的区别⭐⭐

  • v-if:组件的销毁和重建,更适合带有权限的操作,切换开大。如果开始条件为false则什么都不做,只有为true才会编译。
  • v-show:css切换,隐藏显示更适合频繁切换。在任何情况下都会被编译,然后被缓存,而且dom元素会被保留。 (v-show = false 则代表 display: none; true 则显示)

11.vue中数据变了但是视图不跟新怎么解决?⭐

原因:

  • 数组数据变动:使用某些方法操作数组,变动数据时,有些方法无法被vue监测,或者是数组长度的改变。
    (push(),pop(),shift(),unshift(),splice(),sort(),reverse())不会改变原始数组,而是返回一个新的数组,视图不会自动更新。
  • Vue 不能检测到对象属性的添加或删除。
  • 异步更新队列:数据第一次的获取到了,也渲染了,但是第二次之后数据只有在再一次渲染页面的时候更新,并不能实时更新。

解决方法:数组长度变化可以用splice来修改,需要监听某个属性的变化用$set。

12.vue中data为什么是函数而不是对象?⭐⭐

官网中有这么一段介绍,详情可以看组件的复用
在这里插入图片描述
意思就是,在Vue中组件是可以被复用的,而当data是一个函数的时候,每一个实例的data都是独立的,不会相互影响了。

更详细的解释 ==>
请添加图片描述

13.VUE中父子组件传值,父组件异步请求,子组件不能实时更新怎么解决?(VUE中数据不能实时更新怎么解决?)⭐⭐⭐

首先了解父子组件生命周期执行顺序 ==>
加载渲染数据过程
父组件 beforeCreate -->
父组件 created -->
父组件 beforeMount -->
子组件 beforeCreate -->
子组件 created -->
子组件 beforeMount -->
子组件 mounted -->
父组件 mounted -->
原因:因为生命周期只会执行一次,数据是要等到异步请求以后才能拿到,那么子组件的mounted钩子执行的时候,还没有拿到父组件传递过来的数据,但是又必须要打印出来结果,那这样的话,就只能去打印props中的默认值空字符串了,所以打印的结果是一个空字符串。
解决办法:

  1. 使用v-if控制组件渲染的时机
    初始还没拿到后端接口的异步数据的时候,不让组件渲染,等拿到的时候再去渲染组件。使用v-if="变量"去控制,初始让这个变量为false,这样的话,子组件就不会去渲染,等拿到数据的时候,再让这个变量变成true,
    举例:
  data() {
    return {
      isTrue:false // 初始为false
    };
  },
  monted(){
  this.$post.a.b.c.getData(res=>{
        if(res.result){
            this.isTrue = true
         }
     })
  }
  1. 使用watch监听数据的变化
    举例:
  props: {
    tableData: {
      type: Array,
      default: [],
    },
  },
  watch: {
     tableData(val){
         console.log(val)
     }
  },
  1. 使用VueX

14.父子组件传参emit如何传多个参数?⭐

子组件:

submit(){
	this.$emit('g',1,2,3,4,5)
}

父组件

g(val1,val2,val3,val4,val5) {
	console.log(val1,val2,val3,val4,val5)
}

15.VUE路由跳转方式⭐⭐

  • router-link 标签跳转
  • this.$router.push()
  • this.$router.replace()
  • this.$router.go(n):(0:当前页,-1上一页,+1下一页,n代表整数)

16.条件渲染v-if 与 v-for 优先级⭐

vue2.0文档是这么说的
在这里插入图片描述
vue2列表渲染指南

vue3.0文档是这么说的
在这里插入图片描述
vue3条件渲染

17.VUE 中 $nextTick 作用与原理?⭐⭐⭐

异步渲染、获取DOM、Promise等。

Vue 在更新 DOM 时是异步执行的,在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。
$nextTick的作用是:该方法中的代码会在当前渲染完成后执行,就解决了异步渲染获取不到更新后DOM的问题了。
$nextTick 的原理: $nextTick本质是返回一个Promise 。

应用场景:

  • 在created()里面想要获取操作Dom,把操作DOM的方法放在$nextTick中。
  • 在data()中的修改后,页面中无法获取data修改后的数据,使用$nextTick时,当data中的数据修改后,可以实时的渲染页面

官网中是这么说的
在这里插入图片描述

18.VUE中 for循环为什么加 key?⭐⭐

为了性能优化优化diff算法, 因为vue是虚拟DOM,更新DOM时用diff算法对节点进行一一比对,比如有很多li元素,要在某个位置插入一个li元素,但没有给li上加key,那么在进行运算的时候,就会将所有li元素重新渲染一遍,但是如果有key,那么它就会按照key一一比对li元素,只需要创建新的li元素,插入即可,不需要对其他元素进行修改和重新渲染。
key也不能是li元素的index,因为假设我们给数组前插入一个新元素,它的下标是0,那么和原来的第一个元素重复了,整个数组的key都发生了改变,这样就跟没有key的情况一样了。

19.VUE2和VUE3的区别?⭐⭐⭐

  • 响应式不同
    Vue 2 使用 getters 和 setters 来实现响应式。
    Vue3 使用Proxy ,Proxy 提供了更简单的 API 和更高的性能,因为它不需要定义 getters 和 setters。
    Vue 3 的响应式系统比 Vue 2 更快、更简单、更强大。它使用 Proxy 和惰性追踪提供了更高的性能,并通过新的响应式 API 简化了响应式数据的管理。
//Vue2
const data = {
  count: 0
}

Object.defineProperty(data, 'count', {
  get() {
    return this.count
  },
  set(newValue) {
    this.count = newValue
    this.$emit('countChanged', newValue)
  }
})
//Vue3
const data = reactive({
  count: 0
})
  • API 类型不同
    Vue2 使用选项类型api。
    Vue3 使用合成型api。
  • 定义数据变量和方法不同
    Vue2是把数据放到了data 中。
    Vue3使用setup()。
  • 生命周期不同
  • 父子传参不同
  • 指令与插槽不同
  • 是否支持碎片
    Vue2 不支持碎片。
    Vue3 支持碎片,可以拥有多个根节点

20.为什么VUE3不继续用$set?⭐

$set的作用:在vue2.0中:使用对象和数组来定义数据,当需要向对象或数组中新增一个属性或元素,并希望它在更新 View 时响应式地更新,就需要使用 $set方法来完成。
vue2是用object.definedProperty来实现数据响应的,无法监听深层数据的变化

Vue3 中使用Proxy对数据代理通过ref和reactive将值和对象类型变为响应式对象,这样对它的修改和添加就能被vue捕获到,从而实现页面的自动刷新。
vue2
vue3

参考官网响应式基础

21.VUE路由中的history和hash的区别⭐⭐

  • 地址栏带不带"#"号
    hash:http://localhost:8080/#/
    history:http://localhost:8080/

  • 都是利用浏览器的两种特性实现前端路由
    history是利用浏览历史记录栈的API实现
    hash是监听location对象hash值变化事件来实现

  • 相同的url
    history会触发添加到浏览器历史记录栈中,hash不会触发,
    history需要后端配合,如果后端不配合刷新页面会出现404,hash不需要

hashRouter原理:通过window.onhashchange获取url中hash值
historyRouter原理:通过history.pushState,使用它做页面跳转不会触发页面刷新,使用window.onpopstate监听浏览器的前进和后退

在这里插入图片描述
在这里插入图片描述
详情可以看官网不同历史模式|Vue Router

22.Pinia和Vuex的区别⭐

  • 支持选项式api和组合式api
  • pinia没有mutations,只有state、getters、 actions
  • pinia分模块不需要modules
  • 支持TypeScript
  • 自动化代码拆分
  • pinia体积更小
  • pinia可以直接修改state数据

参考https://github.com/vuejs/rfcs/pull/271

23.Vue Diff算法⭐

当组件创建和更新时,vue均会执行内部的update函数,该函数使用render函数生成虚拟dom树,将新旧两树进行对比,找到差异,最终更新到真实dom。

对比差异的过程叫做diff,vue在内部通过一个叫patch的函数完成该过程。

在对比时,vue采用深度优先,同层比较的方式进行对比

在比较两个节点是否相同时,vue通过虚拟节点的key和tag来进行判断。

首先对根节点进行对比,如果相同将旧节点关联的真实dom的引用挂载到新节点上,然后根据需要更新属性到真实dom,然后再对比其子节点数组,如果不相同,则按照新节点的信息递归创建所有真实dom,同时挂载到对应虚拟节点上,然后移除旧的dom。

对比其子节点数组时,vue对每个子节点数组使用两个指针。分别指向头尾,然后不断向中间靠拢来进行对比,目的是尽量复用真实dom,少创建和销毁真实dom。如果发现相同,则进入和根节点一样对比流程,如果不同,则移动真实dom到合适的位置。

这样一直递归的遍历下去,直到整颗树完成对比。

Vue 中的优化策略
在 Vue 的 diff 算法中引入了一些优化策略,以减少不必要的 diff 操作,提高 diff 性能,具体来说,有以下几点:

  • 模板编译时静态节点标记
    Vue 在模板编译时,会对那些不需要变更的静态节点做标记,这样在后续渲染时,就可以省略对这些节点进行 diff 操作,减少 diff 的复杂度,提高性能。
  • 列表遍历的 key 值优化
    在 Vue 中,当对一个列表进行遍历时,我们通常会为每个子元素指定一个 key 值来唯一标识它们,以便于后续的 diff 操作。在这个过程中,Vue 会通过记录 key 值来对比新旧节点是否发生了变化,如果没有变化,则会保留该节点对应的状态,避免不必要的重复渲染。
  • 相同节点的合并优化
    在 diff 算法中,如果新旧节点是相同节点(即两个节点都是相同的标签和属性),并且都不需要更新子节点,则认为这两个节点是相同的,可以直接跳过对该节点的 diff 操作,提高 diff 性能。

Vue 的 diff 算法是一种高效的前端响应式实现方式,能够快速地对比新旧节点间的差异,并快速更新页面视图,提升了用户体验和程序性能。

24. 动态组件 & 异步组件⭐

动态组件和异步组件都是为了实现组件的动态渲染和按需加载,可以提高应用的性能和灵活性。
动态组件 :渲染组件时,根据某个条件动态地选择组件。
在这里插入图片描述
异步组件:组件的加载和渲染过程分成两部分进行,即先加载组件的代码和依赖,等加载成功后再将其渲染到页面上。这样可以避免在初始加载时一次性加载所有组件的代码和依赖,从而提高页面的性能和响应速度。在Vue中,可以使用工厂函数和组件的异步加载特性来实现异步组件的加载。
参考官网
vue2异步组件
vue3异步组件

25. 事件修饰符⭐

.stop:阻止单击事件继续传播
.prevent:提交事件不再重载页面
.capture :添加事件监听器时使用事件捕获模式
.self :当前元素自身时触发处理函数
.once :只会触发一次
.passive :提升移动端的性能。

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
 

详细请看官网事件修饰符

26.路由之间如何传参⭐

  • 通过router-link路由导航跳转传递
<router-link to=`/a/${id}`>routerlink传参</router-link>
  • 跳转时使用push方法拼接携带参数。
  this.$router.push({
          path: `/getlist/${id}`,
        })
  • 通过路由属性中的name来确定匹配的路由,通过params来传递参数。
this.$router.push({
          name: 'Getlist',
          params: {
            id: id
          }
        })
  • 使用path来匹配路由,然后通过query来传递参数。
this.$router.push({
          path: '/getlist',
          query: {
            id: id
          }
        })

注意:query有点像ajax中的get请求,而paramspost请求。

params在地址栏中不显示参数,刷新页面,参数丢失,
其余方法在地址栏中显示传递的参数,刷新页面,参数不丢失。

详情请看Vue-router之简单的路由传参三种方法

27.页面在编译时发生闪烁怎么解决?⭐

首先了解原因:

  • 在页面加载时,Vue.js 组件可能会在数据就绪之前渲染。这可能会导致元素在数据可用之前短暂显示其初始状态。
  • 使用直接在 DOM 中书写的模板时,可能会出现一种叫做“未编译模板闪现”的情况:用户可能先看到的是还没编译完成的双大括号标签,直到挂载的组件将它们替换为实际渲染的内容。

解决办法:使用指令v-cloak

v-cloak 会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。 v-cloak用于隐藏尚未完成编译的 DOM 模板。

<template>
  <div v-cloak>
    <h1>{{ title }}</h1>
    <p>{{ content }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: null,
      content: null
    }
  },
  created() {
    // 从服务器获取数据并更新状态
    this.fetchData();
  },
  methods: {
    fetchData() {
      // 模拟从服务器获取数据
      setTimeout(() => {
        this.title = '标题';
        this.content = '内容';
      }, 500);
    }
  }
}
</script>

在上面的示例中,v-cloak 用于隐藏元素,直到 fetchData 方法从服务器获取数据并更新状态。这将防止在数据加载之前闪烁效果。
相关可以看官网v-cloak

其他

关于前端其他面试题可以看这个

前端面试题(附答案)完善中……

转载请注明出处或者链接地址:https://www.qianduange.cn//article/11282.html
标签
评论
发布的文章

1.10 Unity中的数据存储 JSON

2024-06-13 21:06:30

JSON 数据格式化方法

2024-06-13 21:06:26

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!