使用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
相关产品推荐
相关产品推荐

