element plus table封装

前言

在table数据请求的过程 过于频繁,从而导致页面代码多,封装的目的就是减少相同代码,提高在开发中的效率

封装的目的及好处

  • 隐藏实现细节,逻辑统一处理,只需传递参数内容
  • 低耦合,利于全局扩展,继承所有elemenet plus table的属性及方法
  • 只需配置一个参数及可控制列的显示和隐藏

源码

  • table-props.ts
import { ExtractPropTypes, PropType } from 'vue'

export const tableProps = {/** 是否显示分页 */pagination: {type: Boolean,default: true},/** 请求地址 */url: {type: String,default: ''},/** 默认数据源 */data: {type: Array,default: () => []},/** 请求参数 */params: {type: Object,default: () => ({})},/** 是否立即请求 */init: {type: Boolean,default: true},/** 是否重新加载 */reload: {type: Boolean,default: false},/** 默认显示列 */defaultColumns: {type: Array as PropType<string[]>,default: () => []}
}
export type TableProps = ExtractPropTypes<typeof tableProps> 
  • table.tsx
import { SetupContext } from 'vue'
import { ElTable, ElPagination, vLoading } from 'element-plus'
import { TableProps, tableProps } from './table-props'

import './table.scss'
import { useDataSource } from './composable/userDataSource'
import tableColumn from './TableColumn'
import initMethods from './tableMethods'

export default defineComponent({directives: { loading: vLoading },props: tableProps,emits: ['load', 'update:reload'],setup(props: TableProps, context: SetupContext) {const { slots, attrs, expose } = contextconst tableHeader = slots['table-header']const tableFooter = slots['table-footer']const { paginationState, table, onSortChange } = useDataSource(props, context)const { renderVNode } = tableColumn(props, context)// 初始化 el-table 方法const refTable = ref()const methodObj = initMethods(refTable)expose(methodObj)return () => {// 分页器const paginationEl = (<ElPaginationv-model:current-page={paginationState.currentPage}v-model:page-size={paginationState.pageSize}page-sizes={[10, 20, 30, 50]}total={paginationState.total}layout="total, sizes, prev, pager, next, jumper"class="mt-10px justify-end"/>)return (<div class="c-table h-full flex-1 flex flex-col">{/* 表格头区域 */}<div class="c-table-header mb-10px">{tableHeader && tableHeader()}</div>{/* 表格区域 */}<ElTableref={refTable}v-loading={table.loading}data={table.dataSource}{...attrs}onSort-change={onSortChange}>{renderVNode.value}</ElTable>{/* 表格尾区域 */}<div class="c-table-footer">{tableFooter && tableFooter()}{props.pagination && paginationEl}</div></div>)}}
}) 
  • tableColumns.tsx
import { SetupContext, VNode } from 'vue'
import { ElPopover, ElCheckbox, ElCheckboxGroup, ElButton } from 'element-plus'

import { Icon } from '@/components'
import { TableProps } from './table-props'

// 默认固定列
const fixedColumn = ['selection', 'index', 'operation']
export default function useColumn(props: TableProps, context: SetupContext) {// 默认列const defaultVNode = ref<VNode[]>([])// 需要渲染的列const renderVNode = ref<VNode[]>([])// 复选框选中的列名const checkboxGroupValue = ref<string[]>([])const getProps = (node: VNode) => node.props as any/** 数据列 */const dataColumn = computed(() =>defaultVNode.value.filter((node) => !fixedColumn.includes(getProps(node).type)))/** 表格列 用作 作为 多选框数据源 */const checkboxData = computed(() => {return dataColumn.value.map((item) => {const props = getProps(item)return {field: props.prop,label: props.label}})})/** 设置渲染列 */const setColumn = () => {const result = defaultVNode.value.filter((node) => {const props = getProps(node)if (fixedColumn.includes(props.type)) return nodereturn checkboxGroupValue.value.includes(getProps(node).prop)})renderVNode.value = result}/** 重置渲染列 */const resetColumn = () => {// 如果设置默认显示列if (props.defaultColumns.length > 0) {checkboxGroupValue.value = props.defaultColumns} else {checkboxGroupValue.value = dataColumn.value.map((node) => getProps(node).prop)}setColumn()}const init = () => {if (context.slots.default) {defaultVNode.value = context.slots.default()resetColumn()}}init()// 获取操作列const operation = defaultVNode.value.filter((node) => getProps(node).type === 'operation')if (operation.length > 0) {// 获取操作列 所有插槽const operationSorts = operation[0].children as any// 通过操作 header插槽 自定义内容operationSorts.header = () => {const popoverSlots = {reference: () => <Icon name="ic:round-more-vert" class="ml-5px cursor-pointer" />}const popoverContent = () => {return (<><ElCheckboxGroup v-model={checkboxGroupValue.value}>{checkboxData.value.map((item) => {return <ElCheckbox label={item.field}>{item.label}</ElCheckbox>})}</ElCheckboxGroup><div class="mt-5px"><ElButton type="primary" size="small" onClick={setColumn}>确定</ElButton><ElButton class="ml-5px" size="small" onClick={resetColumn}>重置</ElButton></div></>)}return (<div class="flex flex-y-center">{(operation[0].props as any).label}<ElPopover v-slots={popoverSlots}>{popoverContent()}</ElPopover></div>)}} else {renderVNode.value = defaultVNode.value}return {renderVNode}
} 
  • tableMethods.ts
import { Ref } from 'vue'
export const methods = ['clearSelection','getSelectionRows','toggleRowSelection','toggleAllSelection','toggleRowExpansion','setCurrentRow','clearSort','clearFilter','doLayout','sort','scrollTo','setScrollTop','setScrollLeft'
]
const initMethods = (refTable: Ref) => {const methodObj: Record<string, (...args: any) => void> = {}methods.forEach((method) => {methodObj[method] = (...args: any) => {if (refTable.value && refTable.value[method]) {refTable.value[method](...args)}}})return methodObj
}

export default initMethods 

文档(继承eltable所有属性)

参数 说明 类型 可选值 默认值
pagination 是否分页 boolean true/false true
url 后台请求地址 string - -
data 静态数据源 array - -
params 后台请求参数 object - -
init 是否已经发送请求 boolean true/false true
v-model:reload 是否重新加载数据 boolean true/false true
v-model:firstPage 是否回到第一页 boolean true/false false
defaultColumns(用于控制列的显示) 默认显示列 array - -

事件(继承eltable所有事件)

事件名 说明 事件参数
load 数据加载完成事件 (data:any)=>void

插槽

插槽名 说名 子标签
table-header table 顶部插槽 -
table-footer table 底部插槽 -

基本用法

<template><PageContainer><c-table :data="tableData" :pagination="false" style="width: 100%"><template #table-header><el-button type="primary"><icon name="ep:plus">新增</icon></el-button></template><el-table-column prop="date" label="Date" width="180" /><el-table-column prop="name" label="Name" width="180" /><el-table-column prop="address" label="Address" /></c-table></PageContainer>
</template>
<script lang="ts" setup> import { PageContainer, CTable, Icon } from '@/components'
const tableData = [{date: '2016-05-03',name: 'Tom',address: 'No. 189, Grove St, Los Angeles'},{date: '2016-05-02',name: 'Tom',address: 'No. 189, Grove St, Los Angeles'},{date: '2016-05-04',name: 'Tom',address: 'No. 189, Grove St, Los Angeles'},{date: '2016-05-01',name: 'Tom',address: 'No. 189, Grove St, Los Angeles'}
] </script> 

进阶用法

<template><PageContainer><template #header><el-form inline @submit.prevent><el-form-item label="姓名:"><el-input v-model="queryParams.name" class="w-250px" @change="onQuery" /></el-form-item><el-form-item label="性别:"><el-select v-model="queryParams.sex" class="w-250px"><el-option label="男" value="男" /><el-option label="女" value="女" /></el-select></el-form-item><el-form-item label="是否已婚:"><el-select v-model="queryParams.married" class="w-250px"><el-option label="是" value="是" /><el-option label="否" value="否" /></el-select></el-form-item><el-form-item label="生日:"><el-date-picker v-model="queryParams.birth" type="date" /></el-form-item><el-form-item label="地址:"><el-input v-model="queryParams.addr" class="w-250px" @change="onQuery" /></el-form-item><el-form-item label="邮箱:"><el-input v-model="queryParams.email" class="w-250px" @change="onQuery" /></el-form-item><el-form-item><el-button type="primary" @click.stop="onQuery"><icon name="ep:search"> 查询 </icon></el-button><el-button><icon name="ep:brush">重置</icon></el-button><el-button @click="onClick">全选/反选</el-button></el-form-item></el-form></template><c-table ref="refTable" v-model:reload="reload" url="/user" :params="queryParams"><template #table-header><el-button type="primary"><icon name="ep:plus">新增用户</icon></el-button></template><el-table-column type="selection" width="55" /><el-table-column type="index" width="50" /><el-table-column label="id" prop="id" sortable show-overflow-tooltip></el-table-column><el-table-column label="姓名" prop="name" sortable></el-table-column><el-table-column label="年龄" prop="age"></el-table-column><el-table-column label="财产" prop="asset"></el-table-column><el-table-column label="是否已婚" prop="married"></el-table-column><el-table-column label="生日" prop="birth" show-overflow-tooltip></el-table-column><el-table-column label="地址" prop="addr" show-overflow-tooltip></el-table-column><el-table-column label="邮箱" prop="email" show-overflow-tooltip></el-table-column><el-table-column label="操作" type="operation"><el-button link type="primary" size="small">修改</el-button><el-button link type="danger" size="small">删除</el-button></el-table-column></c-table></PageContainer>
</template>
<script lang="ts" setup> import { CTable, PageContainer, Icon } from '@/components'
defineOptions({ name: 'Workbench' })
const queryParams = reactive({name: undefined,birth: undefined,sex: undefined,married: undefined,addr: '',email: ''
})
const reload = ref(false)
const onQuery = () => {reload.value = true
}

const refTable = ref()
const onClick = () => {refTable.value.toggleAllSelection()
} </script> 

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

猜你喜欢

转载自blog.csdn.net/weixin_53312997/article/details/129597617
今日推荐