我的需求是用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解释如下:
问题是解决了,但是这并没有打消我对前面两个问题的疑问。先写一篇文章放在这里,等待后续再来回顾。