vue3+element-plus+ts elplus table 实现表格动态列 表格列显示与隐藏的动态控制 支持传递插槽与多级表头

如题

先上效果

vue3+element-plus+ts elplus table 实现表格动态列 表格列显示与隐藏的动态控制 支持传递插槽与多级表头_第1张图片
vue3+element-plus+ts elplus table 实现表格动态列 表格列显示与隐藏的动态控制 支持传递插槽与多级表头_第2张图片

vue3+element-plus+ts elplus table 实现表格动态列 表格列显示与隐藏的动态控制 支持传递插槽与多级表头_第3张图片

部分代码展示

Home页面

使用时除了名字不同其他没啥不同,但是我这个封装的函数或者属性较少,如果需要请自行增加

<script setup lang="ts">
import { IPage } from '@/mixins/pagination'
import { TableKey } from '@/types/enum'
import { useRouter } from 'vue-router'

const router = useRouter()

// #region ts接口

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

// #endregion ts接口

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

// #region 跳转

const toTable = () => {
  router.push({
    name: 'Table'
  })
}

// #endregion 跳转

// #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">
    <h1>home页面h1>
    <div class="home-buttons">
      <div class="home-buttons-opra">
        <el-button type="primary" @click="toTable" >跳转到表格页el-button>
      div>
      <div class="home-buttons-tools">
        <ColumnControl :column-key="TableKey.HOME" />
      div>
    div>
    <div class="home-list">
      <ProjectTable :pagination="pagination" :data="tableData" :column-key="TableKey.HOME">
        <ProjectColumn label="">
          <ProjectColumn prop="name" label="姓名" />
          <ProjectColumn prop="age" label="年龄" >
            <template #default="{ row }">
              <div>
                {{ row.age }}
              div>
            template>
          ProjectColumn>
        ProjectColumn>
        <ProjectColumn prop="random" label="随机数">
          <template #default="{ row }">
            <div>
              {{ row.random }}
            div>
          template>
        ProjectColumn>
      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>

二次封装的表格

<script setup lang="ts">
import ProjectColumn from '@/components/ProjectColumn/index.vue'
import { IPage } from '@/mixins/pagination'
import { TableKey } from '@/types/enum'
import { IColumn, ISetColumn, ISetShowColumn } from '@/store/modules/table'
import { useColumn } from '@/use/useColumn'
import { RendererElement } from 'vue'

const store = useStore()

// #region ts接口

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

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

// #endregion ts接口

// #region 组件传值

const props = withDefaults(defineProps<Props>(), {
  height: '100%',
  pagination: () => ({
    currentPage: 1,
    pageSize: 10,
    total: 0
  }),
  hiddenCheckbox: false,
  hiddenIndex: false
})

const emits = defineEmits<Emits>()

// #endregion 组件传值

onMounted(() => {
  initSoltList()
})

// #region 表格

// 多选切换
const selectionChange = (list: any[]) => {
  emits('selection-change', list)
}

// #endregion 表格

// #region 插槽

const slots = useSlots()
// 当前显示的插槽
const { showColumn } = useColumn(props.columnKey)

// 渲染时的插槽列表
const slotList = ref<RendererElement[]>([])

// 递归时保存全部的动态列
const tempAllColumn = ref<IColumn[]>([])
// 递归时顺便设置展示列
const tempShowColumn = ref<string[]>([])

// 初始化
const initSoltList = () => {
  if (slots.default) {
    slotList.value = slots.default() || []
    setUnique(slotList.value)
    // 如果存在展示列, 则不需要重新赋值了
    if (showColumn.value.length > 0) {
      return
    }
    const columnData: ISetColumn = {
      key: props.columnKey,
      value: tempAllColumn.value
    }
    store.dispatch('setAllColumn', columnData)
    const showColumnData: ISetShowColumn = {
      key: props.columnKey,
      value: tempShowColumn.value
    }
    store.dispatch('setShowColumn', showColumnData)
  }
}

// 设置唯一键, 利用js浅拷贝 此函数执行完成会改变 tempAllColumn 并 设置展示列  tempShowColumn
const setUnique = (list: RendererElement[], prefix?: string, column?: IColumn) => {
  list.map(item => {
    // 是column组件 且 具有label属性
    // ProjectColumn 是 组件ProjectColumn
    if (
      (item.type && item.type === ProjectColumn)
      && (item.props && item.props.label)
    ) {
      let tempColumn: IColumn = {
        value: '',
        label: ''
      }
      // 如果存在前缀 表示是子级
      if (prefix && column) {
        tempColumn = {
          value: `${prefix}-${item.props.label}`,
          label: item.props.label
        }
        if (!column.children) {
          column.children = []
        }
        column.children.push(tempColumn)
      } else { // 不存在前缀 表示不是子级
        tempColumn = {
          value: item.props.label,
          label: item.props.label
        }
        tempAllColumn.value.push(tempColumn)
      }
      tempShowColumn.value.push(tempColumn.value) // 设置展示列
      if (item.children && item.children.default) { // 存在子级
        const tempChildrenList = item.children.default({ row: {}, column: {}, $index: -1 })
        // console.log('tempChildrenList', tempChildrenList)
        setUnique(tempChildrenList, tempColumn.value, tempColumn)
      }
    }
  })
}

// #endregion 插槽

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 v-for="(item, index) in slotList" :key="index">
      <component v-if="showColumn.includes(item.props?.label)" :uni-key="item.props?.label" :column-key="columnKey" :is="item">component>
    template>
  el-table>
template>

<style lang="scss" scoped>style>

其余页面不予展示了,请下载代码后自行查看

由于代码和页面较多,所以不在此文档进行展示,以下是项目地址,具体功能请下载会后自行体验

gitee代码

注意: 由于代码使用了自动导入,刚下载完代码如果不启动的话,会有报错,是因为没有引入,当项目启动后就会运行自动导入,这时就不会报错了

代码内具有部分注释,如果不清楚或者有BUG可在本章进行评论,谢谢

你可能感兴趣的:(vue,前端,vue.js)