当elementui的el-dialog组件中包含子组件时,用$refs调用子组件时的undefined问题

本文探讨了在Element UI的el-dialog弹框中嵌套子组件时,如何正确设置子组件属性并避免`fileList` undefined错误。作者分享了两种处理方法,包括使用$nextTick或setTimeout确保数据更新后再操作子组件,并提醒了关于数据绑定时机的重要性和赋值来源的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

elementui的el-dialog弹框组件中包含了一个子组件。

<el-dialog :title="titleMap[dialogStatus]" :visible.sync="dialogFormVisible" width="60%">
      <el-form :rules="rules" ref="dataForm" :model="dataForm" label-position="right" label-width="130px">
        <el-row>
          <el-col :span="8">
            <el-form-item :label="this.$t('logisticsUser.businessLicense')" prop="businessLicense">
              <v-singleImage ref="imageLicense" imageType=1></v-singleImage>
            </el-form-item>
          </el-col>

然后我通过$refs为该子组件里面的属性赋值,在控制台上却显示undefined。

handleWatch(idx) {
        let imgFileList = []
        const ctxPath = process.env.BASE_API;
 
        logisticsUserApi.queryOne(idx).then(res=>{
          this.dataForm = Object.assign({}, res.data.data);
          imgFileList.push({name: res.data.data.businessLicenseImagePath, url: ctxPath +"/attachment/downloadAttachmentFile?filePath="+ res.data.data.businessLicenseImagePath})          
        });
        this.watchDialogFormVisible = true
        
        this.$refs.imageLicenseWatch.fileList = imgFileList
        //查看时,上传图片按钮不可操作
        this.$refs.imageLicenseWatch.showdisabled = true
        //查看时,不显示上传控件
        this.$refs.imageLicenseWatch.uploadDisabled='disabled'

报错如下:

errorLog.js:17 TypeError: Cannot set property 'fileList' of undefined
    at VueComponent.handleWatch (index.vue?52f4:411)
    at Proxy.boundFn (vue.esm.js:188)
    at click (index.vue?8790:431)
    at VueComponent.invoker (vue.esm.js:1997)
    at VueComponent.Vue.$emit (vue.esm.js:2507)
    at VueComponent.handleClick (element-ui.common.js:9560)
    at boundFn (vue.esm.js:188)
    at invoker (vue.esm.js:1997)
    at HTMLButtonElement.fn._withTask.fn._withTask (vue.esm.js:1795) "event handler for "click""

还有一个坑:this.watchDialogFormVisible = true 要写在前面 否则会报错

errorLog.js:17 TypeError: Cannot set property 'fileList' of undefined
    at VueComponent.<anonymous> (index.vue?52f4:403)
    at Array.<anonymous> (vue.esm.js:1806)
    at MessagePort.flushCallbacks (vue.esm.js:1727) "nextTick"

还有一个坑:imgFileList 变量的赋值要使用 res.data.data ,如果使用 this.dataForm 赋值,你会发现this.dataForm为null。

下面附上正确的写法:

方法一:利用 this.$nextTick(function(){ 实现:

handleWatch(idx) {
        let imgFileList = []
        const ctxPath = process.env.BASE_API;
 
        logisticsUserApi.queryOne(idx).then(res=>{
          this.dataForm = Object.assign({}, res.data.data);
          imgFileList.push({name: res.data.data.businessLicenseImagePath, url: ctxPath +"/attachment/downloadAttachmentFile?filePath="+ res.data.data.businessLicenseImagePath})          
        });
        this.watchDialogFormVisible = true
 
        this.$nextTick(function(){
          this.$refs.imageLicenseWatch.fileList = imgFileList
          //查看时,上传图片按钮不可操作
          this.$refs.imageLicenseWatch.showdisabled = true
          //查看时,不显示上传控件
          this.$refs.imageLicenseWatch.uploadDisabled='disabled'  
        })

方法二: 利用 setTimeout(()=>{ 实现:

handleWatch(idx) {
        let imgFileList = []
        const ctxPath = process.env.BASE_API;
 
        logisticsUserApi.queryOne(idx).then(res=>{
          this.dataForm = Object.assign({}, res.data.data);
          imgFileList.push({name: res.data.data.businessLicenseImagePath, url: ctxPath +"/attachment/downloadAttachmentFile?filePath="+ res.data.data.businessLicenseImagePath})          
        });
        this.watchDialogFormVisible = true
        setTimeout(()=>{
          this.$refs.imageLicenseWatch.fileList = imgFileList
          //查看时,上传图片按钮不可操作
          this.$refs.imageLicenseWatch.showdisabled = true
          //查看时,不显示上传控件
          this.$refs.imageLicenseWatch.uploadDisabled='disabled' 
        },0) 
### Vue 中 `this.$refs` 方法为 `undefined` 的原因分析 在 Vue.js 开发过程中,当尝试通过 `this.$refs` 访问 DOM 元素或子组件实例,可能会遇到返回 `undefined` 的问题。这通常发生在生命周期钩子函数中的某些阶段。 #### 原因解析 1. **DOM 尚未渲染完成** 如果在 `beforeMount` 或其他更早的生命周期钩子中访问 `this.$refs`,此模板尚未挂载到页面上,因此 `this.$refs` 返回的结果将是 `undefined`[^2]。 2. **异步更新的影响** 当数据模型发生变化并触发视图重新渲染,如果立即访问 `this.$refs`,可能由于异步特性导致目标元素还未被创建或更新完毕[^3]。 3. **动态条件渲染 (v-if)** 使用 `v-if` 控制显示隐藏的情况下,只有满足条件才会真正渲染对应的节点。如果不满足条件,则即使已经进入 `mounted` 阶段也无法找到该引用[^4]。 --- ### 解决方案 以下是几种常见的解决办法: #### 1. 确保操作位于正确的生命周期钩子里 应始终将涉及 `$refs` 的逻辑放置于 `mounted` 生命周期之后运行。因为在此期间虚拟 DOM 已经转换成真实 DOM 并附加到了文档树当中。 ```javascript mounted() { console.log(this.$refs.videoPlayer); // 正常情况下不会是 undefined } ``` #### 2. 处理动态渲染场景下的延迟加载 对于由 `v-if` 动态控制的内容,在确认对应部分确实已呈现后再去读取它。可以借助回调或者观察器实现这一点: ```javascript watch: { showVideo(newVal) { if (newVal && this.$refs.videoPlayer) { const playerInstance = videojs( this.$refs.videoPlayer, this.options, function onPlayerReady() {} ); console.log(playerInstance); } }, }, data() { return { showVideo: false, }; }, template: ` <div> <video ref="videoPlayer" v-if="showVideo"></video> </div> `, methods: { toggleShow() { this.showVideo = true; }, }, ``` #### 3. 判断是否为数组形式的 $refs开发者误以为单个 HTML 元素总是单独绑定给某个特定名称下,但实际上如果有多个相同名字的选择符存在的话,那么最终得到的就是一个 NodeList 类型对象而非单纯的一个 Element 实体。所以需要额外判断一下再决定如何处理: ```javascript if(Array.isArray(this.$refs.audio)){ this.$refs.audio.forEach(item => item.play()); }else{ this.$refs.audio.play(); } ``` #### 4. 销毁对话框重置状态 如果是基于第三方库构建出来的模态窗口之类的东西(比如 Element UI),记得按照官方建议设置属性防止残留影响下次初始化过程: ```html <el-dialog :visible.sync="dialogVisible" @close="handleClose" destroy-on-close> <!-- Content --> </el-dialog> ``` 上述配置能够保证每次关闭弹窗都会彻底清理内部结构从而避免潜在冲突现象的发生。 --- ### 总结 综上所述,针对 `this.$refs.videoPlayer` 出现 `undefined` 的情况可以从以下几个方面入手排查和修复:调整至合适调用;考虑是否存在多选情形以及特殊插件行为等因素干扰正常流程运转状况即可有效规避此类异常事件再次出现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值