element-plus表格报错:ResizeObserver loop completed with undelivered notifications.

element-plus表格报错:ResizeObserver loop completed with undelivered notifications.

当我点击筛选的时候,就会报错

复制代码
<template>
  <div>
    <el-button type="primary" @click="setTableData">设置数据</el-button>
     <el-table
          ref="normalTable"
          :data="tableData"  
          style="width: 100%" 
          max-height="440px"
        >
          <el-table-column
            v-for="(column, index) in tableDataOption"
            :key="index"
            :prop="column.prop"
            :label="column.label"
            :column-key="column.prop"
             :filter-multiple="false"
            :filters="column.filter ? column.filterOptions : null"
            :filter-method="column.filter ? filterHandler : null"
          />
        </el-table>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

let tableData = ref<any[]>([])
const tableDataOption = ref<any[]>([])

const filterHandler = (value: any, row: any, column: any) => {
  const property = column.property
  return row[property] === value
}
function setTableData(){
  setTimeout(()=>{
    if(!tableDataOption.value?.length){
      tableDataOption.value= [ 
        {  "prop": "bucket",
          "label": "桶名称",
          "filter": true, 
          filterOptions: [
            { "text": "A1", "value": "A1" },
            { "text": "B1", "value": "B1" }
          ] 
       }, 
        { 
          "prop": "projectID", "label": "企业项目", "filter": false, 
        } 
      ]
    }
    tableData.value= [
      {
        "bucket": "bucket-1e1f",
        "childInfo": [],
        "projectID": "default",
        "id": "bucket-1e1f",
        "name": "bucket-1e1f",
        "selectable": true,
        "disabled": false,
      },
      {
        "bucket": "bucket-272e",
        "childInfo": [],
        "projectID": "default",
        "id": "bucket-272e",
        "name": "bucket-272e",
        "selectable": true,
        "disabled": false,
      },
    ]
  },1300)
}

</script>

<style scoped>

</style>

原因分析:

filters 引发布局变化的主要原因;加了filters 后

表头会多渲染一个筛选 → 表头高度/行高变化 → 表格重新布局。

el-table 内部用 ResizeObserver 监听自身尺寸,

叠加你 1300ms 后异步灌数据的时机,

形成"尺寸变 → 触发 observer → 又改布局"的一帧内循环,浏览器就报这个错。

解决办法:给列宽设置宽度

复制代码
<el-table-column
    v-for="(column, index) in tableDataOption"
    :key="index"
    :prop="column.prop"
    :label="column.label"
    :min-width="150" // 通过设置列宽来解决这个问题哈
    :column-key="column.prop"
    :filter-multiple="false"
    :filters="column.filter ? column.filterOptions : null"
    :filter-method="column.filter ? filterHandler : null"
  />

不会报错的

有的小伙伴说:我下面的代码没有设置宽度,也没有报错。

所以不是你说的那个原因。

是因为你这个值的所占的宽度原因,并不是因为值哈

复制代码
<template>
  <div>
    <el-button type="primary" @click="setTableData">设置数据</el-button>
     <el-table
          ref="normalTable"
          :data="tableData"  
          style="width: 100%" 
          max-height="440px"
        >
          <el-table-column
            v-for="(column, index) in tableDataOption"
            :key="index"
            :prop="column.prop"
            :label="column.label"
            :column-key="column.prop"
            :filter-multiple="false"
            :filters="column.filter ? column.filterOptions : null"
            :filter-method="column.filter ? filterHandler : null"
          />
        </el-table>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';

let tableData = ref<any[]>([])
const tableDataOption = ref<any[]>([])

const filterHandler = (value: any, row: any, column: any) => {
  const property = column.property
  return row[property] === value
}
function setTableData(){
  setTimeout(()=>{
    if(!tableDataOption.value?.length){
      console.log('设置数据')
      tableDataOption.value= [ 
        {  "prop": "bucket",
          "label": "桶名称",
          "filter": true, 
          filterOptions: [
            { "text": "选项A", "value": "A1" },
            { "text": "选项B", "value": "B1" }
          ] 
       }, 
        { 
          "prop": "projectID", "label": "企业项目", "filter": false, 
        } 
      ]
    }
    tableData.value= [
      { 
        // bucket的值是:bucket-1e1f,就会报错:
        // ResizeObserver loop completed with undelivered notifications.
        "bucket": "A111",
        "childInfo": [],
        "projectID": "default",
        "id": "bucket-1e1f",
        "name": "bucket-1e1f",
        "selectable": true,
        "disabled": false,
      },
      {
        "bucket": "B11",
        "childInfo": [],
        "projectID": "default",
        "id": "bucket-272e",
        "name": "bucket-272e",
        "selectable": true,
        "disabled": false,
      },
    ]
  },1300)
}

</script>

根据上面的代码,是值"bucket": "bucket-1e1f"引起的?

答:不是。

根本原因是:值所占的宽度造成的哈

我使用AI,AI给的回复

ResizeObserver loop completed with undelivered notifications 不是你的代码报错,

也不是 Element Plus 崩了,它是浏览器(Chrome/Edge)抛出的警告级 error event。

Vite 的 error overlay 会捕获它弹遮罩,所以看起来像报错。

一句一句说

  1. 元素的尺寸一变,浏览器并不会立刻调用你的回调。​

    它先把这条变化「记一笔」放进一个待处理列表中,

    等这一帧走到固定时刻,

    再把列表里攒下的通知一次性交给回调去执行。

    把通知交给回调执行的行为,就叫派发。

  2. 组件库的回调里会写样式。​

    el-table 那个 resizeListener 发现高度变了,

    就调 doLayout(),去写 body 高度、列宽、还有是否要纵向滚动条。

    这一写,元素尺寸又变了。

  3. 于是列表末尾又多了一笔。​

    但这一轮的派发还没结束:浏览器正在挨个通知回调,而你刚刚又制造出一条新通知。

  4. 浏览器到点收摊。​

    规范不允许它在一帧里无限循环下去(否则页面就卡死)。

    所以循环到上限时,它把还没送出的通知留到下一帧,同时在帧末抛一个 error 事件,内容就是那句:

    ResizeObserver loop completed with undelivered notifications.

用大白话再说一遍

通知刚送完,回调又改了尺寸,新的通知又记上了;

浏览器怕死循环,这一帧到点收摊,没送完的留到下一帧,并顺手报一句"本轮结束,我没送完"。

所以这条 message 本质上是一张收摊回执,不是"我崩了"。