使用elementui时,表格的单选样式不明显,使用多选的方式去实现单选的功能

一、问题:

1、现在elementui表格的单选和多选功能

在这里插入图片描述

在这里插入图片描述

2、使用习惯了其他的一些展示组件,对于elementui的table组件,感觉有一些功能还是需要自己去封装的,目前组件的单选和多选感觉不是太好用

二、思路:

想用多选的功能实现单选的功能,使用多选时候的两个方法:select和select-all,针对这两个方法,通过从外部传参的方式,判断是单选还是多选,分别处理

三、实现:

1、展示部分:

<el-table
ref=“tableRef”
v-loading=“loading”
:data=“infoList”
stripe
border
@select=“select”
@select-all=“selectAll”
>

2、外部传参:

(1)infoList:表格的数据

(2)isMultiple:是否多选,true:多选、false:单选

(3)changeParamValueByIdFn:根据id改变参数值 (函数方法)

(4)selectInfoList: 选中的信息列表

3、data中的参数:

(1)selectInfoArr:选择的数据列表,当发生选中的时候,设置选中的信息,根据其发生变化,去执行changeParamValueByIdFn修改外部的内容

4、处理逻辑代码:

(1)select: 手动选择复选框后执行的方法

	select(selection, row) {
      // 判断是否是多选
      if (this.isMultiple) {
        // 多选的时候,直接赋值
        this.selectInfoArr = selection;
      } else {
        // 单选的时候,当选择的数据为0的时候,直接赋值
        if (selection.length == 0) {
          this.selectInfoArr = selection;
        } else {
          // 单选的时候,当选择的数据不为0的时候,把原来选中的内容过滤掉,保留新增的内容,以数组的形式保存
          selection.map((item) => {
            let obj = _.find(this.selectInfoArr, { id: item.id });
            if (!obj) {
              this.selectInfoArr = [item];
            }
          });

          // 设置选中的行,1、先清空原来选中的,2、然后再设置现在需要选中的行
          this.$refs.tableRef.clearSelection(); // 1、清空原来的行

          // 为何不能直接用row呢,因为row和obj不是一个对象,obj这个对象可以选中,row这个对象选不中
          let obj = _.find(this.infoList, {
            id: this.selectInfoArr[0].id,
          });
          // 2、设置现在需要选中的行
          this.$refs.tableRef.toggleRowSelection(obj);
        }
      }
    }

(2)selectAll: 手动选择全部的复选框执行的方法

	selectAll(selection) {
      // 判断是否是多选,不是多选的时候,多选按钮不管用
      if (!this.isMultiple) {
        this.$refs.tableRef.clearSelection();

        // 为何不能直接用row呢,因为row和obj不是一个对象,obj这个对象可以选中,row这个对象选不中
        let obj = _.find(this.infoList, { id: this.selectInfoArr[0].id });
        this.$refs.tableRef.toggleRowSelection(obj);
      } else {
        this.selectInfoArr = selection;
      }
    }

(3)监听方法(在watch中使用):

	infoList: {
      handler() {
        if (
          JSON.stringify(this.infoList) !=
          JSON.stringify(this.selectInfoList)
        ) {
          this.$emit(
            "changeParamValueByIdFn",
            this.infoList,
            this.selectInfoList
          );
        }
      },
      deep: true,
    },

(4)设置默认值的方法:seletDefaultSelectTableIdFn

	seletDefaultSelectTableIdFn() {
      // 设置默认值,因为表格渲染数据也需要一定的时间,如果不设置定时器的话,可能会存在先设置默认值,表格数据再渲染,当表格数据再渲染的时候,就会重新清空选择的内容,所以要设置定时器
      setTimeout(() => {
        // 获取选中图元中的选中的指标信息
        let selectInfoArr= _.cloneDeepWith(
          this.selectInfoList
        );
        if (selectInfoArr.length > 0) {
          selectInfoArr.map((row) => {
            // 为何不能直接用row呢,因为row和obj不是一个对象,obj这个对象可以选中,row这个对象选不中
            let obj = _.find(this.infoList, { id: row.id });
            this.$refs.tableRef.toggleRowSelection(obj);
          });
        } else {
          // 清空选择的内容
          this.$refs.tableRef.clearSelection();
        }

        this.selectInfoArr= selectInfoArr; // 设置选择的指标
      }, 200);
    }

四、注意:

1、element-ui中table设置选中默认值的时候,为何不成功?

(1)不成功的时候的场景:

在获取列表的时候,异步调用查询方法,执行成功后,把数据赋值,然后在此时设置初始值,即使直接获取数据列表中的第一个数据作为默认选中的,也是不可以的,如下代码:

	getList() {
      this.loading = true;
      listIndexInfo(this.queryParams)
        .then((res) => {
          this.indexInfoList = res.rows; // 获取到的数据列表
          this.total = res.total;
          this.synonym = res.synonym;
          this.loading = false;
          // 获取第一个条数据,设置为默认选中第一行数据
           this.$refs.tableRef.toggleRowSelection(res.rows[0]);
        })
        .catch((e) => {
          this.$message.error("接口错误!" + e);
          this.loading = false;
          this.indexInfoList = [];
          this.total = 0;
          this.synonym = [];
        });
    }

如上代码,按道理说是可以选中的对吧,我使用selection-change这个方法,在该方法中打印改变的内容,会发现输出了两次,也就是说selection-change执行了两次,第一次的时候,是更改成了第一条了,但是第二次的时候,又设置成空了,是不是很奇怪
在这里插入图片描述

(2)原因:

a. 第二次执行的原因:

在上述方法中设置的时候,当数据发生变化时,element-ui的table组件内部是会执行一次清楚方法的,这个在切换分页的时候会遇到,当前也选中的位置,在切换到第二页的时候会消失,这个时候,内部是执行的clearSelection方法,这样的话,selection-change就会变化,这个是生成第二次执行的结果的原因

b. 为何第一次的结果不是在第二次执行的后面

因为是顺序执行的,在indexInfoList 赋值完后,会接着执行toggleRowSelection这个方法,table组件中监听indexInfoList 发生变化是需要一定时间的,导致先执行了toggleRowSelection方法,然后table组件再执行了监听方法,然后使用了clearSelection方法,这样就导致了该问题的出现;

(3)解决方法:

a. 现在只想到了一种解决方法,就是在使用toggleRowSelection方法设置默认值的代码片段包一层定时器(使用setTimeout),设置200毫秒,代码片段如下:
	getList() {
      this.loading = true;
      listIndexInfo(this.queryParams)
        .then((res) => {
          this.indexInfoList = res.rows; // 获取到的数据列表
          this.total = res.total;
          this.synonym = res.synonym;
          this.loading = false;
          setTimeout(() => {
          	// 获取第一个条数据,设置为默认选中第一行数据
           	this.$refs.tableRef.toggleRowSelection(res.rows[0]);
           }, 200)
        })
        .catch((e) => {
          this.$message.error("接口错误!" + e);
          this.loading = false;
          this.indexInfoList = [];
          this.total = 0;
          this.synonym = [];
        });
    }

该方法可能会存在问题,因为万一在200毫秒内table组件还没有执行clearSelection这个方法,还是会出现上述的问题;

2、从外部传递来的数据,直接使用toggleRowSelection设置默认值为何不行?

(1)原因:

因为toggleRowSelection是设置的一个对象,该对象必须是当前列表数据中的内容,外部传来的数据跟当前列表中的数据不一致,即便是值都是一样的也不行,存储位置不一样,设置的时候必须是 值 + 存储位置都保持一致才行;

(2)解决方法:

根据id或者列表中的唯一标识,去查找外部传来的默认值对应列表数据中的内容
代码如下:

	// 为何不能直接用defaultRow呢,因为defaultRow和obj不是一个对象,obj这个对象可以选中,defaultRow这个对象选不中
	let defaultRow = {
		id: 22
	}
    let obj = _.find(this.infoList, { id: defaultRow.id });
    this.$refs.indexSelectTableRef.toggleRowSelection(obj);

猜你喜欢

转载自blog.csdn.net/qq_28013889/article/details/126088730
今日推荐