代码之家  ›  专栏  ›  技术社区  ›  Valor_ user3379466

在Vuejs中加载视频(超过最大调用堆栈大小)时显示视频

  •  1
  • Valor_ user3379466  · 技术社区  · 7 年前

    我试图实现当用户鼠标悬停在DIV上时的功能,一些视频将被播放。我有这个组件,每页呈现25次

    <LocationStripeItemComponent
            v-for="(l, index) in locations" :key="index" :location="l">
    </LocationStripeItemComponent>
    

    在这个组件中,有以下代码

    <template>
    <div class="stripe__item card" @mouseover="previewTrailerVideo(true)" @mouseleave="previewTrailerVideo(false)">
    
        <div class="card__gradient"></div>
        <img :src="location.teaser_image" v-show="!hideImage"
             :alt="location.name" class="card__img"/>
    
        <div class="card__trailer_loading" v-show="miniTrailerLoading"></div>
        <video v-show="invokeMiniTrailerDiv" autoplay loop class="card__video" id="miniTrailer">
            <source :src="location.teaser_video">
        </video>
    </div>
    </template>
    
    <script>
    export default {
            name: 'LocationStripeItemComponent',
            props: {
                location: {
                    type: Object,
                    required: true
                }
            },
            data() {
                return {
                    invokeMiniTrailerDiv: false,
                    miniTrailerLoading: false,
                    miniTrailerPlaying: false,
                    hideImage: false
                }
            },
            methods: {
                previewTrailerVideo(showState) {
                    if (showState) {
    
                        this.invokeMiniTrailerDiv = true;
                        this.miniTrailerLoading = true;
    
                        let video = document.getElementById('miniTrailer');
                        if (video.readyState === 4) {
                            this.miniTrailerLoading = false;
                            this.hideImage = true;
                            this.miniTrailerPlaying = true;
                        } else {
                           setTimeout(this.previewTrailerVideo(showState), 1000);
                        }
                    } else {
                        this.invokeMiniTrailerDiv = false;
                        this.miniTrailerLoading = false;
                        this.miniTrailerPlaying = false;
                        this.hideImage = false;
                    }
                },
            }
        };
    </script>
    

    我一直犯的错误是

    Uncaught RangeError: Maximum call stack size exceeded
        at Object.reactiveSetter [as invokeMiniTrailerDiv] (vue.esm.js?efeb:998)
        at VueComponent.proxySetter [as invokeMiniTrailerDiv] (vue.esm.js?efeb:3300)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:93)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
        at VueComponent.previewTrailerVideo (LocationStripeItemComponent.vue?2f13:102)
    

    我认为问题在于:

    setTimeout(this.previewTrailerVideo(showState), 1000);
    

    因为递归函数被调用过多次,但我不知道如何获取视频元素,因为在有人将鼠标添加到元素上之前,它是隐藏的。是否有其他方法来检测元素在页面上何时可见?如何正确实现此功能?坦克你!

    1 回复  |  直到 7 年前
        1
  •  2
  •   yqlim    7 年前

    问题1

    你使用的方式 setTimeout 是不正确的。

    应传递给的第一个参数 seTimeout 应该是一个函数。在你的代码中,你正在通过 undefined :

    setTimeout(this.previewTrailerVideo(showState), 1000);
    

    因为函数 previewTrailerVideo 什么也不返回,意思是 未定义 .

    换句话说,你的 设置超时 根本没有运行。意思是,你得到的错误不是来自 设置超时 .

    问题2

    你所得到的错误实际上是你使用的方式 设置超时 (但不是) 设置超时 本身)。在同一行中:

    设置超时(this.PreviewTrailerVideo(ShowState),1000);
    

    虽然 设置超时 如果调用不正确,则递归可以很好地工作(这就是产生错误的地方),因为在该行中,实际上 打电话 你的功能,一次又一次,何时 showState === true .

    解决方案

    只需将该行编辑为:

    setTimeout(this.previewTrailerVideo.bind(this, showState), 1000);
    

    阅读有关 .bind 详情。

    简而言之, 绑定 方法不会调用函数,但会将参数传递到函数中,并返回函数中已包含这些参数的函数。

    通过使用 绑定 ,现在您正在将假定的函数传递给 设置超时 (问题1),也停止递归(问题2)。

    推荐文章