Javascript 如果突出显示一个单词,并且用户单击了连接单词,则同时突出显示这两个单词

Javascript 如果突出显示一个单词,并且用户单击了连接单词,则同时突出显示这两个单词,javascript,jquery,Javascript,Jquery,我最近发布了一篇文章,要求通过以下方式突出“更聪明”一词: 单击可高亮显示整个单词(默认行为为双击) 单击拖动将仅高亮显示完整单词/术语 阿尔曼提出了一个很好的解决方案 用于测试 我提出这个问题的目的是允许用户单击两个或多个连接词并突出显示它们(扩大突出显示的范围) 证明。如果world,被光标选中: 你好world,lorem ipsum攻击泰坦 如果用户单击lorem,则应选择以下两个词: 你好world,loremipsum攻击泰坦 如果用户单击“你好”,则会出现相同的行为 因此它仅在

我最近发布了一篇文章,要求通过以下方式突出“更聪明”一词:

  • 单击可高亮显示整个单词(默认行为为双击)

  • 单击拖动将仅高亮显示完整单词/术语

阿尔曼提出了一个很好的解决方案

用于测试

我提出这个问题的目的是允许用户单击两个或多个连接词并突出显示它们(扩大突出显示的范围)

证明。如果
world,
被光标选中:

你好
world,
lorem ipsum攻击泰坦

如果用户单击
lorem
,则应选择以下两个词:

你好
world,lorem
ipsum攻击泰坦

如果用户单击“你好”,则会出现相同的行为

因此它仅在单词连接时扩展突出显示。例如,如果选择了
worlds,
,并且用户单击
ipsum
,它应该只选择
ipsum

有什么方法可以扩展高光覆盖范围

JSFIDLE中的代码是:

jQuery(document).ready(function(e){

    (function(els){
        for(var i=0;i<els.length;i++){
            var el = els[i];
            el.addEventListener('mouseup',function(evt){
                if (document.createRange) { // Works on all browsers, including IE 9+
                    var selected = window.getSelection();
                    /* if(selected.toString().length){ */
                    var d = document,
                        nA = selected.anchorNode,
                        oA = selected.anchorOffset,
                        nF = selected.focusNode,
                        oF = selected.focusOffset,
                        range = d.createRange();

                    range.setStart(nA,oA);
                    range.setEnd(nF,oF);

                    // Check if direction of selection is right to left
                    if(range.startContainer !== nA || (nA === nF && oF < oA)){
                        range.setStart(nF,oF);
                        range.setEnd(nA,oA);
                    }

                    // Extend range to the next space or end of node
                    while(range.endOffset < range.endContainer.textContent.length && !/\s$/.test(range.toString())){
                        range.setEnd(range.endContainer, range.endOffset + 1);
                    }
                    // Extend range to the previous space or start of node
                    while(range.startOffset > 0 && !/^\s/.test(range.toString())){
                        range.setStart(range.startContainer, range.startOffset - 1);
                    }

                    // Remove spaces
                    if(/\s$/.test(range.toString()) && range.endOffset > 0)
                        range.setEnd(range.endContainer, range.endOffset - 1);
                    if(/^\s/.test(range.toString()))
                        range.setStart(range.startContainer, range.startOffset + 1);

                    // Assign range to selection
                    selected.addRange(range);

                    el.style.MozUserSelect = '-moz-none';
                    /* } */
                } else {
                    // Fallback for Internet Explorer 8 and earlier
                    // (if you think it still is worth the effort of course)
                }
            });

            /* This part is necessary to eliminate a FF specific dragging behavior */
            el.addEventListener('mousedown',function(){
                if (window.getSelection) {  // Works on all browsers, including IE 9+
                    var selection = window.getSelection ();
                    selection.collapse (selection.anchorNode, selection.anchorOffset);
                } else {
                    // Fallback for Internet Explorer 8 and earlier
                    // (if you think it still is worth the effort of course)
                }
                el.style.MozUserSelect = 'text';
            });
        }
    })(document.getElementsByClassName('taggable'));

});
jQuery(文档).ready(函数(e){
(功能(els){
对于(var i=0;i 0&!/^\s/.test(range.toString())){
range.setStart(range.startContainer,range.startOffset-1);
}
//删除空格
如果(/\s$/.test(range.toString())和&range.endOffset>0)
range.setEnd(range.endContainer,range.endOffset-1);
if(/^\s/.test(range.toString()))
range.setStart(range.startContainer,range.startOffset+1);
//将范围指定给所选内容
选中。添加范围(范围);
el.style.MozUserSelect='-moz none';
/* } */
}否则{
//Internet Explorer 8及更早版本的回退
//(当然,如果你认为这仍然值得努力的话)
}
});
/*此部分是消除FF特定拖动行为所必需的*/
el.addEventListener('mousedown',function(){
if(window.getSelection){//适用于所有浏览器,包括IE9+
var selection=window.getSelection();
selection.collapse(selection.anchorNode,selection.anchorooffset);
}否则{
//Internet Explorer 8及更早版本的回退
//(当然,如果你认为这仍然值得努力的话)
}
el.style.MozUserSelect='text';
});
}
})(document.getElementsByClassName('taggable');
});
HTML:

<p class="taggable">
   Hello world, lorem ipsum attack on titan.
</p>

<p>
   JS doesn't affect this text. 
</p>

你好,世界,洛勒姆·伊普森攻击泰坦。

JS不影响此文本。

赏金信息 奖励现有答案,因为它非常有用。不需要发布更多的解决方案,因为这是一个完整的,因为它得到

升级 好的,我把它放在最上面,因为它是一个主要的更新,我相信,甚至可以被认为是对以前功能的升级

请求是使上一个功能反向工作,即当再次单击突出显示的单词时,它将从总选择中删除

挑战是,当点击段落内
标签边缘或
标签边缘的突出显示单词时,必须将范围的
startContainer
endContainer
带入或移出它们所定位的当前元素,并且还必须重置
startOffset
endOffset
。我不确定这是否清楚地表达了这个问题,但简而言之,由于
Range
对象的工作方式,与HTML标记最接近的单词被证明是一个相当大的挑战

解决方案是引入一些新的正则表达式测试,几个
if
检查,以及一个用于查找下一个/上一个兄弟的本地函数。在这个过程中,我还修复了一些以前没有注意到的东西。新功能如下所示

JS小提琴

更新(在升级之前完成):

如果要使此功能在单击而不是拖动时生效,则只需更改
If(prevRangeInfo.startContainer)
条件,如下所示:

if(prevRangeInfo.startContainer && nA === nF && oA === oF){
    // rest of the code is the same...

更新后的JS小提琴是。

如果它符合条件,我肯定会奖励50分。是的。如果将集合而不是单个元素传递给此函数,则需要将代码放在函数内部(而不是函数本身)的循环中。错误不是由函数本身引起的,而是由
jQuery('document').ready()引起的用作包装器的函数。实际上,如何使用
jQuery('document').ready()并没有什么问题,但JS Fiddle需要通过JAVASCRIPT标题旁边的cog图标将jQuery库添加到Fiddle中。是添加jQuery库时代码保持原样的版本,是
var prevRangeInfo={}的版本声明被从循环中取出,因为它是不必要的。
prevarangeinfo
声明被从循环中取出,因为总是只有一个存储的前一个范围,并且在循环执行之前声明一个空白对象。你能把它包括在循环中吗?是的,但这是JavaScript引擎上的额外工作负载,没有任何原因,因此原则上,您最好避免这样做。我很高兴能帮上忙。保重。我希望这就是你要找的。:)恐怕这远远不是一个容易解决的问题,亨里克。这个
(function(el){
    var prevRangeInfo = {};
    el.addEventListener('mouseup',function(evt){
        if (document.createRange) { // Works on all browsers, including IE 9+

            var selected = window.getSelection();
            /* if(selected.toString().length){ */
                var d = document,
                    nA = selected.anchorNode,
                    oA = selected.anchorOffset,
                    nF = selected.focusNode,
                    oF = selected.focusOffset,
                    range = d.createRange();

                range.setStart(nA,oA);
                range.setEnd(nF,oF);

                // Check if direction of selection is right to left
                if(range.startContainer !== nA || (nA === nF && oF < oA)){
                    range.setStart(nF,oF);
                    range.setEnd(nA,oA);
                }

                // Extend range to the next space or end of node
                while(range.endOffset < range.endContainer.textContent.length && !/\s$/.test(range.toString())){
                    range.setEnd(range.endContainer, range.endOffset + 1);
                }
                // Extend range to the previous space or start of node
                while(range.startOffset > 0 && !/^\s/.test(range.toString())){
                    range.setStart(range.startContainer, range.startOffset - 1);
                }

                // Remove spaces
                if(/\s$/.test(range.toString()) && range.endOffset > 0)
                    range.setEnd(range.endContainer, range.endOffset - 1);
                if(/^\s/.test(range.toString()))
                    range.setStart(range.startContainer, range.startOffset + 1);

        // Check if another range was previously selected
        if(prevRangeInfo.startContainer){
            var rangeTryLeft = d.createRange(),
            rangeTryRight = d.createRange(),
            nAp = prevRangeInfo.startContainer;
            oAp = prevRangeInfo.startOffset;
            nFp = prevRangeInfo.endContainer;
            oFp = prevRangeInfo.endOffset;
          rangeTryLeft.setStart(nFp,oFp-1);
          rangeTryLeft.setEnd(range.endContainer,range.endOffset);
          rangeTryRight.setStart(range.startContainer,range.startOffset);
          rangeTryRight.setEnd(nAp,oAp+1);

          // Add previously selected range if adjacent
          if(/^[^\s]*\s{1}[^\s]*$/.test(rangeTryLeft.toString())) range.setStart(nAp,oAp);
          else if(/^[^\s]*\s{1}[^\s]*$/.test(rangeTryRight.toString())) range.setEnd(nFp,oFp);
        }

        // Save the current range
        prevRangeInfo = {
            startContainer: range.startContainer,
          startOffset: range.startOffset,
          endContainer: range.endContainer,
          endOffset: range.endOffset
        };

                // Assign range to selection
                selected.addRange(range);

        el.style.MozUserSelect = '-moz-none';
            /* } */
        } else { 
           // Fallback for Internet Explorer 8 and earlier
           // (if you think it still is worth the effort of course)
        }
    });

  /* This part is necessary to eliminate a FF specific dragging behavior */
  el.addEventListener('mousedown',function(e){
    if (window.getSelection) {  // Works on all browsers, including IE 9+
         var selection = window.getSelection ();
       selection.collapse (selection.anchorNode, selection.anchorOffset);
    } else {
       // Fallback for Internet Explorer 8 and earlier
           // (if you think it still is worth the effort of course)
    }
    el.style.MozUserSelect = 'text';
  });
})(document.getElementById('selectable'));
if(prevRangeInfo.startContainer && nA === nF && oA === oF){
    // rest of the code is the same...