!24 背景!
我们在使用第三方依赖包时如果遇到了bug,通常解决的方式都是绕过这个问题,使用其他方式解决,较为麻烦。或者给作者提个issue,然后等待作者的修复,等待的时间不可控。
!24 解决方案:“打补丁” - patch-package!
我们可以使用patch-package(patch-package - npm)给我们的三方包进行打补丁 大致步骤如下: 1.在node_modules中找到我们要修复问题或者要新增特性的三方包的文件夹(如:node_modules\element-ui)
2.修改文件夹下有问题的代码的文件中的代码,或者新增新特性
3.测试代码符合预期
4.安装patch-package包(npm i patch-package)
5.运行:npx patch-package "文件夹的名字" (如:element-ui)
6.在package.json中添加scripts脚本:"postinstall": "patch-package"
7.把代码提交到仓库
!24 案例!
解决el-form 设置label-width="auto"时,组件销毁时控制台报错的问题
最近在使用vue2+elementUI 2.15的前端框架时开发项目时,时不时总会发现控制台会报如下图的错误
最终排查下来是 el-form 设置了
label-width="auto" 然后又处于不展示的情况下(display: none,项目里是 el-tab产生的)在离开页面的时候就会有问题。
el-form 在挂载时(display:none也会挂载),会初始化一个 el-label 的 width 的数组,在销毁的时候时候会依次清除 该数组 。问题原因在此获取宽度函数上
// https://github.com/ElemeFE/element/blob/dev/packages/form/src/label-wrap.vue#L32
methods: {
getLabelWidth: function getLabelWidth() {
if (this.$el && this.$el.firstElementChild) {
var computedWidth = window.getComputedStyle(this.$el.firstElementChild).width;
// return computedWidth == 'auto' ? 'auto' : Math.ceil(parseFloat(computedWidth));
return Math.ceil(parseFloat(computedWidth));
} else {
return 0;
}
},
//...
}
在注册的时候取宽度(getLabelWidth)会拿到 NaN,因为 getComputedStyle 在元素未实际渲染时(父元素display:none)会取到 auto, parseFloat('auto') 就会NaN,不会被注册到 数组 potentialLabelWidthArr
registerLabelWidth(val, oldVal) {
if (val && oldVal) {
const index = this.getLabelWidthIndex(oldVal);
this.potentialLabelWidthArr.splice(index, 1, val);
} else if (val) {
this.potentialLabelWidthArr.push(val);
}
}
在销毁的时候自然取不到 就抛错了 [ElementForm]unpected width
// https://github.com/ElemeFE/element/blob/dev/packages/form/src/form.vue#L160
getLabelWidthIndex(width) {
const index = this.potentialLabelWidthArr.indexOf(width);
// it's impossible
if (index === -1) {
throw new Error('[ElementForm]unpected width ', width);
}
return index;
},
原因找到了,更改也比较简单, getLabelWidth 函数中 针对auto做个处理
// lib/element-ui.common.js
getLabelWidth: function getLabelWidth() {
if (this.$el && this.$el.firstElementChild) {
var computedWidth = window.getComputedStyle(this.$el.firstElementChild).width;
return computedWidth == 'auto' ? 'auto' : Math.ceil(parseFloat(computedWidth));
// return Math.ceil(parseFloat(computedWidth));
} else {
return 0;
}
},
我们在node_modules中找到报错的代码并修改,运行测试,报错解决了
但是我们的代码是在node_modules中修改的只会在本地才能生效,要让它在线上的环境也能正确执行,我们就得打补丁了
首先我们安装下patch-package这个包
npm i patch-package
然后确保我们代码修改完成之后
运行npx patch-package element-ui
这样我们就会看到项目的根目录下出现一个patchs的文件夹了 ,这个文件夹就是存放我们补丁的位置了
接下来就是在package.json文件中添加"postinstall": "patch-package"的脚本,这个命令会在npm install之后自动执行patch-package的命令
这样在项目上线打包的时候在执行npm install的命令的时候最新的补丁代码就会出现在包中了
最后我们把代码提交到远程仓库就可以共享本次补丁修改了