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

使用jQuery on()&off()切换事件监听器的技术问题求助

问题:触摸交互控制Ajax加载视频的播放逻辑优化

我有一段名为“代码片段1 - 在用户触摸交互时播放Ajax加载的HTML视频”的JavaScript代码,使用jQuery的on('touchstart')方法绑定事件监听器。当前问题是每次用户交互时,on('touchstart')都会触发函数播放页面所有视频。我需要实现:首次触摸交互时触发函数,随后禁用监听器,直到Ajax加载更多视频内容;每次Ajax请求成功后重新绑定监听器,让函数恢复可用。

已尝试的失败方案

  • 为事件监听器添加{once: true}布尔属性,但仅允许函数执行一次,不符合需求;
  • 使用one()替代on()方法,效果与{once: true}一致;
  • 使用document.body.addEventListener和removeEventListener方法,但removeEventListener会立即执行而非在函数调用时执行;
  • 研究过布尔属性、解绑重绑方法、委托方法、setTimeout和setInterval,尚未取得进展。

代码片段1

function videoEvents2() {
    Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
        get: function() {
            return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
        }
    });

    $(document).on('click', 'body', playVideoOnLowPower);
    $(document).on('touchstart', 'body', playVideoOnLowPower);

    function playVideoOnLowPower() {
        try {
            const videoElements = document.querySelectorAll("video");
            for (i = 0; i < videoElements.length; i++) {
                if (videoElements[i].playing) {
                    // video is already playing so do nothing
                    console.log('Playing');
                } else {
                    // video is not playing so play video now
                    videoElements[i].play();
                    console.log('Not Playing');
                }
            }
        } catch (err) {
            console.log(err);
        }
    }
}

尝试3的代码片段

document.body.addEventListener("click", playVideoOnLowPower, {
    once: true
});
document.body.addEventListener("touchstart", playVideoOnLowPower, {
    once: true
});

function dsdvideoEvents3 {
    document.body.removeEventListener("click", playVideoOnLowPower, {
        once: true
    });
    document.body.removeEventListener("touchstart", playVideoOnLowPower, {
        once: true
    });
}

解决方案:开关变量+命名空间事件控制逻辑

核心思路是用开关变量控制函数执行权限,结合命名空间事件实现精准的解绑与重绑,适配Ajax加载后的场景。

优化后的代码

// 全局开关:控制是否允许触发视频播放逻辑
let allowVideoPlayTrigger = true;

function videoEvents2() {
    Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
        get: function() {
            return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2);
        }
    });

    // 封装事件绑定逻辑,使用命名空间避免冲突
    function bindPlayEvents() {
        $(document).on('click.bodyPlay', 'body', playVideoOnLowPower);
        $(document).on('touchstart.bodyPlay', 'body', playVideoOnLowPower);
    }

    // 封装事件解绑逻辑
    function unbindPlayEvents() {
        $(document).off('click.bodyPlay touchstart.bodyPlay');
    }

    function playVideoOnLowPower() {
        // 开关关闭时直接终止执行
        if (!allowVideoPlayTrigger) return;

        try {
            const videoElements = document.querySelectorAll("video");
            for (let i = 0; i < videoElements.length; i++) {
                if (videoElements[i].playing) {
                    console.log('Playing');
                } else {
                    videoElements[i].play();
                    console.log('Not Playing');
                }
            }
            // 触发后关闭开关并解绑事件
            allowVideoPlayTrigger = false;
            unbindPlayEvents();
        } catch (err) {
            console.log(err);
        }
    }

    // 初始绑定事件
    bindPlayEvents();

    // 暴露给外部的重置方法,用于Ajax成功后恢复触发能力
    window.resetVideoPlayTrigger = function() {
        allowVideoPlayTrigger = true;
        bindPlayEvents();
    };
}

// 初始化调用
videoEvents2();

// 在你的Ajax请求成功回调中调用重置方法
// 示例:
// $.ajax({
//   url: '你的接口地址',
//   success: function() {
//     // 加载新视频后恢复触发逻辑
//     resetVideoPlayTrigger();
//   }
// });

关键说明

  • 命名空间事件:给事件添加bodyPlay命名空间,解绑时不会误删其他同类型事件;
  • 开关变量双重保险:即使事件未及时解绑,开关也能阻止函数重复执行;
  • 封装复用逻辑:绑定/解绑逻辑封装成函数,Ajax成功后直接调用重置方法即可恢复功能。

内容的提问来源于stack exchange,提问作者DCM CODING

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:33:22