面试题:如何使用 Vue 编写一个 Tab 切换组件?请介绍设计思路

编写一个 Tab 切换组件是 Vue 中常见的需求,主要涉及动态渲染和状态管理。以下是设计思路和实现步骤:


设计思路

  1. 组件结构
    • Tabs 组件:外层容器,管理当前选中的 Tab。
    • Tab 组件:单个 Tab 项,包含标题和内容。
  2. 数据驱动
    • 使用 props 传递 Tab 数据(如标题和内容)。
    • 使用 v-model 或 v-on 实现 Tab 切换。
  3. 动态渲染
    • 根据当前选中的 Tab,动态渲染对应的内容。
  4. 样式与交互
    • 使用 CSS 实现 Tab 的选中状态样式。
    • 支持点击切换 Tab。

实现步骤

1. 创建 Tabs 组件

Tabs 组件负责管理当前选中的 Tab 和渲染子组件。

<template>
  <div class="tabs">
    <div class="tabs-header">
      <!-- 渲染 Tab 标题 -->
      <div
        v-for="(tab, index) in tabs"
        :key="index"
        :class="['tab-header-item', { active: index === activeIndex }]"
        @click="changeTab(index)"
      >
        {{ tab.title }}
      </div>
    </div>
    <div class="tabs-content">
      <!-- 渲染当前选中的 Tab 内容 -->
      <slot :name="`tab-${activeIndex}`"></slot>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    tabs: {
      type: Array,
      required: true,
    },
    initialIndex: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      activeIndex: this.initialIndex, // 当前选中的 Tab 索引
    };
  },
  methods: {
    changeTab(index) {
      this.activeIndex = index; // 切换 Tab
    },
  },
};
</script>

<style scoped>
.tabs-header {
  display: flex;
  border-bottom: 1px solid #ccc;
}

.tab-header-item {
  padding: 10px 20px;
  cursor: pointer;
}

.tab-header-item.active {
  border-bottom: 2px solid #42b983;
  font-weight: bold;
}

.tabs-content {
  padding: 20px;
}
</style>

2. 使用 Tabs 组件

在父组件中使用 Tabs 组件,并传递 Tab 数据。

<template>
  <div>
    <Tabs :tabs="tabs" :initialIndex="0">
      <!-- 使用具名插槽渲染 Tab 内容 -->
      <template v-slot:tab-0>
        <div>这是 Tab 1 的内容</div>
      </template>
      <template v-slot:tab-1>
        <div>这是 Tab 2 的内容</div>
      </template>
      <template v-slot:tab-2>
        <div>这是 Tab 3 的内容</div>
      </template>
    </Tabs>
  </div>
</template>

<script>
import Tabs from './Tabs.vue';

export default {
  components: {
    Tabs,
  },
  data() {
    return {
      tabs: [
        { title: 'Tab 1' },
        { title: 'Tab 2' },
        { title: 'Tab 3' },
      ],
    };
  },
};
</script>

优化与扩展

  1. 动态 Tab 内容
    • 可以通过 v-for 动态生成 Tab 内容,而不是硬编码。
  2. 动画效果
    • 使用 Vue 的 <transition> 组件为 Tab 切换添加动画效果。
  3. 支持路由
    • 将 Tab 切换与 Vue Router 结合,实现路由级别的 Tab 切换。
  4. 响应式设计
    • 使用 CSS 媒体查询或 Flexbox/Grid 布局,使 Tab 组件适配移动端。

完整代码示例

以下是完整的 Tabs 组件和父组件的代码:

Tabs.vue

<template>
  <div class="tabs">
    <div class="tabs-header">
      <div
        v-for="(tab, index) in tabs"
        :key="index"
        :class="['tab-header-item', { active: index === activeIndex }]"
        @click="changeTab(index)"
      >
        {{ tab.title }}
      </div>
    </div>
    <div class="tabs-content">
      <slot :name="`tab-${activeIndex}`"></slot>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    tabs: {
      type: Array,
      required: true,
    },
    initialIndex: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      activeIndex: this.initialIndex,
    };
  },
  methods: {
    changeTab(index) {
      this.activeIndex = index;
    },
  },
};
</script>

<style scoped>
.tabs-header {
  display: flex;
  border-bottom: 1px solid #ccc;
}

.tab-header-item {
  padding: 10px 20px;
  cursor: pointer;
}

.tab-header-item.active {
  border-bottom: 2px solid #42b983;
  font-weight: bold;
}

.tabs-content {
  padding: 20px;
}
</style>

App.vue

<template>
  <div>
    <Tabs :tabs="tabs" :initialIndex="0">
      <template v-slot:tab-0>
        <div>这是 Tab 1 的内容</div>
      </template>
      <template v-slot:tab-1>
        <div>这是 Tab 2 的内容</div>
      </template>
      <template v-slot:tab-2>
        <div>这是 Tab 3 的内容</div>
      </template>
    </Tabs>
  </div>
</template>

<script>
import Tabs from './Tabs.vue';

export default {
  components: {
    Tabs,
  },
  data() {
    return {
      tabs: [
        { title: 'Tab 1' },
        { title: 'Tab 2' },
        { title: 'Tab 3' },
      ],
    };
  },
};
</script>

总结

通过 Vue 的动态渲染和状态管理,可以轻松实现一个 Tab 切换组件。通过插槽和 props,组件可以灵活扩展,满足不同的业务需求。

THE END
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容