vue3二次封裝element-ui中的table組件的過程詳解
為什么要做這件事
借助封裝table組件的過程來鞏固一下vue3相關(guān)知識(shí)點(diǎn)。
組件有哪些配置項(xiàng)
- options:表格的配置項(xiàng)
- data: 表格數(shù)據(jù)源
- elementLoadingText:加載文案
- elementLoadingSpinner:加載圖標(biāo)
- elementLoadingBackground:背景遮罩的顏色
- elementLoadingSvg:加載圖標(biāo)(svg)
- elementLoadingSvgViewBox:加載圖標(biāo)是svg的話,配置項(xiàng)
- editIcon:編輯圖標(biāo)
- isEditRow:是否支持編輯
- editRowIndex:編輯行的標(biāo)識(shí)符
- pagination:是否支持分頁(yè)
- paginationAlign:分頁(yè)對(duì)齊方式
- currentPage:當(dāng)前頁(yè)數(shù)
- pageSize:每頁(yè)顯示條目個(gè)數(shù)
- pageSizes:每頁(yè)顯示個(gè)數(shù)選擇器的選項(xiàng)設(shè)置
- total:總條目數(shù)
實(shí)現(xiàn)過程
首先,將一個(gè)普通的element-plus中的table組件引入進(jìn)來,表格數(shù)據(jù)源就是我們通過父組件傳遞進(jìn)來的data,所以我們使用defineProps來定義,并且它的數(shù)據(jù)類型是一個(gè)數(shù)組;同時(shí)我們遵循單向數(shù)據(jù)流的原則,使用lodash中的深拷貝方法將data拷貝一份出來賦值給變量tableData,將tableData傳遞給element-plus中的table組件,用來渲染數(shù)據(jù)。
// 子組件 m-table-copy
<template>
<el-table :data="tableData">
<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 setup>
import { ref } from 'vue'
import cloneDeep from 'lodash/cloneDeep'
let props = defineProps({
data: {
type: Array,
required: true
}
})
// 拷貝一份兒數(shù)據(jù)
let tableData = ref(cloneDeep(props.data))
</script>父組件在使用這個(gè)自定義組件的時(shí)候應(yīng)該這么使用:
<!-- 父組件 -->
<template>
<m-table-copy :data="tableData"></m-table-copy>
</template>
<script setup>
import { ref } from 'vue'
let tableData = ref([])
tableData.value = [
{
name: '張三',
address: '杭州市',
date: '1998-07-16'
},
{
name: '李四',
address: '石家莊市',
date: '2013-09-02'
}
]
</script>這樣頁(yè)面上就能夠顯示出來我們的數(shù)據(jù)了:
第一步完成了,我們接著再分析,還有什么是可以封裝的呢?仔細(xì)看上面的代碼,是不是有了想法?是的,label、width、prop這些也是可以放在一個(gè)配置項(xiàng)里面的,那我們繼續(xù)來進(jìn)行封裝:
// 父組件準(zhǔn)備好的數(shù)據(jù)結(jié)構(gòu)
let options = [
{
prop: 'date',
label: '日期',
align: 'center',
slot: 'date',
editable: true,
width: '230'
},
{
prop: 'name',
label: '姓名',
align: 'center',
slot: 'name'
},
{
prop: 'address',
label: '地址',
align: 'center',
editable: true
},
{
label: '操作',
align: 'center',
action: true
}
]<template>
<el-table :data="tableData">
<template v-for="(item, index) in tableOption" :key="index">
<el-table-column
:label="item.label"
:prop="item.prop"
:align="item.align"
:width="item.width" />
</template>
</el-table>
</template>
<script setup>
import { ref, computed } from 'vue'
let props = defineProps({
// 表格配置項(xiàng)
options: {
type: Array,
required: true
}
})
// 過濾操作項(xiàng)之后的配置
let tableOption = computed(() => props.options.filter((item) => !item.action))
</script>一般來說,表格都會(huì)配置一下loading狀態(tài),所以我們繼續(xù)封裝,將loading相關(guān)的配置項(xiàng)也添加進(jìn)來:
完整代碼
<template>
<el-table
:data="tableData"
v-loading="isLoading"
:element-loading-text="elementLoadingText"
:element-loading-spinner="elementLoadingSpinner"
:element-loading-svg="elementLoadingSvg"
:element-loading-svg-view-box="elementLoadingSvgViewBox"
:element-loading-background="elementLoadingBackground"
@row-click="rowClick"
v-bind="$attrs">
<template v-for="(item, index) in tableOption" :key="index">
<el-table-column
:label="item.label"
:prop="item.prop"
:align="item.align"
:width="item.width">
<template #default="scope">
<!-- 編輯模式 -->
<template v-if="scope.row.rowEdit">
<el-input v-model="scope.row[item.prop]"></el-input>
</template>
<template v-else>
<template v-if="scope.$index + scope.column.id === currentEdit">
<div style="display: flex">
<el-input v-model="scope.row[item.prop]"></el-input>
<div>
<slot
v-if="$slots.cellEdit"
name="cellEdit"
:scope="scope"></slot>
<div class="action-icon" v-else>
<el-icon-check
class="check"
@click.stop="check(scope)"></el-icon-check>
<el-icon-close
class="close"
@click.stop="close(scope)"></el-icon-close>
</div>
</div>
</div>
</template>
<template v-else>
<!-- slot是一個(gè)插槽出口,表示了父元素提供的插槽內(nèi)容將在哪里被渲染 -->
<slot v-if="item.slot" :name="item.slot" :scope="scope"></slot>
<span v-else>{{ scope.row[item.prop] }}</span>
<component
v-if="item.editable"
:is="`el-icon-${toLine(editIcon)}`"
class="edit"
@click.stop="clickEditIcon(scope)"></component>
</template>
</template>
</template>
</el-table-column>
</template>
<el-table-column
:align="actionOption.align"
:label="actionOption.label"
:width="actionOption.width">
<template #default="scope">
<!-- 編輯模式下顯示確認(rèn)和取消 -->
<slot name="editRow" :scope="scope" v-if="scope.row.rowEdit"></slot>
<!-- 正常狀態(tài)下顯示 編輯和刪除 -->
<slot name="action" :scope="scope" v-else></slot>
</template>
</el-table-column>
</el-table>
<div
v-if="pagination && !isLoading"
class="pagination"
:style="{ justifyContent }">
<el-pagination
v-model:currentPage="currentPage"
:page-size="pageSize"
:page-sizes="pageSizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes, prev, pager, next, jumper"
:total="total" />
</div>
</template><script setup>
import cloneDeep from 'lodash/cloneDeep'
import { computed, onMounted, ref, watch } from 'vue'
import { toLine } from '../../../utils'
let props = defineProps({
// 表格配置項(xiàng)
options: {
type: Array,
required: true
},
// 表格數(shù)據(jù)
data: {
type: Array,
required: true
},
// 編輯圖標(biāo)
editIcon: {
type: String,
default: 'Edit'
},
// 顯示在加載圖標(biāo)下方的加載文案
elementLoadingText: {
type: String
},
// 自定義加載圖標(biāo)
elementLoadingSpinner: {
type: String
},
// 自定義加載圖標(biāo)(svg)
elementLoadingSvg: {
type: String
},
// 自定義加載圖標(biāo)(svg)的配置
elementLoadingSvgViewBox: {
type: String
},
// 背景遮罩的顏色
elementLoadingBackground: {
type: String
},
// 是否可用編輯行
isEditRow: {
type: Boolean,
default: false
},
// 編輯行按鈕的標(biāo)識(shí)
editRowIndex: {
type: String,
default: ''
},
// 是否顯示分頁(yè)
pagination: {
type: Boolean,
default: false
},
// 分頁(yè)的對(duì)齊方式
paginationAlign: {
type: String,
default: 'left'
},
// 當(dāng)前第幾頁(yè)
currentPage: {
type: Number,
default: 1
},
// 顯示分頁(yè)數(shù)據(jù)多少條的選項(xiàng)
pageSizes: {
type: Array,
default: () => [10, 20, 30, 40]
},
// 數(shù)據(jù)總條數(shù)
total: {
type: Number,
default: 0
}
})
// 深拷貝一份表格的數(shù)據(jù)
let tableData = ref(cloneDeep(props.data))
let cloneEditRowIndex = ref(props.editRowIndex)
// 過濾操作項(xiàng)之后的配置
let tableOption = computed(() => props.options.filter((item) => !item.action))
let actionOption = computed(() => props.options.find((item) => item.action))
// 監(jiān)聽的標(biāo)識(shí)
let watchData = ref<boolean>(false)
// 如果data的數(shù)據(jù)變了 要重新給tableData賦值
// 只需要監(jiān)聽一次就可以了
let stopWatchData = watch(
() => props.data,
(val) => {
watchData.value = true
tableData.value = val
tableData.value.map((item) => {
item.rowEdit = false
})
if (watchData.value) stopWatchData()
},
{ deep: true }
)
watch(
() => props.editRowIndex,
(val) => {
if (val) cloneEditRowIndex.value = val
}
)
// 當(dāng)前被點(diǎn)擊的單元格的標(biāo)志
let currentEdit = ref('')
let currentPage = computed(() => props.currentPage)
let justifyContent = computed(() => {
if (props.paginationAlign === 'left') return 'flex-start'
else if (props.paginationAlign === 'right') return 'flex-end'
else return 'center'
})
let isLoading = computed(() => !props.data || !props.data.length)
let emits = defineEmits([
'confirm',
'cancel',
'update:editRowIndex',
'size-change',
'current-change'
])
onMounted(() => {
tableData.value.map((item) => {
item.rowEdit = false
})
})
let clickEditIcon = (scope) => {
currentEdit.value = scope.$index + scope.column.id
}
let handleSizeChange = (val) => {
emits('size-change', val)
}
let handleCurrentChange = (val) => {
emits('current-change', val)
}
let check = (scope) => {
emits('confirm', scope)
currentEdit.value = ''
}
let close = (scope) => {
emits('cancel', scope)
currentEdit.value = ''
}
let rowClick = (row, column) => {
if (column.label === actionOption.value.label) {
if (props.isEditRow && cloneEditRowIndex.value === props.editRowIndex) {
row.rowEdit = !row.rowEdit
tableData.value.map((item) => {
if (item !== row) item.rowEdit = false
})
if (!row.rowEdit) emits('update:editRowIndex', '')
}
}
}
</script>以上就是vue3二次封裝element-ui中的table組件的過程詳解的詳細(xì)內(nèi)容,更多關(guān)于vue3二次封裝table的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
axios發(fā)送post請(qǐng)求,提交圖片類型表單數(shù)據(jù)方法
下面小編就為大家分享一篇axios發(fā)送post請(qǐng)求,提交圖片類型表單數(shù)據(jù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03
Vue3中引入SCSS和LESS依賴的基本步驟和注意事項(xiàng)
我們項(xiàng)目開發(fā)中經(jīng)常遇到樣式里面會(huì)使用less和scss寫法, less,scss和stylus都是css的預(yù)處理器,這篇文章主要給大家介紹了關(guān)于Vue3中引入SCSS和LESS依賴的基本步驟和注意事項(xiàng),需要的朋友可以參考下2024-05-05
vue-router權(quán)限控制(簡(jiǎn)單方式)
這篇文章主要介紹了vue-router權(quán)限控制(簡(jiǎn)單方式),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10
element中el-table局部刷新的實(shí)現(xiàn)示例
本文主要介紹了element中el-table局部刷新的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
vue2前端調(diào)用WebSocket有消息進(jìn)行通知代碼示例
在Vue項(xiàng)目中實(shí)現(xiàn)全局的消息鏈接監(jiān)聽主要涉及到了WebSocket技術(shù),這是一種雙向通信協(xié)議,允許客戶端與服務(wù)器之間實(shí)時(shí)、高效地交換數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于vue2前端調(diào)用WebSocket有消息進(jìn)行通知的相關(guān)資料,需要的朋友可以參考下2024-07-07

