Element跨页全选操作(跨页记住已经勾选)【2】

2,077 阅读1分钟

1、需求背景

用户需要在表格初始化的时候显示一些已经默认勾选数据(回显数据)和不可操作的数据(置灰数据: disable=true),在用户勾选完成时,保存当前勾选结果作为下次表格的回显数据(此应用在与弹窗相结合的场景中会遇到)
因此本文是在上文的逻辑上新增两个数组:

  • 1、回显数组redisplayData
  • 2、置灰数组setDisableData

2、思维导图

Image_20210906204634.png

3、 相关代码

3.1 封装的table组件代码

// STable.vue
<template>
  <div class="s-table">
    <el-table
      ref="innerTable"
      class="table"
      style="width: 100%"
      :row-key="getRowKeys"
      :data="tableData"
      :total="total"
      v-bind="$attrs"
      @select="select"
      @select-all="selectAll"
      v-on="$listeners"
    >
      <el-table-column
        v-if="selectable"
        type="selection"
        width="80"
        :reserve-selection="true"
        :selectable="selectableHandler"
      ></el-table-column>
      <el-table-column
        v-for="(item) in columns"
        :key="item.prop"
        :prop="item.prop"
        :label="item.label"
        :sortable="item.sortable"
        :width="parseInt(item.width)"
      >
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  name: 'STable',
  props: {

    // 默认列
    columns: {
      type: Array,
      default: () => []
    },
    tableData: {
      type: Array,
      default: () => []
    },
    // 是否可选
    selectable: {
      type: Boolean,
      default: false
    },
    // 是否跨页全选
    isSelectedAll: {
      type: Boolean,
      default: false
    },
    // table表格的总数据条数
    total: {
      type: Number,
      default: 0
    },
    // 回显数据
    redisplayData: {
      type: Array,
      default: () => []
    },
    // 置灰数据
    setDisableData: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      uncheckedArr: [],
      ifRedisplay: false,
      redisplayArr: [], // 克隆接收到的redisplayData的值
      disabledCheckedArr: [], // 被勾选的置灰数据
      disabledUnCheckedArr: [] // 未被勾选的置灰数据(不可勾选)
    }
  },
  watch: {
    // 分页全选-监听数据变化
    tableData: {
      handler (value) {
        this.isSelectedAll && this.chooseAllPages(this.isSelectedAll)
        !this.isSelectedAll && this.checkedSelected()
        this.ifRedisplay && this.redisplayHandler()
        this.$nextTick(() => {
          if (this.uncheckedArr.length === 0 && this.$refs.innerTable.selection.length === this.total - this.disabledUnCheckedArr.length) {
            this.$emit('update:isSelectedAll', true)
          }
        })
      },
      deep: true
    }
  },
  mounted() {
    if (document) {
      document.addEventListener('click', this.hideSettings)
    }
    this.redisplayData.length > 0 ? this.ifRedisplay = true : this.ifRedisplay = false
    this.redisplayArr = JSON.parse(JSON.stringify(this.redisplayData))
    this.ifRedisplay && this.redisplayHandler()
    this.setDisableData.length > 0 && this.disabledArrHandler()
  },
  methods: {
    getRowKeys(row) {
      return row.id
    },
    // 全选所有页面
    chooseAllPages(val) {
      if (val) {
        // 全选
        this.$nextTick(() => {
          let choosedArr = []
          this.tableData.map(row => {
            if (this.setDisableData.map(v => v.id).indexOf(row.id) < 0) {
              choosedArr.push(row)
            }
          })
          choosedArr.forEach(row => {
            this.$refs.innerTable.toggleRowSelection(row, true)
          })
        })
      } else {
        // 取消全选
        this.uncheckedArr = []
        this.redisplayArr = []
        this.$nextTick(() => {
          this.$refs.innerTable.clearSelection()
          this.$nextTick(() => {
            this.tableData.forEach(row => {
              if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
                this.$refs.innerTable.toggleRowSelection(row, true)
              }
            })
          })
        })
      }
    },
    // 切换分页时选择之前选中
    checkedSelected() {
      if (this.isSelectedAll) {
        // 全选状态
        this.$nextTick(() => {
          this.tableData.forEach(row => {
            this.$refs.innerTable.toggleRowSelection(row, true)
          })
        })
      } else {
        // 非全选状态下
        if (this.uncheckedArr.length > 0) {
          this.$nextTick(() => {
            this.tableData.forEach(row => {
              if ((this.uncheckedArr.map(v => v.id).indexOf(row.id) < 0) && (this.disabledUnCheckedArr.map(v => v.id).indexOf(row.id) < 0)) {
                this.$refs.innerTable.toggleRowSelection(row, true)
              }
              if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
                this.$refs.innerTable.toggleRowSelection(row, true)
              }
            })
          })
        }
        this.$nextTick(() => {
          this.tableData.forEach(row => {
            if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
              this.$refs.innerTable.toggleRowSelection(row, true)
            }
          })
        })
      }
    },
    // 全选后取消单个选择事件,当用户手动勾选数据行的 Checkbox 时触发的事件
    select(selection, row) {
      this.selectExceptCardIds(selection, row)
      this.$emit('select', [selection, row])
    },
    // 单个选择事件
    selectExceptCardIds(selection, row) {
      if (this.isSelectedAll) {
        // 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
        this.uncheckedArr.push(row)
        if (this.ifRedisplay) {
          this.redisplayArr.map((v, index) => {
            if (row.id === v.id) {
              this.redisplayArr.splice(index, 1)
            }
          })
        }
        this.$emit('update:isSelectedAll', false)
      } else {
        // false, 非全选状态下,列表行数据可能被 取消选中 或者 重新勾选
        if (selection.indexOf(row) >= 0) {
          // 勾选
          selection.map(el => {
            this.uncheckedArr.map((v, index) => {
              if (el.id === v.id) {
                this.uncheckedArr.splice(index, 1)
                if (this.uncheckedArr.length === 0) {
                  this.$emit('update:isSelectedAll', true)
                }
              }
            })
          })
        } else {
          // 取消勾选
          // 1、若是uncheckedArr.length > 0,取消勾选的数组加入uncheckedArr
          if (this.uncheckedArr.length > 0) {
            this.uncheckedArr.push(row)
          }
          // 有回显数的取消勾选
          if (this.ifRedisplay) {
            this.redisplayArr.map((v, index) => {
              if (row.id === v.id) {
                this.redisplayArr.splice(index, 1)
              }
            })
          }
        }
        if (selection.length === this.total - this.disabledUnCheckedArr.length) {
          this.$emit('update:isSelectedAll', true)
        }
      }
    },
    // 全选后取消单页选择事件,当用户手动勾选数据行的 Checkbox 时触发的事件
    selectAll(selection) {
      this.selectAllRows(selection)
      this.$emit('selectAll', selection)
    },
    // 单页选择事件
    selectAllRows(selection) {
      if (this.isSelectedAll) {
        // 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
        this.tableData.map(row => {
          this.uncheckedArr.push(row)
          if (this.ifRedisplay) {
            this.redisplayArr.map((v, index) => {
              if (row.id === v.id) {
                this.redisplayArr.splice(index, 1)
              }
            })
          }
        })
        this.$emit('update:isSelectedAll', false)
      } else {
        // false,部分选中状态下
        selection.map(row => {
          // 勾选
          this.uncheckedArr.map((v, index) => {
            if (row.id === v.id) {
              this.uncheckedArr.splice(index, 1)
            }
            if (this.uncheckedArr.length === 0) {
              this.$emit('update:isSelectedAll', true)
            }
          })
          // 取消勾选
          if (this.uncheckedArr.length > 0 && this.tableData.map(v => v.id).indexOf(row.id) === -1) {
            this.uncheckedArr.push(row)
          }
          // 有回显数据
          if (this.ifRedisplay) {
            this.redisplayArr.map((v, index) => {
              if (row.id === v.id) {
                this.redisplayArr.splice(index, 1)
              }
            })
          }
        })
        if (selection.length === this.total - this.disabledUnCheckedArr.length) {
          this.$emit('update:isSelectedAll', true)
        }
      }
    },
    // 回显数据
    redisplayHandler() {
      if (this.redisplayArr.length > 0) {
        this.$nextTick(() => {
          this.tableData.forEach(row => {
            if (this.redisplayArr.map(v => v.id).indexOf(row.id) >= 0) {
              this.$refs.innerTable.toggleRowSelection(row, true)
            }
          })
        })
      }
    },
    // 置灰数组处理
    disabledArrHandler() {
      if (this.redisplayData.length > 0) {
        this.setDisableData.map(row => {
          if (this.redisplayData.map(v => v.id).indexOf(row.id) > 0) {
            this.disabledCheckedArr.push(row)
          } else {
            this.disabledUnCheckedArr.push(row)
          }
        })
      }
    },
    // 置灰操作
    selectableHandler(row, index) {
      let flag = true
      for (let i = 0; i < this.setDisableData.length; i++) {
        if (row.id === this.setDisableData[i].id) {
          flag = false
        }
      }
      return flag
    }
  }
}
</script>
<style lang="scss">
</style>

3.2 示例代码

// example.vue
<template>
  <el-card>
    <el-checkbox
      v-model="isSelectedAll"
      @change="checkboxChange"
    >全选所有</el-checkbox>
    <s-table
      ref="accessControlTable"
      :table-data="tableData.slice((currentPage - 1) * pageSize, currentPage * pageSize)"
      :redisplay-data="redisplayData"
      :set-disable-data="setDisableData"
      :columns="columns"
      :selectable="true"
      :total="tableData.length"
      :is-selected-all.sync="isSelectedAll"
    >
    </s-table>
    <el-pagination
      class="s-pagination"
      :currrent-page="currentPage"
      :page-size="pageSize"
      :page-sizes="[5,10,20,30]"
      :total="tableData.length"
      layout="total, prev, pager, next, sizes, jumper"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    >
    </el-pagination>
  </el-card>
</template>

<script>
import STable from '../components/STable.vue'
export default {
  name: 'selectedAll',
  components: {
    STable
  },
  data() {
    return {
      tableData: [
        {
          id: 1,
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 2,
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 3,
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 4,
          date: '2016-05-05',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 5,
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 6,
          date: '2016-05-07',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 7,
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 8,
          date: '2016-05-09',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 9,
          date: '2016-05-10',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 10,
          date: '2016-05-11',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 11,
          date: '2016-05-12',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }
      ],
      redisplayData: [
        {
          id: 1,
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 3,
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 5,
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 8,
          date: '2016-05-09',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 10,
          date: '2016-05-09',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 11,
          date: '2016-05-12',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }
      ],
      setDisableData: [
        {
          id: 2,
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 3,
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 4,
          date: '2016-05-05',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 7,
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          id: 10,
          date: '2016-05-11',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }
      ],
      columns: [
        {
          label: '日期',
          prop: 'date',
          width: 180
        },
        {
          label: '姓名',
          prop: 'name',
          width: 180
        },
        {
          label: '地址',
          prop: 'address'
        }
      ],
      currentPage: 1, // 当前页码
      pageSize: 5, // 每页的数据条数
      total: 0,
      isSelectedAll: false
    }
  },
  methods: {
    handleSizeChange(val) {
      this.currentPage = 1
      this.pageSize = val
    },
    handleCurrentChange(val) {
      this.currentPage = val
    },
    // 手动点击改变全选/非全选状态触发的事件
    checkboxChange(val) {
      this.$refs.accessControlTable.chooseAllPages(val)
    }
  }
}
</script>
<style scoped>
.s-pagination {
  text-align: right;
  margin-top: 10px;
}
</style>

4、相关属性和方法

属性或者方法名说明类型可选值默认值
columns默认列Array--[]
tableData表格数据Array--[]
selectable是否可选Booleantrue/falsefalse
isSelectedAll是否跨页全选Booleantrue/falsefalse
total表格数据的总条目数Number--0
redisplayData回显数据Array--[]
setDisableData置灰数据Array--[]
chooseAllPages全选所有页面Function----

说明:
isSelectedAll表示表格数据是否全选,可用户传入对初始状态进行设置,设置为true表示初始默认设置全选;
chooseAllPages用户手动改变isSelectedAll的值时,需要调用触发chooseAllPages事件;
注意: 要实现跨页全选,传入的tableData数据中必须包含id属性;