【vue高频面试题—场景篇】:如何优雅地处理跨组件的复杂业务逻辑复用?

48 阅读3分钟

1. 场景背景

面试官提问: “在大型项目中,我们经常遇到多个页面都有相似的功能,比如:‘表格的搜索/分页/加载状态’、‘倒计时功能’或者是‘埋点上报逻辑’。如果每个页面都写一遍,代码会非常臃肿。在 Vue 3 中,你会如何设计一套方案来复用这些逻辑?为什么要这么设计?它比 Vue 2 的 Mixins 好在哪里?”


2. 核心考点

  • Hooks(Composition API) 的设计思想。
  • 逻辑抽象能力(把业务代码抽离为无 UI 的逻辑函数)。
  • 对比 Mixins 的缺陷(命名冲突、来源不明、隐式依赖)。
  • 响应式丢失问题(如何正确解构 Hooks 的返回值)。

3. 综合解决方案

方案:封装自定义 Hook (useTable / useList)

思路: 将“状态”和“改变状态的方法”封装在一个函数中,并返回响应式数据。

实现示例(以通用的表格加载逻辑为例):

TypeScript

// useTable.ts
import { ref, onMounted } from 'vue';

export function useTable(apiFn: Function, params = {}) {
  const data = ref([]);
  const loading = ref(false);
  const total = ref(0);

  const fetchList = async () => {
    loading.value = true;
    try {
      const res = await apiFn(params);
      data.value = res.list;
      total.value = res.total;
    } finally {
      loading.value = false;
    }
  };

  onMounted(fetchList);

  return { data, loading, total, fetchList };
}

业务组件使用:

代码段

<script setup>
import { useTable } from '@/hooks/useTable';
import { getOrderList } from '@/api/order';

// 逻辑一键引入,保持 setup 简洁
const { data: orders, loading } = useTable(getOrderList, { status: 1 });
</script>

4. 满分回答示例

回答要点: “我会优先使用 Vue 3 的 Composition API 封装自定义 Hooks 来解决逻辑复用问题。

  1. 实现方式: 我会将具有通用性的业务逻辑抽离到 src/hooks 文件夹下。每个 Hook 实际上是一个以 use 开头的函数,它内部可以维护自己的 refreactive 状态,并利用 onMounted 等生命周期钩子。最后将组件需要用到的状态和方法 return 出来。

  2. 对比 Mixins 的优势:

    • 来源清晰: 在组件中,我们可以清楚地看到某个变量是从哪个 Hook 中解构出来的,而 Mixins 是‘隐式注入’,很难追溯。
    • 解决命名冲突: Hooks 返回的是普通变量,我们可以在解构时重命名(如 const { data: userList } = useList()),完全避开了 Mixins 变量名覆盖的问题。
    • 灵活性: Hooks 可以接收参数(如 API 函数或配置项),从而根据不同场景动态调整逻辑。
  3. 注意事项: 在封装时,我会注意为了保持响应式,返回的对象通常使用 reftoRefs 处理。此外,我会遵循‘单一职责原则’,一个 Hook 只处理一个独立的业务维度(比如 useAuth 处理权限,usePagination 处理分页)。”


5. 查漏补缺(进阶加分项)

  • 与 Teleport 结合: 如果逻辑涉及弹窗(如全局 Loading),Hook 可以配合 Teleport 实现逻辑与 DOM 的双重解耦。
  • 单例模式: 有些 Hook(如 useUser)需要全局共享状态,我会配合 provide/inject 或者 Pinia 来确保数据在整个应用中是同一份。
  • 组合性: 强调 Hooks 之间是可以互相嵌套使用的,这种“乐高式”的开发体验是 Vue 3 最大的架构进步。