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

3,747 阅读2分钟

1、流程如下

Image_20210830205538.png

2、具体分析

该问题的主要难点在于:用户点击全选之后,对已勾选项进行操作,对跨页后的数据对自己是否被勾选情况不明

具体场景如下:

用户点击全选后(全选状态为true),通过单项或者单页取消勾选 ——>此时(全选状态为false),但是分页的时候其他页面的数据应该也是被选中。

解决办法: 当全选状态为true时,将点击取消勾选的项目存入uncheckedArr中,全选状态变为false
因此主要分为以下三种场景:

  1. 全选状态(isSelectedAll = true)时,切换页面全选

  2. 全不选状态且取消勾选的数组中有指(isSelectedAll = false && uncheckedArr.length>0)时,切换页面时仍然选中全部(但需要排除包含在uncheckedArr中的值)

  3. 全不选状态(isSelectedAll = false)时,切换页面全不选中

在以上三种场景的基础上再对表格的单项勾选/取消勾选事件、单页勾选/取消勾选事件分析:
elementUI的table表格组件中设置reserve-selection属性,即可记住已勾选的项。

20210831100930158.png 因此我们只需要关注取消勾选的项,即场景1和场景2

  1. 全选状态(isSelectedAll = true)时,只有取消勾选操作,取消勾选时将被取消的项存入uncheckedArr中,同时isSelectedAll = false

  2. 全不选状态且取消勾选的数组中有指(isSelectedAll = false && uncheckedArr.length>0)时:

    2.1. 取消勾选:将被取消的项存入uncheckedArr

    2.2. 重新勾选:
    (1)将重新勾选的项从uncheckedArr移除
    (2)当table表格被选中的项数===表格总项数时,isSelectedAll设置为true
    (3)当tuncheckedArr中没有项时,isSelectedAll设置为 true

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"
      :is-selected-all="isSelectedAll"
      :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"
      ></el-table-column>
      <el-table-column
        v-for="(item) in columns"
        :key="item.prop"
        :prop="item.prop"
        :label="item.label"
        :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
    }
  },
  data() {
    return {
      uncheckedArr: []
    }
  },
  watch: {
    // 分页全选-监听数据变化
    tableData: {
      handler (value) {
        this.isSelectedAll && this.chooseAllPages(this.isSelectedAll)
        !this.isSelectedAll && this.checkedSelected()
      },
      deep: true
    }
  },

  methods: {
    getRowKeys(row) {
      return row.id
    },
    // 全选所有页面
    chooseAllPages(val) {
      if (val) {
        // 全选
        this.$nextTick(() => {
          this.tableData.forEach(row => {
            this.$refs.innerTable.toggleRowSelection(row, true)
          })
        })
      } else {
        // 取消全选
        this.uncheckedArr = []
        this.$nextTick(() => {
          this.$refs.innerTable.clearSelection()
        })
      }
    },
    // 切换分页时选择之前选中
    checkedSelected() {
      if (this.isSelectedAll) {
        // 全选状态isSelectedAll=true
        this.$nextTick(() => {
          this.tableData.forEach(row => {
            this.$refs.innerTable.toggleRowSelection(row, true)
          })
        })
      } else {
        // 非全选状态下isSelectedAll=false
        // uncheckedArr有值,切换页面时仍然选中全部(但需要排除包含在uncheckedArr中的值)
        if (this.uncheckedArr.length > 0) {
          this.$nextTick(() => {
            this.tableData.forEach(row => {
              if (this.uncheckedArr.map(v => v.id).indexOf(row.id) < 0) {
                this.$refs.innerTable.toggleRowSelection(row, true)
              }
            })
          })
        }
      }
    },

    // 全选后取消单个选择事件
    select(selection, row) {
      this.selectExceptCardIds(selection, row)
      this.$emit('select', [selection, row])
    },
    // 全选后取消单个选择事件
    selectAll(selection) {
      this.selectAllRows(selection)
      this.$emit('selectAll', selection)
    },
    // 全选后取消单个选择事件
    selectExceptCardIds(selection, row) {
      if (this.isSelectedAll) {
        // 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
        this.uncheckedArr.push(row)
        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)
                }
              }
            })
            if (selection.length === this.total) {
              this.$emit('update:isSelectedAll', true)
            }
          })
        } else {
          // 取消勾选
          // 若是uncheckedArr.length > 0,取消勾选的数组加入uncheckedArr
          if (this.uncheckedArr.length > 0) {
            this.uncheckedArr.push(row)
          }
        }
      }
    },
    // 当前页面全选
    selectAllRows(selection) {
      if (this.isSelectedAll) {
        // 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
        this.tableData.map(row => {
          this.uncheckedArr.push(row)
        })
        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 (selection.length === this.total) {
            this.$emit('update:isSelectedAll', true)
          }
          // 取消勾选
          if (this.uncheckedArr.length > 0) {
            if (this.tableData.map(v => v.id).indexOf(row.id) === -1) {
              this.uncheckedArr.push(row)
            }
          }
        })
      }
    }
  }
}
</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)"
      :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 {
  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 弄'
        }
      ],
      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
chooseAllPages全选所有页面Function----

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

5、参考相关博客

www.jianshu.com/p/8415a0c41…