Come ottenere una parola sotto il cursore utilizzando JavaScript?

Se io, per esempio, sono

<p> some long text </p>

sulla mia pagina HTML, come faccio a sapere che il cursore del mouse, per esempio, è al di sopra della parola ‘testo’?

  • Questa una live demo di come ottenere una parola sotto il cursore utilizzando JavaScript basato sul codice sorgente fornito dalla Damovisa: jsfiddle.net/5gyRx.
  • C’è una nuova risposta a questa domanda da un bounty. Si potrebbe prendere in considerazione la selezione (per il bene di nuovi utenti che arrivano).
InformationsquelleAutor Ivan | 2010-03-15

 

11 Replies
  1. 40

    Ulteriormente per le altre due risposte, si può essere in grado di dividere i paragrafi in campate utilizzando jQuery (javascript o più in generale).

    In quel modo, non avrebbe bisogno di pensare l’output di testo con campate intorno alle parole. Lasciate che il vostro javascript farlo per voi.

    ad esempio

    <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>

    Di notare che il codice di cui sopra, mentre si lavora, si striscia fuori di qualsiasi codice html dentro il tag di paragrafo.

    jsFiddle esempio

    • O si potrebbe solo fare il $(this).text().replace(/\b(\w+)\b/g, "<span>$1</span>") invece del ciclo. Questo permetterà di gestire tutti i caratteri di spaziatura corretta.
    • grazie per questo, io non sono molto bravo con le regex così ho fatto nel modo più semplice 🙂 ho l’aggiornamento.
    • Ci ho pensato ma è un pò imbarazzante ( io sono newbie in JavaScript, in modo che la mia strada era molto peggio della tua ). Grazie per il chiarimento. @Chetan – questo è pulito soluzione.
    • Come possiamo modificarlo in modo che identificherà h1,h2,h3, ecc. tag invece di p i tag?
    • Si dovrebbe solo essere in grado di sostituire il primo $('p') selettore con $('p,h1,h2,h3') e così via. Allo stesso modo, per ottenere il passaggio del mouse per lavorare, hai bisogno di modificare il secondo selettore a $('p span,h1 span,h2 span,h3 span').
    • come faccio ad ottenere due o più parole?

  2. 38

    Mia altra risposta che funziona solo in Firefox. Questa risposta funziona in Chrome. (Potrebbe funzionare anche in Firefox, non so.)

    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);
    }    

    Nel mousemove gestore, chiamata getWordAtPoint(e.target, e.x, e.y);

    • Codice funziona bene su iOS (6/7), ma in Android 4.0.3 getBoundingClientRect possibile risultato nullo. In modo da aggiungere: gamma.getBoundingClientRect() != null come condizione nel primo ciclo (prima di ottenere la proprietà di sinistra).
    • I documenti di stato che il limite per la “parola” è un carattere di spazio. Ma l’espansione non sembra funzionare per gli url. Tutte le idee?
    • Ho trovato il tuo codice funziona bene con chrome e non in firefox.Ma quando gamma.espandere il commento è in grado di dare il carattere sotto il cursore per firefox.Qualche idea per farlo funzionare in firefox?
    • Questo è un bel pezzo di codice, ma si romperà quando si lavora con un mix di textNodes e altri elementi. Ci sono due casi in cui questo viene visualizzato. 1. Un nodo di testo con una interruzione di riga avrà un nonsense casella di delimitazione. 2. Elementi con altezza maggiore di textNode linea può riportare la posizione verticale della gamma. Penso che dovrebbe essere possibile superare quei controllando textNodes carattere per carattere dall’inizio e di compensazione casuale reimposta della posizione verticale assumendo texNodes non può mai essere superiore a qualsiasi dei loro precedenti fratelli (ma che potrebbe non essere sempre vero).
    • Anche il +1 nella condizione del ciclo while è inutile. L’ultimo carattere del textNode inizia a range.endOffset (e finisce a range.endOffset + 1). Quindi, a meno che la condizione è in realtà while(currentPos < endPos) l’ultimo carattere non sarà mai testato.
    • Sembra che potrebbe essere stato scambiato a circa il secondo punto e il problema potrebbe essere stato causato dallo script fermare la ricerca in precedenza di un nodo (perché rotti bounding box).
    • vedere jsfiddle.net/ohaf4ytL e stackoverflow.com/questions/30454530/… per i casi in cui il presente codice si rompe
    • Funziona bene per me. Ho appena provato il tuo jsfiddle e, con la console aperta, vedo tutto il testo che vi compaiono. Sto usando Chrome.

  3. 34

    Preambolo:

    Se si dispone di più campate e nidificate HTML che separano le parole (o anche caratteri a parole), quindi tutte le soluzioni di cui sopra, avrà difficoltà a restituire la piena e corretta parola.

    Qui è un esempio da bounty domanda: Х</span>rт0съ. Come correttamente ritorno Хrт0съ? Questi problemi non sono stati affrontati, nel 2010, così io vi presentiamo due soluzioni (2015).


    Soluzione 1 – Striscia interno tag, avvolgere abbraccia circa ogni parola:

    Una soluzione è quella di rimuovere il tag span all’interno di paragrafi, ma preservare il loro testo. Divisione di parole e frasi così sono entrato di nuovo insieme come testo normale. Ogni parola è trovato da spazi divisione (non solo uno spazio), e quelle parole sono avvolti in campate che individualmente accessibili.

    Nella demo, è possibile evidenziare l’intera parola e, quindi, ottenere il testo di tutta la parola.


    Come ottenere una parola sotto il cursore utilizzando JavaScript?

    Codice:

    JS:

    $(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', ''); }
      );
    });

    HTML:

    <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>

    Soluzione 1-testo demo


    Soluzione 2 – Cursore di ispezione e DOM traversal:

    Qui è una soluzione più sofisticata. E ‘ un algoritmo di soluzione utilizzando nodo di attraversamento che cattura perfettamente la piena e corretta parola sotto il cursore in un nodo di testo.

    Temporanea parola è trovato controllando la posizione del cursore (tramite caretPositionFromPoint o caretRangeFromPoint, crediti per l’idea di @chrisv). Questo può o non può essere pieno di parola, di sicurezza.

    È poi analizzati per vedere se si trova a bordo del suo nodo di testo (inizio o fine). Se lo è, il precedente nodo di testo o il testo seguente nodo viene esaminato per vedere se deve essere aderito a questa parola frammento più lungo.

    Esempio:

    Х</span>rт0съ deve restituire Хrт0съ, non Хrт0съ.

    L’albero del DOM è attraversato per ottenere il prossimo senza barriera nodo di testo. Se due parole, frammenti sono separati da un <p> o qualche altra barriera tag, quindi non sono adiacenti e quindi non fanno parte di una stessa parola.

    Esempio:

    њб.)</p><p>Во non dovrebbe tornare њб.)Во


    Nella demo, la sinistra galleggiante div è la parola sotto il cursore. Il diritto galleggiante div, se visibile, mostra come una parola su un confine è stato formato. Altro tag può tranquillamente essere in linea con il testo in questa soluzione.

    Come ottenere una parola sotto il cursore utilizzando JavaScript?

    Codice:

    JS:

    $(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();
      }
    }

    CSS:

    .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;}

    HTML:

    <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>

    (Nota: mi sono preso la libertà di applicare gli stili per il tag span, che erano presenti nel tuo HTML di esempio per illuminare dove nodo di testo confini.)

    Soluzione 2-testo demo

    (Lavori in Chrome e IE. Per esempio, un metodo da IERange doveva essere utilizzato come un supporto per la compatibilità cross-browser)

    • In questo Slava, la codifica, il { indica un accento, quindi vorrei fare solo per conte una parola come tutto all’interno di uno spazio, anche veri e propri segni di punteggiatura (come rimuoverli a me stesso). La risposta non è tecnicamente soddisfare il bounty, ma se migliori risolve il problema, verrà selezionato.
    • Ho inviato una seconda soluzione, molto più, che utilizza DOM attraversamento e funziona in IE troppo. E ‘ veloce ed è progettato per essere robusto per il futuro HTML. Mi piacciono entrambe le soluzioni, ma questo non fa uso di tag span wrapping, come da lei richiesto.
    • Grazie. Opere finora perfettamente. Ho incapsulato funzioni come un oggetto per farla lavorare al meglio con la mia domanda. jsfiddle.net/ohaf4ytL/1 penso che questo sarà molto utile anche per gli altri.
  4. 11

    A mia conoscenza, non è possibile.

    Unica cosa che posso pensare è quello di mettere ciascuna delle parole nel loro elemento, quindi applicare mouse su eventi di quegli elementi.

    <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>
  5. 5

    C’è un’API per questo, nell’attuale CSSOM Vista la bozza: document.caretPositionFromPoint(x,y)

    È necessario controllare che il browser lo supporta, però. Firefox 7 sembra non lo supportano, mentre le segnalazioni di bug indicare Firefox 9. Chrome 14 supporta caretRangeFromPoint(x,y) che è essenzialmente la stessa, ma da un vecchio CSSOM progetto.

    • Sembra che la tua risposta soddisfa la mia bontà del progetto. Ha solo bisogno di un po ‘ di lavoro, in realtà, la parola ampliato dal punto di inserimento punto. Il nativo gamma di espandere il metodo non funziona abbastanza bene. Posso la ricerca di questo me stesso, ma se è possibile fornire il codice per lavorare con il mio demo jsfiddle.net/ohaf4ytL, che sarebbe grande.
    • Ho implementato questa soluzione (stackoverflow.com/a/30606508/2576706). Non si adatta alle vostre esigenze?
  6. 5

    Ecco la soluzione per il bounty.

    Come suggerito da chrisv è possibile utilizzare document.caretRangeFromPoint (chrome) o document.caretPositionFromPoint (Firefox).
    Penso che questa soluzione migliore risposta alla tua domanda in quanto non modificare il testo o la DOM.

    Questa funzione restituisce la parola sotto il cursore del mouse senza alterare il DOM:

    Dal document.caretRangeFromPoint documentazione:

    Il caretRangeFromPoint() metodo di interfaccia a Documento restituisce un oggetto Range per il frammento di documento in coordinate specificate.

    Dal document.caretPositionFromPoint documentazione:

    Questo metodo viene utilizzato per recuperare la posizione del cursore in un documento basato su due coordinate. Un CaretPosition viene restituito, contenente trovato nodo DOM e il carattere di offset in quel nodo.

    Le due funzioni sono leggermente diversi, ma entrambi restituiscono il nodo contenente il testo e lo spostamento del cursore in questo testo. Così è facile per ottenere la parola sotto il mouse.

    Vedere l’esempio completo:

    JS:

    $(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;
    }

    HTML:

    <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>

    • “Ottenere il codice HTML #hoverText – solo un wrapper per convenienza” – sembra familiare
    • Ho letto tutte le risposte qui e trovato la tua idea di inserire il testo in un div di buono, quindi ho mantenuto lo stesso nome. Ma il codice dopo che è totalmente diverso 🙂
    • A proposito, ho trovato la tua soluzione molto buona. Buona fortuna per il bounty 😉
    • “textNode è definito” per qualche motivo in IE.
    • Grazie per il tuo commento, ultima modifica di correggere questo errore
    • Grazie Ludovic. Proprio quello che mi serviva e funziona meravigliosamente. Io sto usando solo per Safari e ho notato che caretRangeFromPoint tornerà più vicina gamma, anche se si fa clic su uno spazio vuoto della pagina. Sembra un bug di lunga durata: bugs.webkit.org/show_bug.cgi?id=29249

  7. 4

    Ecco una semplice soluzione che funziona in Chrome per la maggior parte dei casi:

    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;
    }

    Mi lascia filtrare la punteggiatura e di gestire correttamente parole spezzate come esercizio per il lettore :).

    • Proprio quello che mi serviva per una estensione di google Chrome.
    • Che è esattamente quello che mi ha spinto a venire con questa ricetta :).
  8. 3

    Aw yiss! Ecco ho!

    Semplice e senza Jquery o qualsiasi altro quadro
    Violino: https://jsfiddle.net/703c96dr/

    Metterà spazia su ogni parola e aggiungere un onmouseover e onomouseout funzione. Potrei creare una semplice classe per renderlo più utilizzabile, ma il codice è così semplice che chiunque può modificare e utilizzare.

    <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>

    Semplice codice

    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;
        }
    }
  9. 2

    Si sarebbe probabilmente a rompere il paragrafo, in modo che ogni parola era contenuta all’interno di una propria <span> elemento e quindi aggiungere onmouseover evento attributi di ciascuno di essi.

    ..E penso che tu intenda “<p>alcuni lunghi testo</p>”; barre rovesciate non sono parte di HTML.

  10. 1

    In Firefox è possibile agganciare l’evento mousemove. La richiamata dispone di un argomento, e. Nella richiamata, fare questo:

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

    Ora str è tutto il testo che il mouse era finita. e.rangeOffset è la posizione del puntatore del mouse all’interno della stringa. Nel tuo caso, str vorresti essere “un po’ di testo lungo” e e.rangeOffset 11 se si erano sopra la “e” nel “testo”.

    Tale codice consentirà di ottenere un po ‘ confuso, se siete ai margini, per esempio quando il puntatore del mouse si trova sulla stessa riga di testo, ma dopo la fine di esso. Per risolvere questo problema, è necessario controllare che siano effettivamente di testo. Ecco il test:

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

    Questa tecnica funziona in Firefox. Non funziona in Chrome.

  11. 0

    JS:

    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);

    CSS:

    #info {
      position: absolute;
      bottom: 0;
      background-color: cyan;
    }

    HTML:

    <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>

    La mia risposta è derivato da Drakes’ “Soluzione 2 – Cursore di ispezione e DOM di attraversamento”. Grazie mille a Drakes di puntare a questa soluzione!

    Tuttavia, ci sono due problemi con Drakes’ soluzione 2 quando si lavora su IE. (1) l’offset calcolato è corretto, e (2) troppo complesso, un sacco di codice.

    Vedere la mia dimostrazione su JSFiddle a qui.

    Per il problema 1, se si clicca da qualche parte circa l’ultima riga del testo, per esempio, da qualche parte in “spalla di maiale shankle turducken gambo di mucca. Pancetta sfera di manzo prosciutto cotto.”, si può notare l’offset di calcolo è diverso, con IE (soluzione originale) e CIOÈ il metodo 2 (la mia soluzione). Inoltre, i risultati da IE metodo 2 (la mia soluzione) e da Chrome, Firefox sono le stesse.

    La mia soluzione è anche molto più semplice. Il trucco è, dopo l’uso TextRange a fare selezione all’assoluta posizione X/Y, ottenere un tipo di IHTMLSelection chiamando il documento.getSelection(). Questo non funziona con IE<9 ma se questo è OK per voi, questo metodo è molto più semplice. Un altro avvertimento è, con IE il metodo di effetti collaterali (come il metodo originale) è il cambiamento di selezione (cioè perdere utente selezione originale).

      //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>";
      }  

Lascia un commento