【问题标题】:window.getSelection().getRange(0) does not work when text is wrapped by <mark>当文本被 <mark> 包裹时,window.getSelection().getRange(0) 不起作用
【发布时间】:2018-06-13 17:49:42
【问题描述】:

我正在尝试使用window.getSelection().getRangeAt(0) 来获取句子中所选单词的索引。它在没有任何&lt;mark&gt;&lt;abbr&gt; 的文本中运行良好。但是当句子中有这样的标签时,这个功能似乎会将句子分成几段。

例如,HTML中的一句话看起来像My car &lt;abbr title="car_state"&gt;&lt;mark&gt;broke down&lt;/mark&gt;&lt;/abbr&gt;. What do I do?

当我选择broke down 之前的文本时,它工作正常。但是当我选择后面的文本时,例如,e What,它将在2 处给出startOffset 而不是22

是否可以获取整个句子的索引?

受 Kaiido 回答的启发,以下方法将起作用。 虽然突出显示的文本不匹配,但无论如何我都不需要突出显示的文本

请随时添加有关解决方案的 cmets。

运行示例

$('#selected_text').click(function(){
var text = "My car is broke down. What do I do?";
var range = window.getSelection().getRangeAt(0);
var start = range.startOffset;
var end = range.endOffset;
var extra = 0;
var selected_string = range.toString();

var t = $('span').contents();
for(var i = 0; i < t.length; i++){
  console.log(extra);
  if(t[i].wholeText === undefined){
    extra += t[i].textContent.length;
  }else if(t[i].wholeText.includes(selected_string)){
    break;
  }else{
    extra += t[i].length;
  }
}

start += extra;
end += extra;
console.log("start index: " + start);
console.log("end index: " + end);
console.log(text.slice(start, end));
console.log(selected_string);
console.log("match: ", (selected_string === text.slice(start, end)));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<span>My car is <abbr title="car_state"><mark>broke down</mark></abbr>. What do <mark>I</mark> d<mark>o</mark>?</span>
<button id='selected_text'>show selected text</button>
</body>
</html>

【问题讨论】:

标签: javascript html getselection


【解决方案1】:

Quoting MDN

Range.startOffset 只读属性返回一个数字,表示 Range 在 startContainer 中的起始位置。

Range.endOffset 也是如此,它返回 endContainer 中的位置。

当您在页面中选择单词 What 时,startContainer 是在您的 &lt;/abbr&gt; 之后开始的 TextNode。所以你得到的指数是相对于这个TextNode的。

如果你想获取选中的文本,那么只需调用 Selection.toString() 方法即可。

$('#selected_text').click(function() {

  var sel = window.getSelection();
  var range = sel.getRangeAt(0);
  var start = range.startOffset;
  var end = range.endOffset;
  console.log("start index: " + start);
  console.log("end index: " + end);
  console.log('startContainer', range.startContainer.nodeName, range.startContainer.textContent);
  console.log('endContainer', range.endContainer.nodeName, range.endContainer.textContent);
  console.log('toString:', sel.toString());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<span>My car is <abbr title="car_state"><mark>broke down</mark></abbr>. What do I do?</span>
<button id='selected_text'>show selected text</button>

如果你知道公共容器并且想知道你相对于这个祖先的文本内容的位置,那么你必须遍历它的子节点,直到找到 startContainer 和 endContainer。

var container = $('#container')[0];
$('#selected_text').click(function() {

  var sel = window.getSelection();
  var range = sel.getRangeAt(0);
  var sel_start = range.startOffset;
  var sel_end = range.endOffset;
  
  var charsBeforeStart = getCharactersCountUntilNode(range.startContainer, container);
  var charsBeforeEnd = getCharactersCountUntilNode(range.endContainer, container);
  if(charsBeforeStart < 0 || charsBeforeEnd < 0) {
    console.warn('out of range');
    return;
  }
  var start_index = charsBeforeStart + sel_start;
  var end_index = charsBeforeEnd + sel_end;
  console.log('start index', start_index);
  console.log('end index', end_index);
  console.log(container.textContent.slice(start_index, end_index));
});

function getCharactersCountUntilNode(node, parent) {
  var walker = document.createTreeWalker(
    parent || document.body,
    NodeFilter.SHOW_TEXT,
    null,
    false
  );
  var found = false;
  var chars = 0;
  while (walker.nextNode()) {
    if(walker.currentNode === node) {
      found = true;
      break;
    }
    chars += walker.currentNode.textContent.length;
  }
  if(found) {
    return chars;
  }
  else return -1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<span id="container">My car is <abbr title="car_state"><mark>broke down</mark></abbr>. What do I do?</span>
<button id='selected_text'>show selected text</button>

【讨论】:

  • 感谢您的回答。那么就没有可能的方法来获取整个句子的索引吗?
  • @Annndy 对不起,我错过了你真的想要这个。现在也为此添加了正确的解决方案。
  • 感谢您这样做。在上述方面,你的方式优于我的方式。从你身上学到了很多!
猜你喜欢
  • 2019-09-19
  • 1970-01-01
  • 2021-01-12
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2017-09-26
  • 2012-12-26
  • 1970-01-01
相关资源
最近更新 更多