在Javascript中使用document.selection时,同时创建多个选择

时间:2014-07-31 09:30:41

标签: javascript jquery html dom web

我已经知道如何使用document.selection进行突出显示。对于example

/* http://jsfiddle.net/4J2dy/ */
$("#content").on('mouseup', function() {
    highlighting();
});
var highlighting = function () {
    var seleted_str = (document.all) ? document.selection.createRange().text : document.getSelection();
    if(seleted_str != "") {
        var stringToBeHighlighted = seleted_str.getRangeAt(0);
        var span = document.createElement("span");
        span.style.cssText = "background-color: #80deea";
        span.className = "MT";
        stringToBeHighlighted.surroundContents(span);
    }
};

但有些事情我不知道如何实现。 让我们说我有四个同时使用相同内容创建的图层。 我想在控制层上选择一个句子,同时也会选择其他三个层中的所有相同句子。(见下图) Step1

选择之后,我想弹出一个菜单(我可以做),并根据按下的按钮获取DOM元素。(见下图) Step2

有人能告诉我如何实现这个目标吗?或者它无法完成?如果有人能为我回答,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

这种可能性,我很感激SO用户Tim Down的输入,因为他对JS Range / Selections有很多了解,但我已经提出了我的部分解决方案。

您可以只存储startOffset&而不是选择4个图层。在endOffset上更新的外部对象中的mouseup。唯一的副作用是,用户的选择只会在点击图层按钮时获得span的颜色。

优点是你现在可以简单地使用DOM文本节点而不是范围/选择(无论如何,对我来说更复杂)。 我已经选择在按钮上找到data-layer属性的图层,并在图层上找到相应的id图层。我处理了'追加'选择的跨度'通过切片图层中文本节点的文本内容,如下所示:

layer.innerHTML = txt.slice(0, selText.start) 
     + '<span class="MT" style="background-color: #80deea">'
     + txt.slice(selText.start, selText.end) + '</span>'
     + txt.slice(selText.end, txt.length);

查看 in action here 。我添加了cleanSelection功能,因此一次只能进行一次选择(开始和结束计数器失败,因为选择范围不考虑HTML标记,所以你必须摆脱的跨度)。

最后的说明:

  • 小提琴不适用于不支持getElementsByClassName
  • 的浏览器
  • 小提琴一次只支持一个选择。
  • 小提琴并没有广泛测试所有条件(例如,第一个孩子的节点类型是否真的是一个文本节点,等等。但是自己很难添加它)

整个JS代码作为参考(也在fiddle中):

// this object will hold the start & end offsets of selection value
var selText = false; 

// selText will be updated on mouseup
document.body.onmouseup = getSelText; 

// on button click, selText will be highlighted
document.body.onclick = function(e) { 
  var target = e.target || e.srcElement, range, layer, txt;

  // only do if it's a layer button & the selection is non-empty
  if (target.getAttribute('data-layer') && selText !== false) {

     // first remove previous spans, they break the startOffset & endOffset of the selection range
     cleanSelection();

     // get the clicked layer
     layer = document.getElementById(target.getAttribute('data-layer'));
     // this assumes that the first node in the layer is a textNode
     txt = layer.firstChild.nodeValue;
     // let's append the selection container now
     layer.innerHTML = txt.slice(0, selText.start) 
     + '<span class="MT" style="background-color: #80deea">'
     + txt.slice(selText.start, selText.end) + '</span>'
     + txt.slice(selText.end, txt.length);

    // ...and empty the 'real selection'
    window.getSelection().collapse(); 
    // log results to console
    console.log('From char ' + selText.start + ' to char ' + selText.end + ', in ' + layer.id);
  }

};
function getSelText () {
    var seleted_str = (document.all) ? document.selection.createRange().text : document.getSelection(), stringToBeHighlighted;
    if(seleted_str !== "") {
        stringToBeHighlighted = seleted_str.getRangeAt(0);
        selText = {
          start: stringToBeHighlighted.startOffset,
          end: stringToBeHighlighted.endOffset
        };
    } else {
        selText = false;
    }
}
function cleanSelection() {
  var getText, mtSpan = document.getElementsByClassName('MT');
  for ( var i = 0; i < mtSpan.length; i++) {
    getText = mtSpan[i].innerHTML;
    mtSpan[i].previousSibling.nodeValue = mtSpan[i].previousSibling.nodeValue + getText + mtSpan[i].nextSibling.nodeValue;
    mtSpan[i].parentNode.removeChild(mtSpan[i].nextSibling);
    mtSpan[i].parentNode.removeChild(mtSpan[i]);
  }
}