使用 uniapp 和 vant 的遇到问题记录
在项目中需要用vant
组件库的ImagePreview
组件遇到报错,导致组件无法正常使用。
按照vant
的文档使用ImagePreview
时,浏览器抛出了下面的异常错误:
通过浏览器断点调试,发现是ImagePreview
组件中的ImagePreviewItem
组件在渲染Image
组件时报错了,如下图:
从报错中看到this.onLoad
方法是undefined
,从图中还可以看到已经定义过onLoad
方法了,那为什么onLoad
方法消失了呢?
探索原因
uniapp
官方文档中写着页面的生命周期中包含onLoad
方法,怀疑是与此方法冲突导致,但是为什么会影响到组件methods
中方法还未知原因。
然后我再一个普通的页面的methods
中也写了一个onLoad
方法,发现他竟然直接被当做生命周期执行了,绑定在DOM
上的onLoad
也变成了undefiend
。现在有理由证明是uniapp
对页面或组件的vue
实例进行操作。
经过翻阅uniapp
的源码发现,他为了支持自己框架的一些life cycle hooks
,对页面或组件的vue
实例进行了mixin
操作,可以看到,当页面或组件的methods
包含了与框架生命周期同名的函数,将会被直接绑定实例外层,然后从methods
中删除。
经过debug
,也完全证实了上面的结论。
解决问题
既然已经发现了问题的原因,那要如何解决问题呢?uniapp
和vant
都是第三方库,去给他们提issue
让两边的团队去协商解决吧,这显然是不可能的。或者放弃使用uniapp
或者vant
?这个主意不错,但是并不能解决根本问题,当你发现其他vant
组件或其他者第三方组件也有冲突时,要怎么办呢。
我想到代码都是要通过babel
转义的,那我是不是能通过babel-plugin
来解决呢?后来发现,项目中的babel-plugin
只能对本地代码的AST
语法树进行操作,并不能解析到第三方库的代码,因为他们都是通过import
导入进来的,babel-plugin
只能解析到import
的AST
。
仔细一想,解析第三方库的话,用babel-loader
就好了。于是我便写了一个替换方法名的loader
,并在vue.config.js
中添加了对vant
库的loader
。// fixConflictLoader.js
const mixedNameReg = /\b(onLoad|onError)\b/g;
module.exports = function (source) {
let _source = source;
if (mixedNameReg.test(_source)) {
_source = _source.replace(mixedNameReg, function ($0) {
return $0 + "InVant";
});
return _source;
} else {
return source;
}
};// vue.config.js
const path = require("path");
const fixConflictLoader = path.join(__dirname, "./fixConflictLoader");
module.exports = {
chainWebpack: config => {
config.module
.rule("compile")
.test(/\.js$/)
.include.add(resolve("node_modules/vant/es")) // vant 的按需引入使用的是此项目包
.end()
.use(fixConflictLoader)
.loader(fixConflictLoader);
}
}
这个方法非常的暴力,直接解析vant
的源码,然后批量替换其中与uniapp
生命周期冲突的方法名,实际也解决了我所遇到的问题。
如果你有更好的方法,欢迎与我探讨交流。