部分设备下JS select选择事件触发滞后一次的问题修复
诗篇站点移动端select选择滞后问题
问题现象
- 站点功能:从150篇诗篇中随机抽取1篇展示,搭配随机配图;支持两种交互:点击「Any Psalm」按钮随机切换诗篇,通过select下拉框手动指定诗篇
- 异常表现:随机切换功能全端正常,select选择功能存在设备差异:
- 笔记本端、本地环境访问时功能正常
- 手机、iPad端访问时选择始终滞后一步:当前展示诗篇20时,第一次选诗篇83页面无响应,第二次选诗篇102时,页面才会加载第一次选中的诗篇83,需要两次操作才能触发上一次选择的内容渲染
- 已尝试方案:将原生JS事件监听替换为jQuery写法,两种写法异常表现完全一致
- 站点地址:站点访问地址
相关代码
selectPsalm 处理函数
const selectPsalm = () => { loadingImage(); let psalms = randomPsalm(psalmsBulk)[1]; let selectedPsalmIndex = document.getElementById("choose").value; let lastIndex = () => { if(psalms.indexOf(psalms[selectedPsalmIndex])<10) { return 2 } else if(psalms.indexOf(psalms[selectedPsalmIndex])<100) { return 3 } else return 4 } strHeading = psalms[selectedPsalmIndex].slice(0, psalms[selectedPsalmIndex].indexOf(psalms.indexOf(psalms[selectedPsalmIndex]))+lastIndex()); strScripture = psalms[selectedPsalmIndex].slice(psalms[selectedPsalmIndex].indexOf(psalms.indexOf(psalms[selectedPsalmIndex]))+lastIndex()); document.getElementById('heading').innerHTML = strHeading; document.getElementById('psalm').innerHTML = strScripture; }
原有事件绑定代码
//document.getElementById("random").addEventListener('click', newRandomPsalm); //document.getElementById("choose").addEventListener('click', selectPsalm); $('document').ready(function(){ $('#random').on('click', newRandomPsalm); $('#choose').on('click', selectPsalm) })
问题成因
核心原因是给select元素绑定了错误的事件类型:
- 现有代码给下拉选择框绑定的是
click事件,该事件触发时机是元素被点击的瞬间,并非选项值变更完成的时机 - 桌面端Chrome、Edge等浏览器的交互逻辑中,用户点击下拉选项完成选择时,会额外触发一次select元素上的click事件,因此代码能拿到最新选中值,表现为功能正常
- 移动端、iPad端的系统select交互为原生弹窗样式:第一次点击select弹出选择器时,click事件就已经触发完成,此时用户还未完成选项选择,代码读取到的是上一次的旧value;用户选完选项关闭选择器后,不会再触发第二次click事件,因此第一次选择不会触发内容更新;等用户第二次点击select准备选新值时,click事件再次触发,此时读取到的是上一次选中的值,就出现了操作滞后一步的现象。
- 额外存在一个语法隐患:*$('document')*写法错误,不需要给document加引号,加引号后jQuery会查找页面中不存在的
<document>标签,而非绑定到真正的文档就绪事件上,只是大部分场景下不会阻塞代码运行。
修复方案
- 将select元素的监听事件从
click替换为change事件,change事件只会在select选中值真正变更完成后触发,全端交互逻辑一致 - 修正jQuery就绪事件的语法错误,移除document的引号
修改后的事件绑定代码:
// 原生JS写法(可按需选用) // document.getElementById("random").addEventListener('click', newRandomPsalm); // document.getElementById("choose").addEventListener('change', selectPsalm); // jQuery写法 $(document).ready(function(){ $('#random').on('click', newRandomPsalm); $('#choose').on('change', selectPsalm) })
可选优化
selectPsalm函数每次执行都会调用randomPsalm(psalmsBulk)[1]重新生成诗篇数组,这个数组是固定的150篇内容,可以提前定义为全局常量,不需要每次选择时重复生成,减少不必要的性能消耗。
内容的提问来源于stack exchange,提问作者chylinski
相关产品推荐
相关产品推荐

