当文本被<mark>包装时,window.getSelection()。getRange(0)不起作用

时间:2018-06-13 17:49:42

标签: javascript html getselection

我正在尝试使用window.getSelection().getRangeAt(0)来获取句子中所选单词的索引。它在没有任何<mark><abbr>的文本中正常工作。但是当一个句子中有这样的标签时,似乎这个功能会将句子分成几个部分。

例如,HTML中的一个句子看起来像My car <abbr title="car_state"><mark>broke down</mark></abbr>. What do I do?

当我在broke down之前选择文本时,它可以正常工作。但是,当我选择之后的文字时,例如,e What,它会在startOffset而不是2处提供22

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

受到Kaiido的回答的启发,以下方法将起作用。 虽然突出显示的文字不匹配,但我仍然不需要突出显示的文字

请随时添加有关该解决方案的评论。

正在运行的例子

&#13;
&#13;
$('#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)));
});
&#13;
<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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

Quoting MDN

  

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

同样适用于Range.endOffset,它返回 endContainer 中的位置。

当您在页面中选择 What 时,startContainer是在</abbr>之后启动的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>

如果您知道公共容器并且想要知道您相对于此祖先的文本内容的位置,那么您必须遍历其childNodes,直到找到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>