vue3+element-plus+ts elplus table 实现表格动态列 表格列显示与隐藏的动态控制

news2024/11/28 2:29:41

工作接了个需求,需要实现表格的动态列,但是后端又不参与,全权交给前端,百度搜了一下,大多都是el-table-column的for循环,我觉得用起来不爽,还得改变el-table-column的书写方式,用对象保存列的相关信息,所以搞了一个这玩应

效果就是不改变书写习惯而且还能达到前端控制列的显示与隐藏

话不多讲,上代码

哦,不对,先上效果
在这里插入图片描述
在这里插入图片描述
动态图没做过,见谅吧

项目结构

简介:

  • ColumnControl为列的控制器
  • ProjectTable为二次封装的el-table表格
  • store中用于存放列的信息以及显示信息
  • Home是使用上述三个东西的页面
    在这里插入图片描述

ColumnControl组件内容

多说一句,由于我的项目使用了自动引入,所以你复制完之后可能有的方法并没有引入,如ref,computed等属于vue,useStore属于vuex,需要自行引入
具体这些个东西都是干什么的见注释吧

<script setup lang="ts">
import { Grid } from '@element-plus/icons-vue'
import { showColumn, allColumn } from '@/store/getters'
import { CheckboxValueType } from 'element-plus'

const store = useStore()

// #region 全选

const checkAll = ref<boolean>(true)

// 选中与半选的状态控制, 条件就是 当前选中的数据个数大于0 且 小于所有列的总数
const isIndeterminate = computed<boolean>(() => {
  return checkList.value.length > 0 && checkList.value.length < allColumn.value.length
})

// 全选与否的事件控制器
const handleCheckAllChange = (boolean: CheckboxValueType) => {
  if (boolean) { // 全选 
    checkList.value = allColumn.value.map(item => item.value)
  }else { // 全不选
    checkList.value = []
  }
}

// #endregion 全选

// #region 多选框

// 当前选中的个数 用了可写的computed属性
const checkList = computed<string[]>({
  get: () => showColumn.value, // showColumn是存在store中的属性
  set: (val: string[]) => {
    store.dispatch('setShowColumn', val)
  }
})

// #endregion 多选框

</script>

<template>
  <el-popover placement="bottom" popper-class="column-popover" :width="200" trigger="click">
    <template #reference>
      <el-button circle :icon="Grid"></el-button>
    </template>
    <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox>
    <el-divider />
    <el-checkbox-group class="column-checkgroup" v-model="checkList">
      <el-checkbox class="column-checkgroup-item" v-for="item in allColumn" :key="item.value" :label="item.value">{{ item.label
      }}</el-checkbox>
    </el-checkbox-group>
  </el-popover>
</template>

<style lang="scss">
.column-popover {
  max-height: 330px;
  overflow-y: auto;
  .el-divider--horizontal {
    margin: 10px 0;
  }
}
.column-checkgroup {
  &-item {
    display: flex;
  }
}
</style>

ProjectTable组件内容

<script setup lang="ts">
import { showColumn } from '@/store/getters'
import { RendererElement } from 'vue'
import { IColumn } from '@/store/modules/table'

// #region ts接口

interface IPage {
  currentPage: number
  pageSize: number
  total: number
}

interface Props {
  data: any[]
  height?: string | number
  pagination?: IPage
  hiddenCheckbox?: boolean
  hiddenIndex?: boolean
}

interface Emits {
  (e: 'selection-change', value: any[]): void
}

// #endregion ts接口

withDefaults(defineProps<Props>(), {
  data: () => [], // 表格数据
  height: '100%', // 表格高度
  hiddenCheckbox: false, // 隐藏表格多选框?
  hiddenIndex: false, // 隐藏表格序号?
  pagination: () => ({ // 翻页,看项目需求,如果翻到第二页需要从11开始,那么就需要这个
    currentPage: 1,
    pageSize: 10,
    total: 0
  })
})

const emits = defineEmits<Emits>()

const store = useStore()

onMounted(() => {
  initSlotList() // 关键, 初始化插槽
})


// #region 插槽

const slots = useSlots()

const slotList = ref<RendererElement[]>([])

const initSlotList = () => {
  if (slots.default) { // el-table-column 使用时不传name 所以属于默认插槽
    slotList.value = slots.default() || [] // 语法
    initDynamicColumn() // 初始化动态列
  }
}

// 初始化动态列
const initDynamicColumn = () => {
  const checkboxList: IColumn[] = [] // 所有列
  slotList.value.map(item => {
    const props = item.props
    // 存在prop属性 label为表头名称
    if (props && typeof props === 'object' && props.prop) {
      checkboxList.push({ value: props.prop, label: props.label })
    }
  })
  store.dispatch('setAllColumn', checkboxList)
}

// #endregion 插槽

// 表格多选事件
const selectionChange = (list: any[]) => {
  emits('selection-change', list)
}

</script>

<template>
  <el-table :data="data" border stripe :height="height" @selection-change="selectionChange"
    header-cell-class-name="header-cell">
    <el-table-column v-if="!hiddenCheckbox" type="selection" align="center" width="55" />
    <el-table-column v-if="!hiddenIndex" type="index" align="center" label="#" width="60">
      <template #default="{ $index }">
        <div>
          {{ $index + (pagination.currentPage - 1) * pagination.pageSize + 1 }}
        </div>
      </template>
    </el-table-column>
    <!-- 这个template 属于核心代码了 -->
    <template v-for="(item, index) in slotList" :key="index">
      <component v-if="showColumn.includes(item.props.prop)" :is="item"></component>
    </template>
  </el-table>
</template>

<style lang="scss" scoped>
</style>

store仓库

别问为什么用vuex 不用pinia 问就是不会

index.ts文件

import table from './modules/table'

const store = createStore({
  modules: {
    table
  }
})

export default store

getters.ts文件


import { IColumn } from './modules/table'
import store from './index'

// vue3 组合api 没法使用mapGetters   弄了个这玩应凑合用

export const allColumn = computed<IColumn[]>(() => {
  return store.getters.allColumn
})

export const showColumn = computed<string[]>(() => {
  return store.getters.showColumn
})


table.ts文件


import { Module } from 'vuex' 

// #region ts接口

export interface IColumn {
  value: string
  label: string
}

interface IState {
  allColumn: IColumn[]
  showColumn: string[]
}

// #endregion ts接口

// Module<S, R> S表示咱们这个页面(table.ts)中的state类型
// R: 由于咱们是模块, 在外面的store使用 store.modules = {table} 挂载的咱们
// 而外面的store也会有 state 属性, 这个R就是外面state属性的类型
// 由于我的store/index.ts没写state,所以这里给个any
const table: Module<IState, any> = {
  state() {
    return {
      allColumn: [], // 表格全部的列 格式 IColumn
      showColumn: [] // 当前展示的列 
    }
  },
  getters: {
    allColumn(state) {
      return state.allColumn
    },
    showColumn(state) {
      return state.showColumn
    }
  },
  mutations: {
    SET_ALL_COLUMN(state, data) {
      state.allColumn = data
    },
    SET_SHOW_COLUMN(state, data) {
      state.showColumn = data
    }
  },
  // 使用时 用actions进行数据更改, 尽量不要使用mutations, 没原因, 建议而已
  actions: {
    setAllColumn({ commit }, data: IColumn[]) {
      commit('SET_ALL_COLUMN', data)
      // 设置全部列时 默认展示所有的列
      const showColumn = data.map(item => item.value)
      commit('SET_SHOW_COLUMN', showColumn)
    },
    setShowColumn({ commit }, data: string[]) {
      commit('SET_SHOW_COLUMN', data)
    }
  }
}

export default table

Home页面

<script setup lang="ts">

// #region ts接口

interface ITableRow {
  name: string,
  age: number,
  random: number
}

interface IPage {
  currentPage: number
  pageSize: number
  total: number
}

// #endregion ts接口

onMounted(() => {
  getList()
})

// #region 表格

// 分页数据, 本例由于动态表格封装所以弄了一个
const pagination = ref<IPage>({
  currentPage: 1,
  pageSize: 10,
  total: 0
})

const tableData = ref<ITableRow[]>([])

// 获取列表
const getList = () => {
  const list: ITableRow[] = []
  for (let i = 0; i < 5; i++) {
    list.push({
      name: '姓名' + Math.floor(Math.random() * 10),
      age: Math.floor(Math.random() * 100),
      random: Math.random()
    })
  }
  tableData.value = list
}

// #endregion 表格

</script>

<template>
  <div class="home">
    <div class="home-buttons">
      <div class="home-buttons-opra">
        <el-button type="primary">没用,占位</el-button>
      </div>
      <div class="home-buttons-tools">
        <ColumnControl />
      </div>
    </div>
    <div class="home-list">
      <!-- 如果要隐藏多选或者序号或者你扩展了什么 <ProjectTable hiddenIndex> 你懂得! -->
      <ProjectTable :pagination="pagination" :data="tableData" >
      	<!-- 使用时就正常使用,不需要写for循环 -->
        <el-table-column prop="name" label="姓名" />
        <el-table-column prop="age" label="年龄" />
        <el-table-column prop="random" label="随机数" />
      </ProjectTable>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.home {
  width: 700px;
  display: flex;
  flex-direction: column;
  &-buttons {
    margin-bottom: 12px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}
</style>

总结

这玩应在使用时除了引用ColumnControl和ProjectTable两个组件以外,与你普通书写el-table是一样的,你也不用重新弄个数组保存所有的列,实现这东西的时候是真的难受,用的时候是爽的不要不要的
注意!!!!!!
我写的这个玩应只是一个最最基本的,没有缓存功能,也没跟用户挂钩,甚至你都不需要关浏览器或者重新登陆,你只要切换一个页面再切回来,这时你刚刚隐藏的列就又会被显示出来,当然要解决这些问题也是完全可以的,不过现在是周五下午五点了,我要下班了,伟大的扩展任务就交给你们了!

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

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

相关文章

软考A计划-2022年05月软件设计师下午真题及答案解析

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

【数据结构】——堆 堆的实现、堆排序、TopK问题

目录 什么是堆&#xff1f;堆的分类堆的实现堆排序——时间复杂度&#xff08;N*logN)TopK问题 什么是堆&#xff1f; 什么是堆&#xff1f; 堆是一种叫做完全二叉树的数据结构&#xff0c;分为大根堆和小堆&#xff0c;堆排序也是基于这种结构产生的。 堆是父亲节点和孩子节点…

爬虫-Webpack逆向实战 有习题

爬虫-Webpack逆向实战 我只要喝点果粒橙关注IP属地: 青海 0.1052022.04.30 19:21:46字数 4,875阅读 5,142 全文目录 webpack打包是前端js模块化压缩打包常用的手段&#xff0c;特征明显&#xff0c;比如下方的形式的代码就是webpack分发器 // 分发器 !function(x){function …

R语言混合效应(多水平/层次/嵌套)模型及贝叶斯实现技术

回归分析是科学研究中十分重要的数据分析工具。随着现代统计技术发展&#xff0c;回归分析方法得到了极大改进。混合效应模型&#xff08;Mixed effect model&#xff09;&#xff0c;即多水平模型&#xff08;Multilevel model&#xff09;/分层模型(Hierarchical Model)/嵌套…

linuxOPS基础_linux安装配置

Linux系统下载 Linux系统版本选择&#xff1a;CentOS7.6 x64&#xff0c;【镜像一般都是CentOS*.iso文件】 问题&#xff1a;为什么不选择最新版的8 版本&#xff1f; 7.x 目前依然是主流 7.x 的各种系统操作模式是基础 官网&#xff1a;https://www.centos.org/ &#xff0c;…

mysql8.0 修改密码

我使用的是 docker&#xff0c;但是这一期主要是讲解 mysql8 版本修改密码&#xff0c;我相信 linux、windows 和不使用 docker 应该都是可以的。 先说一下我的情况&#xff1a; 我在本地 windows 玩 docker 部署 mysql8.0.25 版本&#xff0c;无问题啦~ 然后我在 linux 里面玩…

模拟strcpy函数,assert,const修饰指针与凉皮男孩的故事

那么好了好了&#xff0c;宝子们&#xff0c;今天给大家介绍一下strcpy函数及其模拟&#xff0c;还有assert&#xff0c;const与凉皮男孩间的爱恨情仇&#xff0c;来吧&#xff0c;开始整活&#xff01;⛳️&#xff08;今天的内容和故事非常的有趣&#xff0c;希望大家一键三连…

黑马学生入职B站1年,晒出21K月薪:我想跳槽华为

现在的Z时代&#xff0c;嘴上说着不要&#xff0c;身体却很诚实。 前两天&#xff0c;黑马发布了《2022年度互联网平均薪资出炉&#xff01;高到离谱&#xff01;》&#xff0c;信息传输、软件和信息技术服务业薪资遥遥领先&#xff01;Z时代举头望着天花板&#xff0c;故作潇…

jsvmp逆向实战x-s、x-t算法还原

jsvmp逆向实战x-s、x-t算法还原 什么是jsvmp定位关键点log插桩日志分析代码还原 什么是jsvmp jsvmp就是将js源代码首先编译为自定义的字节码&#xff0c;只有对应的解释器才能执行这种字节码&#xff0c;这是一种前端代码虚拟化保护技术。 整体架构流程是服务器端通过对JavaS…

Sui基金会联合Tencent Cloud和Numen在香港举办的生态交流会圆满结束

5月24日&#xff0c;由Sui基金会、Tencent Cloud和Numen Cyber联合举办的Sui生态交流会在香港圆满结束。感谢Tencent Cloud为本次活动提供了场地支持。本次活动共吸引了60余名行业同仁线上和线下的参与。 本次活动旨在提升Web3产业对Sui生态的认识&#xff0c;并为生态中的开发…

调用华为API实现图像搜索

调用华为API实现图像搜索 1、作者介绍2、华为API介绍2.1 华为云图像搜索2.2 图像搜索应用场景2.2.1商品图片搜索2.2.2版权图片搜索 2.3 调用华为API实现图像标签 3、实验过程3.1完整代码3.2运行结果3.3常见错误 1、作者介绍 张勇进&#xff0c;男&#xff0c;西安工程大学电子…

通过Python的pdfplumber库将pdf转为图片

文章目录 前言一、pdfplumber库是什么&#xff1f;二、安装pdfplumber库三、查看pdfplumber库版本四、pdf素材五、将pdf转为图片1.引入库2.定义pdf路径3.打开PDF文件4.遍历每一页5.将PDF页面转换为Image对象6.将Image对象保存为图片文件7.效果 总结 前言 大家好&#xff0c;我是…

ChatGLM-6B之SSE通信(Server-sent Events)

写这篇博客还是很激动开心的&#xff0c;因为是我经过两周的时间&#xff0c;查阅各个地方的资料&#xff0c;经过不断的代码修改&#xff0c;不断的上传到有显卡的服务器运行才得出的可行的接口调用解决方案&#xff0c;在这里记录并分享一下。 研究历程&#xff08;只是感受&…

更适合iPhone的手柄,按键手感真不赖,LEADJOY M1B上手

很多朋友平时玩手游的时候&#xff0c;操作体验往往不是很好&#xff0c;特别是到了夏天&#xff0c;手机玩久了总是热气腾腾的&#xff0c;对此&#xff0c;只需要配上一副手游手柄&#xff0c;就可以获得媲美掌机的游戏体验。最近我就在用一款LEADJOY M1B游戏手柄&#xff0c…

如何选择语音芯片?主流语音方案如何选,九芯电子来推荐

市场分析 近年来&#xff0c;随着我国半导体的不断发展和技术领域的不断突破&#xff0c;语音芯片实现了越来越多的国产化。其中涌现出的像NVD系列、NRK330X系列等不乏国产优秀产品。凭借其优秀的性能、设计&#xff0c;赢得了市场上的好评如潮。 对比分析 OTP语音芯片&#…

webAPI学习笔记3——BOM浏览器对象模型

目录 1、BOM概述 1.1 什么是 BOM 1.2 BOM 的构成 2. window 对象的常见事件 2.1 窗口加载事件 2.2 调整窗口大小事件 3. 定时器 3.1 两种定时器 3.2 setTimeout() 定时器 案例&#xff1a; 5秒后自动关闭的广告 3.3 停止 setTimeout() 定时器 3.4 setInterval() 定时…

解决不联网环境pip安装librosa、numba、llvmlite报错和版本兼容问题

项目场景&#xff1a; 项目是需要在内网不联网环境部署GitHub上一个有关音频、视频处理的深度学习Python工程&#xff0c;因此许多包需要下载好wheel包或tar包后在内网环境安装。 这个过程遇到了许多兼容性问题引起的报错。Python版本与librosa、numba、llvmlite版本兼容问题…

小狗避障-第14届蓝桥杯省赛Scratch中级组真题第4题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第139讲。 小狗避障&#xff0c;本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组编程第4题&#xf…

从代码审计的角度分析 Ruoyi v4.7.6 的任意文件下载漏洞

前言 Ruoyi 的 v4.7.6 是 2022 年 12 月 16 日发布的一个版本&#xff0c;而任意文件下载漏洞实际上 12 月底的时候就已经爆出了&#xff0c;也陆续有一些文章在写这个漏洞&#xff0c;但是 Ruoyi 一直没有更新修复。 上月中旬&#xff08;2023 年 5 月&#xff09;&#xff0c…

内网渗透(八十四)之ADCS配置启用基于SSL的LDAP(LDAPS)

ADCS配置启用基于SSL的LDAP(LDAPS) 打开AD CS,选择证书颁发机构 选择证书模板,右键管理 选择Kerberos身份验证,右键 复制模板 然后会有一个Kerberos身份验证的副本,右键更改名称,更改为LDAPS 选择LDAPS,右键属性 设置模板属性,请求处理——>允许导出私钥(O) 创建证书…