机试:封装通用Table组件

414 阅读6分钟

前言

各位掘友们,很长时间没有更新文章了,原因是之前我一直在面试,寻找工作,功夫不负有心人,终于在历经三面之后,成功上岸了。wcis,bro,一切艰辛尽在不言中,相信懂的兄弟都懂。经过一段时间在公司的适应之后,我也是迫不及待想和掘友们分享一些面试的经验,这次想先跳过第一轮面试的八股以及一些基础题,直接来到二面的机试。

二面的机试内容主要分为两部分,第一部分是封装一个通用组件,第二部分是通过 Css 实现一个图标,今天先和大家聊一聊如何封装一个简易的通用组件。面试要求使用的技术栈是 Vue3 + TS

先拿ElemenPlus官网中的table组件为实例,一起来实现一个通用的组件,如下图所示:

image.png

话不多说,让我们开始吧!

封装全局通用组件流程

1. 明确需求与功能

在动手之前,我们应该明确一下设计一个table组件的需求与功能,这也是面试官对我重复了三遍的话,要一定要先构思,先想想再动手,不要一上来就thead、th...,于是我看着这个table示例图,陷入了沉思...

表格组件的核心需求:从通用组件的角度来看,表格组件应避免依赖具体的数据源,数据应由父组件传入。组件的作用主要是负责数据的展示与交互,任何数据的处理和逻辑控制都交由父组件完成。

  • 数据展示:表格组件的核心任务是展示父组件传入的数据源,因此,组件内不应有数据源,而是通过 props 接收父组件的数据。

  • 动态列配置:为了适应不同场景需求,表格应支持通过配置对象动态定义列的内容、宽度、对齐方式等。这一设计使表格能够适应多种结构,而无需硬编码列信息。

2. 设计思路与组件架构

  • 组件的灵活性与可扩展性:在设计组件时,尽量做到单一职责和高内聚,使组件既能满足需求,又能在不同场景下被复用。

    • 基础框架:组件的核心框架应独立于具体业务逻辑,使其成为一个能适应不同场景的“骨架”组件。
    • 需求模块化:把展示数据等需求模块化,确保每个功能都能通过 props 动态配置和切换。
  • Props设计:传入数据:Props 设计时需要确保参数的清晰性和简洁性,使父组件在传入参数时更易理解和使用。

    • data: Array<object> - 通过父组件传入的数据源,由组件进行展示,但组件本身不持有或修改数据。
    • columns: Array<object> - 列的配置项,包括每列的 keytitle 等,支持动态显示不同内容的列。
  • 插槽的使用:支持动态内容插入:在表格组件中插槽非常重要,能确保组件灵活性,允许父组件插入自定义内容。

  • 事件传递与自定义事件:在父子组件交互时,通过事件传递能让组件更易复用。

3. TypeScript 类型设计

  • 类型声明:使用 TypeScript 声明 Props 和事件的类型,确保参数传递的规范性与清晰性。

    • 表格组件的类型设计,包括数据源的类型 TableData、列配置类型 TableColumn
// 定义表格数据的类型
export interface DataItem {
    id: number;
    name?: string;
    address?: string
}
// 定义列配置的类型
export interface Column {
    key: string;
    title: string;
}

4. 插槽的使用

  1. 表格插槽的设计

    • 插槽(Slot)设计为一种可选的配置,当需要特殊渲染时,父组件可以通过插槽自定义内容,比如在表格尾部加入自定义内容。
    • 例如,允许在最后一列插入操作按钮,或为表头提供具备交互性的筛选功能。
  2. 插槽实现方式

    • 默认状态下没有插槽内容,父组件若不传入插槽,表格就按基础表格的结构渲染。

5. 事件传递与自定义事件

  1. 事件设计

    • 使用 Vue 的 emit 来触发事件,将事件从子组件传递给父组件。这样父组件可以监听并处理来自表格组件的交互事件,比如点击行触发的选中事件。
  2. 自定义事件的场景

    • 行点击事件:当用户点击某一行时,可以通过事件将该行数据传递到父组件。
    • 按钮事件:如果表格包含操作列,则按钮的点击事件应当传递到父组件,以便做出相应的处理。

6. 组件的封装与插件化

  1. Table 组件封装

    • 使用 defineProps 来定义表格所需的 datacolumns,为组件提供动态数据支持。
    • 基础模板使用 <table> 元素结构展示表格,配合 v-for 渲染每列和每行数据。
<template>
    <div>
        <table>
            <thead>
                <tr>
                    <th v-for="item in columns" :key="item.key">
                        {{ item.title }}
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="item in data" :key="item.id">
                    <td v-for="col in columns" :key="col.key">
                        {{ item[each.key as keyof DataItem] }}
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script setup lang="ts">
import { defineProps,defineOptions } from 'vue';
import type {DataItem} from '../../types/DataItem'
import type {Columns} from '../../types/Columns'

// 定义组件名称
defineOptions({
    name: 'ElTable'
});

const props = defineProps<{
    data: DataItem[];
    columns: Column[];
}>();

</script>

<style scoped>
/* 根据需要编写样式 */
table {
    table-layout: fixed;
    border-collapse: collapse;
}

th, td {
    padding: 5px 30px;
    border-bottom: 1px solid #ddd;
    text-align: left;
}
</style>

  1. 插件化设计

    • index.ts 文件中,将 Table 封装为插件,通过 Vue 的 install 方法实现全局注册,确保组件能够在项目任意位置使用。
// index.ts
import type { App } from 'vue';
import ElTable from './Table.vue';

export default {
    install(app: App) {
        app.component(ElTable.name, ElTable);
    }
};
  • install 方法是 Vue 插件的标准接口,用于在 app 实例上注册全局组件。

  • app.component 方法将 ElTable 注册为全局组件,命名为 'ElTable'

  1. 在 main.ts 中注册插件

    • main.ts 中引入该插件,并使用 app.use(ElTable) 完成全局注册。
import { createApp } from 'vue'
import App from './App.vue'
import ElTable from './components/table/index'

createApp(App).use(ElTable).mount('#app')

7. 组件调用与示例

  1. 在 App.vue 中调用组件

    • 在父组件 App.vue 中,直接使用 <el-table /> 并传入所需的 datacolumns
  2. 数据示例

    • 数据示例可以是一个简单的对象数组,每个对象包含多列信息,同时传入列名的配置项。
// App.vue
<template>
    <div>
        <el-table :data="tableData" :columns="tableColumns" />
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const tableData = [
    {id: 1, name: 'Alice', address: 'xxxxx'},
    {id: 2, name: 'Alice', address: 'xxxxx'},
    {id: 3, name: 'Alice', address: 'xxxxx'},
];

const tableColumns = [
    {title: '', key: 'id'},
    {title: 'Name', key: 'name'},
    {title: 'Address', key: 'address'}
]
</script>

效果展示

image.png

总结与反思

Table 组件通过接收动态列配置和数据源,实现了高扩展性和灵活性,适用于展示不同类型的数据。组件封装过程中注重可配置性和通用性,并通过全局注册便于项目中的重复使用,为实际开发中的表格功能提供了模块化的解决方案。希望以上能够在面试中帮助到你,

记得点赞收藏+关注哦

点赞.jfif