el-table中toggleRowSelection选中方法不生效附解决方案

问题背景

最近在后台管理项目中,需求是需要在A弹窗中有个table表格和按钮,点击查询按钮B弹窗弹出,里面内容还是table表格,选择B弹窗中的table表格某些项,保存之后会把已选中的表格项带到A弹窗中。A弹窗中再次点击查询按钮,B弹窗此时table表格应该回显之前选中项。

遇到的问题,就是再次进入B弹窗的table表格未回显之前选中的某些表格项。通过排查原因是,打开B弹窗时候需要每次请求接口,获取表格数据,导致对象引用不同,所以使用el-table的toggleRowSelection() 选中方法无效。

失效原因

1. DOM渲染未完成

每次请求接口,数据更新后DOM会注销新建,导致我们勾选操作失效;可能是table表格相关的DOM渲染还未完成,无法调用toggleRowSelection() 方法,可以使用nextTick解决。

2. 数据源不符

数据源问题,我们每次请求回来的表格数据,即便数据一模一样,数据对象存储地址的指针不同也会导致失败。
toggleRowSelection 需要接收表格数据中的一项。如果传递的 row 对象与 el-table 的数据源不一致,方法将无法正确选中或取消选中行。

解决方法

1. 使用nextTick,目的是获取更新后的DOM元素

官方对其的定义:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

2. 使用唯一标识符,确保数据对象一致性

可以维护一个 selectedRowIds 的集合来追踪选中的行,并在数据刷新后再重新选中这些行,主要看下B弹窗的代码:

<template>
    <el-dialog v-model="modelValue" title="选择数据" width="800" :before-close="onClose">
        <el-table ref="tableRef" :data="state.tableList" @selection-change="onSelectionChange">
            <el-table-column type="selection" width="50" />
            <el-table-column property="项目名称" label="projectName" width="150" />
            <el-table-column property="推荐分行" label="branchCode" width="100" />
        </el-table>
    </el-dialog>
</template
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue'
import type { TableInstance }from 'element-plus'

const emit = defineEmits(['update:modelValue', 'select-rows'])
const onClose = () => {
    emit('update:modelValue', false)
}
// 从A弹窗传入的值
interface Props {
    modelValue: boolean
    branchCode: string
    year: number
    pushData: any
}

const state = reactive({
    tableList: [],
    selectionList: [] as any[], // 已选中的表格数据
    selectionedRowIds: new Set(), // 解决 toggleRowSelection() 无法选中行问题,因为每次重新请求接口,导致对象引用不同
})
watch(
    () => props.modelValue,
    (val) => {
        if (val) {
            handleData()
        }
    }
)
const tableRef = ref<TableInstance>()
const setDefaultCheckedKeys = (rows: TableRow[] | undefined) => {
    if (!rows) return
    // 遍历数组,更新选中之前选中的行
    rows.forEach((row: anyObj)) =>{
        if(state.selectionedRowIds.has(row.loanId)){
            nextTick(()=>{
                tableRef.value!.toggleRowSelection(row,true)
            })
        }
    }
}
async function handleData(){
    try {
       // await 等待请求接口获取表格数据, 否则后面setDefaultCheckedKeys方法未获取到表格数据,步骤省略。。。
       state.tableList = data?.data??[]

       // 更新 selectionedRowIds 集合
       state.selectionedRowIds.clear()
       props.pushData.forEach(item =>{
          state.selectionedRowIds.add(item.loanId)
       })
       setDefaultCheckedKeys(state.tableList)
    }catch(error){
        console.log(error)
    }
}
cosnt onSelectionChange = (selection:[]) =>{
    state.selectionList = selection
}
</script >

关键点

  • 使用 selectedRowIds:在数据刷新前后,使用唯一标识符来管理选中的行。
  • 表格数据刷新之后,遍历表格数组,和selectedRowIds存储的值作比较,如果存在说明是之前已选中的项;调用 tableRef.value!.toggleRowSelection(row, true) 设置选中项。
  • 确保 tableRef.value 的有效性:在进行选中操作前,确保 tableRef.value 是有效的;使用nextTick 确保Dom元素更新完毕。

通过这些方法,可以确保即使数据源更新,表格中的选中状态也能正确恢复。

参考:toggleRowSelection 失效原因及解决思路

### 关于 `el-table` 多选全选功能失效的问题 当遇到 `toggleAllSelection` 方法不起作用的情况时,通常是因为某些配置未正确设置或存在逻辑错误。以下是详细的解决方案: #### 配置项检查 确保在 `<el-table>` 组件中已经设置了 `row-key` 属性,并指定了唯一的键值作为每一行数据的身份标识[^1]。 ```html <el-table :data="tableData" border style="width: 95%" @selection-change="handleSelectionChange" row-key="id"> ``` 对于选择列,则需确认已开启保留选择状态的功能,即设置 `reserve-selection=true` 的属性给到对应的 `<el-table-column>` 中去。 ```html <el-table-column type="selection" align="center" width="55" :reserve-selection="true"></el-table-column> ``` #### 数据源处理 如果表格的数据源发生了变化(比如通过分页加载新一批记录),那么应该重置当前的选择状态并调用 `clearSelection()` 来清除之前所有的选项,再根据业务需求决定是否要重新勾选部分条目。这一步骤可以放在获取新的页面数据之后执行。 另外,在切换不同页面或其他操作引起数据刷新的情况下,记得保存好用户先前做出过的多选动作以便恢复其历史选择情况。 #### 调试建议 为了更好地定位问题所在,可以在控制台打印出每次触发 `toggleAllSelection` 前后的选中项列表长度以及具体内容来验证该函数确实被执行到了并且参数传递无误。 同时也可以尝试简化场景测试——移除其他可能干扰的因素如复杂的样式表单、额外绑定的事件监听器等,只留下最基本的实现方式看能否正常工作。 最后不要忘了查看浏览器开发者工具中的网络请求面板是否存在异常报错信息影响到了组件的行为表现。 #### 示例代码片段 下面给出一段简单的 Vue.js 实现例子用于说明如何正确运用上述提到的各项要点: ```javascript methods: { handleCurrentPageChange(val) { // 分页改变时回调 this.currentPage = val; this.loadTableData(); // 加载对应页码的数据 // 清空现有选择并将之前的记忆下来的状态应用回去 this.$refs.multipleTable.clearSelection(); const selectedIds = localStorage.getItem('selectedRows') ? JSON.parse(localStorage.getItem('selectedRows')) : []; setTimeout(() => { selectedIds.forEach(id => { let foundRow = this.tableData.find(row => row.id === id); if (foundRow !== undefined){ this.$refs.multipleTable.toggleRowSelection(foundRow, true); } }); }, 0); }, loadTableData() { // 模拟异步获取数据的过程... axios.get('/api/data', { params: { page: this.currentPage, size: this.pageSize } }) .then(response => { this.tableData = response.data.items || []; }).catch(error => console.error(error)); }, toggleSelectAll() { this.$refs.multipleTable.toggleAllSelection(); // 记录下此时全部被选中的ID集合至本地存储供后续使用 let allSelected = this.$refs.multipleTable.selection.map(item=>item.id); localStorage.setItem('selectedRows',JSON.stringify(allSelected)); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁锤妹妹@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值