elementPlus+vue3 table header field setting component drag and drop sorting reset display and hide (vue3+ts)

Insert image description here

1. Install vuedraggable

 npm i -S vuedraggable@next   &   yarn add vuedraggable@next

2. Encapsulate the tableHeades component

  ### components/tableHeades/index.vue
<template>
  <div style="display: inline-block; margin-right: 10px">
    <el-dropdown ref="dropdown" trigger="contextmenu">
      <el-button icon="Setting"  type="primary" plain @click="showClick">字段设置</el-button>
      <template #dropdown>
        <el-dropdown-menu>
          <div class="flex-between" style="height: 30px">
            <p>展示字段</p>
            <el-button type="text" @click="defineFieldReset()">重置</el-button>
          </div>

          <el-dropdown-item style="height:300px;">
            <el-scrollbar>
              <Draggable class="t_table_column_setting_dropdown" v-model="state.columnSet" item-key="prop">
                <template #item="{ element, index }">
                  <el-checkbox @mouseover.native="CheckBoxClick(index)"
                    :class="[{ ActiveDashed: index == state.activeIndex }]" :checked="!element.hidden"
                    v-model="element.AllSelect" @click.native.stop :disabled="element.checkBoxDisabled"
                    @change="checked => checkChanged(checked, index)">
                    {
    
    {
    
     element.label }}
                  </el-checkbox>
                </template>
              </Draggable>
            </el-scrollbar>
          </el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>
<script lang="ts">
  export default {
    
    
    name: 'tableheades'
  }
</script>
<script setup lang="ts">
  import Draggable from 'vuedraggable'
  import {
    
     watch, onMounted, reactive, nextTick } from 'vue'
  import {
    
     ref } from 'vue'
  const dropdown = ref()
  const props = defineProps({
    
    
    columns: {
    
    
      type: Array,//字段设置
      default: () => []
    },
    tableId: {
    
    
      type: String,//每个页面table标识
      default: ''
    }
  })
  const showClick = () => {
    
    
    dropdown.value.handleOpen()
  }
  const hideClick = () => {
    
    
    dropdown.value.handleClose()
  }
  //鼠标移动到每个复选框
  const CheckBoxClick = (i) => {
    
    
    state.activeIndex = i;
  }
  const state: any = reactive({
    
    
    columnSet: [],//列
    defaultColumn: [],//重置默认列
    activeIndex: 0,
    visible: false,
  })
  // 获取缓存数据
  const getColumnSetCache = () => {
    
    
    let value: any = localStorage.getItem(`columnSet-${
      
      props.tableId}`)
    let columnOption = initColumnSet()
    let valueArr = JSON.parse(value) || []
    columnOption.map(item => {
    
    
      let findEle = valueArr.find(ele => ele.label === item.label && ele.prop === item.prop)
      item.hidden = findEle ? findEle.hidden : false
    })
    value = JSON.stringify(columnOption)
    console.log(value)
    return value ? JSON.parse(value) : initColumnSet()
  }
  // 初始化
  const initColumnSet = () => {
    
    
    const columnSet = props.columns.map((col: any, index) => ({
    
    
      label: col.label,
      prop: col.prop,
      hidden: false,
      checkBoxDisabled: false
    }))
    return columnSet
  }
  // 抛出事件
  const emits = defineEmits(['columnSetting'])
  onMounted(() => {
    
    
    state.defaultColumn = props.columns
    state.columnSet = getColumnSetCache()
    emits('columnSetting', state.columnSet)
  })
  watch(() => state.columnSet, (val) => {
    
    
    emits('columnSetting', val)
    localStorage.setItem(`columnSet-${
      
      props.tableId}`, JSON.stringify(val))
  },
    {
    
     deep: true }
  )
  // checkbox改变选中状态
  const checkChanged = (checked, index) => {
    
    
    state.columnSet[index].hidden = !checked
    let obj: any = {
    
    }
    state.columnSet.map(val => {
    
    
      val.hidden in obj || (obj[val.hidden] = [])
      obj[val.hidden].push(val.hidden)
    })
    if (obj.false.length < 2) {
    
    
      state.columnSet.map((val, key) => {
    
    
        if (!val.hidden) {
    
    
          state.columnSet[key].checkBoxDisabled = true
        }
      })
    } else {
    
    
      state.columnSet.map((val, key) => {
    
    
        if (!val.hidden) {
    
    
          state.columnSet[key].checkBoxDisabled = false
        }
      })
    }
  }
  // // 重置
  const defineFieldReset = () => {
    
    
    const columnSet = state.defaultColumn.map((col: any, index) => ({
    
    
      label: col.label,
      prop: col.prop,
      hidden: false,
      checkBoxDisabled: false,
      AllSelect: true
    }))
    state.columnSet = columnSet
    //保存到后端接口
    // tableHeaderReset(props.tableId).then((res) => { });

  }

</script>
<style lang="scss">
  .flex-between {
    
    
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 15px 0 15px;
  }

  .ActiveDashed {
    
    
    width: 100%;
    border: 1px dashed #ccc;
    margin: 0 auto;
    cursor: move;


  }

  .el-scrollbar .el-scrollbar__wrap {
    
    
    overflow-x: hidden;
  }

  .el-dropdown-menu {
    
    
    padding: 10px;
    font-size: 14px;

    .el-dropdown-menu__item {
    
    
      display: flex;
      flex-direction: column;
      align-items: flex-start;

      .title {
    
    
        font-weight: bold;
        margin-bottom: 5px;
      }

      .t_table_column_setting_dropdown {
    
    
        display: flex;
        flex-direction: column;

        .el-checkbox {
    
    
          vertical-align: middle;

          .el-checkbox__input.is-checked+.el-checkbox__label {
    
    
            color: #409eff;
            vertical-align: middle;
          }
        }

      }
    }
  }
</style>
<style scoped>
  /deep/ .el-dropdown-menu__item:not(.is-disabled):focus {
    
    
    background-color: #fff;
  }
</style>

3. Page usage

//这个必须要写 不写的话页面刷新 存储在本地的数据会被刷新掉
<script lang="ts">
  export default {
    
    
    name: 'qualityInspectionTask'
  }
</script>
<script setup lang='ts'>
  import {
    
     qualityInspectionTask } from "/@/constants/quality";//column所用到的字段
  import tableHeades from "/@/components/tableHeades/index.vue";//字段设置组件
  // 所有列(表头数据)
  // 初始化数据
  let state = reactive({
    
    
    columnSet: [],
  })
  const renderColumns = computed(() => {
    
    
    return state.columnSet.length > 0
      ? state.columnSet.reduce((acc: any, cur: any) => {
    
    
        if (!cur.hidden) {
    
    
          let columnByProp: any = qualityInspectionTask.reduce((acc: any, cur: any) => {
    
    
            acc[cur.prop] = cur
            return acc
          }, {
    
    })
          acc.push(columnByProp[cur.prop])
        }
        return acc
      }, [])
      : qualityInspectionTask
  })
</script>
<template>
  <tableHeades v-bind="$attrs" :columns="renderColumns"  tableId="qualityInspectionTask"
              @columnSetting="v => (state.columnSet = v)" />
    <el-table :height="height" :data="source.list" v-loading="source.loading" :cell-style="cellStyle"
        :header-cell-style="headerCellStyle">
        <el-table-column v-for="(item, index) in renderColumns" :key="index + 'i'" :label="item.label" :prop="item.prop"
          :width="item.width" align="center" show-overflow-tooltip>
          <template v-slot="{ row }">
            <span v-if="item.code">
              <el-button type="primary" link @click="onView(row)">{
    
    {
    
    
                row.code
                }}</el-button>
            </span>
            <span v-else-if="item.materialInfoList">
              <span>{
    
    {
    
     viewMaterialInfo(row.materialInfoList) }}</span>
            </span>
            <span v-else-if="item.status">
              <span>{
    
    {
    
     ['待执行','执行中','已完成'][row.status] }}</span>
            </span>
            <span v-else>{
    
    {
    
    row[item.prop] }}</span>
          </template>
        </el-table-column>
        <el-table-column fixed="right" label="操作" width="100">
          <template v-slot="{ row }">
            <el-button type="danger" size="small" @click="onDelete(row)">删 除</el-button>
          </template>
        </el-table-column>
      </el-table>
</template>

4. About constants/quality files

The constants file is at the same level as components and is mainly used to store page header fields.

export const qualityInspectionTask = [
  {
    
    
    label: "质检单号",
    prop: "code",
    code: true
  },
  {
    
    
    label: "工单号",
    prop: "orderNo"
  },
  {
    
    
    label: "工作中心",
    prop: "workCenterName",
    width: "120"
  },
  {
    
    
    label: "产品编码/名称",
    prop: "materialInfoList",
    materialInfoList: true
  },
  {
    
    
    label: "任务状态",
    prop: "status",
    width: "120",
    status: true
  },
  {
    
    
    label: "检验时间",
    prop: "inspectionTime",
    width: "120"
  },
  {
    
    
    label: "检验人",
    prop: "inspectionUser",
    width: "120"
  },
  {
    
    
    label: "创建时间",
    prop: "createTime",
    width: "120"
  }
];

Guess you like

Origin blog.csdn.net/weixin_42268006/article/details/130259819