如何更快速,更智能地突出显示单词/术语?

时间:2016-01-23 12:43:26

标签: javascript jquery

我有一些文字:

<p class="drag">Hello world, Attack on Titan season two!</p>

目前,如果用户想要用光标突出显示单词/术语,他们将逐字逐句地单击并拖动。

我希望这个过程更快。例如,如果用户开始突出显示At,则应自动突出显示单词的其余部分Attack。所以空白区域是分隔线。

我知道这可以通过将单词划分为div来实现,但我希望在一个<p>标记内提供纯文本解决方案。

6 个答案:

答案 0 :(得分:16)

使用public ImageView iv; public TypeWriter tw; 我们可以找到空格并将我们的选择跳到整个单词而无需创建新元素。

主要是为了我未来的潜在用途我写了这个相当模块化的,它也不需要在观察元素上使用鼠标,可以处理元素集合,如果用户使用他们的选择进行选择也会进行选择更改键盘。

node.textContent

An example jsFiddle

我还没有测试它在手机上是如何工作的,还没有让它正常工作 - 但它可能是一个好的开始。

更新:现在只需点击一下即可选择字词

答案 1 :(得分:10)

您可以使用RangeselectionRange对象使用纯JS来完成此操作。

<强> HTML:

<div id="selectable">
  <p>Hello world, <b>Attack on Titan</b> season two!</p>
  <p>Another paragraph with sample text.</p>
</div>
<div id="notSelectable">
  <p>The selection will behave normally on this div.</p>
</div>

<强> JS:

(function(el){
    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);
            /* } */
        } else { 
           // Fallback for Internet Explorer 8 and earlier
           // (if you think it still is worth the effort of course)
        }

        // Stop Moz user select
        el.style.MozUserSelect = '-moz-none';
    });

    /* This part is added 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)
        }

        // Add Moz user select back
        el.style.MozUserSelect = 'text';
    });
})(document.getElementById('selectable'));

请查看工作示例here

<强>更新

  • 点击添加的全字选择
  • 修复Firefox特定拖动 已添加行为

更新了JSFiddle here

答案 2 :(得分:9)

概念

要选择每个单词,首先必须牢记一些事项:

  1. textNode是一个包含所有单词的单个刺,你 将无法选择每个“单词”,因为它不是DOM节点。

  2. 当你“拖动”时,浏览器中没有触发特定事件     选择“一个单词。但是,当你拖动和选择时,有2个事件     被解雇:移动鼠标时会触发mouseover,     释放鼠标按钮时会触发click。 (这是     即使在Mac的触控板上也是如此。

  3. 选择a时,“突出显示”有不同的实现     字。

  4. 步骤

    根据这些概念,您必须按顺序执行以下步骤才能实现目标:

    1. 获取段落中的字词,并使用标记(例如<span>)将其打包以进行DOM选择
    2. 触发click事件(表示您的选择已结束)时,请突出显示您刚刚选择的字词。
    3. 实现将是这样的(使用jQuery)。 你可以在这里看到现场演示:

      $(function() {
      
        // 1. When mouseover the paragraph, wrapped each word with <span>
        $('p').one('mouseover', function(event) {
          $('p').html(function(index, text) {
            var wordsArray = text.split(' ');
      
            var wrappedArray = wordsArray.map(function(val, index) {
              val = '<span class="chunk-' + index + '">' + val + '</span>';
              return val;
            });
      
            var wrappedString = wrappedArray.join(' ');
      
            // 2. Replace the paragraph with wrapped text
            $(this).html(wrappedString);
      
            // 3. When the word is select, highlight the word
            $(this).children('span').on('click', function() {
              var selector = '.' + $(this).attr('class');
              SelectText(selector);
            });
          });
        });
      });
      
      
      function SelectText(element) {
        var doc = document,
          text = doc.querySelector(element),
          range, selection;
        if (doc.body.createTextRange) {
          range = document.body.createTextRange();
          range.moveToElementText(text);
          range.select();
        } else if (window.getSelection) {
          selection = window.getSelection();
          range = document.createRange();
          range.selectNodeContents(text);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem amet suscipit incidunt placeat dicta iure, perspiciatis libero nobis dolore, temporibus et! Quae fugiat necessitatibus ut, molestias aut. Sequi rerum earum facilis voluptates ratione architecto
        officia quod aut unde voluptas? Dignissimos ducimus exercitationem perspiciatis nam numquam minima accusamus quod necessitatibus amet illo vel vero placeat voluptate eos iste ratione veniam quisquam atque non voluptatum sint hic sed, suscipit. Doloremque
        officiis rerum sunt delectus unde odit eos quod earum aspernatur, tempora neque modi tempore minima maiores fuga eaque dolore quos minus veritatis aliquid, vel suscipit dolores. Voluptatem eius obcaecati, laborum ipsa a!</p>

      SelectText函数应在SO上的帖子中归属于@JasonSelecting text in an element: akin to highlighting with your mouse

答案 3 :(得分:7)

此文本是文本节点,文本节点根本不会触发大多数事件。但是他们可以触发DOM mutation events,例如DOMCharacterDataModified,用于检测文本节点文本的更改:

var textNode = document.getElementsByClassName("drag")[0].firstChild;

textNode.addEventListener("DOMCharacterDataModified", function(e) {
    console.log("Text changed from '" + e.prevValue + "' to '" + evt.newValue +"'");
}, false);

但是,<p class="drag">Hello world, Attack on Titan season two!</p>中的文本是单个文本节点,您需要将每个单词作为单独的节点。

我看到的唯一解决方案是将每个字放在span标记中。你不能用纯文本做到这一点。

修改

以下是如何使用span标记执行此操作的示例(我在这里使用jQuery只是为了减少代码量,这不是必需的):

$(function() {
    $('.drag').on('click', 'span', function() {
        var range;
        if (document.selection) {
            range = document.body.createTextRange();
            range.moveToElementText($(this)[0]);
            range.select();
        } 
        else if (window.getSelection) {
            range = document.createRange();
            range.selectNode($(this)[0]);
            window.getSelection().addRange(range);
        }
    });  
});

这是example on JS Bin

更新

我编辑了code snippet,所以选择的行为就像你问的那样(目前它只适用于从左到右的选择,而不是反向选择):

$(function(){

  var range = document.createRange();
  var selectionMode = false;

  $(document).on('mouseup', function() {
    selectionMode = false;
  })
  .on('mousedown', '.drag', function(e) {
    selectionMode = true;
  })
  .on('dragstart', '.drag span', function(e) {
    return false;
  });

  $('.drag').on('mousedown', 'span', function() {
    range.setStartBefore($(this)[0]);
    range.setEndAfter($(this)[0]);
    window.getSelection().addRange(range);
  })
  .on('mousemove', 'span', function() {
    if (!selectionMode) {
      return;
    }
    range.setEndAfter($(this)[0]);
    window.getSelection().addRange(range);
  })
  .on('mouseup', 'span', function() {
    setTimeout(function(){
      window.getSelection().addRange(range);
    }, 1);
  });  

});

您可以在此处详细了解HTML Range API:https://developer.mozilla.org/en-US/docs/Web/API/Range

答案 4 :(得分:3)

所以你将不得不处理文本范围等。我已经解决了这个问题,这非常痛苦,特别是如果你有像DOM这样的内容:

<p>New season of <span class="redtext">Attack on Titan!</span></p>

即。文本节点与其他DOM元素混合,例如在这种情况下的跨度。考虑到这一点,我想强烈推荐图书馆rangy.js:https://github.com/timdown/rangy

当我制作一个标签突出显示系统时,这让我好几天头疼。

答案 5 :(得分:-4)

您无法将事件设置为文本,但可以将事件设置为Html元素。将每个单词放在div元素中,并添加一个onmouseover事件,使用css将div更改为新的突出显示状态。

步骤:

  1. 使用split将单词转换为数组。
  2. 迭代单词并将其放入div中。
  3. 迭代div并设置一个事件,将div更改为css类.highlight。
  4. 那就是它。