一、问题:
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);