前言
各位掘友们,很长时间没有更新文章了,原因是之前我一直在面试,寻找工作,功夫不负有心人,终于在历经三面之后,成功上岸了。wcis,bro,一切艰辛尽在不言中,相信懂的兄弟都懂。经过一段时间在公司的适应之后,我也是迫不及待想和掘友们分享一些面试的经验,这次想先跳过第一轮面试的八股以及一些基础题,直接来到二面的机试。
二面的机试内容主要分为两部分,第一部分是封装一个通用组件,第二部分是通过 Css 实现一个图标,今天先和大家聊一聊如何封装一个简易的通用组件。面试要求使用的技术栈是 Vue3 + TS
先拿ElemenPlus官网中的table组件为实例,一起来实现一个通用的组件,如下图所示:
封装全局通用组件流程
1. 明确需求与功能
在动手之前,我们应该明确一下设计一个table组件的需求与功能,这也是面试官对我重复了三遍的话,要一定要先构思,先想想再动手,不要一上来就thead、th...,于是我看着这个table示例图,陷入了沉思...
表格组件的核心需求:从通用组件的角度来看,表格组件应避免依赖具体的数据源,数据应由父组件传入。组件的作用主要是负责数据的展示与交互,任何数据的处理和逻辑控制都交由父组件完成。
-
数据展示:表格组件的核心任务是展示父组件传入的数据源,因此,组件内不应有数据源,而是通过
props接收父组件的数据。 -
动态列配置:为了适应不同场景需求,表格应支持通过配置对象动态定义列的内容、宽度、对齐方式等。这一设计使表格能够适应多种结构,而无需硬编码列信息。
2. 设计思路与组件架构
-
组件的灵活性与可扩展性:在设计组件时,尽量做到单一职责和高内聚,使组件既能满足需求,又能在不同场景下被复用。
- 基础框架:组件的核心框架应独立于具体业务逻辑,使其成为一个能适应不同场景的“骨架”组件。
- 需求模块化:把展示数据等需求模块化,确保每个功能都能通过
props动态配置和切换。
-
Props设计:传入数据:Props 设计时需要确保参数的清晰性和简洁性,使父组件在传入参数时更易理解和使用。
data:Array<object>- 通过父组件传入的数据源,由组件进行展示,但组件本身不持有或修改数据。columns:Array<object>- 列的配置项,包括每列的key、title等,支持动态显示不同内容的列。
-
插槽的使用:支持动态内容插入:在表格组件中插槽非常重要,能确保组件灵活性,允许父组件插入自定义内容。
-
事件传递与自定义事件:在父子组件交互时,通过事件传递能让组件更易复用。
3. TypeScript 类型设计
-
类型声明:使用 TypeScript 声明 Props 和事件的类型,确保参数传递的规范性与清晰性。
- 表格组件的类型设计,包括数据源的类型
TableData、列配置类型TableColumn。
- 表格组件的类型设计,包括数据源的类型
// 定义表格数据的类型
export interface DataItem {
id: number;
name?: string;
address?: string
}
// 定义列配置的类型
export interface Column {
key: string;
title: string;
}
4. 插槽的使用
-
表格插槽的设计:
- 插槽(Slot)设计为一种可选的配置,当需要特殊渲染时,父组件可以通过插槽自定义内容,比如在表格尾部加入自定义内容。
- 例如,允许在最后一列插入操作按钮,或为表头提供具备交互性的筛选功能。
-
插槽实现方式:
- 默认状态下没有插槽内容,父组件若不传入插槽,表格就按基础表格的结构渲染。
5. 事件传递与自定义事件
-
事件设计:
- 使用 Vue 的
emit来触发事件,将事件从子组件传递给父组件。这样父组件可以监听并处理来自表格组件的交互事件,比如点击行触发的选中事件。
- 使用 Vue 的
-
自定义事件的场景:
- 行点击事件:当用户点击某一行时,可以通过事件将该行数据传递到父组件。
- 按钮事件:如果表格包含操作列,则按钮的点击事件应当传递到父组件,以便做出相应的处理。
6. 组件的封装与插件化
-
Table 组件封装:
- 使用
defineProps来定义表格所需的data和columns,为组件提供动态数据支持。 - 基础模板使用
<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>
-
插件化设计:
- 在
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'。
-
在 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. 组件调用与示例
-
在 App.vue 中调用组件:
- 在父组件
App.vue中,直接使用<el-table />并传入所需的data和columns。
- 在父组件
-
数据示例:
- 数据示例可以是一个简单的对象数组,每个对象包含多列信息,同时传入列名的配置项。
// 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>
效果展示
总结与反思
Table 组件通过接收动态列配置和数据源,实现了高扩展性和灵活性,适用于展示不同类型的数据。组件封装过程中注重可配置性和通用性,并通过全局注册便于项目中的重复使用,为实际开发中的表格功能提供了模块化的解决方案。希望以上能够在面试中帮助到你,
记得点赞收藏+关注哦