You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vuetify元素内$ref失效求助:轮播项自定义HTML渲染异常

问题根源

Vuetify的v-carousel默认做了懒加载优化:仅当前活跃的轮播项会被渲染到DOM中,非活跃项的DOM节点处于未挂载状态。这就导致除第一个轮播项外,其他组件在mounted钩子执行时,<div ref="carousel_html">还未被创建,$refs.carousel_html为undefined,触发设置innerHTML的报错。

解决方案

方案1:用v-html指令替代手动DOM操作(推荐)

直接使用Vue内置的v-html指令绑定解码后的HTML内容,Vue会自动在DOM节点存在时完成渲染,无需手动操作DOM:

<template>
    <v-carousel-item>
        <v-img
            :lazy-src="item.image.sizes.landing_carousel_bg_xs"
            :src="item.image.sizes.landing_carousel_bg_fhd">
            <!-- 用v-html直接绑定解码后的HTML -->
            <div style="height: 100%" class="html" v-html="decodedHtml"></div>
        </v-img>
    </v-carousel-item>
</template>
<script>
export default {
    props: ["item"],
    computed: {
        decodedHtml() {
            return Base64.decode(this.item.html)
        }
    }
}
</script>

方案2:监听轮播项活跃状态,按需渲染

如果必须手动操作DOM,可以通过父组件的活跃索引,给子组件传递active状态,在组件变为活跃时再执行DOM赋值:

子组件(LandingPageCarouselItem.vue)修改:

<template>
    <v-carousel-item>
        <v-img
            :lazy-src="item.image.sizes.landing_carousel_bg_xs"
            :src="item.image.sizes.landing_carousel_bg_fhd">
            <div ref="carousel_html" style="height: 100%" class="html"></div>
        </v-img>
    </v-carousel-item>
</template>
<script>
export default {
    props: ["item", "isActive"],
    data: () => ({
        html: undefined,
    }),
    created() {
        this.html = Base64.decode(this.item.html)
    },
    watch: {
        isActive(newVal) {
            if (newVal) {
                this.$nextTick(() => {
                    this.$refs.carousel_html?.innerHTML = this.html
                })
            }
        }
    },
    mounted() {
        if (this.isActive) {
            this.$nextTick(() => {
                this.$refs.carousel_html.innerHTML = this.html
            })
        }
    }
}
</script>

父组件(LandingPage.vue)修改:

<v-carousel v-model="activeIndex">
   <landing-page-carousel-item
       v-for="(item,i) in page_data.front_page.main_view.carousel_items"
       :key="i"
       :item="item"
       :is-active="activeIndex === i">
   </landing-page-carousel-item>
</v-carousel>
<script>
export default {
    data() {
        return {
            activeIndex: 0
        }
    }
}
</script>

方案3:用v-intersect检测元素可见性

利用Vuetify的v-intersect指令,在轮播项DOM进入视口时再执行渲染:

<template>
    <v-carousel-item>
        <v-img
            :lazy-src="item.image.sizes.landing_carousel_bg_xs"
            :src="item.image.sizes.landing_carousel_bg_fhd">
            <div 
                ref="carousel_html" 
                style="height: 100%" 
                class="html"
                v-intersect="handleRender">
            </div>
        </v-img>
    </v-carousel-item>
</template>
<script>
export default {
    props: ["item"],
    data: () => ({
        html: undefined,
        rendered: false // 避免重复渲染
    }),
    created() {
        this.html = Base64.decode(this.item.html)
    },
    methods: {
        handleRender(entries) {
            if (entries[0].isIntersecting && !this.rendered) {
                this.$refs.carousel_html.innerHTML = this.html
                this.rendered = true
            }
        }
    }
}
</script>

内容的提问来源于stack exchange,提问作者sal-k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:20:31