基于element-plus定义表格行内编辑配置化

news2024/11/28 20:51:31

文章目录

  • 前言
  • 一、新增table组件
  • 二、使用步骤


前言

在 基于element-plus定义表单配置化 基础上,封装个Element-plus的table表格
由于表格不同于form组件,需自定义校验器,以下组件配置了单个校验,及提交统一校验方法,且自定义必填校验*显示和校验错误部分边框标红等,实际可根据业务及不同场景优化改造相关定义

后期抽空新增表格行及删除行等功能,

在这里插入图片描述


一、新增table组件

  • table-configuration/index.vue
<template>
  <el-table
    border
    ref="tableRef"
    :show-header="showHeader"
    :data="tableData"
    style="width: 100%"
    tooltip-effect
    :max-height="tablemaxHeight"
  >
    <el-table-column type="selection" :fixed="selectionFixed" width="55" v-if="hasSelection"/>
    <template v-for="(item, index) in tableProperty" :key="item">
      <el-table-column
        :align="align"
        :sortable="item.sortable"
        :min-width="item.width"
        :show-overflow-tooltip="showOverflowTooltip"
        :label="item.label"
      >
        <template #header>
          <div :class="[getTableHeader(item.property.rules)]" v-html="item.label"></div>
        </template>
        <template #default="scope">
          <component 
            :class="[scope.$index >=0 && getIsErrorClass(scope.$index, index)]"
            v-model:content="scope.row[item.field]"
            v-model="scope.row[item.field]"
            :property="{...item.property, name: item.field}"
            :is="item.type"
            @fieldBlur="(val) => blur(val, item, scope.$index, index)"
            @fieldChange="(val) => change(val, item, scope.$index, index)" />
        </template>
      </el-table-column>
    </template>
  </el-table>
</template>
<script lang="ts" src="./index.ts"/>
<style lang="less">
.is-error .el-select-v2__wrapper,.is-error .el-select-v2__wrapper:focus,.is-error .el-textarea__inner,.is-error .el-textarea__inner:focus {
  box-shadow: 0 0 0 1px var(--el-color-danger) inset
}

.is-error .el-input__wrapper {
  box-shadow: 0 0 0 1px var(--el-color-danger) inset
}
.table {
  &_header:before {
    content: "*";
    color: var(--el-color-danger);
    margin-right: 4px;
  }
}
</style>
  • table-configuration/index.ts
import { tableHooks } from "@/composables/table-hooks";
import { computed, defineComponent, reactive, ref } from "vue";
import Input from "@/components/form-configuration/input.vue";
import Select from "@/components/form-configuration/select.vue";
import Vhtml from "@/components/form-configuration/v-html.vue";
import Upload from "@/components/form-configuration/upload.vue";
import Switch from "@/components/form-configuration/switch.vue";
import Radio from "@/components/form-configuration/radio.vue";
import Checkbox from "@/components/form-configuration/checkbox.vue";
import Date from "@/components/form-configuration/date.vue";
import Cascader from "@/components/form-configuration/cascader.vue";
import { isArray } from "lodash-es";
import { ElMessage } from "element-plus";
import type { rulesType } from "@/interface";

const ruleType = {
  required: false,
  message: '',
  trigger: '',
  validator: (val: any) =>{return val}
}
const fieldProperty = {
  label: 'demo',
  type: 'Input',
  field: 'demo',
  width: '120px',
  err: '',
  property: {
    maxlength: 200,
    rules: [ruleType]
  }
}
export default defineComponent({
  components: {
    Input,
    Select,
    Vhtml,
    Upload,
    Switch,
    Radio,
    Checkbox,
    Date,
    Cascader,
  },
  props: {
    align: {
      type: String,
      default: 'left', // left / center / right
    },
    showHeader: {
      type: Boolean,
      default: true,
    },
    selectionFixed: {
      type: Boolean,
      default: false,
    },
    showOverflowTooltip: {
      type: Boolean,
      default: true,
    },
    hasSelection: {
      type: Boolean,
      default: false,
    },
    property: {
      type: Object,
      default() {
        return [ fieldProperty ];
      },
    },
    data: {
      type: Object,
      default() {
        return {};
      },
    },
  },
  setup(props, { emit }) {
    const { tablemaxHeight } = tableHooks();
    const tableRef = ref()
    const tableData = computed({
      get() {
        return props.data;
      },
      set(val) {
        emit("update:data", val);
      },
    });
    const noType = 'noType'
    const tableProperty = computed(() => props.property);
    const blur = (val: any, item: typeof fieldProperty, rowIndex: number, colIndex: number) => {
      let arr: Array<boolean> = []
      if (item.property.rules && isArray(item.property.rules)) {
        arr = validateForField(item, val, 'blur', rowIndex, colIndex)
      }
      if (!arr.length) {
        emit('blur', {
          val, field: item.field, rowIndex, colIndex
        }) // 触发
        clearIsError(rowIndex, colIndex)
      }
    }
    const change = (val: any, item: typeof fieldProperty, rowIndex: number, colIndex: number) => {
      let arr: Array<boolean> = []
      if (item.property.rules && isArray(item.property.rules)) {
        arr = validateForField(item, val, 'change', rowIndex, colIndex)
      }
      if (!arr.length) {
        emit('change', {
          val, field: item.field, rowIndex, colIndex
        }) // 触发
        clearIsError(rowIndex, colIndex)
      }
    }
    const isError = ref<{rowIndex: number, colIndex: number}[]>([])
    const validateForField = (item: typeof fieldProperty, val: any, type: string, rowIndex: number, colIndex: number) => {
      let arr: Array<boolean> = []
      item.property.rules.forEach((valid) => {
        const types = [valid.trigger, noType]
        if (valid.required && !val) {
          ElMessage.error(valid.message)
          arr.push(false)
          isError.value.push({
            rowIndex, colIndex,
          })
          return
        }
        if (!valid.required && !val || !types.includes(type)) return
        if (!valid.validator) return
        const bool = valid.validator(val)
        if (!bool) {
          ElMessage.error(valid.message)
          arr.push(bool)
          isError.value.push({
            rowIndex, colIndex,
          })
        }
      })
      return arr
    }
    const clearIsError = (rowIndex: number, colIndex: number) => {
      if (rowIndex === -1) {
        isError.value = []
      } else {
        isError.value = isError.value.filter((item) => {
          return !((item.rowIndex === rowIndex) && (item.colIndex === colIndex))
        })
      }
    }
    const validate = () => {
      let arr: Array<boolean> = []
      clearIsError(-1, -1)
      tableData.value.forEach((data: object, rowIndex: number) => {
        tableProperty.value.forEach((tabPro: any, colIndex: number) => {
          if (!tabPro.property.rules) return
          const field = tabPro.field as keyof typeof data
          arr.push(...validateForField(tabPro, data[field], noType, rowIndex, colIndex))
        });
      });
      return !arr.length
    }
    const getIsErrorClass = computed(() => {
      return (rowIndex: number, colIndex: number) => {
        let bool = false
        isError.value.forEach((error) => {
          (error.rowIndex === rowIndex) && (error.colIndex === colIndex) && (bool = true)
        })
        return bool ? 'is-error' : ''
      }
    })
    const getTableHeader = (rules: rulesType[]) => {
      if (!rules) return ''
      return !!rules.filter((item) => item.required).length ? 'table_header' : ''
    }
    return {
      tableRef,
      tablemaxHeight,
      tableProperty,
      tableData,
      isError,
      getIsErrorClass,
      getTableHeader,
      change,
      blur,
      validate
    };
  },
});

二、使用步骤

<TableConfiguration
   ref="supplierListRef"
   v-model:data="supplierListEntity.product"
   :hasSelection="true"
   :selectionFixed="true"
   :property="tableProperty"
   align="center"
   />
import { defineComponent, reactive, ref } from 'vue'
import TableConfiguration from '@/components/table-configuration/index.vue'
export default defineComponent({
  components: {
    TableConfiguration
  },
  setup() {
    const tableRef = ref()
    const tableProperty = reactive([
      { label: 'Input01', type: 'Input', field: 'Input01',  property: {
        maxlength: 500,
        rules: [{ required: false, message: 'error', trigger: 'blur', validator: (value: string) => {
          return /^\+?[1-9][0-9]*$/.test(value)
        }}]
      }},
      { label: 'Input02', type: 'Input', field: 'Input02', width: '200px', property: {
        maxlength: 500,
        rules: [{ required: true, message: 'error', trigger: 'blur' }]
      }}
    ])
    const tableEntity = reactive({
      table: [{
        Input01: '',
        Input02: '',
      }]
    })
    const validate = () => {
      tableRef.value.validate()
    }
    return {
      tableRef,
      tableProperty,
      tableEntity,
      validate
    }
  },
})


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

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

相关文章

【vue会员管理系统】篇六之退出系统功能

一、效果图 点击之后跳转到登陆界面 二、实现步骤 2.1Easy Mock新增接口 打开Easy Mock新建接口 方法:post URL:user/logout 描述&#xff1a;退出系统 2.2新增api 在api/login.js下添加以下代码 export function logout(token) {return request({url: /user/logout,method:…

【2021研电赛】管道巡检机器人

本作品介绍参与极术社区的有奖征集|分享研电赛作品扩大影响力&#xff0c;更有重磅电子产品免费领取! 团队介绍 参赛单位&#xff1a;广西科技大学 参赛队伍&#xff1a;OMEN 参赛队员&#xff1a;吴海晨 陈永亮 乔亚坤 第1章 项目意义 1.1 研究背景及意义 据媒体报道&am…

NIO 笔记(二)Netty框架专题

【笔记来自&#xff1a;it白马】 Netty框架 前面我们学习了Java为我们提供的NIO框架&#xff0c;提供使用NIO提供的三大组件&#xff0c;我们就可以编写更加高性能的客户端/服务端网络程序了&#xff0c;甚至还可以自行规定一种通信协议进行通信。 NIO框架存在的问题 但是之…

全国消费者行为和购买力的大数据可视化动态大屏【可视化项目案例-01】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本文选自专栏:可视化技术专栏100例 可视化技术专栏100例,包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不…

瑞芯微:基于RK3568的深度估计模型部署

根据单张图像估计深度信息是计算机视觉领域的经典问题&#xff0c;也是一项具有挑战的难题。由于单目图像的尺度不确定&#xff0c;传统方法无法计算深度值。 随着深度学习技术的发展&#xff0c;该范式已经成为了估计单目图像的深度信息的一种解决方案。早期的深度估计方法大多…

InSAR数据处理、地形三维重建、形变信息提取、监测丨GMTSAR合成孔径雷达干涉测量丨GNSS、北斗高精度数据处理

目录 ①合成孔径雷达干涉测量InSAR数据处理、地形三维重建、形变信息提取、监测等应用 ②基于GMTSAR合成孔径雷达干涉测量InSAR数据处理、形变信息提取与分析 ③GNSS、北斗高精度数据处理暨新版GAMITGLOBK软件应用 更多应用 ①合成孔径雷达干涉测量InSAR数据处理、地形三维…

sCrypt 现在支持 Ordinals 了

比特币社区对 1Sat Ordinals 的接受度正在迅速增加&#xff0c;已有超过 4800 万个铭文被铸造&#xff0c;这一新创新令人兴奋不已。 尽管令人兴奋&#xff0c;但 Ordinals 铭文的工具仍然不发达&#xff0c;这使得使用 Ordinals 进行构建具有挑战性。 更具体地说&#xff0c;缺…

智慧城市照明为城市节能降耗提供支持继电器开关钡铼S270

智慧城市照明&#xff1a;为城市节能降耗提供支持——以钡铼技术S270继电器开关为例 随着城市化进程的加速&#xff0c;城市照明系统的需求也日益增长。与此同时&#xff0c;能源消耗和环境污染问题日益严重&#xff0c;使得城市照明的节能减排成为重要议题。智慧城市照明系统…

MapBox免Token离线部署全套成熟方案

看了网上的一些Mapbox离线部署使用的文章,有些讲述的不是很全面,有些简直就是跟风胡说。 这篇文章我们来给大家提供一个完整的成熟的mapbox-gl离线部署方案。 首先我们要搞清楚为什么mapbox-gl需要申请token才能使用,其实并不是框架本身的源码不想让大家用,否则mapbox也不…

微软宣布称Windows 再不会偷偷下载更新文件,真的吗?

导读时钟拨回到2015年&#xff0c;微软刚刚推出Windows 10操作系统时&#xff0c;一些Windows 7用户首次在线Update的升级文件大小居然高达6~8GB。这件事引发了大量的不满&#xff0c;一些按照流量计费和宽带不给力的用户怨言极为严重&#xff0c;其中德国用户把此事闹上了当地…

使用小程序插件【用户信息功能页】获取用户昵称、头像、openid

摘要 因为获取用户信息的接口 wx.getUserInfo 存在滥用&#xff0c;使用不规范等原因&#xff0c;微信官方已经将这个接口权限回收&#xff0c;改为用户信息填写&#xff0c;即引导用户主动填写微信昵称和上传头像。这种做法确实是麻烦了点。 但是微信小程序插件&#xff0c;…

LeetCode算法题解(回溯、难点)|LeetCode51. N 皇后

LeetCode51. N 皇后 题目链接&#xff1a;51. N 皇后 题目描述&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。…

19.8 Boost Asio 异或加密传输

异或加密是一种对称加密算法&#xff0c;通常用于加密二进制数据。异或操作的本质是对两个二进制数字进行比较&#xff0c;如果它们相同则返回0&#xff0c;如果不同则返回1。异或加密使用一把密钥将明文与密文进行异或运算&#xff0c;从而产生密文。同时&#xff0c;使用相同…

大厂面试题-MySQL中的RR隔离级别,到底有没有解决幻读问题?

就MySQL中的RR(Repeatable Reads)事务隔离级别&#xff0c;到底有没有解决幻读问题发起了激烈的讨论。 一部分人说有&#xff0c;一部分人说没有。 结论&#xff0c;MySQL中的RR事务隔离级别&#xff0c;在特定的情况下会出现幻读的问题。 所谓的幻读&#xff0c;表示在同一…

git拉取项目所有分支

1、执行git clone &#xff0c;随便拉取一个分支 2、进入成功拉取去的分支生成的文件夹中&#xff0c;执行下面的命令即可完成拉拉取&#xff0c;如下图所示 for branch in git branch -a | grep remotes | grep -v HEAD | grep -v master ; dogit branch --track ${branch#r…

【JVM】类加载器 Bootstrap、Extension、Application、User Define

以下环境为 jdk1.8 两大类 分类成员语言继承关系引导类加载器bootstrap 引导类加载器C/C无自定义类加载器extension 拓展类加载器、application 系统/应用类加载器、user define 用户自定义类加载器Java继承于 java.lang.ClassLoader 四小类 Bootstrap 引导类加载器 负责加…

js实现向上、向下、向左、向右无缝滚动

向左滚动 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, ini…

如何修改NX二次开发菜单到NX自带的标签页

最近一个项目需求&#xff0c;客户希望NX二次开发自定义的菜单能够集成在NX原来的标签页面上&#xff0c;但是我们以前从来没有这么做过&#xff0c;经过一番探索&#xff0c;后来解决了问题。 默认菜单在自定义页面&#xff0c;如下图所示&#xff1a; 但是我们希望这两个按钮…

TCP/IP卷一详解第二章Internet地址结构概要

在这一章中介绍了Internet中使用的网络层地址&#xff08;也就是IP地址&#xff09;&#xff0c;还有如何为Internet中的设备分配地址&#xff0c;以及各种类型的地址等等…… 一、IP地址的表示 为大家所常见的有IPV4地址和IPV6地址&#xff0c;但在IPV4地址中&#xff0c;通…

Docker安装ewomail

ewomail相关链接 官网官方安装文档gitee 开始安装 快速安装 wget -c https://down.ewomail.com/install-03.sh && sh install-03.sh 域名docker安装 创建docker容器 docker run -idt \-p 25:25 \-p 110:110 \-p 143:143 \-p 465:465 \-p 587:587 \-p 993:993 \-…