错误 Error
使用 Element UI 时, 在 el-diag 里嵌入了 el-form 并设置了label-width="auto"
属性, 发现一旦发生 tab 之间的跳转, 就会报错:
vue.runtime.esm.js?2b0e:1888 Error: [ElementForm]unpected width
at VueComponent.getLabelWidthIndex (element-ui.common.js?5c96:22872)
at VueComponent.deregisterLabelWidth (element-ui.common.js?5c96:22885)
at VueComponent.updateLabelWidth (element-ui.common.js?5c96:23084)
at VueComponent.beforeDestroy (element-ui.common.js?5c96:23111)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at callHook (vue.runtime.esm.js?2b0e:4219)
at VueComponent.Vue.$destroy (vue.runtime.esm.js?2b0e:3978)
at destroy (vue.runtime.esm.js?2b0e:3159)
at invokeDestroyHook (vue.runtime.esm.js?2b0e:6114)
at invokeDestroyHook (vue.runtime.esm.js?2b0e:6119)
找了一下 Element UI 的 github 发现有同样的问题存在issues/17617. 目前还没有修复.
既然没有修复, 那么先分析看看能不能自己解决, 看调用栈, beforeDestroy
-> updateLabelWidth
-> deregisterLabelWidth
-> getLabelWidthIndex
源码分析
在源码里搜一下getLabelWidthIndex
方法, 找到 form 组件, 对比了一下调用栈, 好像不对.
再看看getLabelWidthIndex
方法的上一个方法, 搜一下deregisterLabelWidth
, 找到 label-wrap 组件, 再对比一下调用栈, 没错了.
来, 看看 Element UI 的 label-wrap 组件源码, 位置在\node_modules\element-ui\packages\form\src\label-wrap.vue
.
找到getLabelWidth
方法:
getLabelWidth() {
if (this.$el && this.$el.firstElementChild) {
const computedWidth = window.getComputedStyle(this.$el.firstElementChild).width;
return Math.ceil(parseFloat(computedWidth));
} else {
return 0;
}
},
模拟一下出错的操作, 关闭 el-diag 后,
window.getComputedStyle(document.querySelector('.el-form-item__label-wrap')).width
// "auto"
输出为auto
, 那么使用parseFloat
就会出现NaN
的错误.
解决办法:
一. 用 v-if 取消渲染 form
这个方法比较简单, 因为 el-dialog 会有:visible.sync="show"
属性, 只要在 el-form 里加上v-if="show"
使之随 el-dialog 组件隐藏而删除, 显示而渲染即可.
既然在 el-dialog 关闭时已经没有 el-form, 那么要注意重置方法this.$refs.elForm.resetFields();
也没有必要了, 删除或注释掉即可.
二. 用 patch-package 插件方法为源码打补丁
- 安装 patch-package:
npm i patch-package --save-dev
- 修改package.json,新增命令
postinstall
"scripts": {
"postinstall": "patch-package"
}
- 修改
\node_modules\element-ui\packages\form\src\label-wrap.vue
里面的代码
把返回修改成:return Math.ceil(parseFloat(computedWidth) || 0);
- 执行命令:
npx patch-package element-ui
第一次使用 patch-package 会在项目根目录生成 patches 文件夹并创建一个名为 package-name+version.patch 的文件(这里是 element-ui+2.13.2.patch), 里面有修改过的文件diff记录.
将该 patch 文件提交至版本控制中, 在后续运行npm install
或是yarn install
命令更新或安装依赖时, 它会在 npm 的生命周期 postinstall
自动为依赖包根据 patch 文件的 diff 打上我们编写的补丁.
这样就可以避免更新或者安装依赖时源码更新导致我们的修改被还原了.