Nuxt3应用中Cloudinary UploadWidget点击失效,刷新后才可正常打开
Cloudinary上传组件点击报错,仅刷新后可用
相关代码
<div class="img__container"> <CldUploadWidget v-if="!editMiner.img" v-slot="{ open, widget }" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div @click="open" class="add__image d-flex justify-content-center align-items-center"> <IconCSS size="65px" name="material-symbols:note-stack-add-outline" /> </div> </CldUploadWidget> <div class="add__image" v-else> <CldUploadWidget v-slot="{ open, widget }" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div> <CldImage alt="miner-img" @click="open" width="150" height="150" :src="miner?.img || editMiner.img"> </CldImage> </div> </CldUploadWidget> </div> </div>
错误现象
点击组件时只有刷新页面后才能正常打开上传模态框,否则抛出以下错误:
Uncaught TypeError: Cannot read properties of undefined (reading 'open') at invokeInstanceMethod (CldUploadWidget.vue:160:31) at open (CldUploadWidget.vue:192:7) at callWithErrorHandling (chunk-RAKT47ZN.js?v=f55911a4:1565:18) at callWithAsyncErrorHandling (chunk-RAKT47ZN.js?v=f55911a4:1573:17) at HTMLImageElement.invoker (chunk-RAKT47ZN.js?v=f55911a4:9397:5)
尝试用v-if/v-else条件渲染处理,但插槽传递的open、widget属性不具备响应式,问题未解决。
解决方法
方案1:合并组件结构,避免重复渲染
把两种状态的内容放到同一个CldUploadWidget内部,用条件渲染控制显示内容,而非重复渲染整个组件。这样能保证组件实例稳定,避免因v-if切换导致的实例重建问题:
<div class="img__container"> <CldUploadWidget v-slot="{ open, widget }" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div @click="open" class="add__image" :class="{ 'd-flex justify-content-center align-items-center': !editMiner.img }" > <IconCSS v-if="!editMiner.img" size="65px" name="material-symbols:note-stack-add-outline" /> <CldImage v-else alt="miner-img" width="150" height="150" :src="miner?.img || editMiner.img" /> </div> </CldUploadWidget> </div>
方案2:先判断open存在再调用
在点击事件中增加判断,确保open方法初始化完成后再调用:
<!-- 无图片状态的组件示例 --> <CldUploadWidget v-if="!editMiner.img" v-slot="{ open, widget }" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div @click="open && open()" class="add__image d-flex justify-content-center align-items-center"> <IconCSS size="65px" name="material-symbols:note-stack-add-outline" /> </div> </CldUploadWidget>
方案3:通过ref调用组件实例方法
给CldUploadWidget添加ref,直接调用组件实例的open方法,绕过插槽属性的响应式问题:
<template> <div class="img__container"> <CldUploadWidget ref="uploadWidget" v-if="!editMiner.img" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div @click="handleOpenUpload" class="add__image d-flex justify-content-center align-items-center"> <IconCSS size="65px" name="material-symbols:note-stack-add-outline" /> </div> </CldUploadWidget> <div class="add__image" v-else> <CldUploadWidget ref="uploadWidgetElse" uploadPreset="****" @upload="handleUploadClick($event.value.info)"> <div @click="handleOpenUploadElse"> <CldImage alt="miner-img" width="150" height="150" :src="miner?.img || editMiner.img"> </CldImage> </div> </CldUploadWidget> </div> </div> </template> <script setup> import { ref } from 'vue'; const uploadWidget = ref(null); const uploadWidgetElse = ref(null); const handleOpenUpload = () => { uploadWidget.value?.open(); }; const handleOpenUploadElse = () => { uploadWidgetElse.value?.open(); }; </script>
内容的提问来源于stack exchange,提问作者Nikodem Wicon - Nicode.pl
相关产品推荐
相关产品推荐

