当前位置: 首页 > news >正文

2025 vue3面试题汇总,通俗易懂

一、基础概念与核心特性

1. Vue3 相比 Vue2 的改进(通俗版)

问题:Vue3 比 Vue2 好在哪?
答案

  • 更快
    • Proxy 代理:Vue2 的响应式像“逐个监听保险箱”(每个属性单独监听),Vue3 的 Proxy 像“直接监控整个房间”(监听整个对象变化)。
    • 编译优化:Vue3 在编译阶段标记哪些是动态内容(如 {{ count }}),更新时跳过静态内容(如纯文字)。
  • 更小:通过 Tree-shaking(摇树优化),只打包你用到的功能,减少代码体积。
  • 更好用
    • Composition API:像搭积木一样组合逻辑(比如把“计数器逻辑”抽成函数,多个组件复用)。
    • 新组件
      • <Teleport>:把组件渲染到任意位置(比如弹窗放到 body 下,避免被父组件样式影响)。
      • <Suspense>:优雅处理异步加载(比如数据加载时显示 Loading 动画)。

2. Composition API vs Options API(场景对比)

问题:为什么要用 Composition API?
答案

  • Options API(Vue2 风格)

    • 把代码按类型分块(data、methods、生命周期),适合简单组件。
    • 缺点:逻辑分散,比如一个“搜索功能”的 data、methods 可能分布在多处。
    // Options API 示例  
    export default {  
      data() { return { keyword: '' } },  
      methods: { search() { ... } },  
      mounted() { this.search() }  
    }  
    
  • Composition API(Vue3 风格)

    • setup() 中,按功能组织代码(比如把搜索相关的数据、方法写在一起)。
    • 优点:逻辑复用更方便(类似 React Hooks)。
    // Composition API 示例  
    export default {  
      setup() {  
        const keyword = ref('');  
        const search = () => { ... };  
        onMounted(search);  
        return { keyword, search };  
      }  
    }  
    

二、响应式原理(手绘理解)

3. Vue3 的响应式原理

问题:Vue3 如何实现数据变化自动更新视图?
答案

  • Proxy 代理对象

    • 当你修改数据时,Proxy 会“拦截”操作(比如 obj.a = 1),通知视图更新。
    • 对比 Vue2:Vue2 使用 Object.defineProperty,无法监听新增属性和数组下标变化(必须用 this.$set)。
  • 代码模拟(简化版):

    function reactive(obj) {  
      return new Proxy(obj, {  
        get(target, key) {  
          console.log('读取了', key);  
          return Reflect.get(target, key);  
        },  
        set(target, key, value) {  
          console.log('更新了', key);  
          return Reflect.set(target, key, value);  
        }  
      });  
    }  
    const obj = reactive({ a: 1 });  
    obj.a = 2; // 触发 set 拦截,更新视图  
    

4. refreactive 的区别(买菜比喻)

问题:什么时候用 ref?什么时候用 reactive
答案

  • ref

    • 用于包装 基本类型(数字、字符串等),因为 Proxy 无法直接监听基本类型。
    • 使用方式:必须通过 .value 访问(就像买菜用袋子装,取菜要打开袋子)。
    const count = ref(0);  
    console.log(count.value); // 0  
    count.value++;  
    
  • reactive

    • 用于包装 对象/数组,可以直接访问属性(就像直接拿菜篮子,不用拆包装)。
    const user = reactive({ name: '张三' });  
    console.log(user.name); // 张三  
    user.name = '李四';  
    
  • 总结

    • 简单值用 ref,复杂对象用 reactive
    • 如果不想写 .value,可以用 toRefs 解构对象(见下文)。

toRefs 是 Vue 3 中用于处理响应式对象的重要工具函数,主要用于将 reactive 对象转换为普通对象,同时确保每个属性都保持响应性。这在解构响应式对象或将其属性传递给子组件时非常有用。

使用场景

  1. 解构响应式对象:直接解构 reactive 对象会失去响应性,而使用 toRefs 可以避免这一问题。
  2. 组件间通信:通过 toRefs 将响应式数据传递给子组件,确保数据在传递过程中仍能保持响应性。

基本用法

import { reactive, toRefs } from 'vue';

const state = reactive({
  foo: 1,
  bar: 2,
});

const stateRefs = toRefs(state);
// stateRefs 的每个属性都是 ref 对象,修改它们的值会触发视图更新

stateRefs.foo.value++; // 视图会自动更新

示例代码

解构并保持响应性
<template>
  <div>
    <p>Foo: {{ foo }}</p>
    <p>Bar: {{ bar }}</p>
    <button @click="incrementFoo">Increment Foo</button>
  </div>
</template>

<script>
import { reactive, toRefs } from 'vue';

export default {
  setup() {
    const state = reactive({
      foo: 1,
      bar: 2,
    });

    const { foo, bar } = toRefs(state);

    function incrementFoo() {
      foo.value++;
    }

    return {
      foo,
      bar,
      incrementFoo,
    };
  },
};
</script>
在组合式 API 中使用
import { reactive, toRefs } from 'vue';

function useCounter() {
  const state = reactive({
    count: 0,
  });

  function increment() {
    state.count++;
  }

  return {
    ...toRefs(state),
    increment,
  };
}

注意事项

  • 访问方式:返回的对象属性是 ref 对象,在 JavaScript 中需通过 .value 访问;模板中则无需 .value
  • 适用范围:仅适用于 reactive 对象,不支持普通对象或 ref 对象。
  • 性能影响:大量属性可能带来一定性能开销。

总结而言,toRefs 提供了一种便捷的方式来处理响应式对象,尤其在需要解构或传递响应式数据时,能够有效简化逻辑并保持数据的响应性。

三、进阶 API 与实战技巧

5. watchwatchEffect(场景区分)

问题:监听数据变化用哪个?
答案

  • watch

    • 明确监听某个数据,适合精确控制(比如监听搜索关键词变化,触发请求)。
    watch(  
      keyword,  
      (newVal) => { fetchData(newVal) },  
      { immediate: true } // 立即执行一次  
    );  
    
  • watchEffect

    • 自动追踪依赖,适合副作用操作(比如根据多个数据变化更新 DOM)。
    watchEffect(() => {  
      console.log('关键词和页码变化了:', keyword.value, page.value);  
      fetchData();  
    });  
    

6. 组件通信:Provide/Inject(跨层级传参)

问题:爷爷组件如何直接传数据给孙子组件?
答案

  • 步骤
    1. 爷爷组件用 provide 提供数据。
    2. 孙子组件用 inject 获取数据。
  • 代码示例
    // 爷爷组件  
    import { provide } from 'vue';  
    setup() {  
      provide('theme', 'dark'); // 提供数据  
    }  
    
    // 孙子组件  
    import { inject } from 'vue';  
    setup() {  
      const theme = inject('theme', 'light'); // 第二个参数是默认值  
      return { theme };  
    }  
    

四、性能优化(通俗策略)

7. 如何让 Vue3 应用更快?

答案

  • 代码层面

    • 使用 v-once 标记静态内容(只渲染一次)。
    • v-memo 缓存动态组件(比如表格行,只有 ID 变化时才重新渲染)。
    <div v-for="item in list" :key="item.id" v-memo="[item.id]">  
      {{ item.name }}  
    </div>  
    
  • 打包优化

    • 按需引入组件库(比如 Element Plus 只导入用到的 Button、Input)。
    • 使用异步组件(懒加载),减少首屏代码体积。
    // 异步加载组件  
    const AsyncComponent = defineAsyncComponent(() => import('./MyComponent.vue'));  
    

五、高频面试代码片段

8. 自定义指令:点击外部关闭弹窗

场景:点击弹窗外部区域关闭弹窗。
代码

// 全局指令 v-click-outside  
app.directive('click-outside', {  
  mounted(el, { value: callback }) {  
    el.handler = (e) => {  
      if (!el.contains(e.target)) callback();  
    };  
    document.addEventListener('click', el.handler);  
  },  
  unmounted(el) {  
    document.removeEventListener('click', el.handler);  
  }  
});  

// 使用  
<template>  
  <div v-click-outside="closeModal">弹窗内容</div>  
</template>  

六、项目经验(回答技巧)

9. 如何回答“封装通用组件”?

示例

  • 场景:封装一个表单组件,支持校验和提交。
  • 步骤
    1. 通过 props 接收表单配置(如字段规则)。
    2. 使用 v-model 绑定每个输入项的值。
    3. 暴露 validate() 方法供父组件调用。
    4. 使用插槽(slot)允许自定义布局。
    <template>  
      <form @submit.prevent="submit">  
        <slot></slot>  
        <button type="submit">提交</button>  
      </form>  
    </template>  
    <script>  
    export default {  
      methods: {  
        validate() { /* 校验逻辑 */ },  
        submit() { this.$emit('submit'); }  
      }  
    }  
    </script>  
    

总结

以上内容通过通俗比喻、实际场景和代码示例,拆解了 Vue3 的核心知识点。建议边学边写代码实践,结合 Vue3 官方文档 查漏补缺!

相关文章:

  • 微信小程序客服消息接收不到微信的回调
  • RT-Thread+STM32L475VET6实现呼吸灯
  • 【PLL】应用:同步
  • EasyRTC:轻量化SDK赋能嵌入式设备,开启智能硬件音视频通讯新篇章
  • 用 Python 构建简易操作系统:探索与实践
  • 在 Mac ARM 架构 (Apple Silicon,例如 M1, M2, M3 芯片) 上使用官方安装包安装 MySQL
  • 贴片式TF卡——雷龙CS SD NAND实测体验
  • shell编程总结
  • Leetcode 位计算
  • 【算法】------区间问题(贪心)
  • 本地部署DeepSeek大模型
  • ORM框架详解:为什么不直接写SQL?
  • MYSQL的第一次
  • C++中const T为什么少见?它有什么用途?
  • 使用 Docker 部署 Flask 应用
  • 【Android】Android 悬浮窗开发 ( 动态权限请求 | 前台服务和通知 | 悬浮窗创建 )
  • Java反射机制
  • Golang访问Google Sheet
  • Java常见问题(一)
  • 新数据结构(12)——代理
  • 下任美联储主席热门人选沃什:美联储犯下“系统性错误”,未能控制一代人以来最严重的通胀
  • 图像编辑新增一款开源模型,阶跃星辰发布Step1X-Edit
  • QFII一季度现身超300家公司:持有南京银行市值最高,5家青睐立航科技
  • 我国对国家发展规划专门立法
  • 泽连斯基与特朗普进行简短会谈
  • 谢震业、梁小静等名将在列,世界田联接力赛中国队名单出炉