Vue實(shí)現(xiàn)極致舒適的可編輯表格
使用ElementPlus的Table啥都好,就是沒有可編輯表格!??!
既然UI庫不支持,那我們實(shí)現(xiàn)一個可編輯表格是很難的事么?難么?不難么?...
個人覺得如果是業(yè)務(wù)固定的可編輯表格,使用ElementPlus實(shí)現(xiàn)都不難。但是如果需要的是一個通用的可編輯表格,這好像還真說不好。
對于通用的可編輯表格,網(wǎng)上的實(shí)現(xiàn)方案也是五花八門,但是看下來多少都有些問題。個人認(rèn)為一個通用的可編輯表格需要給使用方提供以下能力:
- 支持新增、刪除、編輯、保存
- 定義可編輯列
- 定義表單組件,既可以是原生標(biāo)簽,也可以是自定義組件
- 定義表單校驗(yàn)規(guī)則
- 定義數(shù)據(jù)展示部分
- 定義操作區(qū)域
- 幾乎無學(xué)習(xí)成本
實(shí)現(xiàn)了以上需求的可編表格,就可以滿足基本的生產(chǎn)需求了。
在<el-table>組件的基礎(chǔ)上實(shí)現(xiàn)可編輯表格,保留<el-table>的使用方式不變,還能提供可編輯功能。同時可編輯功能的配置與<el-table>的使用風(fēng)格一致,降低學(xué)習(xí)成本。
準(zhǔn)備數(shù)據(jù)
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',
},
]基礎(chǔ)表格
基礎(chǔ)表格的用法與<el-table>幾乎沒有區(qū)別,唯一的不同就是<el-table>中的data,在<EditTable>中被data-source替換。

<section>
<h1>無編輯效果</h1>
<EditTable class="edit-table" :data-source="tableData">
<EditTableColumn prop="date" label="時間"> </EditTableColumn>
<EditTableColumn prop="name" label="姓名"> </EditTableColumn>
<EditTableColumn prop="address" label="地址"> </EditTableColumn>
</EditTable>
</section>可修改表格
<EditTableColumn>存在一個#default默認(rèn)插槽和一個#edit具名插槽,默認(rèn)插槽和具名插槽都提供了row、actions、$index等值。
可修改表格是在基礎(chǔ)表格上給<EditTableColumn>添加名為edit的具名插槽<template #edit>。
- 通過
row可以獲取到當(dāng)前行的數(shù)據(jù)。插槽中的表單組件可通過v-model="row.*"對編輯值進(jìn)行雙向綁定。 - 通過
actions可以獲取編輯表格的能力,通過action.startEditable($index)開啟編輯,action.cancelEditable($index)取消編輯,action.saveEditable保存編輯。

<section>
<h1>可編輯效果</h1>
<EditTable class="edit-table" :data-source="tableData">
<EditTableColumn prop="date" label="時間">
<template #edit="{ row }">
<input v-model="row.date" />
</template>
</EditTableColumn>
<EditTableColumn prop="name" label="姓名">
<template #edit="{ row }">
<input v-model="row.name" />
</template>
</EditTableColumn>
<EditTableColumn prop="address" label="地址">
<template #edit="{ row }">
<input v-model="row.address" />
</template>
</EditTableColumn>
<EditTableColumn label="操作">
<template #default="{ actions, $index }">
<button @click="actions.startEditable($index)">操作</button>
</template>
<template #edit="{ actions, $index }">
<button @click="actions.saveEditable($index)">保存</button>
<button @click="actions.cancelEditable($index)">取消</button>
</template>
</EditTableColumn>
</EditTable>
</section>刪除效果
在上述表格的操作區(qū)域增加刪除按鈕,刪除按鈕點(diǎn)擊時調(diào)用actions.delete($index)用來刪除當(dāng)前行。

<section>
<h1>刪除效果</h1>
<EditTable class="edit-table" :data-source="tableData">
<EditTableColumn prop="date" label="時間">
<template #edit="{ row }">
<input v-model="row.date" />
</template>
</EditTableColumn>
<EditTableColumn prop="name" label="姓名">
<template #edit="{ row }">
<input v-model="row.name" />
</template>
</EditTableColumn>
<EditTableColumn prop="address" label="地址">
<template #edit="{ row }">
<input v-model="row.address" />
</template>
</EditTableColumn>
<EditTableColumn label="操作">
<template #default="{ actions, $index }">
<button @click="actions.startEditable($index)">操作</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
<template #edit="{ actions, $index }">
<button @click="actions.saveEditable($index)">保存</button>
<button @click="actions.cancelEditable($index)">取消</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
</EditTableColumn>
</EditTable>
</section>新增效果
組件<EditTable>并不需要提供新增按鈕,如果直接將新增按鈕封裝在組件內(nèi),那么這個組件就太呆了。因此<EditTable>只提供了actions.addRow方法,調(diào)用方可以根據(jù)自己的需求完成新增功能。

<script lang="ts" setup>
import { ref } from 'vue';
import EditTable from '@/components/EditTable.vue';
import EditTableColumn from '@/components/EditTableColumn.vue';
const tableData = [...];
const addEditTableRef = ref<InstanceType<typeof EditTable>>();
</script>
<template>
<div class="wrapper">
<section>
<h1>新增效果</h1>
<EditTable ref="addEditTableRef" class="edit-table" :data-source="tableData">
<EditTableColumn prop="date" label="時間">
<template #edit="{ row }">
<input v-model="row.date" />
</template>
</EditTableColumn>
<EditTableColumn prop="name" label="姓名">
<template #edit="{ row }">
<input v-model="row.name" />
</template>
</EditTableColumn>
<EditTableColumn prop="address" label="地址">
<template #edit="{ row }">
<input v-model="row.address" />
</template>
</EditTableColumn>
<EditTableColumn label="操作">
<template #default="{ actions, $index }">
<button @click="actions.startEditable($index)">操作</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
<template #edit="{ actions, $index }">
<button @click="actions.saveEditable($index)">保存</button>
<button @click="actions.cancelEditable($index)">取消</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
</EditTableColumn>
</EditTable>
<button @click="addEditTableRef?.editActions.addRow()">新增</button>
</section>
</div>
</template>表單校驗(yàn)
組件<EditTableColumn>允許驗(yàn)證用戶的輸入是否符合規(guī)范,來找到和糾正錯誤。只需要為<EditTableColumn :rules="rules">的rules屬性傳入約定的驗(yàn)證規(guī)則,高級用法可參考async-validator。
總之校驗(yàn)規(guī)則和表單的校驗(yàn)規(guī)則一致。

<section>
<h1>表單校驗(yàn)效果</h1>
<EditTable ref="formEditTableRef" class="edit-table" :data-source="tableData">
<EditTableColumn
prop="date"
label="時間"
:rules="[{ required: true, message: '時間是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.date" />
</template>
</EditTableColumn>
<EditTableColumn
prop="name"
label="姓名"
:rules="[{ required: true, message: '姓名是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.name" />
</template>
</EditTableColumn>
<EditTableColumn
prop="address"
label="地址"
:rules="[{ required: true, message: '地址是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.address" />
</template>
</EditTableColumn>
<EditTableColumn label="操作">
<template #default="{ actions, $index }">
<button @click="actions.startEditable($index)">操作</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
<template #edit="{ actions, $index }">
<button @click="actions.saveEditable($index)">保存</button>
<button @click="actions.cancelEditable($index)">取消</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
</EditTableColumn>
</EditTable>
<button @click="formEditTableRef?.editActions.addRow()">新增</button>
</section>獲取編輯后的表單數(shù)據(jù)
組件<EditTable>對外暴露了resultData響應(yīng)式對象,可以用來獲取表格的最新數(shù)據(jù)。

<section>
<h1>獲取編輯結(jié)果</h1>
<EditTable ref="formEditTableRef" class="edit-table" :data-source="tableData">
<EditTableColumn
prop="date"
label="時間"
:rules="[{ required: true, message: '時間是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.date" />
</template>
</EditTableColumn>
<EditTableColumn
prop="name"
label="姓名"
:rules="[{ required: true, message: '姓名是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.name" />
</template>
</EditTableColumn>
<EditTableColumn
prop="address"
label="地址"
:rules="[{ required: true, message: '地址是必填項(xiàng)', trigger: 'blur' }]"
>
<template #edit="{ row }">
<input v-model="row.address" />
</template>
</EditTableColumn>
<EditTableColumn label="操作">
<template #default="{ actions, $index }">
<button @click="actions.startEditable($index)">操作</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
<template #edit="{ actions, $index }">
<button @click="actions.saveEditable($index)">保存</button>
<button @click="actions.cancelEditable($index)">取消</button>
<button @click="actions.deleteRow($index)">刪除</button>
</template>
</EditTableColumn>
</EditTable>
<button @click="formEditTableRef?.editActions.addRow()">新增</button>
<p>獲取數(shù)據(jù):{{ formEditTableRef?.resultData }}</p>
</section>另一種數(shù)據(jù)配置
組件<EditTable>除了支持data-source的方式配置數(shù)據(jù)外,還支持request屬性傳入返回數(shù)據(jù)的函數(shù)。

<script lang="ts" setup name="Page-B">
import { ref } from 'vue';
import EditTable from '@/components/EditTable.vue';
import EditTableColumn from '@/components/EditTableColumn.vue';
const loadData = async () => [
{
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>
<div class="wrapper">
<section>
<h1>另一種數(shù)據(jù)配置</h1>
<EditTable class="edit-table" :request="loadData">
<EditTableColumn prop="date" label="時間"> </EditTableColumn>
<EditTableColumn prop="name" label="姓名"> </EditTableColumn>
<EditTableColumn prop="address" label="地址"> </EditTableColumn>
</EditTable>
</section>
</div>
</template>以上就是Vue實(shí)現(xiàn)極致舒適的可編輯表格的詳細(xì)內(nèi)容,更多關(guān)于Vue可編輯表格的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue中v-form標(biāo)簽里的:rules作用及定義方法
文章介紹了在Vue項(xiàng)目中使用ElementUI或ElementPlus組件庫時,如何通過`el-form`標(biāo)簽的`:rules`屬性進(jìn)行表單驗(yàn)證,`:rules`屬性用于定義表單項(xiàng)的驗(yàn)證規(guī)則,包括必填項(xiàng)、格式校驗(yàn)、長度限制等,文章還展示了如何定義基本驗(yàn)證規(guī)則和自定義驗(yàn)證函數(shù),感興趣的朋友一起看看吧2025-03-03
vue開發(fā)中的base和publicPath的區(qū)別
本文主要介紹了vue開發(fā)中的base和publicPath的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
Element實(shí)現(xiàn)登錄+注冊的示例代碼
登錄注冊是最常用的網(wǎng)站功能,本文主要介紹了Element實(shí)現(xiàn)登錄+注冊的示例代碼,具有一定的參考價值,感興趣的可以了解一下2023-09-09

