vue3面试题及详细答案120道(106 - 120)

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

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

在这里插入图片描述

一、本文面试题目录

106. Vue3 中如何使用 v-memo 优化性能?

v-memo 是 Vue3 新增的指令,用于缓存虚拟 DOM 节点,避免不必要的渲染,提升性能。

基本用法

<!-- 仅当 count 变化时才重新渲染 -->
<div v-memo="[count]">
  <p>{{ count }}</p>
  <ExpensiveComponent /> <!-- 复杂组件,避免重复渲染 -->
</div>

适用场景

  • 渲染大量列表且其中部分数据不变时,可缓存不变的列表项。
<!-- 仅当 item.id 或 item.name 变化时才重新渲染 -->
<div v-for="item in list" :key="item.id" v-memo="[item.id, item.name]">
  {{ item.name }}
</div>
  • 组件包含复杂计算或嵌套层级深,且依赖数据变化频率低。

注意事项

  • 需传入依赖数组(如 [a, b]),数组中值变化时才重新渲染。
  • 滥用可能导致内存占用增加,仅在性能敏感场景使用。

107. 请解释 Vue3 中 customRef 的作用及使用场景?

customRef 用于创建自定义响应式引用,可自定义依赖追踪和触发更新的逻辑,适用于:

  1. 防抖/节流输入
import { customRef } from 'vue';

function useDebouncedRef(value, delay = 200) {
  let timeout;
  return customRef((track, trigger) => {
    return {
      get() {
        track(); // 收集依赖
        return value;
      },
      set(newValue) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          value = newValue;
          trigger(); // 触发更新
        }, delay);
      }
    };
  });
}

// 组件中使用
const searchText = useDebouncedRef('');
  1. 自定义缓存策略
function useCachedRef(value) {
  let cache = value;
  return customRef((track, trigger) => {
    return {
      get() {
        track();
        return cache;
      },
      set(newValue) {
        // 仅当值变化超过阈值时才更新
        if (Math.abs(newValue - cache) > 10) {
          cache = newValue;
          trigger();
        }
      }
    };
  });
}

核心原理

  • 通过 customRef 返回一个包含 getset 的对象。
  • track() 手动收集依赖,trigger() 手动触发更新。

108. Vue3 中如何实现跨组件的状态管理?

Vue3 中跨组件状态管理方案有:

  1. 小型项目:provide/inject
// 祖先组件
import { provide, ref } from 'vue';
const count = ref(0);
provide('count', count);

// 后代组件
import { inject } from 'vue';
const count = inject('count');
  1. 中型项目:Pinia(Vue 官方推荐):
import { defineStore } from 'pinia';

const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++; }
  }
});

// 组件中使用
const store = useCounterStore();
store.count;
store.increment();
  1. 大型项目:Vuex 4
import { createStore } from 'vuex';

const store = createStore({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++; }
  }
});

// 组件中使用
const count = computed(() => store.state.count);
store.commit('increment');
  1. 简单状态:自定义事件总线
// eventBus.js
import { createApp } from 'vue';
const eventBus = createApp({}).config.globalProperties;

// 发送事件
eventBus.$emit('update', data);

// 监听事件
eventBus.$on('update', (data) => { /* 处理 */ });

109. 请描述 Vue3 中 teleport 的使用场景?

teleport 用于将组件内容渲染到 DOM 中的其他位置,适用于:

  1. 模态框/弹窗:避免样式层级问题:
<teleport to="body">
  <div class="modal" v-if="showModal">
    <!-- 模态框内容 -->
  </div>
</teleport>
  1. 固定位置组件:如悬浮按钮、通知栏:
<teleport to="#fixed-elements">
  <button class="floating-btn">返回顶部</button>
</teleport>
  1. 与第三方 UI 库集成
<!-- 将组件内容渲染到外部容器 -->
<teleport to=".third-party-container">
  <MyComponent />
</teleport>

注意

  • to 属性支持 CSS 选择器或 DOM 元素引用。
  • 内容仍保留组件实例关系,状态管理不受影响。

110. Vue3 中如何实现组件的过渡动画?

Vue3 提供 <Transition><TransitionGroup> 组件实现动画:

  1. 单个元素过渡
<Transition name="fade">
  <div v-if="show">Hello</div>
</Transition>
/* 淡入淡出效果 */
.fade-enter-from, .fade-leave-to { opacity: 0; }
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
  1. 列表过渡
<TransitionGroup name="slide" tag="ul">
  <li v-for="item in list" :key="item.id">{{ item.name }}</li>
</TransitionGroup>
/* 滑动效果 */
.slide-enter-active { animation: slide-in 0.5s; }
.slide-leave-active { animation: slide-in 0.5s reverse; }
@keyframes slide-in {
  from { transform: translateX(-100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}
  1. 自定义动画钩子
<Transition
  @before-enter="beforeEnter"
  @enter="enter"
  @leave="leave"
>
  <div v-if="show">动画元素</div>
</Transition>
const beforeEnter = (el) => {
  el.style.opacity = 0;
};
const enter = (el, done) => {
  setTimeout(() => {
    el.style.opacity = 1;
    done();
  }, 0);
};

111. 请解释 Vue3 中 unref 的作用?

unref 是 Vue3 的工具函数,用于获取 ref 对象的值,自动处理 ref 或普通值:

import { ref, unref } from 'vue';

const count = ref(10);
console.log(unref(count)); // 10(等价于 count.value)

const num = 20;
console.log(unref(num)); // 20(普通值直接返回)

使用场景

  • 函数参数可能是 ref 或普通值时:
function add(a, b) {
  return unref(a) + unref(b);
}

add(ref(1), 2); // 3
add(3, 4); // 7
  • 简化模板中 ref 的使用:
const msg = ref('Hello');
const upperMsg = computed(() => unref(msg).toUpperCase());

112. Vue3 中如何实现组件的错误边界?

错误边界用于捕获子组件的运行时错误,避免应用崩溃,Vue3 中通过 onErrorCaptured 钩子实现:

import { onErrorCaptured } from 'vue';

export default {
  setup() {
    onErrorCaptured((err, instance, info) => {
      // err:错误对象
      // instance:抛出错误的组件实例
      // info:错误信息(如生命周期钩子名称)
      
      // 处理错误(如记录日志、显示错误界面)
      console.error('捕获到错误:', err);
      
      // 阻止错误向上传播
      return true;
    });
  }
};

结合 Suspense 使用

<Suspense>
  <MyComponent />
  <template #fallback>加载中...</template>
</Suspense>
// 全局错误捕获
app.config.errorHandler = (err, instance, info) => {
  console.error('全局错误捕获:', err);
};

113. 请描述 Vue3 中 v-bind 的修饰符及其作用?

Vue3 中 v-bind 支持以下修饰符:

  1. .prop:强制绑定为 DOM 属性而非特性:
<!-- 绑定为 DOM 的 innerHTML 属性 -->
<div v-bind:innerHTML.prop="htmlContent"></div>
  1. .camel:将 kebab-case 特性名转换为 camelCase:
<!-- 绑定为 myProp(而非 my-prop) -->
<MyComponent v-bind:my-prop.camel="value" />
  1. .sync:双向绑定语法糖(Vue3 推荐使用 v-model):
<!-- Vue2 写法 -->
<ChildComponent :title.sync="parentTitle" />

<!-- Vue3 等价写法 -->
<ChildComponent 
  :title="parentTitle" 
  @update:title="parentTitle = $event" 
/>

114. Vue3 中如何优化大型列表渲染?

大型列表渲染优化策略:

  1. 虚拟列表:仅渲染可视区域内的元素:
// 使用第三方库如 vue-virtual-scroller
<RecycleScroller
  class="items"
  :items="list"
  :item-size="32"
  key-field="id"
>
  <template #default="{ item }">
    <div class="item">{{ item.name }}</div>
  </template>
</RecycleScroller>
  1. 分批渲染
const itemsPerBatch = 20;
const visibleItems = ref([]);

const loadMore = () => {
  const start = visibleItems.value.length;
  visibleItems.value = [
    ...visibleItems.value,
    ...list.slice(start, start + itemsPerBatch)
  ];
};

// 初始加载第一批
onMounted(() => {
  loadMore();
});
  1. 列表项缓存
<div v-for="item in list" :key="item.id" v-memo="[item.value]">
  {{ item.value }}
</div>
  1. 减少 DOM 操作
<!-- 避免频繁更新整个列表 -->
<MyComponent v-if="shouldUpdate" :items="items" />

115. 请解释 Vue3 中 markNonReactive 的作用?

markNonReactive 用于标记对象的属性为非响应式,避免被 reactive 代理:

import { reactive, markNonReactive } from 'vue';

const obj = reactive({
  name: 'Vue3',
  config: { /* 大型配置对象,无需响应式 */ }
});

// 标记 config 为非响应式
markNonReactive(obj.config);

适用场景

  • 大型静态数据(如配置、常量),避免响应式开销。
  • 第三方库实例(如 new Chart()),无需响应式追踪。

116. Vue3 中如何实现组件的单元测试?

Vue3 组件单元测试方案:

  1. 使用 Vitest + Vue Test Utils
// Counter.vue
<template>
  <button @click="count++">{{ count }}</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>

// Counter.spec.js
import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import Counter from './Counter.vue';

describe('Counter', () => {
  it('should increment count on click', () => {
    const wrapper = mount(Counter);
    wrapper.find('button').trigger('click');
    expect(wrapper.text()).toBe('1');
  });
});
  1. 测试 Composition API
// useCounter.js
import { ref } from 'vue';
export function useCounter() {
  const count = ref(0);
  const increment = () => count.value++;
  return { count, increment };
}

// useCounter.spec.js
import { describe, it, expect } from 'vitest';
import { useCounter } from './useCounter';

describe('useCounter', () => {
  it('should increment count', () => {
    const { count, increment } = useCounter();
    increment();
    expect(count.value).toBe(1);
  });
});

117. 请描述 Vue3 中 v-model 的修饰符及其作用?

Vue3 中 v-model 支持以下修饰符:

  1. .trim:自动过滤输入首尾空格:
<input v-model.trim="message" />
  1. .number:将输入转换为数字类型:
<input v-model.number="age" type="number" />
  1. .lazy:将 input 事件改为 change 事件触发更新:
<input v-model.lazy="message" />
  1. 自定义修饰符
// 注册全局修饰符
app.config.globalProperties.$customModifiers = {
  uppercase: (value) => value.toUpperCase()
};

// 使用
<input v-model.uppercase="message" />

118. Vue3 中如何实现服务端渲染(SSR)?

Vue3 SSR 实现方案:

  1. 使用 Vite + @vue/server-renderer
// server.js
import { createSSRApp } from 'vue';
import { renderToString } from '@vue/server-renderer';
import App from './App.vue';

const server = require('http').createServer(async (req, res) => {
  const app = createSSRApp(App);
  const html = await renderToString(app);
  res.end(`
    <!DOCTYPE html>
    <html>
      <body>
        <div id="app">${html}</div>
        <script src="/client.js"></script>
      </body>
    </html>
  `);
});
  1. 使用 Nuxt3(官方推荐框架):
npx nuxi init my-nuxt-app
cd my-nuxt-app
npm install
npm run dev
  1. 关键注意事项
  • 避免在 setup 中使用浏览器专属 API(如 document)。
  • 使用 onBeforeMountonMounted 替代 setup 中的副作用。
  • 通过 process.server 区分客户端/服务端环境。

119. 请解释 Vue3 中 effectScope 的作用及使用场景?

effectScope 用于创建一个作用域,捕获其中的响应式副作用(如计算属性、watch),便于统一管理:

  1. 手动控制副作用
import { effectScope, ref, computed } from 'vue';

const scope = effectScope();
scope.run(() => {
  const count = ref(0);
  const double = computed(() => count.value * 2);
  
  // 可通过 scope.stop() 停止所有副作用
});

// 停止所有副作用
scope.stop();
  1. 插件/库开发
// 插件中使用
export function createMyPlugin() {
  const scope = effectScope(true); // detached: true 独立作用域
  scope.run(() => {
    // 插件逻辑
  });
  return {
    install(app) {
      app.provide('myPlugin', { scope });
    }
  };
}
  1. 组件卸载后保留副作用
const scope = effectScope(true);
scope.run(() => {
  watch(source, () => { /* 即使组件卸载仍执行 */ });
});

120. Vue3 中如何优化响应式系统的性能?

优化响应式系统性能的策略:

  1. 避免过度响应式
// 使用 readonly 包装无需修改的数据
const config = readonly({
  apiUrl: 'https://api.example.com',
  timeout: 5000
});
  1. 冻结大型静态对象
const largeData = Object.freeze([/* 大型数据 */]);
const state = reactive({
  data: largeData // 不会被转为响应式
});
  1. 使用 shallowReactive/shallowRef
// 仅第一层属性响应式
const state = shallowReactive({
  list: [/* 大型列表 */]
});

// 修改 list 需替换整个数组
state.list = [...state.list, newItem];
  1. 批量更新
import { nextTick } from 'vue';

const state = reactive({
  count: 0,
  text: ''
});

// 批量修改,避免多次触发更新
const updateState = async () => {
  state.count++;
  state.text = 'Loading...';
  
  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)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还是大剑师兰特

打赏一杯可口可乐

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

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

打赏作者

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

抵扣说明:

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

余额充值