vue3 动态配置element 的table

需求

合并行、合并标题、列宽可调整、列顺序可调整、可以控制列是否显示、列布局可保存、导出excel…
需求

参考效果

在这里插入图片描述
在这里插入图片描述

代码

引入

npm i xlsx
npm install element-plus --save

table组件


<template>
  <div>
    <div class="table-btn">
      <el-tooltip content="高级筛选" placement="bottom" effect="light">
        <el-button :icon="Search" circle @click="dialogRulesVisible = true" />
      </el-tooltip>
      <el-tooltip content="修改table" placement="bottom" effect="light">
        <el-button :icon="EditPen" circle @click="dialogVisible = true" />
      </el-tooltip>
      <el-tooltip content="导出xlsx" placement="bottom" effect="light">
        <el-button :icon="Download" circle @click="exportBtn" />
      </el-tooltip>
    </div>

    <el-table :data="tableData" style="width: 100%" ref="exportTableRef">
      <template v-for="item in tablePropList">
        <el-table-column
          sortable
          :key="item.prop"
          :prop="item.prop"
          :label="item.label"
          :align="item.align"
          :width="item.width == 0 ? '' : item.width"
          v-if="item.isShow == 0"
          :fixed="item.fixed"
        >
          <template v-if="item.children.length > 0">
            <template v-for="itemChildren in item.children">
              <el-table-column
                :key="itemChildren.prop"
                sortable
                :prop="itemChildren.prop"
                :label="itemChildren.label"
                :align="itemChildren.align"
                :width="itemChildren.width == 0 ? '' : itemChildren.width"
                v-if="itemChildren.isShow == 0"
              >
              </el-table-column>
            </template>
          </template>
        </el-table-column>
      </template>
      <!-- 插槽 -->
      <slot />
    </el-table>

    <!-- 把这个改成表格 -->
    <el-dialog v-model="dialogVisible" title="修改表格" width="80%">
      <div class="over-height">
        <el-table :data="tablePropList" style="width: 100%" row-key="prop">
          <el-table-column prop="date" label="表格名">
            <template #default="scope">
              <el-input v-model="scope.row.label" />
            </template>
          </el-table-column>
          <el-table-column prop="date" label="序列">
            <template #default="scope">
              <el-input-number v-model="scope.row.index" :min="0" :max="100" />
            </template>
          </el-table-column>
          <el-table-column prop="date" label="宽度(0为自适应)">
            <template #default="scope">
              <el-input-number v-model="scope.row.width" :min="0" :max="1000" />
            </template>
          </el-table-column>
          <el-table-column prop="date" label="对齐方式">
            <template #default="scope">
              <el-select v-model="scope.row.align">
                <el-option label="左对齐" value="left" />
                <el-option label="居中" value="center" />
                <el-option label="右对齐" value="right" />
              </el-select>
            </template>
          </el-table-column>
          <el-table-column prop="date" label="是否固定">
            <template #default="scope">
              <el-select v-model="scope.row.fixed">
                <el-option label="左侧固定" value="left" />
                <el-option label="右侧固定" value="right" />
              </el-select>
            </template>
          </el-table-column>
          <el-table-column prop="date" label="是否显示">
            <template #default="scope">
              <el-select v-model="scope.row.isShow">
                <el-option label="显示" value="0" />
                <el-option label="隐藏" value="1" />
              </el-select>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="sortTableData(0)"
            >保存并确定</el-button
          >
          <el-button type="primary" @click="sortTableData(1)">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <el-dialog v-model="dialogRulesVisible" title="高级筛选" width="80%">
      <el-button-group class="ml-4">
        <el-button type="primary" plain @click="rulesTableData(0)"
          >保存方案</el-button
        >
        <el-button type="primary" plain>另存方案</el-button>
        <el-button type="primary" plain>重置条件</el-button>
      </el-button-group>
      <div class="over-height">
        <div v-for="item in tablePropList" :key="item.prop">
          <!-- 允许筛选且显示状态下出现筛选列表 -->
          <template v-if="item.isSwitch && item.isShow">
            <el-form :inline="true" :model="item" class="demo-form-inline">
              <el-form-item>
                <el-select v-model="item.rules.a" placeholder="表格">
                  <el-option
                    :label="propItem.label"
                    :value="propItem.prop"
                    v-for="propItem in tablePropList"
                    :key="propItem.prop"
                  />
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-select v-model="item.rules.a" placeholder="并且">
                  <el-option label="并且" value="0" />
                  <el-option label="" value="1" />
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-select v-model="item.rules.b" placeholder="等于">
                  <template v-if="item.propType == 'string'">
                    <el-option label="等于" value="0" />
                    <el-option label="包含" value="1" />
                    <el-option label="大于" value="2" />
                    <el-option label="小于" value="3" />
                  </template>
                  <template v-else-if="item.propType == 'number'">
                    <el-option label="等于" value="0" />
                    <el-option label="大于" value="2" />
                    <el-option label="小于" value="3" />
                  </template>
                  <template v-else>
                    <el-option label="等于" value="0" />
                    <el-option label="大于" value="2" />
                    <el-option label="小于" value="3" />
                  </template>
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-input v-model="item.rules.value" />
              </el-form-item>
              <el-form-item>
                <el-button :icon="Close" circle @click="exportBtn" />
              </el-form-item>
            </el-form>
          </template>
        </div>
      </div>

      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="rulesTableData(1)">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
// npm i xlsx
// npm install element-plus --save
import { EditPen, Download, Search, Close } from "@element-plus/icons-vue";
import { ref } from "vue";
import { toRefs, defineProps, defineEmits } from "vue";
const emit = defineEmits(["tableRules"]);

// 弹窗布尔值
const dialogVisible = ref(false);
const dialogRulesVisible = ref(false);

// 接收值
const props = defineProps({
  //子组件接收父组件传递过来的值
  tableData: Array,
  tablePropsList: Object,
});
//使用父组件传递过来的值
const { tableData, tablePropsList } = toRefs(props);

// 获取当前页的配置表
const localTable = JSON.parse(localStorage.getItem("table"));
var configuration = [];
var configurationRules = [];

if (localTable) {
  configuration = localTable[tablePropsList.value.id].configuration;
  configurationRules = localTable[tablePropsList.value.id].rules;
} else {
  // 没有的话就新建一个保存
  let obj = {
    [tablePropsList.value.id]: {
      configuration: [],
      rules: [],
    },
  };
  localStorage.setItem("table", JSON.stringify(obj));
}

const tablePropList = ref([]);
// 处理数据(原始传入数据,本地存储的数据,导出的数据)
const switchTableData = (tableData, localStorageData, addData) => {
  // prop: 表格绑定字段, label:当前名, index:表格当前序列,width:表格当前宽度,align: 对齐方式 left左 center中 right右,isShow:是否显示 0显示,1隐藏
  tableData.forEach((e, index) => {
    if (localStorageData && localStorageData.length > 0) {
      localStorageData.forEach((ec) => {
        if (ec.prop == e.prop) {
          let obj = {
            prop: ec.prop,
            label: ec.label,
            index: ec.index,
            width: ec.width,
            isShow: ec.isShow,
            align: ec.align,
            fixed: ec.fixed,
            children: [],
            rules: ec.rules,
            propType: ec.propType,
            isSwitch: ec.isSwitch,
          };
          addData.push(obj);
          if (e.children) {
            switchTableData(e.children, ec.children, obj.children);
          }
        }
      });
    } else {
      let obj = {
        prop: e.prop,
        label: e.label,
        index: index,
        width: e.width ? e.width : 0,
        isShow: e.isShow ? e.isShow : "0",
        align: e.align ? e.align : "center",
        fixed: e.fixed ? e.fixed : "",
        children: [],
        rules: {},
        propType: e.propType ? e.propType : "string",
        isSwitch: e.isSwitch ? e.isSwitch : true,
      };
      addData.push(obj);
      if (e.children) {
        switchTableData(e.children, null, obj.children);
      }
    }
  });
};

switchTableData(tablePropsList.value.props, configuration, tablePropList.value);

// 给数组排序
const sortTableData = (type) => {
  // type 0 保存并确定 1 确定
  tablePropList.value.sort(function (a, b) {
    return a.index - b.index; // 根据升序排序
  });
  dialogVisible.value = false;
  if (type == 0) {
    let arr = JSON.parse(localStorage.getItem("table")) || {};
    arr[tablePropsList.value.id].configuration = tablePropList.value;
    localStorage.setItem("table", JSON.stringify(arr));
  }
};

// 数据添加筛选规则
const rulesTableData = (type) => {
  // type 0 保存并确定 1 确定
  dialogRulesVisible.value = false;
  let rulesList = [];
  tablePropList.value.forEach((e) => {
    rulesList.push(e.rules);
  });
  if (type == 0) {
    let arr = JSON.parse(localStorage.getItem("table")) || {};
    arr[tablePropsList.value.id].rules = configurationRules;
    localStorage.setItem("table", JSON.stringify(arr));
  }

  //传递给父组件
  emit("tableRules", rulesList);
};

// 导出功能
import * as XLSX from "xlsx";
const exportTableRef = ref(null);
const exportBtn = () => {
  const tableDom = exportTableRef.value?.$el;
  if (!tableDom) {
    return;
  }

  const wb = XLSX.utils.table_to_book(tableDom);
  XLSX.writeFile(wb, "表格数据.xlsx");
};
</script>


<style scoped>
.over-height {
  max-height: 60vh;
  overflow-y: auto;
}
.el-select,
.el-input {
  width: 200px;
}
.table-btn {
  float: right;
  margin-bottom: 2px;
}
.last-table {
  width: 94%;
  margin: 0 auto;
}
</style>


demo

<template>
  <div>
    <h2>直接使用</h2>
    <!-- 
      tableData 是渲染表单的原始数据,
      tablePropsList是表单的规则数据,
      tableRules 是表单返回的筛选数据,数据在tableRules(val)方法中取返回值 val
      -->
    <tableVue
      :tableData="tableData"
      :tablePropsList="tablePropsList"
      @tableRules="tableRules"
    />

    <h2>添加操作等栏目</h2>
    <tableVue :tableData="tableData" :tablePropsList="tablePropsList">
      <!-- 该组件可继续添加表格数据 -->
      <!-- 如果需要增加操作栏列等,可以按照以下格式添加 -->
      <el-table-column fixed="right" label="Operations" width="120">
        <template #default="scope">
          <el-button link type="primary" size="small">
            Remove{{ scope.$index }}
          </el-button>
        </template>
      </el-table-column>
    </tableVue>
  </div>
</template>
<script setup>
import { ref } from "vue";
import tableVue from "./components/table.vue";
// 定义的数据
const tableData = ref([
  {
    id:1,
    date: "2016-05-03",
    name: "Aom1",
    address: "No. 189, Grove St, Los Angeles",
    count: 1,
    address3: "address3",
    address4: "address4",
  },
  {
    id:2,
    date: "2016-05-02",
    name: "BTom2",
    address: "No. 189, Grove St, Los Angeles",
    count: 1,
    address3: "address3",
    address4: "address4",
  },
  {
    id:3,
    date: "2016-05-04",
    name: "CTom",
    address: "No. 189, Grove St, Los Angeles",
    count: 1,
    address3: "address3",
    address4: "address4",
  },
  {
    id:4,
    date: "2016-05-01",
    name: "DTom",
    address: "No. 189, Grove St, Los Angeles",
    count: 1,
    address3: "address3",
    address4: "address4",
  },
]);

// 需要定义关键字和关键字的label
const tablePropsList = ref({
  // id 唯一值
  id: "text-table",
  /**
   * 必填项
   * label为表格名
   * prop对应表格的参数
   * 
   * 选填
   * width 表格宽度,0自适应,可填数字,默认自适应
   * isShow 是否显示 0 显示,1不显示,默认0
   * align 对其方式 left 左对齐, center居中对其,right:右对齐,默认center
   * fixed 是否固定 left 固定左侧,right 固定右侧,空值不固定,默认空
   * propType 数据类型,默认为空
   * isSwitch 是否可筛选 默认true
   */
  props: [
    { label: "姓名", prop: "name", propType: "string", isSwitch: true, isShow: "0"},
    { label: "时间", prop: "date", propType: "string", isSwitch: true, isShow: "0" },
    { label: "地址", prop: "address", propType: "string" , isSwitch: true, isShow: "0"},
    { label: "数量", prop: "count", propType: "number", isSwitch: true, isShow: "0" },
    {
      label: "其他地址",
      prop: "address2",
      // children 为子数据
      children: [
        { label: "地址3", prop: "address3" , propType: "string", isSwitch: true, isShow: "0" },
        { label: "地址4", prop: "address4" , propType: "string", isSwitch: false , isShow: "0"},
      ],
    },
  ],
});

// 接收子组件返回的筛选规则
const tableRules = (val) => {
  console.log("rules", val);
};
</script>


<style scoped>
</style>


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开发一套java语言的智能导诊需要什么技术?java+ springboot+ mysql+ IDEA互联网智能3D导诊系统源码

开发一套java语言的智能导诊需要什么技术&#xff1f;java springboot mysql IDEA互联网智能3D导诊系统源码 医院导诊系统是一种基于互联网和3D人体的智能化服务系统&#xff0c;旨在为患者提供精准、便捷的医院就诊咨询服务。该系统整合了医院的各种医疗服务资&#xff1b;智慧…

selenium 简介以及 selenium 环境配置

文章目录 一、初识 selenium1.selenium 简介2.selenium 三大组件3.selenium工作过程和原理4.selenium自动化测试流程5.selenium优点 二、自动化测试1.UI自动化本质2.UI自动化的前提3.适用场景4.UI自动化的原则5.UI自动化的覆盖率 三、selenium 环境配置 一、初识 selenium 1.s…

Win11找不到组策略编辑器(gpedit.msc)解决

由于需要同时连接有线网络和无线网络&#xff0c;且重启后双网络都自动连接&#xff0c;因此需要配置组策略。 但是win11找不到组策略编辑器。 灵感来源&#xff1a;Win11找不到组策略编辑器&#xff08;gpedit.msc&#xff09;解决教程 - 知乎 (zhihu.com) 在Win11中&#…

安装KB5039212更新卡在25% 或者 96% 进度

系统之家7月1日消息&#xff0c;微软在6月11日的补丁星期二活动中&#xff0c;为Windows 11系统推出了KB5039212更新。然而&#xff0c;部分用户在Windows社区中反映&#xff0c;安装过程中出现失败&#xff0c;进度条在25%或96%时卡住。对于遇到此类问题的Windows 11用户&…

创意无界:探索国产创成式填充的无限潜力

在数字艺术与设计的世界中&#xff0c;创新技术不断涌现&#xff0c;而"创成式填充"无疑是其中的一颗璀璨新星。今天米兔要安利的这款国产ps插件-StartaAI拥有强大的AI功能&#xff0c;其AI扩图和局部重绘更是成为PS创成式填充的国产平替。 什么是创成式填充&#x…

Linux运维:mysql高级查询语句(2)

目 录 一、创建数据库&#xff1a; 二、创建表结构&#xff1a;DDL 2.1 学生表s&#xff1a; 2.2 成绩表sc&#xff1a; 2.3 课程表c&#xff1a; 三、录入数据&#xff1a;DML 3.1 对学生表s的数据录入&#xff1a; 3.2 对成绩表sc的数据录入&#xff1a; 3.3 对课…

Linux内核——Linux内核体系模式(二)

1 Linux系统的中断机制 Linux内核将中断分为两类&#xff1a;硬件中断和软件中断&#xff08;异常&#xff09;。每个中断是由0-255之间的一个数字进行标识。 中断int0-int31&#xff08;0x00-0x1f&#xff09;作为异常int32-int255由用户自己设定 int32-int47对应与8259A中断…

4PCS点云配准算法实现

4PCS点云配准算法的C实现如下&#xff1a; #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/common/common.h> #include <pcl/common/distances.h> #include <pcl/common/transforms.h> #in…

经典案列|淘宝商品数据爬取与分析

商品详情页 API接口测试代码 -- 请求示例 url 默认请求参数已经URL编码处理 curl -i "https://api-服务器.cn/taobao/item_get/?key<您自己的apiKey>&secret<您自己的apiSecret>&num_iid45887133725&is_promotion1" API测试页 商品详情页返…

解析 Ferret-UI:多模态大模型在移动用户界面理解中的应用

移动应用的爆炸性增长&#xff0c;用户界面&#xff08;UI&#xff09;的设计越来越复杂&#xff0c;功能也越来越丰富。但现有的多模态大模型&#xff08;MLLMs&#xff09;在理解用户界面时存在局限&#xff0c;尤其是在处理具有特定分辨率和包含众多小型对象&#xff08;如图…

重生之算法刷题之路之链表初探(三)

算法刷题之路之链表初探&#xff08;三&#xff09; 今天来学习的算法题是leecode2链表相加&#xff0c;是一道简单的入门题&#xff0c;但是原子在做的时候其实是有些抓耳挠腮&#xff0c;看了官解之后才恍然大悟&#xff01; 条件 项目解释 有题目可以知道&#xff0c;我们需…

EAGLE-2:一种高效无损的推测性采样方法,提升LLM的推理速度。

欢迎关注我的公众号&#xff1a;Halo咯咯 01。概述 北京大学的研究人员联合微软研究院、滑铁卢大学以及Vector研究所共同推出了EAGLE-2&#xff0c;这是一种利用上下文感知的动态草图树来增强推测性采样的方法。EAGLE-2在先前的EAGLE方法基础上进行了改进&#xff0c;不仅显著…

运维锅总详解RocketMQ

本文尝试从Apache RocketMQ的简介、主要组件及其作用、3种部署模式、Controller集群模式工作流程、最佳实践等方面对其进行详细分析。希望对您有所帮助&#xff01; 一、Apache RocketMQ 简介 Apache RocketMQ 是一个开源的分布式消息中间件&#xff0c;由阿里巴巴集团开发并…

uniapp微信小程序电子签名

先上效果图&#xff0c;不满意可以直接关闭这页签 新建成单独的组件&#xff0c;然后具体功能引入&#xff0c;具体功能点击签名按钮&#xff0c;把当前功能页面用样式隐藏掉&#xff0c;v-show和v-if也行&#xff0c;然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…

JVM与Java体系结构

1.JVM与Java体系结构 1.1. 前言 作为Java工程师的你曾被伤害过吗&#xff1f;你是否也遇到过这些问题&#xff1f; 运行着的线上系统突然卡死&#xff0c;系统无法访问&#xff0c;甚至直接OOM想解决线上JVM GC问题&#xff0c;但却无从下手新项目上线&#xff0c;对各种JVM…

运算放大器重要参数详解

运算放大器是一种用于放大电压并实现信号处理和放大的电子设备。以下是运算放大器的一些重要参数及其详解: 增益(Gain): 定义:增益是运算放大器输出电压与输入电压之比,表示运算放大器在输入信号上的放大倍数。重要性:增益决定了信号的放大程度,是运算放大器的基本功能…

python基础语法 004-2流程控制- for遍历

1 遍历 1.1 什么是遍历&#xff1f; 可以遍历的元素&#xff1a;字符串、列表、元组、字典、集合字符串是可以进行for 循环。&#xff08;容器对象&#xff0c;序列&#xff09;可迭代对象iterable 例子&#xff1a; 1 &#xff09;、for遍历字符串&#xff1a; name xiao…

某安全公司DDoS攻击防御2024年6月报告

引言&#xff1a; 在2024年6月&#xff0c;网络空间的安全挑战汹涌澎湃。分布式拒绝服务&#xff08;DDoS&#xff09;攻击频发&#xff0c;针对云服务、金融科技及在线教育平台的精密打击凸显出当前网络威胁环境的严峻性。 某安全公司作为网络安全防护的中坚力量&#xff0c…

中电金信:金Gien乐道 | 6月热门新闻盘点 回顾这一月的焦点事件

“以检之力 e企守护”——上海市检一分院与中电金信开展联学联建 6月24日&#xff0c;上海市人民检察院第一分院与中电金信数字科技集团股份有限公司联合开展“以检之力 e企守护”联学联建活动。双方共同参观了全国检察机关证券期货犯罪办案基地和重大职务犯罪案件办理&#xf…

【办公类-21-18】20240701 养老护理员初级选择题488,制作PyQt5图形界面GUI

背景需求&#xff1a; 6月16日育婴师高级考完了。运气好&#xff0c;抽到的是”护理患腹泻的幼儿”&#xff0c;“晨检与家长沟通”&#xff0c;“4个月婴儿喂蛋黄”&#xff0c;“21个月食谱”&#xff0c;都是我背过的题目&#xff08;没有抽到感统&#xff09; 于是一放假&…