我正在尝试为文章中的选择的开始和结束获取字符偏移量。但是,我想在这个过程中忽略一些元素。
在我的应用程序中,服务器正在使用HTML之前JS动态注入一些元素,并且文本中的字符数在服务器和客户端之间保持一致非常重要。
我希望它和window.getSelection()
以及user-select: none;
一样简单。遗憾的是,尽管文本看起来没有被选中,但它仍然包含在选择范围内。
我在下面写了一个简短的例子。我曾经写过removeFromSelection
作为解决方法而没有取得多大成功。也许我需要删除重叠.unselectable
的范围,并手动填补全新范围对象的空白。我觉得这应该比我做的更容易。我应该怎么做?
function findAncestorOffset(container, node, offset)
{
if (node == container)
return offset;
var parent = node.parentNode;
var syblings = parent.childNodes;
for (var i = 0, len = syblings.length; i < len; i++)
{
if (syblings[i] == node)
break;
offset += $(syblings[i]).text().length;
}
return findAncestorOffset(container, parent, offset);
}
function removeFromSelection(selector, selection)
{
$(selector).each(function(i, node){
var range = document.createRange();
range.selectNodeContents(node);
selection.removeAllRanges(range);
});
}
var onSelect = function(){
var sel = window.getSelection();
//removeFromSelection('.unselectable', sel);
var text = sel.toString();
$('#out').text(text);
var range = sel.getRangeAt(0).cloneRange();
var i = findAncestorOffset($('.article')[0], range.startContainer, range.startOffset);
$('#from').text(i);
$('#to').text(i + text.length);
}
$('.article').mouseup(onSelect);
$('.article').focusout(onSelect);
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
pre, .article {
border: solid 1px black;
padding: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Select This</h1>
<div class="article">
<p>
This can be selected.
</p>
<p class="unselectable">
This can't.
</p>
<p>
And this can again.
</p>
</div>
<h1>Output</h1>
<div>
From: <span id="from"></span>, To: <span id="to"></span>
</div>
<pre id="out">
</pre>
答案 0 :(得分:0)
嗯,这不是一个完整的解决方案,但它是一个开始。我们的想法是遍历每个段落元素,如果是unselectable
,则将其从选择中删除。我将选择转换为字符数组并在开始时填充它,以便索引匹配整个文档中的索引。
我没有注意最终的to
和from
值,它们可能不对 - 但更重要的是,如果您选择整个文本,您可以看到它已被关闭第二个不可选块上的几个字符。我没时间摆弄它,但也许别人可以在我离开的地方接我。
function findAncestorOffset(container, node, offset)
{
if (node == container)
return offset;
var parent = node.parentNode;
var syblings = parent.childNodes;
for (var i = 0, len = syblings.length; i < len; i++)
{
if (syblings[i] == node)
break;
offset += $(syblings[i]).text().length;
}
return findAncestorOffset(container, parent, offset);
}
var onSelect = function(){
var sel = window.getSelection();
var textArray = sel.toString().split('');
var range = sel.getRangeAt(0).cloneRange();
var from = findAncestorOffset($('.article')[0], range.startContainer, range.startOffset);
var to = from + textArray.length;
textArray = (new Array(from)).concat(textArray);
var i = 0;
$('.article p').each((_, rawElement) => {
var element = $(rawElement);
var sectionStart = i;
var lengthOfSection = element.text().length;
if(element.hasClass('unselectable')) {
textArray.splice(sectionStart, lengthOfSection);
} else {
i += lengthOfSection;
}
});
var text = textArray.join('');
$('#from').text(from);
$('#to').text(to);
$('#out').text(text);
}
$('.article').mouseup(onSelect);
$('.article').focusout(onSelect);
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
pre, .article {
border: solid 1px black;
padding: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Select This</h1>
<div class="article">
<p>
This can be selected.
</p>
<p class="unselectable">
This can't.
</p>
<p>
And this can again.
</p>
<p>
This can be selected.
</p>
<p class="unselectable">
This can't.
</p>
<p>
And this can again.
</p>
</div>
<h1>Output</h1>
<div>
From: <span id="from"></span>, To: <span id="to"></span>
</div>
<pre id="out">
</pre>