当前位置:   article > 正文

️️️Vue3+Element-Plus二次封装一个可定制化的table组件_element-plus封装table表格

element-plus封装table表格

前言

为什么需要二次封装

开发后台管理系统,会接触到很多表格和表单,一但表格表单多起来,仅仅只需要一小部分改变,都需要在中重写一大堆代码,许多重复逻辑,我们可以把重复逻辑抽离出来二次封装一个组件
使用,减少在开发中需要编写的代码。

为什么需要定制化

每个项目或业务都有自己的特点和需求,可能需要特定的样式、交互行为或功能。通过定制化组件,可以根据具体需求进行定制提高复用性,使得组件更符合业务场景,而且定制化可以使组件更加贴近实际业务需求。

需要了解的前置知识

vue3中插槽slot与template

v-bind的使用

v-bind=“$attrs”

el-table的基本属性

不多废话,创建文件Hytable,开始代码

这是一个el-plus基础表格

//Hytable.vue
<template>
  <el-table :data="tableData" style="width: 100%">
    <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" />
  </el-table>
</template>

<script lang="ts" setup>
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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

一般的表格数据(TableData)是在父组件中请求返回的

//HyTable.vue
<template>
 <el-table :data="tableData" style="width: 100%">
    <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" /> 
   </el-table>
</template>
<script lang="ts" setup>
import requestTabledata from '../api/index.ts'
interface TableProps{
requestApi?: (params: any) => Promise<any>; 
}
// 接受父组件参数,配置默认值
const props = withDefaults(defineProps<TableProps>(), {
	requestApi: requestTableData
});
let tableData= ref([])

const getTableList = async (api:any) => {
let { data } = await api();
tableData.value = data
};
onMounted(() => {
getTableList(props.requestApi)
})	
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

我们可以看到el-table-column有很多重复的代码,如何让他根据父组件的传递值来动态的生成列的配置呢

我们先来看下table-column的属性
image.png
这里我们可以用\<template>来包裹el-table-column组件再用v-for来遍历

为什么要使用<template>来包裹,因为等下需要根据列配置用v-if判断el-table-column是否存在列配置type或prop属性,父组件需要传递列配置。

//HyTable.vue

<template>
 <el-table :data="tableData" style="width: 100%" row-key="id">
<template v-for="item in columnData" :key="columnData.item">
<el-table-column

v-if="item.type && ['selection','index','expand'].includes(item.type)"

v-bind="item"

:align="'center'"

:reserve-selection="item.type == 'selection'">

<template #default="scope">

<template v-if="item.type === 'expand'">

<slot :name="item.type" v-bind="scope" />

</template>

</template>

</el-table-column>

<el-table-column v-if="!item.type && item.prop" v-bind="item" :align="'center'" >

<template #default="scope">

<slot :name="item.prop" v-bind="scope" :row="scope.row">

{{ scope.row[item.prop] }}

</slot>

</template>

</el-table-column>
</template> 
  </el-table>
</template>
<script setup lang="ts" name="Hytable">
import { onMounted, ref } from "vue";
import {requestTableData} from "../../api/index.ts"

interface TableProps{
columns: any,
requestApi?: (params?: any) => Promise<any>;
}

const props = withDefaults(defineProps<TableProps>(), {
columns: [],
requestApi: requestTableData
});
// 将列设置响应化
const columnData = ref(props.columns);

let tableData= ref([])

const getTableList = async (api:any) => {
let { data } = await api();
tableData.value = data
};
onMounted(() => {
getTableList(props.requestApi)
})	
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

增加无数据和表格最后一行的插槽

<template>
 <el-table :data="tableData" style="width: 100%">
<template v-for="item in columnData" :key="columnData.item">
<el-table-column
v-if="item.type && ['selection','index','expand'].includes(item.type)"
v-bind="item"
:align="'center'"
:reserve-selection="item.type == 'selection'">
<template #default="scope">

<template v-if="item.type === 'expand'">

<slot :name="item.type" v-bind="scope" />

</template>

</template>

</el-table-column>

<el-table-column v-if="!item.type && item.prop" v-bind="item" :align="'center'" >

<template #default="scope">

<slot :name="item.prop" v-bind="scope" :row="scope.row">

{{ scope.row[item.prop] }}

</slot>
</template>
</el-table-column>
</template> 
<!-- 这是el-table组件自带的插槽 -->
<template #append>
<slot name="append" />
</template>
<!-- 无数据 -->
<template #empty>
<div class="table-empty">
<slot name="empty">
<div>暂无数据</div>
</slot>
</div>
</template>
  </el-table>
</template> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

基本封装已经完成了 实现根据父组件传入数据来实现表格的行与列

让我们来使用一波

//父组件
<template>

<Hytable :columns="columnData" >

<template #expand="scope">

{{scope.row}}

</template>

<template #gender="scope">

<el-button type="primary"  plain>

{{ scope.row.gender}}

</el-button>

</template>

<template #operation>

<el-button

type="primary"

link

:icon="View"

>查看</el-button

>

<el-button

type="primary"

link

:icon="EditPen"

>编辑</el-button

>

<el-button

type="primary"

link

:icon="Delete"

>删除</el-button

>

</template>

</HyTable>

</template>

  

<script setup lang="ts">

import Hytable from '../components/testTable/index.vue';

import {Delete, EditPen, View} from "@element-plus/icons-vue";

import { ElMessage} from "element-plus";

const columnData =

[

{ type: 'selection', fixed: 'left', width: 70 },

{ type: 'expand', label: 'Expand', width: 80 },

{ prop: 'name', label: '姓名', search: { el: 'input' } },

{ prop: 'email', label: '邮箱' },

{ prop: 'address', label: '居住地址' },

{ prop:'gender', label: '性别'},

{prop: 'state', label:'用户状态'},

{ prop: 'operation', label: '操作', fixed: 'right', width: 300 },

]

</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

来看实现效果

image.png

基本封装已经可以了,接下来可以增加些功能 如滚动条和内容溢出处理

// Hytable.vue
<template>
...
<el-table-column v-if="!item.type && item.prop" v-bind="item" :align="'center'" show-overflow-tooltip="showOverflowTooltip">

<template #default="scope">

<slot :name="item.prop" v-bind="scope" :row="scope.row">

{{ scope.row[item.prop] }}

</slot>
</template>
</el-table-column>
...
<slot name="pagination" v-if="pagination">
<el-pagination

:background="true"

:current-page="pageable.pageNum"

:page-size="pageable.pageSize"

:page-sizes="[10, 25, 50, 100]"

:total="pageable.total"

layout="total, sizes, prev, pager, next, jumper"

@size-change="handleSizeChange"

@current-change="handleCurrentChange"

>
</el-pagination>
</slot>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";

import {requestTableData} from "../../api/index.ts"

import { reactive } from "vue";

import { toRefs } from "vue";

import { computed } from "vue";

interface TableProps{

columns: any,

requestApi?: (params?: any) => Promise<any>;

pagination?: boolean,

showOverflowTooltip?: boolean;

}

const props = withDefaults(defineProps<TableProps>(), {

columns: [],

requestApi: requestTableData,

pagination: true,

showOverflowTooltip:true,

});

const columnData = ref(props.columns);

// let tableData= ref([])

onMounted(() => {

getTableList(props.requestApi)

})

const handlePage:()=>any = ()=>{

const state = reactive({

tableData: [],

pageable: {

pageNum:1,

pageSize:10,

total: 0,

}

})

const getTableList = async (api:any) => {

let { data } = await api();

state.tableData = data

state.pageable.total = data.length

};

  

const handleSizeChange = (val:any) => {

state.pageable.pageNum = 1;

state.pageable.pageSize = val;

getTableList(props.requestApi)

}

const handleCurrentChange = (val: any) => {

state.pageable.pageNum = val;

getTableList(props.requestApi)

}

// pageable.total = data

return{

...toRefs(state),

getTableList,

handleSizeChange,

handleCurrentChange,

}
}
const {tableData,pageable,handleSizeChange,handleCurrentChange,getTableList} = handlePage()

const processTableData = computed(() => {

if (!props.pagination) return tableData.value
return tableData.value.slice(
pageable.value.pageNum - 1) * pageable.value.pageSize,
pageable.value.pageSize * pageable.value.pageNum
)
})
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156

看看效果

image.png

额。。。还有很多可以加的比如增删改查、查询表单慢慢更新吧

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/684235
推荐阅读
相关标签
  

闽ICP备14008679号