una texto subrayar resaltar para palabras palabra pagina iluminar etiqueta como buscar buscador javascript jquery

javascript - subrayar - resaltar texto html css



¿Cómo puedo resaltar una palabra/término más rápido y más inteligente? (6)

Conceptos

Para seleccionar cada palabra, hay algo que debes tener en cuenta primero:

  1. textNode es una sola textNode contiene todas las palabras, no podrá seleccionar cada "palabra", ya que no es un nodo DOM.

  2. No hay un evento específico activado en el navegador cuando "arrastra y selecciona" una palabra. Sin embargo, cuando arrastra y selecciona, hay 2 eventos que se activan: el mouseover se activa cuando mueve el mouse, el click se activa cuando suelta el botón del mouse. (Esto es cierto incluso en el touchpad de Mac).

  3. Hay diferentes implementaciones en "resaltar" cuando selecciona una palabra.

Pasos

En función de los conceptos, debe realizar los siguientes pasos de forma secuencial para lograr su objetivo:

  1. Obtenga las palabras en el párrafo y envuélvalas con una etiqueta (por ejemplo, <span> ) para la selección de DOM
  2. Cuando se activa el evento de click (que indica que su selección ha finalizado), resalte la palabra que acaba de seleccionar.

La implementación sería algo como esto (con jQuery ). Y puedes ver la demostración en vivo aquí:

$(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 función SelectText debe atribuirse a @Jason en esta publicación en SO: Seleccionar texto en un elemento: similar a resaltar con el mouse

Tengo un texto:

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

Actualmente, si un usuario desea resaltar una palabra / término con el cursor, hará clic y arrastrará, letra por letra.

Quiero que este proceso sea más rápido. Por ejemplo, si el usuario comienza a resaltar At , debería resaltar automáticamente el resto de la palabra, Attack . Así que el espacio vacío es el divisor.

Soy consciente de que esto es posible dividiendo las palabras en divs, pero espero una solución con texto puro dentro de una etiqueta <p> .


Así que vas a tener que lidiar con los rangos de texto y tal. He lidiado con esto, y es extremadamente doloroso, especialmente si tiene contenidos DOM como:

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

es decir, nodos de texto mezclados con otros elementos DOM, como un tramo en este caso. Con esto en mente, me gustaría recomendar altamente la biblioteca rangy.js: https://github.com/timdown/rangy

Me ahorré varios días de dolor de cabeza cuando estaba haciendo un hashtag para resaltar el sistema.


Este texto es un nodo de texto y los nodos de texto simplemente no activan la mayoría de los eventos. Pero pueden activar eventos de mutación DOM , por ejemplo, DOMCharacterDataModified , que se usa para detectar cambios en el texto de un nodo de texto:

var textNode = document.getElementsByClassName("drag")[0].firstChild; textNode.addEventListener("DOMCharacterDataModified", function(e) { console.log("Text changed from ''" + e.prevValue + "'' to ''" + evt.newValue +"''"); }, false);

Sin embargo, el texto en <p class="drag">Hello world, Attack on Titan season two!</p> es un nodo de texto único y necesita que cada palabra sea un nodo separado.

La única solución que veo es poner cada palabra en una etiqueta de span . No puedes hacer esto con texto puro.

Editar

Aquí hay un ejemplo de cómo hacer esto con las etiquetas span (estoy usando jQuery aquí solo para reducir la cantidad de código, no es necesario):

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

Aquí hay un ejemplo en JS Bin

Actualizar

Edité el fragmento de código para que la selección se comporte como pediste (actualmente solo funciona para selecciones de izquierda a derecha, no para selecciones inversas):

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

Puede leer más sobre HTML Range API aquí: https://developer.mozilla.org/en-US/docs/Web/API/Range


No puede establecer eventos en Texto, pero puede establecer eventos en Elementos HTML. Coloque cada palabra dentro de un elemento div y agregue un evento onmouseover que cambie div a un nuevo estado resaltado usando css.

Pasos:

  1. Use dividir para obtener palabras en la matriz.
  2. Iterar palabras y ponerlo en un div.
  3. Iterate divs y configúrelo como un evento que cambie la div a una clase css. Highlight.

Eso es.


Puede hacerlo con JS puro utilizando los objetos Range y selectionRange .

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

Por favor, consulte el ejemplo de trabajo here .

ACTUALIZACIONES:

  • Selección de la palabra entera en el clic añadido
  • Se ha corregido el comportamiento de arrastre específico de Firefox.

JSFiddle actualizado here .


Usando node.textContent podemos encontrar espacios y pasar nuestra selección a palabras completas sin la necesidad de crear nuevos elementos.

Principalmente para mi potencial uso futuro, he escrito esto bastante modular, tampoco requiere un mouseup en el elemento observado, puede tratar una colección de elementos y también realiza cambios en la selección si el usuario realiza su selección con su teclado.

var WordJumpSelection = (function() { var watchList = []; var WordJumpSelection = { stopWatching: function(elem) { var wlIdx = watchList.indexOf(elem); if(wlIdx > -1) watchList.splice(wlIdx,1); }, watch: function(elem) { var elems = Array.prototype.slice.call(typeof elem.length === "number" ? elem : arguments); if(watchList.length === 0) { WordJumpSelection.init(); } elems.forEach(function(elem) { if(watchList.indexOf(elem) === -1) { watchList.push(elem); } }); }, init: function() { function handleSelectionChange() { if(watchList.length === 0) return; var selection = window.getSelection(); var selDir = getSelectionDir(selection); var startNode,endNode,startPos,endPos; if(selDir === 1) { startNode = selection.anchorNode; endNode = selection.focusNode; startPos = selection.anchorOffset; endPos = selection.focusOffset; } else { startNode = selection.focusNode; endNode = selection.anchorNode; startPos = selection.focusOffset; endPos = selection.anchorOffset; } var rangeStart = textNodeIsWatched(startNode) ? roundSelectionIndex(startNode,0,startPos) : startPos-1; var rangeEnd = textNodeIsWatched(endNode) ? roundSelectionIndex(endNode,1,endPos) : endPos; var r = document.createRange(); r.setStart(startNode,rangeStart+1) r.setEnd(endNode,rangeEnd) selection.removeAllRanges(); selection.addRange(r); } document.documentElement.addEventListener(''mouseup'', handleSelectionChange); document.documentElement.addEventListener(''keyup'', function(e) { if(e.keyCode === 16) { handleSelectionChange(); } }); WordJumpSelection.init = function(){}; } }; return WordJumpSelection; function getSelectionDir(sel) { var range = document.createRange(); range.setStart(sel.anchorNode,sel.anchorOffset); range.setEnd(sel.focusNode,sel.focusOffset); if(range.startContainer !== sel.anchorNode || (sel.anchorNode === sel.focusNode && sel.focusOffset < sel.anchorOffset)) return -1; else return 1; } function roundSelectionIndex(textNode,nodeId,idx) { var isStart = nodeId === 0; var contents = textNode.textContent; var nearestSpaceIdx = -1; if(isStart) { nearestSpaceIdx = contents.lastIndexOf('' '',idx); if(nearestSpaceIdx === -1) nearestSpaceIdx = -1; } else { nearestSpaceIdx = contents.indexOf('' '',idx); if(nearestSpaceIdx === -1) nearestSpaceIdx = contents.length; } return nearestSpaceIdx; } function textNodeIsWatched(textNode) { return watchList.indexOf(textNode.parentElement) > -1; } })();

Un ejemplo de jsFiddle.

Todavía tengo que probar cómo funciona esto en el móvil, y aún no lo he hecho funcionar en vivo, pero podría ser un buen comienzo.

Actualización: ahora selecciona la palabra con un solo clic