vue3 动态配置element 的table

news2024/10/7 16:19:48

需求

合并行、合并标题、列宽可调整、列顺序可调整、可以控制列是否显示、列布局可保存、导出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>


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

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

相关文章

Java学习笔记(一)Java内容介绍、程序举例、DOS命令、Java跨平台特性的本质、课后练习

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍Java内容介绍、程序举例、DOS命令、Java跨平台特性的本质还有几道课后练习详细介绍以及部分理论知识 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主收将持续更新学习记录获,友友们有任何问题可以在评论区留言 …

互联网信任危机:Perplexity搜索引擎如何破坏内容创作者的权益

前段时间&#xff0c;Perplexity搜索引擎还是一颗冉冉升起的明日之星&#xff0c;手握巨额投资&#xff0c;有很美好的未来前景&#xff0c;这时&#xff0c;如果不出意外的话&#xff0c;要出意外。 喜好儿网 Perplexity这家公司&#xff0c;它正试图通过创建一个新型的“答…

使用python基于经纬度获取高德地图定位地址【逆地址解析】

一、高德地图api申请 1. 高德开放平台注册&#xff0c;登录 进入网址&#xff1a;高德开放平台 | 高德地图API 注册 -- 支付宝扫码认证 -- 完善个人信息 -- 登录 2. 申请API &#xff08;1&#xff09;点击头像 -- 应用管理 -- 我的应用 -- 创建新应用 &#xff08;2&…

【小程序静态页面】猜拳游戏大转盘积分游戏小程序前端模板源码

猜拳游戏大转盘积分游戏小程序前端模板源码&#xff0c; 一共五个静态页面&#xff0c;首页、任务列表、大转盘和猜拳等五个页面。 主要是通过做任务来获取积分&#xff0c;积分可以兑换商品&#xff0c;也可用来玩游戏&#xff1b;通过玩游戏既可能获取奖品或积分也可能会消…

C++再谈构造函数、隐式类型转换、static成员、友元函数、内部类等的介绍

目录 前言一、再谈构造函数1. 构造函数体赋值2. 初始化列表3. 初始化列表初始化顺序4. 初始化隐式类转换 二、static成员1. 概念2. 特性 三、 友元1. 友元函数2. 友元类 四、内部类总结 前言 C再谈构造函数、隐式类型转换、static成员、友元函数、内部类等的介绍 一、再谈构造…

Go 实现SFTP连接服务

我们将SFTP连接和处理逻辑&#xff0c;以及登录账户信息封装&#xff0c;这样可以在不同的地方重用代码&#xff0c;并且可以轻松地更改登录凭据。下面我将演示如何使用Go语言中的结构体来封装这些信息&#xff0c;并实现一个简单的SFTP服务器&#xff1a; package mainimport…

亚太杯赛题思路发布(中文版)

导读&#xff1a; 本文将继续修炼回归模型算法&#xff0c;并总结了一些常用的除线性回归模型之外的模型&#xff0c;其中包括一些单模型及集成学习器。 保序回归、多项式回归、多输出回归、多输出K近邻回归、决策树回归、多输出决策树回归、AdaBoost回归、梯度提升决策树回归…

3d模型里地毯的材质怎么赋予?---模大狮模型网

在进行3D建模时&#xff0c;赋予地毯逼真的材质是营造现实感和增强场景氛围的重要步骤。模大狮将介绍在常见的3D建模软件中&#xff0c;如何有效地为地毯赋予各种材质&#xff0c;以及一些实用的技巧和注意事项。 一、选择合适的地毯材质 在3D建模中&#xff0c;地毯的材质选择…

【ai】tx2 nx: trition client安装nvidia-pyindex 一直失败

系统版本的pip和python虚拟环境的pipyolov4-triton-tensorrt的master分支 官方client jetson:pip3 install --user nvidia-pyindex 不成功啊 这个是让nvidia-pyindex 拉取nvidia@tx2-nx:~$ pip3 install --user nvidia-pyindex Collecting nvidia-pyindexDownloading https://…

center()方法——字符串居中填充

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 字符串对象的center()方法用于将字符串填充至指定长度&#xff0c;并将原字符串居中输出。center()方法的语法格式如下&#xff1a; str.…

用Python将PowerPoint演示文稿转换到图片和SVG

PowerPoint演示文稿作为展示创意、分享知识和表达观点的重要工具&#xff0c;被广泛应用于教育、商务汇报及个人项目展示等领域。然而&#xff0c;面对不同的分享场景与接收者需求&#xff0c;有时需要我们将PPT内容以图片形式保存与传播。这样能够避免软件兼容性的限制&#x…

使用Colly库进行高效的网络爬虫开发

引言 随着互联网技术的飞速发展&#xff0c;网络数据已成为信息获取的重要来源。网络爬虫作为自动获取网页内容的工具&#xff0c;在数据分析、市场研究、信息聚合等领域发挥着重要作用。本文将介绍如何使用Go语言中的Colly库来开发高效的网络爬虫。 什么是Colly库&#xff1…

笔记本电脑为什么可以链接热点,却无法连接WiFi

① 在开始菜单的搜索栏中&#xff0c;输入 cmd 。 ② 右击上方该程序&#xff0c;选择 以管理员身份运行 ③ 输入&#xff1a;nestsh winsock reset ④ 敲击回车&#xff0c;显示如下页面 ⑤ 再输入 ipconfig/flushdns 回车 ⑥ 然后重启电脑&#xff0c;OVER&#xff01;

MySQL高级-SQL优化- count 优化 - 尽量使用count(*)

文章目录 1、count 优化2、count的几种用法3、count(*)4、count(id)5、count(profession)6、count(null)7、 count(1) 1、count 优化 MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count&#xff08;*&#xff09;的时候会直接返回这个数&#xff0c;效率很高&a…

【python】socket通信代码解析

目录 一、socket通信原理 1.1 服务器端 1.2 客户端 二、socket通信主要应用场景 2.1 简单的服务器和客户端通信 2.2 并发服务器 2.3 UDP通信 2.4 文件传输 2.5 HTTP服务器 2.6 邮件发送与接收 2.7 FTP客户端 2.8 P2P文件共享 2.9 网络游戏 三、python中Socket编…

信息学奥赛初赛天天练-38-CSP-J2021阅读程序-约数个数、约数和、埃氏筛法、欧拉筛法筛素数应用

PDF文档公众号回复关键字:20240628 2021 CSP-J 阅读程序3 1阅读程序(判断题1.5分 选择题3分 共计40分 ) 01 #include<stdio.h> 02 using namespace std; 03 04 #define n 100000 05 #define N n1 06 07 int m; 08 int a[N],b[N],c[N],d[N]; 09 int f[N],g[N]; 10 11 …

Linux操作系统学习:day07

内容来自&#xff1a;Linux介绍 视频推荐&#xff1a;[Linux基础入门教程-linux命令-vim-gcc/g -动态库/静态库 -makefile-gdb调试]( 目录 day0742、使用 grep 搜索文件内容43、使用 locate 搜索文件44、 vim 的安装和介绍vim的模式 45、命令模式下光标的移动1、保存退出2、代…

昇思MindSpore学习总结四——数据变换Transforms

1、数据变换 数据变换&#xff0c;字面意思&#xff0c;就是将我们在实际项目中获取的数据进行相应的操作&#xff0c;方便后期处理。数据变换的方法很多&#xff0c;例如归一化、标准化等。 为什么要进行数据变换&#xff1f;&#xff08;1&#xff09;我们采集到的数据&#…

Linux——echo命令,管道符,vi/vim 文本编辑器

1.echo 命令 作用 向终端设备上输出字符串或变量的存储数据 格式 echo " 字符串 " echo $ 变 量名 [rootserver ~] # echo $SHELL # 输出变量的值必须加 $ /bin/bash [rootserver ~] # str1" 我爱中国 " # 自定义变量 echo 重定向输出到文件 ec…

简单的本地局域网的前后端接口联调

由于项目被赶进度了&#xff0c;急于前后端联调接口&#xff0c;但是我又没钱买服务器&#xff08;主要我也不会部署&#xff09;&#xff0c;所以我这里就紧急找一个后端的大神朋友请教了一下&#xff1a;苏泽SuZe-CSDN博客 提示&#xff1a;这里不讲后端怎么写接口、前端怎么…