我需要使用DOM选择API getSelection
选择HTML文档中的所有节点。
用户不能选择的节点(即用鼠标)不能使用。
因此,如果一个元素应用了CSS规则user-select: none
或-moz-user-select: none
,则我的编程选择应排除这些元素。
如果我手动(通过鼠标)选择文本,则不会选择这些元素。如果我将window.getSelection().selectAllChildren
应用于其父元素之一,则非可选元素也会被选中。
我尝试了Selection
和Range
对象的不同方法,但是还没有找到只以编程方式选择那些可以手动选择的元素的方法。
<body>
<div>Selectable</div>
<div style="-moz-user-select:none">
<span id="span">Non-Selectable</span>
</div>
<script>
const sel = window.getSelection();
sel.selectAllChildren(document.body);
console.log(sel.containsNode(document.getElementById('span')));
// outputs true
</script>
</body>
有人知道一种以编程方式仅选择那些可以手动选择的元素的方法吗?
编辑因此,我需要一个函数,该函数接收节点作为参数并在该节点可选的情况下返回布尔值:
function isSelectable(node) {
// determine if node is selectable
}
答案 0 :(得分:1)
可能是这样的:
-
基本上,如果此元素或其任何祖先是不可选择的,那么此元素也是不可选择的。我们先检查此元素,然后使用递归检查祖先元素,在我们用完祖先或发现设置为不可选择的元素时停止。
我对用户选择的工作方式的假设可能是错误的;即使将祖先设置为不可选择,也有可能迫使内部元素可选择。逻辑可以重新组织以减少混乱。当然可以使用循环来删除递归。 var userselect = [
'-webkit-touch-callout', /* iOS Safari */
'-webkit-user-select', /* Safari */
'-khtml-user-select', /* Konqueror HTML */
'-moz-user-select', /* Firefox */
'-ms-user-select', /* Internet Explorer/Edge */
'user-select'
];
function isSelectable(element) {
var style = getComputedStyle(element);
var canSelect = !userselect.some(key => style[key] === 'none');
if(canSelect) {
if(element.parentElement) return isSelectable(element.parentElement);
return true;
}
return false;
}
数组可以使用一些智能;如果这是扩展,则可以使用它来告知需要检查的属性。此代码需要元素而不是节点。我尚未真正测试过此代码,但似乎应该可以。
答案 1 :(得分:0)
好吧,我怀疑您的代码部分不错(99%不错),这是因为浏览器不同,结合了我已经发送给您的脚本和链接,我对此进行了管理:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
</style>
</head>
<body>
<div>Selectable</div>
<div class="noselect">
<span id="span">Non-Selectable</span>
</div>
<div id="r">
</div>
<script>
window.onload = function() {
var sel = window.getSelection();
sel.selectAllChildren(document.body);
document.getElementById('r').innerHTML = sel.containsNode(document.getElementById('span'));
// outputs true
};
</script>
</body>
</html>
在此处运行时,您会看到它有效!我的意思是-moz-user-select:无;仅适用于Firefox ...
在说我也检查了其他浏览器(IE,Firefox,Chrome和Edge)之后,此方法仅在Chrome中有效。
答案 2 :(得分:0)
这是一种无需循环通过节点祖先的方法:
function isSelectable(textNode) {
const selection = getSelection();
selection.selectAllChildren(textNode.parentNode);
const selectable = !!selection.toString();
selection.collapseToStart();
return selectable;
}
说明:
如果节点不是用户可选择的,您仍然可以通过编程方式选择它(selectAllChildren
),但是toString()
仍然不会包含该节点的文本内容。
就我而言,我需要遍历document.body
的所有文本节点,不幸的是,出于我的目的,此解决方案仍然太慢。