Vue3 面试题及详细答案120道(16-30 )

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

一、本文面试题目录

16. Vue3 中如何创建响应式对象?

在 Vue3 中,创建响应式对象主要通过 reactiveref 两个 API 实现:

  • reactive:用于将对象或数组转换为响应式数据,基于 Proxy 实现,直接代理整个对象。示例:
    import { reactive } from 'vue';
    const user = reactive({
      name: '张三',
      age: 25
    });
    // 修改属性时会触发响应式更新
    user.age = 26;
    
  • ref:主要用于基本数据类型(如字符串、数字等),也可用于对象。它会将数据包装为一个带有 value 属性的响应式对象,访问或修改时需通过 .value。示例:
    import { ref } from 'vue';
    const count = ref(0);
    // 访问
    console.log(count.value); // 0
    // 修改
    count.value++; // 触发更新
    
  • 区别:reactive 仅支持对象/数组,且访问属性无需额外操作;ref 支持所有数据类型,但需通过 .value 访问(模板中使用时会自动解包,无需 .value)。

17. Vue3 中如何监听数据变化?

Vue3 提供 watchwatchEffect 两种方式监听数据变化:

  • watch:需明确指定监听的数据源,支持监听单个或多个数据,可获取新旧值。示例:
    import { ref, watch } from 'vue';
    const count = ref(0);
    // 监听单个数据
    watch(count, (newVal, oldVal) => {
      console.log(`count从${oldVal}变为${newVal}`);
    });
    // 监听多个数据
    watch([count, () => user.age], ([newCount, newAge], [oldCount, oldAge]) => {
      console.log('count或age变化了');
    });
    
  • watchEffect:自动收集依赖,无需指定数据源,回调函数中使用的响应式数据变化时会触发执行,且初始会执行一次。示例:
    import { ref, watchEffect } from 'vue';
    const count = ref(0);
    watchEffect(() => {
      console.log(`count当前值:${count.value}`); // 初始执行,后续count变化时再执行
    });
    
  • 适用场景:watch 适合需要明确监听目标或需要新旧值对比的场景;watchEffect 适合依赖不明确、需要自动追踪的场景。

18. Vue3 的生命周期钩子有哪些?与 Vue2 有何区别?

Vue3 保留了 Vue2 的核心生命周期概念,但在组合式 API 中以函数形式提供,部分钩子名称略有调整:

  • 常用钩子:onBeforeMount(挂载前)、onMounted(挂载后)、onBeforeUpdate(更新前)、onUpdated(更新后)、onBeforeUnmount(卸载前)、onUnmounted(卸载后)、onErrorCaptured(捕获子组件错误)。
  • 与 Vue2 的区别:
    1. 写法不同:Vue3 需从 vue 中导入钩子函数,在 setup 中使用;Vue2 是在组件选项中定义(如 mounted() {})。
    2. 名称调整:Vue2 的 beforeDestroy 改为 onBeforeUnmountdestroyed 改为 onUnmounted
    3. 新增钩子:onRenderTracked(追踪响应式依赖时触发,用于调试)、onRenderTriggered(响应式依赖变化触发更新时触发,用于调试)。
  • 示例(组合式 API 中使用):
    import { onMounted, onUnmounted } from 'vue';
    setup() {
      onMounted(() => {
        console.log('组件已挂载');
      });
      onUnmounted(() => {
        console.log('组件已卸载');
      });
    }
    

19. Vue3 中如何实现父子组件通信?

父子组件通信主要通过 props 传值事件触发 实现:

  • 父传子(props)
    1. 父组件在使用子组件时,通过属性传递数据:
      <ChildComponent :message="parentMsg" :count="10" />
      
    2. 子组件通过 defineProps 声明接收的 props(<script setup> 中):
      import { defineProps } from 'vue';
      const props = defineProps({
        message: String, // 类型校验
        count: {
          type: Number,
          required: true, // 必传
          default: 0 // 默认值(非必传时生效)
        }
      });
      // 使用
      console.log(props.message);
      
  • 子传父(自定义事件)
    1. 子组件通过 defineEmits 声明可触发的事件,然后通过 emit 触发:
      import { defineEmits } from 'vue';
      const emit = defineEmits(['change', 'submit']); // 声明事件
      // 触发事件并传递数据
      const handleClick = () => {
        emit('change', '新数据');
        emit('submit');
      };
      
    2. 父组件监听子组件触发的事件:
      <ChildComponent @change="handleChange" @submit="handleSubmit" />
      <script setup>
      const handleChange = (data) => {
        console.log('子组件传递的数据:', data);
      };
      </script>
      

20. setup 函数的作用是什么?它有哪些参数?

setup 是 Vue3 中 Composition API 的入口函数,用于组织组件逻辑,在组件创建前(beforeCreate 之前)执行。

  • 作用
    1. 替代 Vue2 中的 datamethods 等选项,将组件逻辑以函数形式组织。
    2. 提供响应式 API(如 refreactive)、生命周期钩子等的使用入口。
    3. 返回的对象属性或方法可直接在模板中使用。
  • 参数
    1. props:接收父组件传递的 props,是响应式对象,不可直接解构(需用 toRefs 解构)。
    2. context:包含组件上下文信息,如 attrs(非 props 属性)、slots(插槽)、emit(触发事件的函数)。
  • 示例:
    import { toRefs } from 'vue';
    setup(props, context) {
      // 解构 props(保持响应式)
      const { message } = toRefs(props);
      // 使用 context
      const { emit, attrs, slots } = context;
      const handleClick = () => {
        emit('submit'); // 触发事件
      };
      // 返回给模板
      return { message, handleClick };
    }
    

21. Vue3 中如何实现计算属性(computed)?

计算属性通过 computed 函数创建,用于依赖响应式数据的衍生值,具有缓存特性(依赖不变时不会重新计算)。

  • 基本用法
    import { ref, computed } from 'vue';
    const count = ref(0);
    // 只读计算属性
    const doubleCount = computed(() => {
      return count.value * 2;
    });
    console.log(doubleCount.value); // 0(初始值)
    count.value = 1;
    console.log(doubleCount.value); // 2(依赖变化后重新计算)
    
  • 可写计算属性(需指定 getset):
    const fullName = computed({
      get: () => `${firstName.value} ${lastName.value}`,
      set: (newValue) => {
        const [f, l] = newValue.split(' ');
        firstName.value = f;
        lastName.value = l;
      }
    });
    // 赋值时触发 set
    fullName.value = '李四 王';
    
  • 特点:依赖变化时自动更新,适合处理需要基于现有数据计算衍生值的场景(如过滤列表、格式化数据)。

22. Vue3 中如何实现跨层级组件通信(祖孙组件)?

跨层级通信可通过 provideinject 实现,无需手动逐层传递 props:

  • 祖先组件提供数据(provide)
    import { provide, ref } from 'vue';
    setup() {
      const theme = ref('dark');
      // 提供数据(key 为标识,value 为数据)
      provide('themeKey', theme);
      provide('userInfo', { name: '张三', age: 25 });
    }
    
  • 后代组件接收数据(inject)
    import { inject } from 'vue';
    setup() {
      // 接收数据(第一个参数为 key,第二个参数为默认值)
      const theme = inject('themeKey', 'light'); // 响应式数据(保持响应式)
      const userInfo = inject('userInfo', { name: '默认名称' }); // 普通数据
      return { theme, userInfo };
    }
    
  • 注意:
    1. provide 传递响应式数据(如 ref/reactive 对象)时,后代组件接收后可感知数据变化。
    2. 若需在后代组件修改祖先提供的数据,建议祖先同时提供修改方法(如 provide('updateTheme', (newVal) => { theme.value = newVal; }))。

No.大剑师精品GIS教程推荐
0地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】
1Openlayers 【入门教程】 - 【源代码+示例 300+】
2Leaflet 【入门教程】 - 【源代码+图文示例 150+】
3MapboxGL【入门教程】 - 【源代码+图文示例150+】
4Cesium 【入门教程】 - 【源代码+综合教程 200+】
5threejs【中文API】 - 【源代码+图文示例200+】

23. Vue3 中如何使用插槽(Slot)?

插槽用于父组件向子组件传递模板内容,Vue3 中插槽用法与 Vue2 类似,但支持更简洁的语法:

  • 默认插槽
    1. 子组件中用 <slot> 定义插槽位置:
      <!-- 子组件 -->
      <div class="container">
        <slot></slot> <!-- 父组件传递的内容会插入这里 -->
      </div>
      
    2. 父组件使用子组件时,在标签内写入内容:
      <ChildComponent>
        <p>这是默认插槽的内容</p>
      </ChildComponent>
      
  • 具名插槽(多个插槽区分):
    1. 子组件用 name 属性定义具名插槽:
      <slot name="header"></slot> <!-- 头部插槽 -->
      <slot></slot> <!-- 默认插槽(name 默认为 default) -->
      <slot name="footer"></slot> <!-- 底部插槽 -->
      
    2. 父组件用 v-slot:name(或缩写 #name)指定内容插入的插槽:
      <ChildComponent>
        <template #header>
          <h1>页面标题</h1>
        </template>
        <p>默认内容</p>
        <template #footer>
          <p>页脚信息</p>
        </template>
      </ChildComponent>
      
  • 作用域插槽(子组件向父组件传递数据):
    1. 子组件在插槽中通过 v-bind 传递数据:
      <slot :user="userInfo" :count="10"></slot>
      
    2. 父组件接收数据并使用:
      <ChildComponent>
        <template #default="slotProps"> <!-- 接收数据 -->
          <p>用户名:{{ slotProps.user.name }}</p>
          <p>数量:{{ slotProps.count }}</p>
        </template>
      </ChildComponent>
      

24. Vue3 中如何使用 Teleport 组件将内容渲染到指定位置?

Teleport(瞬移)用于将组件内的部分内容渲染到 DOM 树的其他位置(如 <body>),解决样式层级限制问题(如模态框、弹窗)。

  • 基本用法
    <template>
      <button @click="showModal = true">打开弹窗</button>
      <!-- to 指定目标位置(CSS 选择器或 DOM 元素) -->
      <Teleport to="body">
        <div v-if="showModal" class="modal">
          <p>这是弹窗内容</p>
          <button @click="showModal = false">关闭</button>
        </div>
      </Teleport>
    </template>
    <script setup>
    import { ref } from 'vue';
    const showModal = ref(false);
    </script>
    
  • 特点
    1. 渲染位置改变,但内容仍受当前组件的响应式数据控制(如 showModal)。
    2. 可避免弹窗被父组件的 overflow: hiddenz-index 样式影响。
    3. to 属性支持动态值(如 :to="targetElement")。

25. Vue3 中 Suspense 组件的作用是什么?如何使用?

Suspense 用于处理异步操作(如异步组件、异步数据加载),在等待异步内容时显示占位符(loading 状态),提升用户体验。

  • 使用步骤
    1. 定义异步组件(通过 defineAsyncComponent 创建):
      import { defineAsyncComponent } from 'vue';
      const AsyncComponent = defineAsyncComponent(() => 
        import('./AsyncComponent.vue') // 动态导入(返回 Promise)
      );
      
    2. Suspense 包裹异步组件,通过 default 插槽放异步内容,fallback 插槽放加载提示:
      <Suspense>
        <template #default>
          <AsyncComponent /> <!-- 异步组件 -->
        </template>
        <template #fallback>
          <div>加载中...</div> <!-- 等待时显示 -->
        </template>
      </Suspense>
      
  • 注意
    1. Suspense 仅能处理返回 Promise 的异步操作(如异步组件、setup 中使用 await 的组件)。
    2. 若异步操作失败,需配合错误边界(onErrorCaptured)处理错误。

26. Vue3 中 <script setup> 如何声明 props 和 emits?

<script setup> 是 Vue3 中简化组件写法的语法糖,声明 props 和 emits 需使用 definePropsdefineEmits 编译宏(无需导入):

  • 声明 props
    // 方式1:数组形式(仅指定名称)
    const props = defineProps(['name', 'age']);
    
    // 方式2:对象形式(带类型校验和配置)
    const props = defineProps({
      name: {
        type: String,
        required: true, // 必传
        default: '默认名称' // 非必传时的默认值
      },
      age: {
        type: Number,
        validator: (value) => { // 自定义校验
          return value >= 0;
        }
      }
    });
    
    // 使用
    console.log(props.name);
    
  • 声明 emits
    // 方式1:数组形式(仅指定事件名)
    const emit = defineEmits(['change', 'delete']);
    
    // 方式2:对象形式(带参数校验)
    const emit = defineEmits({
      change: (value) => { // 校验参数
        return typeof value === 'string';
      },
      delete: null // 无参数
    });
    
    // 触发事件
    const handleClick = () => {
      emit('change', '新值');
      emit('delete');
    };
    

27. Vue3 中如何动态绑定样式(class 和 style)?

动态绑定样式通过 :class:style 实现,支持对象、数组等形式:

  • 动态 class
    1. 对象形式(键为类名,值为布尔值,true 则添加类):
      <div :class="{ active: isActive, 'text-danger': hasError }"></div>
      <script setup>
      import { ref } from 'vue';
      const isActive = ref(true);
      const hasError = ref(false);
      </script>
      
    2. 数组形式(直接指定类名列表):
      <div :class="[activeClass, errorClass]"></div>
      <script setup>
      const activeClass = ref('active');
      const errorClass = ref('text-danger');
      </script>
      
  • 动态 style
    1. 对象形式(键为样式名,值为样式值):
      <div :style="{ color: textColor, fontSize: `${fontSize}px` }"></div>
      <script setup>
      import { ref } from 'vue';
      const textColor = ref('red');
      const fontSize = ref(16);
      </script>
      
    2. 数组形式(多个样式对象合并):
      <div :style="[baseStyle, customStyle]"></div>
      <script setup>
      const baseStyle = ref({ backgroundColor: 'white' });
      const customStyle = ref({ border: '1px solid black' });
      </script>
      

28. Vue3 中如何注册全局组件?

注册全局组件需通过 app.component 方法,在应用实例上注册,所有组件均可直接使用:

  • 步骤
    1. 导入组件:
      import GlobalButton from './components/GlobalButton.vue';
      import GlobalCard from './components/GlobalCard.vue';
      
    2. 在创建应用实例后,通过 component 方法注册:
      import { createApp } from 'vue';
      import App from './App.vue';
      
      const app = createApp(App);
      // 注册单个组件(参数:组件名,组件对象)
      app.component('GlobalButton', GlobalButton);
      // 链式注册多个
      app.component('GlobalCard', GlobalCard)
         .component('GlobalInput', GlobalInput);
      
      app.mount('#app');
      
    3. 在任意组件中直接使用,无需局部导入:
      <GlobalButton label="全局按钮"></GlobalButton>
      <GlobalCard></GlobalCard>
      
  • 注意:全局组件名建议使用 kebab-case 格式(如 global-button),符合 HTML 标签规范。

29. Vue3 中如何实现自定义指令?

自定义指令用于封装 DOM 操作,通过 app.directive 注册,支持多个钩子函数(如 mountedupdated 等):

  • 全局注册
    import { createApp } from 'vue';
    import App from './App.vue';
    
    const app = createApp(App);
    // 注册自定义指令(参数:指令名,配置对象)
    app.directive('focus', {
      // 钩子函数:元素挂载到 DOM 时执行
      mounted(el) {
        el.focus(); // 自动聚焦
      },
      // 元素更新时执行(如组件重新渲染)
      updated(el) {
        el.focus();
      }
    });
    
    app.mount('#app');
    
  • 局部注册(仅在当前组件生效):
    // 在组件中
    export default {
      directives: {
        focus: {
          mounted(el) {
            el.focus();
          }
        }
      }
    };
    
  • 使用自定义指令
    <input v-focus type="text" /> <!-- 应用指令,会自动聚焦 -->
    
  • 常用钩子函数:
    • mounted:元素挂载后执行(初始化操作)。
    • updated:元素更新时执行(更新操作)。
    • unmounted:元素卸载时执行(清理操作)。

30. Vue3 中 nextTick 的作用是什么?如何使用?

nextTick 用于在 DOM 更新完成后执行回调函数,解决数据修改后立即操作 DOM 无法获取最新状态的问题(Vue 会批量更新 DOM,而非同步更新)。

  • 作用:等待当前组件的 DOM 完成更新后,再执行后续逻辑(如获取更新后的 DOM 尺寸、操作新渲染的元素等)。
  • 使用方式
    import { ref, nextTick } from 'vue';
    
    const count = ref(0);
    const el = ref(null);
    
    const handleClick = async () => {
      count.value++; // 修改数据,触发 DOM 更新(异步)
      // 此时直接操作 DOM 可能获取旧状态
      console.log(el.value.offsetHeight); // 可能为更新前的高度
      
      // 等待 DOM 更新完成后执行
      await nextTick();
      console.log(el.value.offsetHeight); // 最新高度
    };
    
  • 场景:
    • 数据修改后需要立即获取 DOM 元素的位置、尺寸等。
    • 数据修改后需要操作新渲染的 DOM 元素(如滚动到指定位置)。
  • 注意:nextTick 返回 Promise,可配合 async/await 使用,也可使用回调函数(nextTick(() => { ... }))。

二、120道面试题目录列表

文章序号vue3面试题120道
1vue3 面试题及详细答案(01 - 15)
2vue3 面试题及详细答案(16 - 30)
3vue3 面试题及详细答案(31 - 45)
4vue3 面试题及详细答案(46 - 60)
5vue3 面试题及详细答案(61 - 75)
6vue3 面试题及详细答案(76 - 90)
7vue3 面试题及详细答案(91 - 105)
8vue3 面试题及详细答案(106 - 120)
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还是大剑师兰特

打赏一杯可口可乐

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

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

打赏作者

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

抵扣说明:

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

余额充值