如何以编程方式仅选择用户可选择的所有文本节点
如何以编程方式仅选择用户可选择的所有文本节点
我需要使用DOM选择API getSelection
来选择HTML文档中的所有节点。
\n不可由用户选择的节点(即使用鼠标)应该被排除在外。
\n因此,如果一个元素应用了CSS规则user-select: none
或-moz-user-select: none
,我的编程选择应该排除这些元素。\n如果我手动选择文本(通过鼠标),这些元素将不会被选中。如果我在其中一个父元素上应用window.getSelection().selectAllChildren
,不可选择的元素也会被选中。\n我尝试了不同的方法,包括Selection
和Range
对象,但没有找到一种只通过编程选择那些可手动选择的元素的方式。\n
可选择的
不可选择的
\n有人知道一种只通过编程选择可手动选择的元素的方法吗?\n编辑 所以我需要一个接收节点作为参数并返回一个布尔值的函数,判断该节点是否可选择:
\n
function isSelectable(node) { // 判断节点是否可选择 }
问题的出现原因:
这篇文章介绍了一种方法来编程地选择用户可选择的所有文本节点。作者提到,他需要遍历整个文档的所有文本节点,并且他发现现有的方法对于他的目的来说速度太慢了。
解决方法:
作者提供了一种解决方法,即使用selectAllChildren
方法来编程地选择文本节点,并通过toString()
方法来判断选择的文本是否包含在节点中。具体的解决方案如下:
function isSelectable(textNode) { const selection = getSelection(); selection.selectAllChildren(textNode.parentNode); const selectable = !!selection.toString(); selection.collapseToStart(); return selectable; }
该方法首先获取当前选中的文本区域,然后使用selectAllChildren
方法来选择文本节点的父节点。然后,通过判断toString()
的结果是否为空来确定选择的文本是否包含在节点中。最后,使用collapseToStart
方法将选择的文本区域折叠到起始位置,并返回是否可选择的结果。
然而,作者提到这种解决方法对于他的目的来说速度还是太慢了,需要寻找更高效的解决方案。
如我所料,你的代码部分正确(99%正确),这是由于不同的浏览器造成的,结合你的脚本和我之前发送给你的链接,我成功地做到了这一点:
JS Bin SelectableNon-Selectable
当你在这里运行它,你会看到它可以工作!我的意思是,-moz-user-select: none; 只在Firefox中起作用...
在说这之前,我也检查了其他浏览器(IE,Firefox,Chrome和Edge),这个在Chrome中可行。
我真的很感谢你的帮助!:)不幸的是,我仍然不明白这如何帮助确定一个节点是否可选择。在你的例子中,我可以通过class noselect
来判断是否可选择,但是大多数网页不会这么容易。
所以,我需要一个像这样的函数:isSelectable(node) { ... return selectable }
是的,因为它是针对特定浏览器的,我认为我们应该分别为每个浏览器构建该函数。在Chrome中使用 noselect 和你的JavaScript代码完美地工作,但在Firefox,Edge和IE中不行。(我使用 noselect 是因为它在所有浏览器中都适用于用户选择)
问题的出现原因:
该问题的出现是因为作者想要以编程方式选择用户可以选择的所有文本节点,但是作者目前的方法效率太低,需要遍历所有的祖先节点来检查是否可选择。
解决方法:
作者提供了一种解决方法,即通过递归检查元素及其祖先元素的可选择性来判断一个元素是否可选择。具体的解决方法如下:
1. 定义一个数组userselect
,其中包含各种浏览器的可选择性属性。
2. 定义一个函数isSelectable
,接受一个元素作为参数。
3. 在isSelectable
函数中,首先获取元素的计算样式style
。
4. 使用some
方法遍历userselect
数组,检查是否有一个属性的值为'none'
,如果没有,则该元素可选择。
5. 如果该元素可选择,则递归调用isSelectable
函数,传入当前元素的父元素作为参数,继续检查父元素的可选择性。
6. 如果递归调用返回true
,则说明当前元素或其祖先元素中有一个是不可选择的,当前元素也是不可选择的。
7. 如果递归调用返回false
,则说明当前元素及其所有祖先元素都是可选择的,当前元素可选择。
作者对解决方法的一些补充说明:
作者推测关于user-select
属性的工作原理可能是错误的,可能可以在将祖先元素设置为不可选择后,强制内部元素可选择。逻辑可以重新组织得更清晰。可以使用循环而不是递归来遍历元素的祖先元素。userselect
数组可以更智能地使用,可以根据实际需求选择需要检查的属性。该代码期望传入一个元素而不是节点。作者并没有实际测试过这段代码,但它看起来应该可以工作。
作者感谢回答者的回答,并解释了自己的需求。作者知道自己可以通过遍历所有祖先元素并检查getComputedStyle(node).MozUserSelect
来判断一个元素是否可选择,但是这种方法效率太低,因为需要对body
内的每个节点进行遍历。作者希望能够找到一种简单的检查方法,而不需要遍历所有的祖先元素。
回答者表示目前没有这样的方法,但是如果作者提供一个使用案例,可能可以提供替代方法。