문제

예를 들어 내가 가지고 있다면

<p> some long text </p>

내 HTML 페이지에서 마우스의 커서가 예를 들어 '텍스트'라는 단어 위에 있다는 것을 어떻게 알 수 있습니까?

도움이 되었습니까?

해결책

다른 두 가지 답변에 따라, 당신은 jQuery (또는 JavaScript)를 사용하여 단락을 스팬으로 나눌 수 있습니다.

그렇게하면 단어 주위에 텍스트를 출력하는 것에 대해 생각할 필요가 없습니다. 당신의 JavaScript가 당신을 위해 그것을하도록하십시오.

예를 들어

<p>Each word will be wrapped in a span.</p>
<p>A second paragraph here.</p>
Word: <span id="word"></span>

<script type="text/javascript">
    $(function() {
        // wrap words in spans
        $('p').each(function() {
            var $this = $(this);
            $this.html($this.text().replace(/\b(\w+)\b/g, "<span>$1</span>"));
        });

        // bind to each span
        $('p span').hover(
            function() { $('#word').text($(this).css('background-color','#ffff66').text()); },
            function() { $('#word').text(''); $(this).css('background-color',''); }
        );
    });
</script>

위의 코드는 작동하는 동안 단락 태그 내부의 HTML을 제거합니다.

JSFIDDLE 예제

다른 팁

내 다른 대답은 Firefox에서만 작동합니다. 이 답변은 Chrome에서 작동합니다. (Firefox에서도 작동 할 수도 있습니다. 모르겠습니다.)

function getWordAtPoint(elem, x, y) {
  if(elem.nodeType == elem.TEXT_NODE) {
    var range = elem.ownerDocument.createRange();
    range.selectNodeContents(elem);
    var currentPos = 0;
    var endPos = range.endOffset;
    while(currentPos+1 < endPos) {
      range.setStart(elem, currentPos);
      range.setEnd(elem, currentPos+1);
      if(range.getBoundingClientRect().left <= x && range.getBoundingClientRect().right  >= x &&
         range.getBoundingClientRect().top  <= y && range.getBoundingClientRect().bottom >= y) {
        range.expand("word");
        var ret = range.toString();
        range.detach();
        return(ret);
      }
      currentPos += 1;
    }
  } else {
    for(var i = 0; i < elem.childNodes.length; i++) {
      var range = elem.childNodes[i].ownerDocument.createRange();
      range.selectNodeContents(elem.childNodes[i]);
      if(range.getBoundingClientRect().left <= x && range.getBoundingClientRect().right  >= x &&
         range.getBoundingClientRect().top  <= y && range.getBoundingClientRect().bottom >= y) {
        range.detach();
        return(getWordAtPoint(elem.childNodes[i], x, y));
      } else {
        range.detach();
      }
    }
  }
  return(null);
}    

MouseMove 핸들러에서 전화하십시오 getWordAtPoint(e.target, e.x, e.y);

전문:

여러 개의 스팬과 중첩 된 HTML이있는 경우 별도의 단어 (또는 단어로 문자)를 분리하는 경우 위의 모든 솔루션은 전체적이고 올바른 단어를 반환하는 데 어려움을 겪게됩니다.

다음은 현상금 질문의 예입니다. Х</span>rт0съ. 올바르게 반환하는 방법 Хrт0съ? 이러한 문제는 2010 년에 해결되지 않았으므로 지금은 두 가지 솔루션을 발표 할 것입니다 (2015).


솔루션 1- 내부 태그 스트립, 각 전체 단어 주위에 스파를 랩합니다.

한 가지 해결책은 단락 내부의 스팬 태그를 제거하지만 텍스트를 보존하는 것입니다. 따라서 분할 단어와 문구는 일반 텍스트로 함께 연결됩니다. 각 단어는 공간이 아닌 공백 부문에서 발견되며, 그 단어는 개별적으로 액세스 할 수있는 범위로 싸여 있습니다.

데모에서는 전체 단어를 강조하여 전체 단어의 텍스트를 얻을 수 있습니다.


pic 0

암호:

$(function() {
  // Get the HTML in #hoverText - just a wrapper for convenience
  var $hoverText = $("#hoverText");

  // Replace all spans inside paragraphs with their text
  $("p span", $hoverText).each(function() {
    var $this = $(this);
    var text = $this.text(); // get span content
    $this.replaceWith(text); // replace all span with just content
  });

  // Wrap words in spans AND preserve the whitespace
  $("p", $hoverText).each(function() {
    var $this = $(this);
    var newText = $this.text().replace(/([\s])([^\s]+)/g, "$1<span>$2</span>");
    newText = newText.replace(/^([^\s]+)/g, "<span>$1</span>");
    $this.empty().append(newText);
  });

  // Demo - bind hover to each span
  $('#hoverText span').hover(
    function() { $(this).css('background-color', '#ffff66'); },
    function() { $(this).css('background-color', ''); }
  );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="hoverText">
  <p><span class="kinovar"><span id="selection_index3337" class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">со 
стіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.</span>
  </p>
</div>

솔루션 1 전체 텍스트 데모


솔루션 2 -Caret 검사 및 DOM 트래버스 :

다음은보다 정교한 솔루션입니다. 텍스트 노드의 커서 아래에서 전체적이고 올바른 단어를 정확하게 캡처하는 노드 트래버스를 사용하는 알고리즘 솔루션입니다.

캐럿 위치를 확인하여 임시 단어가 발견됩니다 (사용 caretPositionFromPoint 또는 caretRangeFromPoint, @chrisv에 대한 아이디어에 대한 크레딧). 이것은 아직 전체 단어 일 수도 있고 아닐 수도 있습니다.

그런 다음 텍스트 노드의 가장자리에 있는지 확인하기 위해 분석됩니다 (시작 또는 끝). 그렇다면 이전 텍스트 노드 또는 다음 텍스트 노드를 검사 하여이 단어 조각을 더 길게 만들기 위해 결합되어야하는지 확인합니다.

예시:

Х</span>rт0съ 반환해야합니다 Хrт0съ, 아니다 Х ...도 아니다 rт0съ.

DOM 트리는 다음이 아닌 텍스트 노드를 얻기 위해 통과합니다. 두 단어 조각이 a로 분리 된 경우 <p> 또는 다른 장벽 태그, 그들은 인접하지 않으므로 같은 단어의 일부가 아닙니다.

예시:

њб.)</p><p>Во 반환해서는 안됩니다 њб.)Во


데모에서 왼쪽 떠 다니는 div는 커서 아래의 단어입니다. 오른쪽 부동 부동은 보이시면 경계의 단어가 어떻게 형성되었는지를 보여줍니다. 다른 태그는이 솔루션의 텍스트와 함께 안전하게 내려갈 수 있습니다.

pic 1

암호:

$(function() {
  // Get the HTML in #hoverText - just a wrapper for convenience
  var $hoverText = $("#hoverText");

  // Get the full word the cursor is over regardless of span breaks
  function getFullWord(event) {
     var i, begin, end, range, textNode, offset;
    
    // Internet Explorer
    if (document.body.createTextRange) {
       try {
         range = document.body.createTextRange();
         range.moveToPoint(event.clientX, event.clientY);
         range.select();
         range = getTextRangeBoundaryPosition(range, true);
      
         textNode = range.node;
         offset = range.offset;
       } catch(e) {
         return ""; // Sigh, IE
       }
    }
    
    // Firefox, Safari
    // REF: https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint
    else if (document.caretPositionFromPoint) {
      range = document.caretPositionFromPoint(event.clientX, event.clientY);
      textNode = range.offsetNode;
      offset = range.offset;

      // Chrome
      // REF: https://developer.mozilla.org/en-US/docs/Web/API/document/caretRangeFromPoint
    } else if (document.caretRangeFromPoint) {
      range = document.caretRangeFromPoint(event.clientX, event.clientY);
      textNode = range.startContainer;
      offset = range.startOffset;
    }

    // Only act on text nodes
    if (!textNode || textNode.nodeType !== Node.TEXT_NODE) {
      return "";
    }

    var data = textNode.textContent;

    // Sometimes the offset can be at the 'length' of the data.
    // It might be a bug with this 'experimental' feature
    // Compensate for this below
    if (offset >= data.length) {
      offset = data.length - 1;
    }

    // Ignore the cursor on spaces - these aren't words
    if (isW(data[offset])) {
      return "";
    }

    // Scan behind the current character until whitespace is found, or beginning
    i = begin = end = offset;
    while (i > 0 && !isW(data[i - 1])) {
      i--;
    }
    begin = i;

    // Scan ahead of the current character until whitespace is found, or end
    i = offset;
    while (i < data.length - 1 && !isW(data[i + 1])) {
      i++;
    }
    end = i;

    // This is our temporary word
    var word = data.substring(begin, end + 1);

    // Demo only
    showBridge(null, null, null);

    // If at a node boundary, cross over and see what 
    // the next word is and check if this should be added to our temp word
    if (end === data.length - 1 || begin === 0) {

      var nextNode = getNextNode(textNode);
      var prevNode = getPrevNode(textNode);

      // Get the next node text
      if (end == data.length - 1 && nextNode) {
        var nextText = nextNode.textContent;

        // Demo only
        showBridge(word, nextText, null);

        // Add the letters from the next text block until a whitespace, or end
        i = 0;
        while (i < nextText.length && !isW(nextText[i])) {
          word += nextText[i++];
        }

      } else if (begin === 0 && prevNode) {
        // Get the previous node text
        var prevText = prevNode.textContent;

        // Demo only
        showBridge(word, null, prevText);

        // Add the letters from the next text block until a whitespace, or end
        i = prevText.length - 1;
        while (i >= 0 && !isW(prevText[i])) {
          word = prevText[i--] + word;
        }
      }
    }
    return word;
  }

  // Return the word the cursor is over
  $hoverText.mousemove(function(e) {
    var word = getFullWord(e);
    if (word !== "") {
      $("#result").text(word);
    }
  });
});

// Helper functions

// Whitespace checker
function isW(s) {
  return /[ \f\n\r\t\v\u00A0\u2028\u2029]/.test(s);
}

// Barrier nodes are BR, DIV, P, PRE, TD, TR, ... 
function isBarrierNode(node) {
  return node ? /^(BR|DIV|P|PRE|TD|TR|TABLE)$/i.test(node.nodeName) : true;
}

// Try to find the next adjacent node
function getNextNode(node) {
  var n = null;
  // Does this node have a sibling?
  if (node.nextSibling) {
    n = node.nextSibling;

    // Doe this node's container have a sibling?
  } else if (node.parentNode && node.parentNode.nextSibling) {
    n = node.parentNode.nextSibling;
  }
  return isBarrierNode(n) ? null : n;
}

// Try to find the prev adjacent node
function getPrevNode(node) {
  var n = null;

  // Does this node have a sibling?
  if (node.previousSibling) {
    n = node.previousSibling;

    // Doe this node's container have a sibling?
  } else if (node.parentNode && node.parentNode.previousSibling) {
    n = node.parentNode.previousSibling;
  }
  return isBarrierNode(n) ? null : n;
}

// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
function getChildIndex(node) {
  var i = 0;
  while( (node = node.previousSibling) ) {
    i++;
  }
  return i;
}

// All this code just to make this work with IE, OTL
// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
function getTextRangeBoundaryPosition(textRange, isStart) {
  var workingRange = textRange.duplicate();
  workingRange.collapse(isStart);
  var containerElement = workingRange.parentElement();
  var workingNode = document.createElement("span");
  var comparison, workingComparisonType = isStart ?
    "StartToStart" : "StartToEnd";

  var boundaryPosition, boundaryNode;

  // Move the working range through the container's children, starting at
  // the end and working backwards, until the working range reaches or goes
  // past the boundary we're interested in
  do {
    containerElement.insertBefore(workingNode, workingNode.previousSibling);
    workingRange.moveToElementText(workingNode);
  } while ( (comparison = workingRange.compareEndPoints(
    workingComparisonType, textRange)) > 0 && workingNode.previousSibling);

  // We've now reached or gone past the boundary of the text range we're
  // interested in so have identified the node we want
  boundaryNode = workingNode.nextSibling;
  if (comparison == -1 && boundaryNode) {
    // This must be a data node (text, comment, cdata) since we've overshot.
    // The working range is collapsed at the start of the node containing
    // the text range's boundary, so we move the end of the working range
    // to the boundary point and measure the length of its text to get
    // the boundary's offset within the node
    workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange);

    boundaryPosition = {
      node: boundaryNode,
      offset: workingRange.text.length
    };
  } else {
    // We've hit the boundary exactly, so this must be an element
    boundaryPosition = {
      node: containerElement,
      offset: getChildIndex(workingNode)
    };
  }

  // Clean up
  workingNode.parentNode.removeChild(workingNode);

  return boundaryPosition;
}

// DEMO-ONLY code - this shows how the word is recombined across boundaries
function showBridge(word, nextText, prevText) {
  if (nextText) {
    $("#bridge").html("<span class=\"word\">" + word + "</span>  |  " + nextText.substring(0, 20) + "...").show();
  } else if (prevText) {
    $("#bridge").html("..." + prevText.substring(prevText.length - 20, prevText.length) + "  |  <span class=\"word\">" + word + "</span>").show();
  } else {
    $("#bridge").hide();
  }
}
.kinovar { color:red; font-size:20px;}.slavic { color: blue;}#result {top:10px;left:10px;}#bridge { top:10px; right:80px;}.floater { position: fixed; background-color:white; border:2px solid black; padding:4px;}.word { color:blue;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id="bridge" class="floater"></div> <div id="result" class="floater"></div> <div id="hoverText"><p><span class="kinovar"><span id="selection_index3337" class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">со стіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.</span></p><div class="slavic"> <input value="Works around other tags!"><p><span id="selection_index3737" class="selection_index"></span>(л. рo7з њб.)</p><p><span class="kinovar"><span id="selection_index3738" class="selection_index"></span>Во вт0рникъ вeчера</span> </p><p><span class="kinovar"><span id="selection_index3739" class="selection_index"></span>tдaніе прaздника пaсхи.</span></p><p><span class="kinovar"><span id="selection_index3740" class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">со стіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.<input value="Works around inline tags too"></span></p><p><span class="kinovar"><span id="selection_index3741" class="selection_index"></span>На ГDи воззвaхъ: поeмъ стіхи6ры самоглaсны, слэпaгw, на ѕ7. Глaсъ в7:</span></p></div>

(메모: 텍스트 노드 테두리가있는 위치를 밝히기 위해 샘플 html에 존재하는 스팬 태그에 스타일을 적용 할 자유를 얻었습니다.)

솔루션 2 전체 텍스트 데모

(Chrome과 IE에서 지금까지 일하는 것. 즉, 즉 Ierange 크로스 브라우저 호환성을위한 심로 사용해야했습니다)

내 지식으로, 당신은 할 수 없습니다.

내가 생각할 수있는 유일한 것은 각 단어를 자신의 요소에 넣은 다음 해당 요소에 이벤트를 적용하는 것입니다.

<p><span>Some</span> <span>long</span> <span>text</span></p>

<script>
$(document).ready(function () {
  $('p span').bind('mouseenter', function () {
    alert($(this).html() + " is what you're currently hovering over!");
  });
});
</script>

전류에는 이것에 대한 API가 있습니다 CSSOM보기 초안: document.caretPositionFromPoint(x,y)

그래도 어떤 브라우저가 지원하는지 확인해야합니다. Firefox 7은 전혀 지원하지 않는 것처럼 보이지만 버그 보고서는 Firefox 9의 Will을 나타냅니다. Chrome 14 지원 caretRangeFromPoint(x,y) 본질적으로 동일하지만 구형 CSSOM 초안에서 나온 것입니다.

다음은 현상금 솔루션입니다.

제안한대로 Chrisv 당신이 사용할 수있는 document.caretRangeFromPoint (크롬) 또는 document.caretPositionFromPoint (Firefox). 이 솔루션은 텍스트 나 DOM을 변경하지 않기 때문에 귀하의 질문에 더 잘 대답한다고 생각합니다.

이 함수는 DOM을 변경하지 않고 마우스 커서 아래에서 단어를 반환합니다.

로부터 document.caretRangeFromPoint 선적 서류 비치:

문서 인터페이스의 CARETRANGEFROMPOINT () 메소드는 지정된 좌표 아래 문서 조각의 범위 객체를 리턴합니다.

로부터 document.caretPositionFromPoint 선적 서류 비치:

이 방법은 두 좌표를 기반으로 문서에서 간병 위치를 검색하는 데 사용됩니다. 발견 된 DOM 노드와 해당 노드의 문자 오프셋이 포함 된 간병이 반환됩니다.

두 함수는 약간 다르지만이 텍스트에서 텍스트와 커서의 오프셋이 포함 된 노드를 반환합니다. 따라서 마우스 아래에서 단어를 쉽게 얻을 수 있습니다.

전체 예를 참조하십시오.

$(function () {
    function getWordUnderCursor(event) {
        var range, textNode, offset;

        if (document.body.createTextRange) {           // Internet Explorer
            try {
                range = document.body.createTextRange();
                range.moveToPoint(event.clientX, event.clientY);
                range.select();
                range = getTextRangeBoundaryPosition(range, true);
  
                textNode = range.node;
                offset = range.offset;
            } catch(e) {
                return "";
            }
        }
        else if (document.caretPositionFromPoint) {    // Firefox
            range = document.caretPositionFromPoint(event.clientX, event.clientY);
            textNode = range.offsetNode;
            offset = range.offset;
        } else if (document.caretRangeFromPoint) {     // Chrome
            range = document.caretRangeFromPoint(event.clientX, event.clientY);
            textNode = range.startContainer;
            offset = range.startOffset;
        }

        //data contains a full sentence
        //offset represent the cursor position in this sentence
        var data = textNode.data,
            i = offset,
            begin,
            end;

        //Find the begin of the word (space)
        while (i > 0 && data[i] !== " ") { --i; };
        begin = i;

        //Find the end of the word
        i = offset;
        while (i < data.length && data[i] !== " ") { ++i; };
        end = i;

        //Return the word under the mouse cursor
        return data.substring(begin, end);
    }

    //Get the HTML in a div #hoverText and detect mouse move on it
    var $hoverText = $("#hoverText");
    $hoverText.mousemove(function (e) {
        var word = getWordUnderCursor(e);
        
        //Show the word in a div so we can test the result
        if (word !== "") 
            $("#testResult").text(word);
    });
});

// This code make it works with IE
// REF: https://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
function getTextRangeBoundaryPosition(textRange, isStart) {
  var workingRange = textRange.duplicate();
  workingRange.collapse(isStart);
  var containerElement = workingRange.parentElement();
  var workingNode = document.createElement("span");
  var comparison, workingComparisonType = isStart ?
    "StartToStart" : "StartToEnd";

  var boundaryPosition, boundaryNode;

  // Move the working range through the container's children, starting at
  // the end and working backwards, until the working range reaches or goes
  // past the boundary we're interested in
  do {
    containerElement.insertBefore(workingNode, workingNode.previousSibling);
    workingRange.moveToElementText(workingNode);
  } while ( (comparison = workingRange.compareEndPoints(
    workingComparisonType, textRange)) > 0 && workingNode.previousSibling);

  // We've now reached or gone past the boundary of the text range we're
  // interested in so have identified the node we want
  boundaryNode = workingNode.nextSibling;
  if (comparison == -1 && boundaryNode) {
    // This must be a data node (text, comment, cdata) since we've overshot.
    // The working range is collapsed at the start of the node containing
    // the text range's boundary, so we move the end of the working range
    // to the boundary point and measure the length of its text to get
    // the boundary's offset within the node
    workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange);

    boundaryPosition = {
      node: boundaryNode,
      offset: workingRange.text.length
    };
  } else {
    // We've hit the boundary exactly, so this must be an element
    boundaryPosition = {
      node: containerElement,
      offset: getChildIndex(workingNode)
    };
  }

  // Clean up
  workingNode.parentNode.removeChild(workingNode);

  return boundaryPosition;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<b><div id="testResult"></div></b>
<div id="hoverText">   <p><span class="kinovar"><span id="selection_index3337" class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">со стіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.</span> </p> <div class="slavic"><p><span id="selection_index3737" class="selection_index"></span>(л. рo7з њб.)</p> <p><span class="kinovar"><span id="selection_index3738" class="selection_index"></span>Во вт0рникъ вeчера</span></p> <p><span class="kinovar"><span id="selection_index3739" class="selection_index"></span>tдaніе прaздника пaсхи.</span></p><p><span class="kinovar"><span id="selection_index3740" class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">состіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.</span> </p><p><span class="kinovar"><span id="selection_index3741" class="selection_index"></span>На ГDи воззвaхъ: поeмъ стіхи6ры самоглaсны, слэпaгw, на ѕ7. Глaсъ в7:</span> </p><p><span class="kinovar"><span id="selection_index3742" class="selection_index"></span>С</span>лэпhй роди1выйсz, въ своeмъ п0мыслэ глаг0лаше: є3дA ѓзъ грBхъ рaди роди1тельныхъ роди1хсz без8 џчію; (л. рo7и) є3дA ѓзъ за невёріе kзhкwвъ роди1хсz во њбличeніе; не домышлsюсz вопрошaти: когдA н0щь, когдA дeнь; не терпи1та ми2 н0зэ кaменнагw претыкaніz, не ви1дэхъ сlнца сіsюща, нижE во џбразэ менE создaвшагw. но молю1 ти сz хrтE б9е, при1зри на мS, и3 поми1луй мS.</p></div></div>

다음은 대부분의 경우 Chrome에서 작동하는 간단한 솔루션입니다.

function getWordAtPoint(x, y) {
  var range = document.caretRangeFromPoint(x, y);

  if (range.startContainer.nodeType === Node.TEXT_NODE) {
    range.expand('word');
    return range.toString().trim();
  }

  return null;
}

나는 문장 부호를 필터링하고 독자에게 연습으로 하이픈이 된 단어를 올바르게 처리합니다 :).

아 요! 여기 Ho가 있습니다!

그대로 단순하고 Whitout JQuery 또는 다른 프레임 워크 바이올린 : https://jsfiddle.net/703c96dr/

각 단어에 스팬을 넣고 OnMouseOver 및 OnomouseOut 기능을 추가합니다. 간단한 클래스를 만들 수 있도록 간단한 클래스를 만들 수 있지만 코드는 매우 간단하여 누구나 편집하고 사용할 수 있습니다.

<p>This is my text example of word highlighting or, if you want, word hovering</p>
<p>This is another text example of word highlighting or, if you want, word hovering</p>

간단한 코드

function onmouseoverspan(){
    this.style.backgroundColor = "red";
}
function onmouseoutspan(){
    this.style.backgroundColor = "transparent";
}
var spans,p = document.getElementsByTagName("p");
for(var i=0;i<p.length;i++) {
    if(p[i]==undefined) continue;
    p[i].innerHTML = p[i].innerHTML.replace(/\b(\w+)\b/g, "<span>$1</span>");
    spans = p[i].getElementsByTagName("span")
    for(var a=0;a<spans.length;a++) {
        spans[a].onmouseover = onmouseoverspan;
        spans[a].onmouseout = onmouseoutspan;
    }
}

각 단어가 자신의 별도의 u003Cspan>요소u003C/span> 내부에 포함되도록 단락을 분해해야 할 것입니다. onmouseover 각각의 이벤트 속성.

.. 그리고 나는 당신이 의미하는 것 같아요 "u003Cp> 긴 텍스트u003C/p> "; 백 슬래시는 HTML의 일부가 아닙니다.

Firefox에서는 MouseMove 이벤트를 연결할 수 있습니다. 콜백에는 하나의 주장이 있습니다. e. 콜백에서 다음을 수행하십시오.

var range = HTTparent.ownerDocument.createRange();
range.selectNode(e.rangeParent);
var str = range.toString();
range.detach();

이제 STR에는 마우스가 끝났던 전체 텍스트가 있습니다. E.RangeOffset은 해당 문자열 내에서 무스 오페인의 위치입니다. 귀하의 경우, STR은 "일부 긴 텍스트"이며 "텍스트"의 "E"를 넘어 서면 E.RangeOffset은 11이됩니다.

예를 들어 마우스 포인터가 텍스트와 같은 줄에 있지만 끝이 끝난 후에는 여백에 있으면이 코드가 약간 혼란스러워집니다. 이 문제를 해결하려면 실제로 텍스트 위에 있는지 확인해야합니다. 테스트는 다음과 같습니다.

if(e && e.rangeParent && e.rangeParent.nodeType == e.rangeParent.TEXT_NODE
   && e.rangeParent.parentNode == e.target)

이 기술은 Firefox에서 작동합니다. 크롬에서는 작동하지 않습니다.

function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
function getChildIndex(node) {
  var i = 0;
  while( (node = node.previousSibling) ) {
    i++;
  }
  return i;
}

// All this code just to make this work with IE, OTL
// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
function getTextRangeBoundaryPosition(textRange, isStart) {
  var workingRange = textRange.duplicate();
  workingRange.collapse(isStart);
  var containerElement = workingRange.parentElement();
  var workingNode = document.createElement("span");
  var comparison, workingComparisonType = isStart ?
    "StartToStart" : "StartToEnd";

  var boundaryPosition, boundaryNode;

  // Move the working range through the container's children, starting at
  // the end and working backwards, until the working range reaches or goes
  // past the boundary we're interested in
  do {
    containerElement.insertBefore(workingNode, workingNode.previousSibling);
    workingRange.moveToElementText(workingNode);
  } while ( (comparison = workingRange.compareEndPoints(
    workingComparisonType, textRange)) > 0 && workingNode.previousSibling);

  // We've now reached or gone past the boundary of the text range we're
  // interested in so have identified the node we want
  boundaryNode = workingNode.nextSibling;
  if (comparison == -1 && boundaryNode) {
    // This must be a data node (text, comment, cdata) since we've overshot.
    // The working range is collapsed at the start of the node containing
    // the text range's boundary, so we move the end of the working range
    // to the boundary point and measure the length of its text to get
    // the boundary's offset within the node
    workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange);

    boundaryPosition = {
      node: boundaryNode,
      offset: workingRange.text.length
    };
  } else {
    // We've hit the boundary exactly, so this must be an element
    boundaryPosition = {
      node: containerElement,
      offset: getChildIndex(workingNode)
    };
  }

  // Clean up
  workingNode.parentNode.removeChild(workingNode);

  return boundaryPosition;
}

function onClick(event) {
  var elt = document.getElementById('info');
  elt.innerHTML = "";
  var textNode;
  var offset;
  // Internet Explorer
  if (document.body.createTextRange) {
		  elt.innerHTML = elt.innerHTML+("*************** IE **************<br/>");
      range = document.body.createTextRange();
      range.moveToPoint(event.clientX, event.clientY);
      range.select();
      range = getTextRangeBoundaryPosition(range, true);

      textNode = range.node;
      offset = range.offset;
      elt.innerHTML = elt.innerHTML + "IE ok, result: [" + escapeHtml(textNode.nodeName) + "]/[" + escapeHtml(textNode.textContent) + "] @" + offset + "</br>";

  }
  
  // Internet Explorer method 2
  if (document.body.createTextRange) {
		  elt.innerHTML = elt.innerHTML+("*************** IE, Method 2 **************<br/>");
      range = document.body.createTextRange();
      range.moveToPoint(event.clientX, event.clientY);
      range.select();
			var sel = document.getSelection();
      textNode = sel.anchorNode;
      offset = sel.anchorOffset;
      elt.innerHTML = elt.innerHTML + "IE M2 ok, result: [" + escapeHtml(textNode.nodeName) + "]/[" + escapeHtml(textNode.textContent) + "] @" + offset + "</br>";
  }  

  // Firefox, Safari
  // REF: https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint
  if (document.caretPositionFromPoint) {
		  elt.innerHTML = elt.innerHTML+("*************** Firefox, Safari **************<br/>");  
    range = document.caretPositionFromPoint(event.clientX, event.clientY);
    textNode = range.offsetNode;
    offset = range.offset;
    elt.innerHTML = elt.innerHTML + "caretPositionFromPoint ok, result: [" + escapeHtml(textNode.nodeName) + "]/[" + escapeHtml(textNode.textContent) + "] @" + offset + "</br>";
    // Chrome
    // REF: https://developer.mozilla.org/en-US/docs/Web/API/document/caretRangeFromPoint
  }
  if (document.caretRangeFromPoint) {
		  elt.innerHTML = elt.innerHTML+("*************** Chrome **************<br/>");  
    range = document.caretRangeFromPoint(event.clientX, event.clientY);
    textNode = range.startContainer;
    offset = range.startOffset;
    elt.innerHTML = elt.innerHTML + "caretRangeFromPoint ok, result: [" + escapeHtml(textNode.nodeName) + "]/[" + escapeHtml(textNode.textContent) + "] @" + offset + "</br>";
  }
}

document.addEventListener('click', onClick);
#info {
  position: absolute;
  bottom: 0;
  background-color: cyan;
}
<div class="parent">
  <div class="child">SPACE&nbsp;SPACE Bacon ipsum dolor amet <span>SPAN SPANTT SPOOR</span> meatball bresaola t-bone tri-tip brisket. Jowl pig picanha cupim SPAXE landjaeger, frankfurter spare ribs chicken. Porchetta jowl pancetta drumstick shankle cow spare ribs jerky
    tail kevin biltong capicola brisket venison bresaola. Flank sirloin jowl andouille meatball venison salami ground round rump boudin turkey capicola t-bone. Sirloin filet mignon tenderloin beef, biltong doner bresaola brisket shoulder pork loin shankle
    turducken shank cow. Bacon ball tip sirloin ham.
  </div>
  <div id="info">Click somewhere in the paragraph above</div>
</div>

내 대답은 Drakes의 "Solution 2- Caret Inspection and Dom Traversal"에서 파생되었습니다. 이 솔루션을 가리키신 드레이크에 감사드립니다!

그러나 IE에서 작업 할 때 Drakes의 솔루션 2에는 두 가지 문제가 있습니다. (1) 계산 된 오프셋은 잘못되었고 (2) 너무 복잡하고 많은 코드가 있습니다.

jsfiddle at에서 내 시연을 참조하십시오 여기.

문제 1의 경우 텍스트의 마지막 줄에 어딘가에 클릭하면 "어깨 돼지 고기 허리 Shankle Turducken Shank Cow. 베이컨 볼 팁 Sirloin Ham"의 어딘가에 어딘가에 있습니다. 오프셋 계산이 IE (원본)가 다릅니다. 해결책) 및 IE 방법 2 (내 솔루션). 또한 IE 방법 2 (내 솔루션)와 Chrome의 결과는 동일합니다.

내 솔루션도 훨씬 간단합니다. 트릭은 TexTrange를 사용하여 절대 x/y 위치에서 선택한 후 document.getSelection ()을 호출하여 ihtmlSelection의 유형을 가져옵니다. 이것은 IE <9에는 효과가 없지만 괜찮다면이 방법은 훨씬 간단합니다. 또 다른 경고는, 즉, 메소드 부작용 (원래 메소드와 동일)이 선택의 변경 (즉, 사용자의 원래 선택을 잃는)입니다.

  // Internet Explorer method 2
  if (document.body.createTextRange) {
          elt.innerHTML = elt.innerHTML+("*************** IE, Method 2 **************<br/>");
      range = document.body.createTextRange();
      range.moveToPoint(event.clientX, event.clientY);
      range.select();
      var sel = document.getSelection();
      textNode = sel.anchorNode;
      offset = sel.anchorOffset;
      elt.innerHTML = elt.innerHTML + "IE M2 ok, result: [" + escapeHtml(textNode.nodeName) + "]/[" + escapeHtml(textNode.textContent) + "] @" + offset + "</br>";
  }  
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top