记录--极致舒适的Vue可编辑表格

news2025/2/2 20:59:40

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

使用ElementPlus的Table啥都好,就是没有可编辑表格!!!😭

既然UI库不支持,那我们实现一个可编辑表格是很难的事么?😒难么?😢不难么?...

个人觉得如果是业务固定的可编辑表格,使用ElementPlus实现都不难。但是如果需要的是一个通用的可编辑表格,这好像还真说不好。

对于通用的可编辑表格,网上的实现方案也是五花八门,但是看下来多少都有些问题。个人认为一个通用的可编辑表格需要给使用方提供以下能力:

  • 支持新增、删除、编辑、保存
  • 定义可编辑列
  • 定义表单组件,既可以是原生标签,也可以是自定义组件
  • 定义表单校验规则
  • 定义数据展示部分
  • 定义操作区域
  • 几乎无学习成本

实现了以上需求的可编表格,就可以满足基本的生产需求了。

<el-table>组件的基础上实现可编辑表格,保留<el-table>的使用方式不变,还能提供可编辑功能。同时可编辑功能的配置与<el-table>的使用风格一致,降低学习成本。

放心食用:演示地址

准备数据

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',
  },
]

基础表格

基础表格的用法与<el-table>几乎没有区别,唯一的不同就是<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默认插槽和一个#edit具名插槽,默认插槽和具名插槽都提供了rowactions$index等值。

可修改表格是在基础表格上给<EditTableColumn>添加名为edit的具名插槽<template #edit>

  • 通过row可以获取到当前行的数据。插槽中的表单组件可通过v-model="row.*"对编辑值进行双向绑定。
  • 通过actions可以获取编辑表格的能力,通过action.startEditable($index)开启编辑,action.cancelEditable($index)取消编辑,action.saveEditable保存编辑。

可编辑效果.gif

<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>

删除效果

在上述表格的操作区域增加删除按钮,删除按钮点击时调用actions.delete($index)用来删除当前行。

删除效果.gif

<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>并不需要提供新增按钮,如果直接将新增按钮封装在组件内,那么这个组件就太呆了。因此<EditTable>只提供了actions.addRow方法,调用方可以根据自己的需求完成新增功能。

新增效果.gif

<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>

表单校验

组件<EditTableColumn>允许验证用户的输入是否符合规范,来找到和纠正错误。只需要为<EditTableColumn :rules="rules">rules属性传入约定的验证规则,高级用法可参考async-validator

总之校验规则和表单的校验规则一致。

表单校验效果.gif

<section>
  <h1>表单校验效果</h1>
  <EditTable ref="formEditTableRef" class="edit-table" :data-source="tableData">
    <EditTableColumn
      prop="date"
      label="时间"
      :rules="[{ required: true, message: '时间是必填项', trigger: 'blur' }]"
    >
      <template #edit="{ row }">
        <input v-model="row.date" />
      </template>
    </EditTableColumn>
    <EditTableColumn
      prop="name"
      label="姓名"
      :rules="[{ required: true, message: '姓名是必填项', trigger: 'blur' }]"
    >
      <template #edit="{ row }">
        <input v-model="row.name" />
      </template>
    </EditTableColumn>
    <EditTableColumn
      prop="address"
      label="地址"
      :rules="[{ required: true, message: '地址是必填项', 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>

获取编辑后的表单数据

组件<EditTable>对外暴露了resultData响应式对象,可以用来获取表格的最新数据。

获取编辑效果.gif

<section>
  <h1>获取编辑结果</h1>
  <EditTable ref="formEditTableRef" class="edit-table" :data-source="tableData">
    <EditTableColumn
      prop="date"
      label="时间"
      :rules="[{ required: true, message: '时间是必填项', trigger: 'blur' }]"
    >
      <template #edit="{ row }">
        <input v-model="row.date" />
      </template>
    </EditTableColumn>
    <EditTableColumn
      prop="name"
      label="姓名"
      :rules="[{ required: true, message: '姓名是必填项', trigger: 'blur' }]"
    >
      <template #edit="{ row }">
        <input v-model="row.name" />
      </template>
    </EditTableColumn>
    <EditTableColumn
      prop="address"
      label="地址"
      :rules="[{ required: true, message: '地址是必填项', 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>获取数据:{{ formEditTableRef?.resultData }}</p>
</section>

另一种数据配置

组件<EditTable>除了支持data-source的方式配置数据外,还支持request属性传入返回数据的函数。

<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>另一种数据配置</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>

关于源码

由于就是一个简单的组件实现,所以也懒得去打包发布npm。直接在下面给出demo地址和演示环境:

GitHub地址

codesandbox

最后

<el-table>的属性配置基本都可以在<EditTable>中使用,所以只要会使用el-table对于<EditTable>就可以立即使用。

本文转载于:

https://juejin.cn/post/7242140832379584567

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Avalon 学习系列(五)—— 过滤器

Avalon 本身有很多过滤器&#xff0c;例如 date、number等文本过滤器、循环过滤器&#xff1b;avalon 也提供了方法可以根据需求自定义过滤器。 示例&#xff1a; &#xff08;1&#xff09;定义一个 myFunc 的个性化过滤器&#xff0c;并加在元素上&#xff1b; &#xff0…

一文带你玩转 RustChinaConf 2023,内含赞助商展位活动福利和 Workshop 介绍

除了两天干货满满的会议外&#xff0c;RustChinaConf 的赞助商也准备了精美的周边礼物等待大家去打卡。每位参会者在签到的时候会获得一张集章卡&#xff0c;集齐上面所有的章&#xff0c;可至签到处兑换精美礼物一份。偷偷剧透一下&#xff0c;奖品有大家喜欢的 Rust 小螃蟹玩…

【计算机网络】第一章 概述(上)

文章目录 第一章 概述1.2 因特网概述1.2.1 网络、互连网&#xff08;互联网&#xff09;和因特网1.2.2 因特网发展的三个阶段1.2.4 因特网的组成 1.3 三种交换方式1.3.1 电路交换1.3.2 分组交换1.3.3 报文交换1.3.4 三种方式对比 1.4 计算机网络的定义 第一章 概述 1.2 因特网概…

「深度学习之优化算法」笔记(二)优化算法的分类

1. 优化算法的分类 1.1常见的优化算法 在分类之前&#xff0c;我们先列举一下常见的优化算法&#xff08;不然我们拿什么分类呢&#xff1f;&#xff09; 1.遗传算法Genetic algorithm 2.粒子群优化算法Particle Swarm Optimization 3.差分进化算法Differential Evolution 4.人…

springboot第27集:springboot-mvc,WxPay

在数据库中&#xff0c;DISTINCT 关键字用于查询去重后的结果集。它用于从查询结果中去除重复的行&#xff0c;只返回唯一的行。 要使用 DISTINCT 关键字&#xff0c;可以将其放置在 SELECT 关键字之前&#xff0c;指示数据库返回去重后的结果。 请注意&#xff0c;DISTINCT 关…

Linux常用命令——getenforce命令

在线Linux命令查询工具 getenforce 显示当前SELinux的应用模式&#xff0c;是强制、执行还是停用。 补充说明 grename命令可以重命名卷组的名称。 语法 getenforce例子 查看当前SELinux的应用模式。 [rootlocalhost ~]# getenforce Enforcing在线Linux命令查询工具 原文…

ChatGPT时代,我的新书《智慧共生》上市了

告诉你一个好消息&#xff0c;我在人民邮电出版社的第二本书《智慧共生&#xff1a;ChatGPT 与 AIGC 生产力工具实践》刚刚上市&#xff0c;你现在就可以在 京东 和 当当买到了。 有人把 2022 年称作 AIGC&#xff08;人工智能生成内容&#xff09; 的元年&#xff0c;我深表赞…

浅谈数据中台之数据开发

目 录 01 前言‍ 02 中台概念及背景 ‍‍‍‍‍‍‍ 03 数据中台建设方法‍‍‍‍‍‍ 04 数据开发实践 01‍ 前言‍‍ 2015年阿里在国内首次提出了中台概念&#xff0c;由阿里引领发展&#xff0c;迅速在互联网企业中形成了一股浪潮。在数字化转型的道路上&#xff0c;为了…

【AUTOSAR】UDS协议的代码分析与解读(五)----ECU诊断服务

8 诊断服务 8.1 总览 此章节定义了本规范中可使用的诊断服务及其执行规则。 下表列出了h事业部定义的所有UDS诊断服务。ECU最终实现与下述定义不符之处必须得到h事业部 的认可。服务实现内容需在零部件诊断规范中详细说明。 表 9 诊断服务支持列表 诊断服务列表 APP Bootlo…

【手撕代码】同步 FIFO、LIFO/Stack

FIFO 是FPGA设计中最有用的模块之一。FIFO 在模块之间提供简单的握手和同步机制&#xff0c;是设计人员将数据从一个模块传输到另一个模块的常用选择。 在这篇文章中&#xff0c;展示了一个简单的 RTL 同步 FIFO&#xff0c;可以直接在自己的设计中配置和使用它&#xff0c;该设…

社区供稿 | RLHF 实践中的框架使用与一些坑 (TRL, LMFlow)

1 前言 之前看见文章总结了常见的一些 RLHF 框架的经验, 但是似乎没看见 Hugging Face 自己维护的 TRL 库的相关文章, 正好最近调 TRL 比较多, 就想写一个文章分享一下使用过程中踩到的坑&#xff0c;另外也介绍一下我们的全流程框架 LMFlow 。 LMFlow 框架示意图。 我们主要用…

架构思维的六要素

很多人都在私信问我随着ChatGPT等技术的兴起&#xff0c;自己的饭碗会不会没了。我的观点是&#xff1a;ChatGPT能做的工作十几年前早就没了。 十几年前还看到过招聘广告上写招程序员的&#xff0c;现在都是工程师起步&#xff0c;工程师是要有架构思维的。 像十几年前的黄金时…

手写SpringBoot启动器主要步骤

这里写目录标题 背景过程2.1自启动实现原理2.2手动实现SpringBoot自启动2.2.1宏观2.2.1微观2.2.1.1三个服务之间调用2.2.1.2自定义注解2.2.1.1业务组装2.2.1.3启动类 升华自定义注解&#xff1a;手动装配组件&#xff1a;简化启动过程&#xff1a;自动化注入依赖&#xff1a;简…

马原第三章复习1.

唯物史观和唯心史观过去出过小题 社会意识出小题 社会存在一般出大题 124 社会存在和社会意识(往往出大题) 社会历史性的基本问题 两种根本对立的历史史观 唯心主义: 至多考察人的思想动机 没有考虑思想背后的物质动因和经济根源 把社会史观看成人的思想,,不懂得…

关于酒店宾馆电气火灾隐患的预防与整改措施介绍 安科瑞 许敏

摘要&#xff1a;本文分析了酒店、宾馆电气火灾隐患的特点及产生的主要原因&#xff0c;并依此提出了消除火灾隐患的整改措施。 关键词:酒店宾馆&#xff1b;火灾&#xff1b;隐患&#xff1b;预防&#xff1b;整改&#xff1b;措施 1前言 随着旅居服务业的快速发展&#xf…

CVPR 2023 | 香港理工提出GrowSP:3D场景的无监督语义分割

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 点击进入—>【目标检测和Transformer】交流群 GrowSP: Unsupervised Semantic Segmentation of 3D Point Clouds 论文链接&#xff1a;https://arxiv.org/abs/2305.16404 代码&#xff1…

2023/6/11总结

CSS Less嵌套 子元素的选择器可以直接写在父元素里面。 如果不是它的后代元素&#xff0c;比如你想写伪类选择器、交集选择器&#xff0c;需要在前面加&号。 Less运算&#xff1a; 加减乘除都可以&#xff0c;运算符必须用空格隔开。如果俩个元素都有单位&#xff0…

binfmt_misc

一&#xff1a;binfmt_misc是什么 binfmt_misc是内核中的一个功能&#xff0c;它能将非本机的二进制文件与特定的解析器自动匹配起来&#xff0c;进行二进制解析。 例如&#xff0c;在x86上解析arm64架构的二进制。 通过binfmt_misc可以注册解析器来处理指定二进制文件格式的请…

Qt|QDialog的创建及使用

文章目录 创建一个新的类继承QDialog设置标题去掉问号&#xff0c;只保留关闭使窗口在屏幕中心显示设置窗口大小QDialog没有任务栏窗口图标问题将窗口永远置于上层可见 不会被遮盖阻塞除当前窗口之外的所有窗口添加closeEvent hideEvent同理调用dialog类接收dialog返回状态&…

华为OD机试真题 JavaScript 实现【跳房子II】【2023 B卷 100分】,附详细解题思路

一、题目描述 跳房子&#xff0c;也叫跳飞机&#xff0c;是一种世界性的儿童游戏。 游戏参与者需要分多个回合按顺序跳到第1格直到房子的最后一格&#xff0c;然后获得一次选房子的机会&#xff0c;直到所有房子都被选完&#xff0c;房子最多的人获胜。 跳房子的过程中&…