MST

星途 面试题库

面试题:Vue 2 升级到 Vue 3 过程中,Composition API 对代码重构与组织的深度实践

假设你正在将一个大型 Vue 2 项目升级到 Vue 3 并全面使用 Composition API 重构代码。请详细描述你会采取的步骤,如何将原有的 Options API 逻辑迁移到 Composition API 以增强代码组织能力,怎样处理可能出现的兼容性问题和性能瓶颈,以及在重构过程中如何保证代码的可维护性和扩展性。
35.4万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

1. 项目初始化与环境准备

  1. 安装 Vue 3: 确保项目的 package.json 中,将 vue 版本更新为 Vue 3 相关版本,例如 ^3.0.0。然后执行 npm installyarn install 安装依赖。
  2. 构建工具升级: 如果项目使用 webpack,需确保 webpack 及相关 loader(如 vue - loader)版本支持 Vue 3。对于 vue - cli 创建的项目,可使用 vue - cli 最新版本来初始化新项目结构,再将原项目文件逐步迁移进去。

2. Options API 逻辑迁移到 Composition API

  1. 组件转换
    • 数据属性: 在 Options API 中,数据定义在 data 函数里。在 Composition API 中,使用 reactiveref 来定义响应式数据。例如:
// Options API
export default {
  data() {
    return {
      count: 0
    }
  }
}

// Composition API
import { ref } from 'vue';
export default {
  setup() {
    const count = ref(0);
    return {
      count
    };
  }
}
- **计算属性**:

Options API 中的计算属性在 computed 对象中定义。在 Composition API 中,使用 computed 函数。例如:

// Options API
export default {
  data() {
    return {
      count: 1
    }
  },
  computed: {
    doubleCount() {
      return this.count * 2;
    }
  }
}

// Composition API
import { ref, computed } from 'vue';
export default {
  setup() {
    const count = ref(1);
    const doubleCount = computed(() => count.value * 2);
    return {
      count,
      doubleCount
    };
  }
}
- **方法**:

Options API 中的方法定义在 methods 对象里。在 Composition API 中,直接在 setup 函数中定义函数并返回。例如:

// Options API
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++;
    }
  }
}

// Composition API
import { ref } from 'vue';
export default {
  setup() {
    const count = ref(0);
    const increment = () => {
      count.value++;
    };
    return {
      count,
      increment
    };
  }
}
- **生命周期钩子**:

Options API 中的生命周期钩子直接在组件对象中定义,如 createdmounted 等。在 Composition API 中,使用对应的生命周期函数。例如:

// Options API
export default {
  created() {
    console.log('Component created');
  }
}

// Composition API
import { onBeforeMount } from 'vue';
export default {
  setup() {
    onBeforeMount(() => {
      console.log('Component created');
    });
  }
}
  1. 逻辑拆分与复用
    • 提取逻辑到独立函数: 可以将相关逻辑提取到独立的函数中,在 setup 函数中调用。例如,对于一个获取用户信息的逻辑:
// userInfo.js
import { ref, onMounted } from 'vue';
export const useUserInfo = () => {
  const userInfo = ref(null);
  onMounted(() => {
    // 模拟异步获取用户信息
    setTimeout(() => {
      userInfo.value = { name: 'John' };
    }, 1000);
  });
  return {
    userInfo
  };
};

// 组件中使用
import { setup } from 'vue';
import { useUserInfo } from './userInfo.js';
export default {
  setup() {
    const { userInfo } = useUserInfo();
    return {
      userInfo
    };
  }
}

3. 处理兼容性问题

  1. API 兼容性
    • 废弃 API: Vue 3 废弃了一些 Vue 2 的 API,如 this.$onthis.$offthis.$once。对于事件总线功能,Vue 3 推荐使用 mitttiny - emitter 等第三方库实现。例如,安装 mittnpm install mitt,使用方式如下:
import mitt from'mitt';
const emitter = mitt();
// 监听事件
emitter.on('eventName', () => {
  console.log('Event received');
});
// 触发事件
emitter.emit('eventName');
- **全局 API 变更**:

Vue 3 中全局 API 有变更,如 Vue.component 在 Vue 3 中变为 app.component。对于创建全局应用实例,Vue 3 使用 createApp 方法。例如:

// Vue 2
import Vue from 'vue';
import App from './App.vue';
new Vue({
  render: h => h(App)
}).$mount('#app');

// Vue 3
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
  1. 模板语法兼容性
    • v - model 语法: Vue 3 中 v - model 语法有变化。在 Vue 2 中,v - model 对自定义组件默认绑定 value 属性和 input 事件。在 Vue 3 中,v - model 绑定 modelValue 属性和 update:modelValue 事件。例如:
<!-- Vue 2 自定义组件 -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)">
</template>
<script>
export default {
  props: ['value']
};
</script>

<!-- Vue 3 自定义组件 -->
<template>
  <input :modelValue="modelValue" @input="$emit('update:modelValue', $event.target.value)">
</template>
<script>
export default {
  props: ['modelValue']
};
</script>

4. 处理性能瓶颈

  1. 优化响应式数据
    • 避免不必要的响应式: 使用 refreactive 时,确保只对需要响应式的部分进行定义。例如,如果一个对象只有部分属性需要响应式,可使用 ref 包裹单个属性,而不是用 reactive 包裹整个对象。
    • 深度响应式与浅层响应式reactive 创建的是深度响应式对象,对于大型对象可能存在性能问题。如果不需要深度响应式,可使用 shallowReactive 创建浅层响应式对象。例如:
import { shallowReactive } from 'vue';
const obj = shallowReactive({
  data: {
    subData: 'initial value'
  }
});
// 直接修改 obj.data 不会触发视图更新,需手动处理
obj.data = { newSubData: 'new value' };
  1. 组件优化
    • 懒加载组件: 对于大型项目中不常用的组件,使用懒加载。在 Vue 3 中,可使用 defineAsyncComponent 实现。例如:
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue'));
- **缓存组件**:

对于频繁切换但内容不变的组件,可使用 keep - alive 进行缓存。在 Vue 3 中用法与 Vue 2 类似:

<keep - alive>
  <component :is="currentComponent"></component>
</keep - alive>

5. 保证代码的可维护性和扩展性

  1. 代码结构优化
    • 文件夹和文件命名: 保持清晰的文件夹结构,按照功能或模块划分文件夹。文件命名采用有意义的命名方式,如 userInfo.jsuserList.vue 等。
    • 逻辑分层: 将业务逻辑、数据获取、UI 展示等逻辑进行分层。例如,将数据获取逻辑放在 api 文件夹下的文件中,业务逻辑放在 composables 文件夹下的自定义 composable 函数中。
  2. 文档编写
    • 组件文档: 为每个组件编写详细的文档,包括组件的功能、props、emits、使用示例等。可以使用 vue - docgen - api 等工具自动生成文档。
    • 逻辑文档: 对于复杂的逻辑,特别是自定义 composable 函数,添加注释说明其功能、参数、返回值以及使用场景。
  3. 测试与持续集成
    • 单元测试: 使用测试框架(如 jest 结合 @vue/test - utils)对组件和 composable 函数进行单元测试。确保每个功能模块都有相应的测试用例覆盖。
    • 集成测试: 进行集成测试,验证组件之间的交互和整个系统的功能。可以使用 cypress 等工具进行端到端测试。
    • 持续集成: 设置持续集成(如使用 GitHub ActionsGitLab CI 等),在每次代码提交或合并时自动运行测试,确保代码质量。