美文网首页
el-table树形表格下拉新增功能和子列表的折叠功能

el-table树形表格下拉新增功能和子列表的折叠功能

作者: 刘其瑞 | 来源:发表于2021-03-08 15:54 被阅读0次

公司新来了一个需求:表格最左侧为新增,然后分类可以展开,子列表超过5条进行折叠收缩

视频操作顺序依次为:展开分类=> 展开更多=> 删除 => 新增 => 编辑=> 设置生效与失效


录制的gif

重要难点:新增和删除时,会对折叠功能造成影响

其他难点:

  1. 新增列必须使用多选框改造, 否则会被el-table认成展开图标列
  2. 每次点击都需要通过id找到当前数据,因为树表格会把坐标打乱
  3. 将子级数量超过5条后的全部折叠起来
  4. 需要复制一个表格数据出来,需要每次新增或删除需要重排下索引值和折叠功能
  5. 点击新增使当前的分类展开后,需要将:expand-row-keys数组置空,否则新增其他分类时,会将上一个分类也给展开

因为代码量不算多,我直接简化拿了过来,并加上注释

    <el-table 
      v-loading="loading"
      element-loading-background="rgba(255, 255, 255, 0.7)"
      :data="tableData" 
      class="tableBox" 
      border 
      style="width: 100%" 
      :row-class-name="tableRowClassName" 
      :row-key="getRowKeys"
      :span-method="arraySpanMethod"
      :expand-row-keys="expands"
      :tree-props="{children: 'children'}"
      @selection-change="handleSelectionChange">
      <!-- <el-table-column align="center" type="selection" class-name="DisabledSelectionAll" label-class-name="DisabledSelection" width="55"></el-table-column> -->
      <el-table-column align="center" type="selection" label-class-name="DisabledSelection" width="50"> 
        <template slot-scope="scope">
          <span @click="addRow(scope.row)" v-if="scope.row.type == 'father'" class="hand">+</span>
        </template>
      </el-table-column>
      <el-table-column align="left"  prop="post" label="适用岗位" width="130"> </el-table-column>
      <el-table-column align="center"  prop="index" label="序号" width="50"> </el-table-column>
      <el-table-column align="center"  prop="address" label="工作内容" width="180">
        <template slot-scope="scope">
          <div v-if="!scope.row.type">
            <span v-if="scope.row.modify">{{scope.row.name}}</span>
            <el-input v-else v-model="scope.row.name" type="text" />
          </div>
        </template>  
      </el-table-column>
      <el-table-column align="center" label="创建日期"> 
        <template slot-scope="scope" >
          <span v-if="!scope.row.type">{{scope.row.date}}</span>
          <el-button v-if="scope.row.type === 'shrink'" type="text" @click="handleShrink(scope.row)">{{scope.row.date}}</el-button>
        </template>
      </el-table-column>
      <el-table-column align="center"  prop="requency" label="频率">
        <template slot-scope="scope" v-if="!scope.row.type">
          <span v-if="scope.row.modify">{{optionsFrequency[Number(scope.row.requency)-1].label}}</span>
          <el-select v-else v-model="scope.row.requency" placeholder="请选择">
            <el-option
              v-for="item in optionsFrequency"
              :key="item.value"
              :label="item.label"
              :value="item.value">
            </el-option>
          </el-select>
        </template>
      </el-table-column>
      <el-table-column align="center" label="操作">
        <template slot-scope="scope" v-if="!scope.row.type">
          <el-button v-if="scope.row.modify" type="text" @click="handleEdit(scope.row, true)">修改</el-button>
          <el-button v-else type="text" @click="handleSave(scope.row)">保存</el-button>
          <el-button v-if="scope.row.takeEffect"@click="handleTakeEffect(scope.row)" type="text">生效</el-button>
          <el-button v-else type="text"@click="handleTakeEffect(scope.row)">失效</el-button>
          <el-button @click="handleDelete(scope.row)" type="text">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
js

moment插件和lodash可以不用,自己用其他方法

<script>
import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';

export default {
  data() {
    return {
      loading: false,
      num: 10000,
      tableData: [],
      tableDataCopy: [],
      optionsFrequency: [
        {
          value: '1',
          label: '工作日'
        }, 
        {
          value: '2',
          label: '每周一'
        }, 
        {
          value: '3',
          label: '每周二'
        }, 
        {
          value: '4',
          label: '每周三'
        }, 
        {
          value: '5',
          label: '每周四'
        }, 
        {
          value: '6',
          label: '每周五'
        }, 
        {
          value: '7',
          label: '每月初'
        }, 
        {
          value: '8',
          label: '每周五'
        }, 
        {
          value: '9',
          label: '每月末'
        }, 
        {
          value: '10',
          label: '不定期'
        }, 
      ],
      expands: [],
    };
  },
  created(){
    this.start()
  },
  mounted() {
    // 默认展开第0个
    this.expands = [this.tableData[0].id.toString()]
    this.$nextTick(() => {
      this.expands = []
    })
  },
  methods: {
    start(){
      this.tableData = [
        {
          id: 1,
          post: 'OPM运营岗',
          type:'father',
          takeEffect: false,
          children: [
            {
              id: 2,
              date: '2016-05-01',
              name: '王小虎',
              requency: '2',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '3',
            }, {
              id: 3,
              date: '2016-05-01',
              name: '王小虎',
              requency: '10',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            },
            {
              id: 12,
              date: '2016-05-01',
              name: '王小虎',
              requency: '2',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '3',
            }, {
              id: 13,
              date: '2016-05-01',
              name: '王小虎',
              requency: '10',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            },
            {
              id: 14,
              date: '2016-05-01',
              name: '王小虎',
              requency: '2',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '3',
            }, {
              id: 15,
              date: '2016-05-01',
              name: '王小虎',
              requency: '10',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            }
          ]
        }, 
        {
          id: 4,
          post: '参数录入岗',
          type:'father',
          children: [
            {
              id: 5,
              date: '2016-05-01',
              name: '王小虎',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '3',
            }, {
              id: 6,
              date: '2016-05-01',
              name: '王小虎',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            }
          ]
        }, 
        {
          id: 7,
          post: '基金会计港',
          type:'father',
          children: [
            {
              id: 31,
              date: '2016-05-01',
              name: '王小虎',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '2',
            }, {
              id: 32,
              date: '2016-05-01',
              name: '王小虎',
              requency: '4',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            },
            {
              id: 33,
              date: '2016-05-01',
              name: '王小虎',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '2',
            }, {
              id: 34,
              date: '2016-05-01',
              name: '王小虎',
              requency: '4',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            },
            {
              id: 35,
              date: '2016-05-01',
              name: '王小虎',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '2',
            }, {
              id: 36,
              date: '2016-05-01',
              name: '王小虎',
              requency: '4',
              takeEffect: false,
              address: '上海市普陀区金沙江路 1519 弄',
              state: '1',
            },
          ]
        }, 
        {
          id: 10,
          name: '王小虎',
          state: '3',
          post: '头寸管理岗',
          requency: '6',
          type:'father',
          takeEffect: true,
          address: '上海市普陀区金沙江路 1516 弄',
          children:[
            {
              id: 41,
              date: '2016-05-01',
              name: '王小虎1',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄1',
              state: '3',
            }, {
              id: 42,
              date: '2016-05-01',
              name: '王小虎2',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄2',
              state: '1',
            },
            {
              id: 43,
              date: '2016-05-01',
              name: '王小虎3',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄3',
              state: '3',
            }, {
              id: 44,
              date: '2016-05-01',
              name: '王小虎4',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄4',
              state: '1',
            },
            {
              id: 45,
              date: '2016-05-01',
              name: '王小虎5',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄5',
              state: '3',
            }, {
              id: 46,
              date: '2016-05-01',
              name: '王小虎6',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄6',
              state: '1',
            },
            {
              id: 47,
              date: '2016-05-01',
              name: '王小虎7',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄7',
              state: '3',
            }, {
              id: 48,
              date: '2016-05-01',
              name: '王小虎8',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄8',
              state: '1',
            },
            {
              id: 49,
              date: '2016-05-01',
              name: '王小虎9',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄9',
              state: '3',
            }, {
              id: 410,
              date: '2016-05-01',
              name: '王小虎10',
              requency: '3',
              takeEffect: true,
              address: '上海市普陀区金沙江路 1519 弄10',
              state: '1',
            }
          ]
        },       
      ]
      this.tableDataCopy = cloneDeep(this.tableData)
      this.serialnumber()
      this.tableShrink()
    },
    // 设置序号
    serialnumber(){
      this.tableData.forEach((item,index) => {
      if(item.children && item.children.length){
        item.children.forEach((item2, index2) => {
         // 设置序号
          if(item.type !== 'shrink'){ // 收缩键
            this.$set(item2, 'index', index2 + 1)
          }else{
            this.$set(item2, 'index', '')
          }
         // 当前为保存状态(无可编辑需求可以忽略)
          this.$set(item2, 'modify', true)
        })
      }
      })
    },

    // 展开/收缩
    tableShrink(){
      this.tableData.forEach(item => {
        if(item.children.length > 5){
          const newChildren = item.children.splice(5, item.children.length)
          this.$set(item, 'newChildren', newChildren)
          this.num ++
          item.children.push({
            id: this.num,
            type:'shrink',
            date:'展开》'
          })
        }
      })
    },

    // 获取row的key值
    getRowKeys(row) {
      return row.id;
    },

    handleShrink(row, indexArr=null){
      const arr = indexArr? indexArr : this.ObtainIndex(row.id)
      if(row.date == '展开》'){
        // 取出被折叠的数据
        const oldChildren = this.tableData[arr[0]].newChildren.splice(0, this.tableData[arr[0]].newChildren.length)
        // 取出最后的折叠按钮
        const Shrink = this.tableData[arr[0]].children.splice(this.tableData[arr[0]].children.length-1, 1)
        this.$nextTick(() => {
          this.tableData[arr[0]].children.push(...oldChildren)
          Shrink[0].date = '收起》'
          this.tableData[arr[0]].children.push(...Shrink)
        })
      }else{
        // 需要折叠的数据
        const newChildren = this.tableData[arr[0]].children.splice(5, this.tableData[arr[0]].children.length -6)
        this.tableData[arr[0]].newChildren = newChildren
        // 最后的折叠按钮
        this.tableData[arr[0]].children[this.tableData[arr[0]].children.length-1].date = '展开》'
      }

    },

    // 合并
    arraySpanMethod({ row, column, rowIndex, columnIndex }){
      // 合并展开/收缩
      // if(row.type === 'shrink'){
      //   if (columnIndex === 4) {
      //     return { 
      //       rowspan: 1,
      //       colspan: 6
      //     }
      //   }
      // }

      // 合并岗位
      if(row.type === 'father'){
        if (columnIndex === 1) {
          return { 
            rowspan: 1,
            colspan: 6
          }
        }
      }
    },

    // 新增
    addRow(row){
      const index = this.tableData.findIndex(item => {
        return item.id === row.id
      })
      console.log(row.id)
      this.tableDataCopy[index].children.unshift({
        id: Date.now(),
        index: 1,
        post:'',
        name:'',
        date:moment(new Date()).format("YYYY-MM-DD"),
        requency:'1',
        modify: false,
        takeEffect: false,
      })
      this.tableData = cloneDeep(this.tableDataCopy)

      this.serialnumber()
      this.tableShrink([index])

      this.expands = [this.tableData[index].id.toString()]
      this.$nextTick(() => {
        this.expands = []
      })
    },

    // 获取坐标
    ObtainIndex(id){
      const indexArr = []
      for(let i = 0;i < this.tableData.length;i ++){
        if(!(this.tableData[i].children && this.tableData[i].children.length)) continue
        const itemIndex = this.tableData[i].children.findIndex(item => {
          return item.id == id
        })
        if(itemIndex > -1){
          indexArr.push(i)
          indexArr.push(itemIndex)
          break
        }
      }
      return indexArr
    },

    // 编辑
    handleEdit(row){
      const arr = this.ObtainIndex(row.id)
      this.tableData[arr[0]].children[arr[1]].modify = !this.tableData[arr[0]].children[arr[1]].modify
    },

    // 保存
    handleSave(row){
      this.loading = true
      const that = this
      // ajax
      setTimeout(() => {
        this.handleEdit(row)
        that.loading = false
      },300)
    },

    // 生效/失效
    handleTakeEffect(row){
      const arr = this.ObtainIndex(row.id)
      this.loading = true
      
      // ajax
      setTimeout(() => {
        this.loading = false
        this.tableData[arr[0]].children[arr[1]].takeEffect = !this.tableData[arr[0]].children[arr[1]].takeEffect
      },300)
    },

    // 删除
    handleDelete(row){
      this.loading = true

      setTimeout(() => {
      this.loading = false
      const arr = this.ObtainIndex(row.id)
      this.tableData = []
      this.tableDataCopy[arr[0]].children.splice(arr[1], 1)
      this.tableData = cloneDeep(this.tableDataCopy)
      this.serialnumber()
      this.tableShrink(arr)
      }, 300)
    },
    
    // 设置失效行的class
    tableRowClassName({row, rowIndex}) {
      if (!row.type && row.takeEffect === false) {
        return 'warning-row';
      }
      return '';
    },
  }
};
</script>
css
<style lang='scss' scoped>
.hand{
  cursor: pointer;
}

.el-table /deep/ .DisabledSelection .cell .el-checkbox__inner {
  display: none;
  position: relative;
}
/*表格全选框改为:新增*/
.el-table /deep/ .DisabledSelection .cell:before {
  content: "新增";
  position: absolute;
  left: 14px;
}

.tableBox /deep/ .el-input__inner{
  // border: none;
  width: 86px;
}
</style>

相关文章