Error in beforeDestroy hook: “Error: [ElementForm]unpected width “

news2025/5/29 7:02:14

使用 element 的 form 时候报错:

vue.runtime.esm.js:3065  Error: [ElementForm]unpected width 
    at VueComponent.getLabelWidthIndex (element-ui.common.js:23268:1)
    at VueComponent.deregisterLabelWidth (element-ui.common.js:23281:1)
    at VueComponent.updateLabelWidth (element-ui.common.js:23483:1)
    at VueComponent.beforeDestroy (element-ui.common.js:23510:1)

原因:el-form-item 的 label 组件有个 beforeDestroy 生命同期,el-form 组件的 display: none 获取labelWidth 有问题导致的

解决办法:el-form 上加 v-if,用 el-dialog 的 :visible.sync="dialogVisible" 的话,也加 v-if="dialogVisible"

由于 el-form 标签 label-width 设为 "auto" ,而 el-form-item 会继承这个属性,在某种情况下页面销毁时获取这个 el-form-item 的 label 的 width 为 'auto',然后用 parseFloat 转换后为 NaN 就报错了。

这个方法是在 element-ui 共通方法里写的 node_modules\element-ui\lib\element-ui.common.js

或是

computedWidth 为 “auto" 或 "" 都会返回 NaN

网上说是因为代码中使用了 v-show 以及 el-form 标签中使用了label-width="auto",导致离开页面后产生报错

解决方法一:label-width 换成固定值

解决方法二: v-show 换成  v-if

但我的原因是因为使用了 keep-alive 用下面代码可以再现出来

src\router\index.js

import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import Layout from '../views/management/Layout.vue';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/management',
      component: Layout,
      children: [
        {
          path: '/management/audit',
          component: () => import("@/views/management/audit/index.vue"),
          name: "memberAudit",
        },
        {
          path: '/management/detail',
          component: () => import("@/views/management/detail/index.vue"),
          name: "memberAudit",
        }
      ]
    }
  ]
});

export default router;

src\views\management\Layout.vue

<template>
  <div class="main">
    <el-scrollbar>
      <div class="left">
        <el-menu
          default-active="$route.path"
          background-color="#545c64"
          text-color="#fff"
          router
        >
          <el-menu-item :router="true" index="/management/audit">
            <i class="el-icon-menu"></i>
            <span slot="title">审核</span>
          </el-menu-item>
          <el-menu-item :router="true" index="/management/detail?label=menu">
            <i class="el-icon-menu"></i>
            <span slot="title">详情</span>
          </el-menu-item>
          <el-menu-item :router="true" index="/management/about">
            <i class="el-icon-menu"></i>
            <span slot="title">About</span>
          </el-menu-item>
        </el-menu>
      </div>
      <div class="right">
        <keep-alive>
          <router-view />
        </keep-alive>
      </div>
    </el-scrollbar>
  </div>
</template>

<style lang="scss">
.left {
  float: left;
  width: 200px;
}
.right {
  float: left;
  width: 80%;
}
</style>

src\views\management\audit\index.vue

<template>
  <div class="hello1" style="margin-top: 100px">
    audit
    <span @click="detail">click</span>
  </div>
</template>

<script>
export default {
  methods: {
    detail() {
      this.$router.push("/management/detail?label=测试");
    },
  },
};
</script>

src\views\management\detail\index.vue

<template>
  <div>
    <el-form
      :model="ruleForm"
      status-icon
      ref="ruleForm"
      label-width="auto"
      class="demo-ruleForm"
    >
      <el-form-item label="年龄" prop="age">
        <el-input v-model.number="ruleForm.age"></el-input>
      </el-form-item>
      <el-form-item :label="$route.query.label" prop="name">
        <el-input v-model.number="ruleForm.name"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="resetForm()">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "Home",
  components: {},
  data() {
    return {
      ruleForm: {
        age: "",
        name: "",
      },
    };
  },
  methods: {
    resetForm() {
      this.$router.push("/management/audit");
    },
  },
};
</script>

点击详情

点击重置

再点击 about

报错了,这里注意报错的主要写法

1、src\views\management\Layout.vue

使用 keep-alive

2、src\router\index.js

这里我没设置 about 页面路由,可能这样会触发 VueComponent.beforeDestroy

3、src\views\management\detail\index.vue

el-form-item 必须两个以上,并且其中一个的 label 使用动态值 :label="$route.query.label"

我的这种情况即使设置 label-width 为固定值也不行,因为最后页面消失,获取  label-width 为空

parseFloat(label-width) 为 NaN 就报错了

去掉 keep-alive 就不会报错

去掉后就不会走 'update' 分支,因为页面切换时因为有个 label 是动态赋值的,所以即使页面销毁因为是 keep-alive 且 label 动态值变没了,导致 el-form 认为是 label 值 update ,走的这个方法,而这个时候页面找不到元素, label-width 就是空,所以报错了。

其实是因为 el-form-item 的 label 设为响应式的了,而且在页面销毁时响应式值还更新,可以换一种响应式使它在页面销毁时不更新值

<el-form-item :label="qLabel" prop="name">

  created() {

    this.qLabel = this.$route.query.label;

  },

<template>
  <div>
    <el-form
      :model="ruleForm"
      status-icon
      ref="ruleForm"
      label-width="auto"
      class="demo-ruleForm"
    >
      <el-form-item label="年龄" prop="age">
        <el-input v-model.number="ruleForm.age"></el-input>
      </el-form-item>
      <el-form-item :label="qLabel" prop="name">
        <el-input v-model.number="ruleForm.name"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="resetForm()">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "Home",
  components: {},
  created() {
    this.qLabel = this.$route.query.label;
  },
  data() {
    return {
      qLabel: "",
      ruleForm: {
        age: "",
        name: "",
      },
    };
  },
  methods: {
    resetForm() {
      this.$router.push("/management/audit");
    },
  },
};
</script>

这么写不会报错,算是完美避开了这个 bug

但是公司的是另一个问题,是用 el-dialog 组件包裹 el-form 也出这个 bug了

<el-dialog
      title="提示"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose"
      :destroy-on-close="true"
    >
      <el-form
        :model="ruleForm"
        status-icon
        ref="ruleForm"
        label-width="auto"
        class="demo-ruleForm"
      >
        <el-form-item :span="24" label="年龄" prop="age">
          <el-input v-model.number="ruleForm.age"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button @click="resetForm()">重置</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>


    resetForm() {
      this.dialogVisible = false;
      this.$router.push("/management/detail");
    },

查看源码仔细分析发现,虽然报错在 element-ui.common.js 但其实报错是在源码里 label-wrap.vue

 

<script>

export default {
  props: {
    isAutoWidth: Boolean,
    updateAll: Boolean
  },

  inject: ['elForm', 'elFormItem'],

  render() {
    const slots = this.$slots.default;
    if (!slots) return null;
    if (this.isAutoWidth) {
      const autoLabelWidth = this.elForm.autoLabelWidth;
      const style = {};
      if (autoLabelWidth && autoLabelWidth !== 'auto') {
        const marginLeft = parseInt(autoLabelWidth, 10) - this.computedWidth;
        if (marginLeft) {
          style.marginLeft = marginLeft + 'px';
        }
      }
      return (<div class="el-form-item__label-wrap" style={style}>
        { slots }
      </div>);
    } else {
      return slots[0];
    }
  },

  methods: {
    getLabelWidth() {
      if (this.$el && this.$el.firstElementChild) {
        const computedWidth = window.getComputedStyle(this.$el.firstElementChild).width;
        return Math.ceil(parseFloat(computedWidth));
      } else {
        return 0;
      }
    },
    updateLabelWidth(action = 'update') {
      if (this.$slots.default && this.isAutoWidth && this.$el.firstElementChild) {
        if (action === 'update') {
          this.computedWidth = this.getLabelWidth();
        } else if (action === 'remove') {
          this.elForm.deregisterLabelWidth(this.computedWidth);
        }
      }
    }
  },

  watch: {
    computedWidth(val, oldVal) {
      if (this.updateAll) {
        this.elForm.registerLabelWidth(val, oldVal);
        this.elFormItem.updateComputedLabelWidth(val);
      }
    }
  },

  data() {
    return {
      computedWidth: 0
    };
  },

  mounted() {
    this.updateLabelWidth('update');
  },

  updated() {
    this.updateLabelWidth('update');
  },

  beforeDestroy() {
    this.updateLabelWidth('remove');
  }
};
</script>

因为 form-item 组件用了 label 组件,而 label 组件是用上面的 label-wrap 包裹的,所以 el-dialog 关闭并跳转到新页面时就调用了 label-wrap beforeDestroy生命周期函数,这个时候因为 el-dialog 是用的 v-show 所以 display 为 none,这个时候获取 label 的 width 

if (this.$el && this.$el.firstElementChild) 这个判断条件是获取 label 标签因为用了 <keep-alive>,所以还是能找到的,但是window.getComputedStyle(this.$el.firstElementChild).width 获取的值就是 空或者 ’auto'

解决办法 v-show 改为 v-if 就是让 this.$el.firstElementChild 根本查询不到 label 标签,就不会走这个条件分支了,就不会报错了,对功能也没影响。

所以可以在 el-dialog 上加 v-if 和 visible 用一个变量即可,或是在 el-form 上加,或是 el-form-item上加 v-if 但是这种情况得所有 el-form-item 都加上

测试解决了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2387187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

私有知识库 Coco AI 实战(七):摄入本地 PDF 文件

是否有些本地文件要检索&#xff1f;没问题。我们先对 PDF 类的文件进行处理&#xff0c;其他的文件往后稍。 Coco Server Token 创建一个 token 备用。 PDF_Reader 直接写个 python 程序解析 PDF 内容&#xff0c;上传到 Coco Server 就行了。还记得以前都是直接写入 Coco …

【Unity3D】将自动生成的脚本包含到C#工程文件中

我们知道&#xff0c;在用C#开发中&#xff0c;通过vs编辑器新建的脚本&#xff0c;会自动包含到vs工程中&#xff0c;而通过外部创建&#xff0c;比如复制别的工程或代码创建的C#脚本不会包含到vs工程。 在我们的日常开发中&#xff0c;通常会自动创建C#脚本&#xff0c;特别…

【Python 深度学习】1D~3D iou计算

一维iou 二维 import numpy as npdef iou_1d(set_a, set_b):# 获得集合A和B的边界 x1, x2 set_ay1, y2 set_b# 计算交集的上下界low max(x1,y1)high - min(x2, y2)# 计算交集if high - low < 0:inter 0else:inter high - low# 计算并集union (x2 -x1) (y2 - y1) - in…

java23

1.美化界面 添加背景图片 所以我们添加背景图片要放在后面添加 添加图片边框 绝对路径&#xff1a; 相对(模块)路径&#xff1a; 第一个是绝对路径&#xff0c;第二个是相对路径&#xff0c;但是斜杠的方向不对 总结&#xff1a; 2.图片移动 先实现KeyListener接口&#xf…

LitCTF2025 WEB

星愿信箱 使用的是python&#xff0c;那么大概率是ssti注入 测试{{5*5}} 发现需要包含文字&#xff0c;那么添加文字 可以看到被waf过滤了&#xff0c;直接抓包查看参数上fenjing 可以看到这里是json格式&#xff0c;其实fenjing也是支持json格式的 https://github.com/Marv…

Linux 下VS Code 的使用

这里以创建helloworld 为例。 Step 0:准备工作&#xff1a; Install Visual Studio Code. Install the C extension for VS Code. You can install the C/C extension by searching for c in the Extensions view (CtrlShiftX). Step 1: 创建工作目录 helloworld&#xff0…

Qt 布局管理器的层级关系

1、HomeWidget.h头文件&#xff1a; #ifndef HOMEWIDGET_H #define HOMEWIDGET_H#include <QWidget> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout>class HomeWidget : public QWidget {Q_OBJECTpublic:HomeWidget(QWidget …

maven模块化开发

使用方法 将项目安装到本地仓库 mvn install 的作用 运行 mvn install 时&#xff0c;Maven 会执行项目的整个构建生命周期&#xff08;包括 compile、test、package 等阶段&#xff09;&#xff0c;最终将构建的 artifact 安装到本地仓库&#xff08;默认路径为 ~/.m2/repos…

云原生安全之网络IP协议:从基础到实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 IP协议&#xff08;Internet Protocol&#xff09;是互联网通信的核心协议族之一&#xff0c;负责在设备间传递数据包。其核心特性包括&…

C++——QT 文件操作类

QFile 概述 QFile是Qt框架中用于文件操作的类&#xff08;位于QtCore模块&#xff09;&#xff0c;继承自 QIODevice&#xff0c;提供文件的读写、状态查询和路径管理功能。它与 QTextStream、QDataStream 配合使用&#xff0c;可简化文本和二进制数据的处理&#xff0c;并具备…

[spring] spring 框架、IOC和AOP思想

目录 传统Javaweb开发的困惑 loC、DI和AOP思想提出 Spring框架的诞生 传统Javaweb开发的困惑 问题一&#xff1a;层与层之间紧密耦合在了一起&#xff0c;接口与具体实现紧密耦合在了一起 解决思路&#xff1a;程序代码中不要手动new对象&#xff0c;第三方根据要求为程序提…

尚硅谷redis7 37-39 redis持久化之AOF简介

37 redis持久化之AOF简介 AOF 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工…

GitLab 备份所有仓库(自动克隆)

一、准备工作 1. 环境要求 已安装 Git&#xff08;版本 2.10&#xff09;本地磁盘空间充足&#xff08;根据仓库总大小预估&#xff09;已配置 SSH 密钥到 GitLab&#xff08;推荐方式&#xff09; 2. 获取 GitLab API 访问权限 登录 GitLab&#xff0c;点击右上角头像 → …

[浏览器]缓存策略机制详解

在做页面性能优化的时候&#xff0c;有一个点容易被忽略&#xff0c;那就是资源缓存优化。 浏览器里缓存策略分为强缓存&#xff0c;协商缓存以及不缓存&#xff0c;每个缓存策略都有其适用的优化场景。 下面为大家详解何为强缓存&#xff0c;协商缓存 先说结论强缓>协商&g…

OpenCV CUDA 模块图像过滤-----创建一个计算图像导数的滤波器函数createDerivFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::createDerivFilter 是 OpenCV CUDA 模块中的一个工厂函数&#xff0c;用于创建一个计算图像导数的滤波器。这个滤波器可以用来计算图像…

AWS関連職種向け:日本語面接QA集

1. 自己紹介&#xff08;じこしょうかい&#xff09; Q&#xff1a;簡単に自己紹介をお願いします。 A&#xff1a; はい、〇〇と申します。これまで約4年間、主にAWSを基盤としたインフラ設計・構築・運用に従事してまいりました。VPCやEC2、RDS、S3などの基本サービスの設計…

(01)华为GaussDB((基于PostgreSQL))高斯数据库使用记录,dbeaver客户端配置高斯驱动,连接高斯数据库

高斯数据库是华为推出的一款基于PostgreSQL的企业级数据库产品&#xff0c;客户端使用通用的dbeaver dbeaver客户端配置高斯驱动 建议使用 dbeaver24.3.1及以上客户端&#xff0c;选择模式后执行sql会绑定模式名&#xff0c;如果使用dbeaver23.2版本&#xff0c;选择模式后执…

ARM Linux远程调试

准备 虚拟机既能ping通开发板,又能ping通外网,还要能ping通Windows主机(如果你有上位机通信(tftp、vsftp、ssh)的需求) VMware 添加网络适配器2用作桥接网卡,原有的网络适配器保持为NAT模式 打开虚拟网络编辑器,配置VMnet0为桥接模式,外部连接设置为Realtek PCIe G…

day24Node-node的Web框架Express

1. Express 基础 1.1 什么是Express node的web框架有Express 和 Koa。常用Express 。 Express 是一个基于 Node.js 的快速、极简的 Web 应用框架,用于构建 服务器端应用(如网站后端、RESTful API 等)。它是 Node.js 生态中最流行的框架之一,以轻量、灵活和易用著称。 …

让MySQL更快:EXPLAIN语句详尽解析

前言 在数据库性能调优中&#xff0c;SQL 查询的执行效率是影响系统整体性能的关键因素之一。MySQL 提供了强大的工具——EXPLAIN 语句&#xff0c;帮助开发者和数据库管理员深入分析查询的执行计划&#xff0c;从而发现潜在的性能瓶颈并进行针对性优化。 EXPLAIN 语句能够模…