如何在Android端用JavaScript+Cordova检测单词语本选中操作
检测Android Cordova中单词文本选中的完成事件
问题背景
我需要在Android端用Cordova和JavaScript检测用户完成文本选中的操作。目前已有检测多词选中的方案(见下方parthibeyond提供的代码),但无法检测单词选中的情况。
长按单词发起选中时,事件触发顺序为:
selectstartcontextmenuselectionchangetouchcancel
此时用户有两种操作:要么抬起手指仅选中初始单词,要么移动手指选中更多单词。我需要检测第一种仅选中单个单词的情况。
touchcancel会阻止touchend事件触发,定时器方案也不可行——因为用户可能在移动手指选多词前长时间按住屏幕。系统会在选中文本两端添加“抓取手柄”来提示手指已离开、选中结束(单词和多词选中均是如此),但目前找不到在JavaScript中捕获这个状态的方法。我试过的临时方案是在touchstart事件中调用event.preventDefault(),但这会移除所有文本选中和滚动功能,不符合需求。
原多词选中结束事件代码,感谢parthibeyond
function customisedSelectListener(el = document, callbackFn) { // events to be listened - 'selectstart', 'selectionchange', 'contextmenu' let eventSequence = []; el.addEventListener('selectstart', function() { eventSequence = []; eventSequence.unshift(event.type); }) el.addEventListener('selectionchange', function() { if (eventSequence[0] != 'selectionchange') { eventSequence.unshift(event.type); } }) el.addEventListener('contextmenu', function() { eventSequence.unshift(event.type); if (eventSequence[1] == 'selectionchange') { callbackFn.call(); } }) }
使用示例:
customisedSelectListener(document, function (){ alert('Text Selection Completed !!'); })
解决方案:结合选中范围与事件序列检测单词选中完成
核心思路是通过跟踪选中状态、记录初始选中范围,在touchcancel或contextmenu事件触发时校验当前选中内容是否未发生变化且为单个单词,以此判断用户完成了单词语句选中。
实现代码
function detectSingleWordSelection(el = document, callbackFn) { let isSelecting = false; let initialSelectionRange = null; el.addEventListener('selectstart', () => { isSelecting = true; initialSelectionRange = null; }); el.addEventListener('selectionchange', () => { if (!isSelecting) return; const selection = window.getSelection(); if (selection.rangeCount === 1) { const range = selection.getRangeAt(0); // 记录首次选中的范围(单个单词的初始状态) if (!initialSelectionRange) { initialSelectionRange = { startContainer: range.startContainer, startOffset: range.startOffset, endContainer: range.endContainer, endOffset: range.endOffset }; } else { // 选中范围变化,说明用户在选多词,重置标记 initialSelectionRange = null; } } }); el.addEventListener('touchcancel', () => { if (!isSelecting || !initialSelectionRange) return; const selection = window.getSelection(); // 校验当前选中范围是否和初始一致 if (selection.rangeCount === 1) { const currentRange = selection.getRangeAt(0); const isRangeUnchanged = currentRange.startContainer === initialSelectionRange.startContainer && currentRange.startOffset === initialSelectionRange.startOffset && currentRange.endContainer === initialSelectionRange.endContainer && currentRange.endOffset === initialSelectionRange.endOffset; if (isRangeUnchanged) { const selectedText = selection.toString().trim(); // 验证选中内容为单个单词(可根据需求调整正则规则) if (/^\w+$/.test(selectedText)) { callbackFn.call(null, selectedText); } } } // 重置选中状态 isSelecting = false; initialSelectionRange = null; }); // 兼容上下文菜单触发的场景 el.addEventListener('contextmenu', (e) => { e.preventDefault(); // 阻止默认菜单,避免干扰选中判断 if (isSelecting && initialSelectionRange) { const selection = window.getSelection(); const selectedText = selection.toString().trim(); if (/^\w+$/.test(selectedText)) { callbackFn.call(null, selectedText); } } isSelecting = false; initialSelectionRange = null; }); }
使用示例
detectSingleWordSelection(document, (selectedWord) => { alert(`单个单词选中完成:${selectedWord}`); });
关键说明
- 状态跟踪:用
isSelecting标记是否处于文本选中状态,initialSelectionRange记录首次选中的范围,若选中范围变化则重置标记,排除多词选中的情况。 - 事件校验:在
touchcancel(手指离开触发)和contextmenu(长按弹出菜单触发)事件中,对比当前选中范围与初始范围,确认未发生变化,再通过正则验证选中内容为单个单词。 - 保留原生功能:未在
touchstart中调用preventDefault(),保留了原生的文本选中、滚动等功能,避免影响用户体验。
内容的提问来源于stack exchange,提问作者Will
相关产品推荐
相关产品推荐

