实现分页列表跨页全选

前言

新需求是要支持跨页全选,因为习惯了element的当页全选以及惯性思维,第一步是想到了前端分页,但是这种方法显然是不可取的,因此花了点时间写了个demo分享


因为是个demo,所以就一直按照思路往下写,变量命名没有花心思,if判断也有可优化的地方,后续有空优化后会更新一下代码

如果直接复制完整代码可能会报错,因为项目用了AVUE,删掉这个标签或者安装一个avue就可以,没什么影响

一、思路以及注意点

思路:
跨页全选状态下显然不能可传入所有ID(后端分页只拿当前页ID也不可能知道所有ID),所以:
跨页全选状态记录未选中数据(点击跨页全选后,一定能记住未选中ID,因为用户需要手动勾选才能让其 '未选中‘)
非跨页全选状态记录选中数据 (同理)

注意点:
1、跨页全选应该有三种状态(未选,选但是没选完,全选),主要需要注意中间状态 ,因为用户全选后取消勾选某列此时变为 ‘选但是没选完’ 状态,且在用户下一次点击全选按钮,应变为全选状态,而不是未选状态。(有点绕口,实际参考element表格当前页全选切换)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
2、翻页时处理选中和未选

二、方法详解

1.需要用到的变量

        <el-checkbox
          :indeterminate="indeterminate"
          v-model="ifSelectAll"
          @change="changeIfSelectAll"
          style="margin-left: 20px"
          >全部选择</el-checkbox>
          
     	<el-table
      	  ref="list"
       	 :data="list"
    	  style="width: 100%"
     	  @select="changeSelect"
    	  @select-all="changeSelectAll"
     	  :row-key="getRowKey"
    	 > </el-table>
    	 
      indeterminate: false,//控制跨页全选状态
      ifSelectAll: false, //是否跨页全选
      checkedList: [], //非全选状态下,记录被选中
      uncheckedList: [], //全选状态下,记录取消选中

2.监听

1.监听列表 : 列表数据改变 == 翻页 => 处理选中/未选
2.监听 ‘是否跨页全选’ : 当每次’是否跨页全选改变’ 清空两个记录数组以重新记录
3.监听未选中数组/选中数组:根据选中数量判断当前全选按钮样式以及所处状态

  watch: {
    list() {
      this.backfillSelect();
    },
    ifSelectAll() {
        this.checkedList = [];
        this.uncheckedList = [];
    },
    //监听未选中的数组
    uncheckedList: {
      handler(value) {
        //1.未选中数组长度和总数相等,取消选中状态,取消样式
        if (value.length === this.pagination.total) {
          this.ifSelectAll = false;
          this.indeterminate = false;
        }
        //2.未选中数组长度为0,取消样式
        if (value.length === 0) this.indeterminate = false;
        //3.选了但没选完,设置待定样式
        if (value.length > 0 && value.length < this.pagination.total)
          this.indeterminate = true;
      },
      deep: true,
    },
    //监听选中数组
    checkedList: {
      handler(value) {
        if (value.length === this.pagination.total) {
          this.ifSelectAll = true;
          this.indeterminate = false;
        }
        if (value.length === 0) this.indeterminate = false;
        if (value.length > 0 && value.length < this.pagination.total)
          this.indeterminate = true;
      },
    },
  },

3.方法

  1. changeSelect:手动勾选列表数据行触发,判断用户当前操作是 ‘勾选’ / ‘取消勾选’ ,判断当前状态是’跨页全选’/‘非跨页全选’,然后对表格行勾选/取消勾选处理
  2. changeSelectAll:手动勾选列表当前也全选触发,判断用户是 ‘全选’ / ‘取消全选’,判断当前状态是 ‘跨页全选’ / ‘非跨页全选’,然后对表格当前页数据进行处理
  3. changeIfSelectAll:用户勾选" 跨页全选 "触发,判断当前用户选择状态,如果是 ‘选了但是没选完’ ,则点击后 全选所有,反正则正常勾选所有/取消勾选所有
  4. backfillSelect:回填选中,在数据更新后,判断当前状态是’跨页全选’/‘非跨页全选’,对表格进行勾选/取消勾选操作
  5. clearSelect:取消所有勾选,数据更新后,取消所有勾选
 //手动勾选数据行
    changeSelect(selection, row) {
      // 判断勾选数据行是选中还是取消
      let selected = selection.length && selection.indexOf(row) !== -1;
      if (this.ifSelectAll) {
        if (selected) {
          // 选中,从未选中数组中去掉
          if (this.uncheckedList.length != 0) {
            this.uncheckedList.forEach((item, index) => {
              if (item.id == row.id) this.uncheckedList.splice(index, 1);
            });
          }
        } else this.uncheckedList.push(row); //取消则记录选中数据
      } else {
        if (selected) {
          if (this.checkedList.indexOf(row) == -1) this.checkedList.push(row);
        } else {
          if (this.checkedList.indexOf(row) != -1)
            this.checkedList.splice(this.checkedList.indexOf(row), 1);
        }
      }
    },
    //手动勾选当页全选
    changeSelectAll(selection) {
      if (this.ifSelectAll) {
        // 判断全选本页,是选中还是取消
        if (selection.length > 0) {
          //选中,从未选中数组中去掉当前页所有数据
          this.list.forEach((item) => {
            this.uncheckedList.forEach((item_un, index_un) => {
              if (item.id == item_un.id) this.uncheckedList.splice(index_un, 1);
            });
          });
        } else {
          //取消,未选中的数组中记录该数据
          this.list.forEach((item) => {
            if (this.uncheckedList.indexOf(item) == -1)
              this.uncheckedList.push(item);
          });
        }
      } else {
        //非跨页全选状态,记录当前页选中数据
        if (selection.length > 0) {
          this.list.forEach((item, index) => {
            if (this.checkedList.indexOf(item) == -1)
              this.checkedList.push(item);
          });
        } else {
          this.list.forEach((item, index) => {
            this.checkedList.forEach((item_check, index_check) => {
              if (item.id == item_check.id) {
                this.checkedList.splice(index_check, 1);
              }
            });
          });
        }
      }
    },
    //是否跨页全选
    changeIfSelectAll() {
      if (this.indeterminate) {
        //当不为全选样式时,点击变为全选
        this.$nextTick(() => {
          this.ifSelectAll = true;
          this.backfillSelect();
        });
      }
      if (this.ifSelectAll) this.backfillSelect();
      else this.clearSelect();
    },
    //回填选中
    backfillSelect() {
      this.$nextTick(() => {
        //跨页全选记录未选中
        if (this.ifSelectAll) {
          this.list.forEach((item, index) => {
            if (this.uncheckedList.length > 0) {
              let ifSelection = true;
              this.uncheckedList.forEach((item_un) => {
                if (item.id == item_un.id) ifSelection = false;
              });
              if (ifSelection)
                this.$refs.list.toggleRowSelection(this.list[index], true);
            } else this.$refs.list.toggleRowSelection(this.list[index], true);
          });
          //非跨页全选记录选中
        } else {
          if (this.checkedList.length > 0) {
            this.list.forEach((item, index) => {
              let ifSelection = false;
              this.checkedList.forEach((item_check) => {
                if (item.id == item_check.id) ifSelection = true;
              });
              if (ifSelection)
                this.$refs.list.toggleRowSelection(this.list[index], true);
            });
          }
        }
      });
    },
    //全部取消选中
    clearSelect() {
      this.$nextTick(() => {
        this.$refs.list.clearSelection();
      });
    },

完整代码

selectGoods.vue

<!--
 * @Author: hwd
 * @Description:   选择商品
 * @FilePath: \tik-tok-crm\src\views\tiktok\equityManage\integral\selectGoods.vue
-->
<template>
  <el-dialog
    title="选择商品"
    v-dialogdrag
    :visible="true"
    class="avue-dialog"
    width="1300px"
    :close-on-click-modal="false"
    :before-close="
      () => {
        $emit('close');
      }
    "
  >
    <el-form :inline="true" label-width="120px" :model="query">
      <el-form-item label="商品名称:">
        <el-input
          v-model="query.name"
          size="small"
          style="width: 200px"
          placeholder="请输入商品名称"
        ></el-input>
      </el-form-item>
      <el-form-item label="商品名称ID:">
        <el-input
          size="small"
          style="width: 200px"
          placeholder="请输入商品名称ID"
        ></el-input>
      </el-form-item>
      <el-form-item label="商品状态:">
        <el-select size="small" v-model="query.status" placeholder="请选择">
        </el-select>
      </el-form-item>
      <el-form-item style="margin-right: 50px" label="售 价 :">
        <el-input size="small" style="width: 94px"></el-input> -
        <el-input size="small" style="width: 94px"></el-input>
      </el-form-item>
      <el-form-item label="">
        <el-button size="small" type="primary">查询</el-button>
        <el-button size="small">重置</el-button>
        <el-checkbox :indeterminate="indeterminate" v-model="ifSelectAll" @change="changeIfSelectAll" style="margin-left: 20px">全部选择</el-checkbox >
      </el-form-item>
    </el-form>
    <el-table
      ref="list"
      :data="list"
      style="width: 100%"
      @select="changeSelect"
      @select-all="changeSelectAll"
      :row-key="getRowKey"
    >
      <el-table-column type="selection" width="55"> </el-table-column>
      <el-table-column prop="date" label="商品" width="300">
        <template slot-scope="scope">
          <div class="goodsMsg">
            <el-image class="left image" :src="scope.row.imgUrl"></el-image>
            <div class="right">
              <avue-text-ellipsis
                :key="scope.row.id"
                :text="scope.row.name"
                :height="40"
                :width="200"
                use-tooltip
                placement="top"
              >
                <small slot="more">...</small>
              </avue-text-ellipsis>
              <el-tag type="success" size="mini">{{ scope.row.id }}</el-tag>
            </div>
          </div>
        </template>
      </el-table-column>
      <el-table-column prop="id" label="售价" width="180"> </el-table-column>
      <el-table-column prop="销量" label="销量"> </el-table-column>
      <el-table-column prop="库存" label="库存"> </el-table-column>
      <el-table-column prop="状态" label="状态">
        <template slot-scope="scope">
          <el-tag type="info">下架</el-tag>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      class="pagination"
      background
      @size-change="sizeChange"
      @current-change="currentChange"
      layout="total, sizes, prev, pager, next, jumper"
      :page-size="pagination.size"
      :page-sizes="[10, 50, 100]"
      :current-page="pagination.current"
      :total="pagination.total"
    >
    </el-pagination>
    <div class="avue-dialog__footer">
      <el-button @click="$emit('close')">取 消</el-button>
      <el-button @click="handleClick" type="primary">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { getGoods } from "./test";
export default {
  data() {
    return {
      indeterminate: false,//跨页全选状态变换
      ifSelectAll: false, //是否跨页全选
      checkedList: [], //非全选状态下,记录被选中
      uncheckedList: [], //全选状态下,记录取消选中

      activeName: "first",
      query: {},
      ifShowEdit: true,
      pagination: {
        total: 20,
        current: 1,
        size: 10,
      },
      list: [],
    };
  },
  components: {},
  watch: {
    list() {
      this.backfillSelect();
    },
    ifSelectAll: {
      handler() {
        this.checkedList = [];
        this.uncheckedList = [];
      },
    },
    //监听未选中的数组
    uncheckedList: {
      handler(value) {
        //1.未选中数组长度和总数相等,取消选中状态,取消样式
        if (value.length === this.pagination.total) {
          this.ifSelectAll = false;
          this.indeterminate = false;
        }
        //2.未选中数组长度为0,取消样式
        if (value.length === 0) this.indeterminate = false;
        //3.选了但没选完,设置待定样式
        if (value.length > 0 && value.length < this.pagination.total)
          this.indeterminate = true;
      },
      deep: true,
    },
    //监听选中数组
    checkedList: {
      handler(value) {
        if (value.length === this.pagination.total) {
          this.ifSelectAll = true;
          this.indeterminate = false;
        }
        if (value.length === 0) this.indeterminate = false;
        if (value.length > 0 && value.length < this.pagination.total)
          this.indeterminate = true;
      },
    },
  },
  created() {
    this.getGoods(1);
  },

  methods: {
    getRowKey(row) {
      return row.id;
    },
    //手动勾选数据行
    changeSelect(selection, row) {
      // 判断勾选数据行是选中还是取消
      let selected = selection.length && selection.indexOf(row) !== -1;
      if (this.ifSelectAll) {
        if (selected) {
          // 选中,从未选中数组中去掉
          if (this.uncheckedList.length != 0) {
            this.uncheckedList.forEach((item, index) => {
              if (item.id == row.id) this.uncheckedList.splice(index, 1);
            });
          }
        } else this.uncheckedList.push(row); //取消则记录选中数据
      } else {
        if (selected) {
          if (this.checkedList.indexOf(row) == -1) this.checkedList.push(row);
        } else {
          if (this.checkedList.indexOf(row) != -1)
            this.checkedList.splice(this.checkedList.indexOf(row), 1);
        }
      }
    },
    //手动勾选当页全选
    changeSelectAll(selection) {
      if (this.ifSelectAll) {
        // 判断全选本页,是选中还是取消
        if (selection.length > 0) {
          //选中,从未选中数组中去掉当前页所有数据
          this.list.forEach((item) => {
            this.uncheckedList.forEach((item_un, index_un) => {
              if (item.id == item_un.id)
                this.uncheckedList.splice(index_un, 1);
            });
          });
        } else {
          //取消,未选中的数组中记录该数据
          this.list.forEach((item) => {
            if (this.uncheckedList.indexOf(item) == -1)
              this.uncheckedList.push(item);
          });
        }
      } else {
        //非跨页全选状态,记录当前页选中数据
        if (selection.length > 0) {
          this.list.forEach((item, index) => {
            if (this.checkedList.indexOf(item) == -1)
              this.checkedList.push(item);
          });
        } else {
          this.list.forEach((item, index) => {
            this.checkedList.forEach((item_check, index_check) => {
              if (item.id == item_check.id) {
                this.checkedList.splice(index_check, 1);
              }
            });
          });
        }
      }
    },
    //是否跨页全选
    changeIfSelectAll() {
      if (this.indeterminate) {
        //当不为全选样式时,点击变为全选
        this.$nextTick(() => {
          this.ifSelectAll = true;
          this.backfillSelect();
        });
      }
      if (this.ifSelectAll) this.backfillSelect();
      else this.clearSelect();
    },
    //回填选中
    backfillSelect() {
      this.$nextTick(() => {
        //跨页全选记录未选中
        if (this.ifSelectAll) {
          this.list.forEach((item, index) => {
            if (this.uncheckedList.length > 0) {
              let ifSelection = true;
              this.uncheckedList.forEach((item_un) => {
                if (item.id == item_un.id) ifSelection = false;
              });
              if (ifSelection)
                this.$refs.list.toggleRowSelection(this.list[index], true);
            } else this.$refs.list.toggleRowSelection(this.list[index], true);
          });
          //非跨页全选记录选中
        } else {
          if (this.checkedList.length > 0) {
            this.list.forEach((item, index) => {
              let ifSelection = false;
              this.checkedList.forEach((item_check) => {
                if (item.id == item_check.id) ifSelection = true;
              });
              if (ifSelection)
                this.$refs.list.toggleRowSelection(this.list[index], true);
            });
          }
        }
      });
    },
    //全部取消选中
    clearSelect() {
      this.$nextTick(() => {
        this.$refs.list.clearSelection();
      });
    },
    //获取商品列表
    getGoods(type) {
      this.list = getGoods(type);
    },
    handleClick() {
      if (this.ifSelectAll) console.log("全选", this.uncheckedList);
      else console.log("非全选", this.checkedList);
    },
    sizeChange(val) {
      this.getGoods(val);
    },
    currentChange(val) {
      this.getGoods(val);
    },
  },
};
</script>
<style lang="scss" scoped>
.image {
  width: 50px;
  height: 50px;
  border-radius: 5px;
}
.goodsMsg {
  display: flex;
  .left {
    margin-right: 10px;
  }
}
</style>

test.js

/*
 * @Author: hwd
 * @Description:
 * @FilePath: \tik-tok-crm\src\views\tiktok\equityManage\integral\test.js
 */
export function getGoods(type) {
  // return request({
  //   url: '/gen/dsconf/',
  //   method: 'put',
  //   data: obj
  // })
  let list = [
    {
      id: 1,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 2,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 3,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 4,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 5,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 6,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 7,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 8,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 9,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 10,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 11,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 12,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 13,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 14,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 15,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 16,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 17,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 18,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 19,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
    {
      id: 20,
      imgUrl:
        "https://p9-aio.ecombdimg.com/obj/ecom-shop-material/v1_rXNkLqu_70812225812687751790881_3c057df3070c0b6ca54368b17ed9c644_sx_242657_www800-800",
      name: "商品名称,商品名称商品名称商品名称商品名称商品名称商品名称",
    },
  ];
  if (type == 1) return list.slice(0, 10);
  if (type == 2) return list.slice(10, 20);
}

你可能感兴趣的:(跨页全选,javascript,vue)