利用 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 都加上
测试办理了
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|