我的需求是用element-ui的messagebox,来实现验证码接受的功能。并将cancel按钮换成刷新功能,在beforeClose中实现验证码刷新。元素都是在$msgbox中生成的,下面是最开始出错的核心代码。
let result = await this.$API.reqCaptchaImg();
this.captchaImg = "data:image/png;base64," + result.img;
this.uuid = result.uuid;
const h = this.$createElement;
const inputElem = h(
"input",
{
attrs: {
value: this.inputCaptcha,
id: "input1",
},
on: {
input: function (event) {
this.inputCaptcha = event.target.value;
}.bind(this),
},
},
""
);
const imgElem = h("img", {
ref: "captchaImg",
attrs: {
src: this.captchaImg,
},
});
// 将 input 和 img 元素放到 Vue 组件之外的 div 中
const divElem = h("div", [inputElem, imgElem]);
await this.$msgbox({
title: "Please enter the verification code",
message: divElem,
type: "warning",
center: true,
showCancelButton: true,
confirmButtonText: "confirm",
cancelButtonText: "refresh",
distinguishCancelAndClose: true,
beforeClose: async (action, instance, done) => {
// console.log(action);
if (action === "confirm") {
flag = true;
done();
} else if (action === "cancel") {
let result = await this.$API.reqCaptchaImg();
this.captchaImg = "data:image/png;base64," + result.img;
this.uuid = result.uuid;
this.$nextTick(() => {
// 更新captchaImg元素的src属性
this.$refs.captchaImg.src = this.captchaImg;
});
} else {
flag = false;
done();
}
},
})
.then((action) => {})
.catch((action) => {});
其中,通过解决方法,可知错误主要集中在这俩处。
const imgElem = h("img", {
ref: "captchaImg",
attrs: {
src: this.captchaImg,
},
});
this.$nextTick(() => {
// 更新captchaImg元素的src属性
this.$refs.captchaImg.src = this.captchaImg;
});
这样写,之后,出现了非常奇怪的bug。我测试的过程中,大部分时候的刷新验证码功能是完好的。但有时候就会出现无法获取ref元素的情况。出现下面的报错。
Error in nextTick: "TypeError: Cannot set properties of undefined (setting 'src')"
第一个奇怪的地方:首次出现验证码界面时,每一次都是正常显示的。只有点击刷新时,才有可能会出现报错。这说明节点元素明明已经更新到页面上了,但后续确找不到ref绑定。且报错会一直存在。除非手动刷新浏览器,才能正常刷新验证码。
第二个奇怪的地方:开发的时候,我发现报错是偶尔才会出现的,但一直不清楚报错出现的情况。后来,我发现:如果你每次都手动刷新浏览器,功能是正常的。但如果你是修改了代码,哪怕只是删了一行注释。然后ctrl+s保存,vue帮你自动刷新页面。你再重新打开messagebox刷新验证码,便会出现ref找不到绑定的情况。
在全网论坛上寻找原因,并没有找到解决方法。后面在chatgpt上寻找原因,发现chatgpt也不是万能的,最开始几次提供的都是错误的思路。(包括但不限于清除浏览器缓存,divElem放到msgbox外面,为$refs.captchaImg提供初始图片等)
多试了几次后,gpt找到了正确的方法。如下:尝试将 $refs.captchaImg 替换为 document.getElementById('captcha-img')。修改后代码的核心如下:
const imgElem = h("img", {
//不要这个
//ref: "captchaImg",
attrs: {
src: this.captchaImg,
//要这个
id:"captcha-img",
},
style: {
"margin-top": "20px",
},
});
this.$nextTick(() => {
// 更新captchaImg元素的src属性
// this.$refs.captchaImg.src = this.captchaImg;
document.getElementById('captcha-img').src = this.captchaImg;
});
关于为什么使用ref会出现这么诡异的bug,id却不会。gpt解释如下:
问题是解决了,但是这并没有打消我对前面两个问题的疑问。先写一篇文章放在这里,等待后续再来回顾。