当前位置: 首页 > article >正文

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

使用 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-menudefault-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-iconref="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-iconref="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-dialogtitle="提示":visible.sync="dialogVisible"width="30%":before-close="handleClose":destroy-on-close="true"><el-form:model="ruleForm"status-iconref="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.lryc.cn/news/2387187.html

相关文章:

  • vscode包含工程文件路径
  • 私有知识库 Coco AI 实战(七):摄入本地 PDF 文件
  • GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【二】
  • NtfsLookupAttributeByName函数分析之和Scb->AttributeName的关系
  • STM32H7系列USART驱动区别解析 stm32h7xx_hal_usart.c与stm32h7xx_ll_usart.c的区别?
  • 网络原理 | TCP与UDP协议的区别以及回显服务器的实现
  • IP动态伪装开关
  • 【Unity3D】将自动生成的脚本包含到C#工程文件中
  • 解决leetcode第3509题.最大化交错和为K的子序列乘积
  • 【Python 深度学习】1D~3D iou计算
  • java23
  • 嵌入式工程师常用软件
  • LitCTF2025 WEB
  • Redisson WatchDog会一直续期吗?
  • Linux 下VS Code 的使用
  • Android开发namespace奇葩bug
  • watchEffect
  • Qt 布局管理器的层级关系
  • Android 之 kotlin 语言学习笔记一
  • maven模块化开发
  • 为什么要使用stream流
  • 语义分割的image
  • 云原生安全之网络IP协议:从基础到实践指南
  • C++——QT 文件操作类
  • 【排错】kylinLinx环境python读json文件报错UTF-8 BOM
  • [spring] spring 框架、IOC和AOP思想
  • LInux—shell编程
  • 尚硅谷redis7 37-39 redis持久化之AOF简介
  • GitLab 备份所有仓库(自动克隆)
  • [浏览器]缓存策略机制详解