javascript 突出显示元素中的子字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9051369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Highlight substring in element
提问by Ayman
What is the best way to highlight a specific substring in a div element in an event? By highlight, I mean apply some CSS style, like yellow background or something.
在事件中突出显示 div 元素中特定子字符串的最佳方法是什么?高亮,我的意思是应用一些 CSS 样式,比如黄色背景或其他东西。
Basically I need a simple JS client side function of the form:
基本上我需要一个简单的 JS 客户端函数的形式:
function (element, start, end) {
// element is the element to manipulate. a div or span will do
// start and end are the start and end positions within the text of that
// element where highlighting should be.
// do the stuff
}
Only one highlight will be active.
只有一个突出显示将处于活动状态。
采纳答案by jfriend00
You will need to wrap the text that you want to in it's own <span>
tag so you can give that text its own style. Using your requested function definition, you could do it like this:
您需要将您想要的文本包装在它自己的<span>
标签中,以便您可以为该文本赋予自己的样式。使用您请求的函数定义,您可以这样做:
function (element, start, end) {
var str = element.innerHTML;
str = str.substr(0, start) +
'<span class="hilite">' +
str.substr(start, end - start + 1) +
'</span>' +
str.substr(end + 1);
element.innerHTML = str;
}
You can then define CSS for the class hilite to control the style of that text.
然后,您可以为 hilite 类定义 CSS 以控制该文本的样式。
.hilite {color: yellow;}
This assumes that start and end are indexes into the innerHTML of the first and last characters that you want highlighted.
这假设 start 和 end 是您想要突出显示的第一个和最后一个字符的 innerHTML 的索引。
If you want to be able to call it repeatedly on the same element (to move the higlight around), you could do it like this:
如果您希望能够在同一个元素上重复调用它(以移动高亮显示),您可以这样做:
function (element, start, end) {
var item = $(element);
var str = item.data("origHTML");
if (!str) {
str = item.html();
item.data("origHTML", str);
}
str = str.substr(0, start) +
'<span class="hilite">' +
str.substr(start, end - start + 1) +
'</span>' +
str.substr(end + 1);
item.html(str);
}
回答by Blender
If you have no attached events or complicated HTML, you can just do search and replace on the HTML:
如果您没有附加事件或复杂的 HTML,您可以在 HTML 上进行搜索和替换:
element.innerHTML = element.innerHTML.replace(/search/gi, function(match) {
return '<span class="highlight">' + match + '</span>'
});
If you want something better, you can manipulate the DOM directly without using innerHTML
, which will preserve events and work for more complicated HTML:
如果你想要更好的东西,你可以直接操作 DOM 而不使用innerHTML
,这将保留事件并适用于更复杂的 HTML:
/*
* Takes in an array of consecutive TextNodes and returns a document fragment with `word` highlighted
*/
function highlight_text_nodes($nodes, word) {
if (!$nodes.length) {
return;
}
var text = '';
// Concatenate the consecutive nodes to get the actual text
for (var i = 0; i < $nodes.length; i++) {
text += $nodes[i].textContent;
}
var $fragment = document.createDocumentFragment();
while (true) {
// Tweak this if you want to change the highlighting behavior
var index = text.toLowerCase().indexOf(word.toLowerCase());
if (index === -1) {
break;
}
// Split the text into [before, match, after]
var before = text.slice(0, index);
var match = text.slice(index, index + word.length);
text = text.slice(index + word.length);
// Create the <mark>
var $mark = document.createElement('mark');
$mark.className = 'found';
$mark.appendChild(document.createTextNode(match));
// Append it to the fragment
$fragment.appendChild(document.createTextNode(before));
$fragment.appendChild($mark);
}
// If we have leftover text, just append it to the end
if (text.length) {
$fragment.appendChild(document.createTextNode(text));
}
// Replace the nodes with the fragment
$nodes[0].parentNode.insertBefore($fragment, $nodes[0]);
for (var i = 0; i < $nodes.length; i++) {
var $node = $nodes[$nodes.length - i - 1];
$node.parentNode.removeChild($node);
}
}
/*
* Highlights all instances of `word` in `$node` and its children
*/
function highlight($node, word) {
var $children = $node.childNodes;
var $current_run = [];
for (var i = 0; i < $children.length; i++) {
var $child = $children[i];
if ($child.nodeType === Node.TEXT_NODE) {
// Keep track of consecutive text nodes
$current_run.push($child);
} else {
// If we hit a regular element, highlight what we have and start over
highlight_text_nodes($current_run, word);
$current_run = [];
// Ignore text inside of our <mark>s
if ($child.nodeType === Node.ELEMENT_NODE && $child.className !== 'found') {
highlight($child, word);
}
}
}
// Just in case we have only text nodes as children
if ($current_run.length) {
highlight_text_nodes($current_run, word);
}
}
/*
* Removes all highlighted <mark>s from the given node
*/
function unhighlight($node) {
var $marks = [].slice.call($node.querySelectorAll('mark.found'));
for (var i = 0; i < $marks.length; i++) {
var $mark = $marks[i];
// Replace each <mark> with just a text node of its contents
$mark.parentNode.replaceChild(document.createTextNode($mark.childNodes[0].textContent), $mark);
}
}
Demo: https://jsfiddle.net/wLkbbo5m/4/
演示:https: //jsfiddle.net/wLkbbo5m/4/
If you want even more features, just use a library (like mark.js). There's no point in reinventing the entirewheel.
如果您想要更多功能,只需使用库(例如mark.js)。重新发明整个轮子是没有意义的。
回答by dude
Why using a selfmade highlighting function is a bad idea
为什么使用自制的高亮功能是个坏主意
The reason why it's probably a bad idea to start building your own highlighting function from scratch is because you will certainly run into issues that others have already solved. Challenges:
从头开始构建自己的突出显示功能可能是一个坏主意的原因是因为您肯定会遇到其他人已经解决的问题。挑战:
- You would need to remove text nodes with HTML elements to highlight your matches without destroying DOM events and triggering DOM regeneration over and over again (which would be the case with e.g.
innerHTML
) - If you want to remove highlighted elements you would have to remove HTML elements with their content and also have to combine the splitted text-nodes for further searches. This is necessary because every highlighter plugin searches inside text nodes for matches and if your keywords will be splitted into several text nodes they will not being found.
- You would also need to build tests to make sure your plugin works in situations which you have not thought about. And I'm talking about cross-browser tests!
- 您需要删除带有 HTML 元素的文本节点以突出显示您的匹配项,而不会破坏 DOM 事件并一遍又一遍地触发 DOM 重新生成(例如,就是这种情况
innerHTML
) - 如果要删除突出显示的元素,则必须删除 HTML 元素及其内容,并且还必须组合拆分的文本节点以进行进一步搜索。这是必要的,因为每个荧光笔插件都会在文本节点内搜索匹配项,并且如果您的关键字将被拆分为多个文本节点,它们将不会被找到。
- 您还需要构建测试以确保您的插件在您没有考虑过的情况下工作。我说的是跨浏览器测试!
Sounds complicated? If you want some features like ignoring some elements from highlighting, diacritics mapping, synonyms mapping, search inside iframes, separated word search, etc. this becomes more and more complicated.
听起来很复杂?如果您想要一些功能,例如从突出显示、变音符号映射、同义词映射、iframe 内搜索、分离词搜索等中忽略某些元素,这将变得越来越复杂。
Use an existing plugin
使用现有插件
When using an existing, well implemented plugin, you don't have to worry about above named things. The article 10 jQuery text highlighter pluginson Sitepoint compares popular highlighter plugins.
使用现有的、实现良好的插件时,您不必担心上述命名的事情。Sitepoint 上的文章10 jQuery 文本荧光笔插件比较了流行的荧光笔插件。
Have a look at mark.js
看看mark.js
mark.jsis such a plugin that is written in pure JavaScript, but is also available as jQuery plugin. It was developed to offer more opportunities than the other plugins with options to:
mark.js就是这样一个用纯 JavaScript 编写的插件,但也可以作为 jQuery 插件使用。它的开发目的是提供比其他插件更多的机会,可以选择:
- search for keywords separately instead of the complete term
- map diacritics (For example if "justo" should also match "justò")
- ignore matches inside custom elements
- use custom highlighting element
- use custom highlighting class
- map custom synonyms
- search also inside iframes
- receive not found terms
- 单独搜索关键字而不是完整的术语
- 映射变音符号(例如,如果“justo”也应该匹配“justò”)
- 忽略自定义元素内的匹配项
- 使用自定义高亮元素
- 使用自定义突出显示类
- 映射自定义同义词
- 也在 iframe 内搜索
- 收到未找到的条款
Alternatively you can see this fiddle.
或者你可以看到这个 fiddle。
Usage example:
用法示例:
// Highlight "keyword" in the specified context
$(".context").mark("keyword");
// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);
It's free and developed open-source on GitHub (project reference).
它是在 GitHub 上免费开发的开源软件(项目参考)。
回答by Nicolas Roehm
You can use mark.jswhich provides a simple and powerful jqueryplugin :
你可以使用mark.js,它提供了一个简单而强大的jquery插件:
$('p').mark('sit');
mark {
background: orange;
color: black;
}
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdn.jsdelivr.net/mark.js/8.6.0/jquery.mark.min.js"></script>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
回答by Thomas Fauskanger
In a React project
在 React 项目中
I was worried about how other libraries' DOM-manipulation would work in a React project, so I used react-hightlight-wordsto solve this problem.
我担心其他库的 DOM 操作在 React 项目中会如何工作,所以我使用react-hightlight-words来解决这个问题。
See the table of propsfor configuration.
配置见道具表。
Out of the box it takes search words instead of index ranges, but solves the same problem as in the question unless one is locked to indices. However, ifthat is the case, the findChunks
property can be given a function to arbitrarily detect parts to hightlight. (See herehow the default findChunks
is defined.)
开箱即用,它采用搜索词而不是索引范围,但解决了与问题中相同的问题,除非一个锁定到索引。但是,如果是这种情况,则findChunks
可以赋予该属性一个功能,以任意检测要突出显示的部分。(请参阅此处如何findChunks
定义默认值。)
Simple example from the description on GitHub.
GitHub 上描述的简单示例。
import React from "react";
import ReactDOM from "react-dom";
import Highlighter from "react-highlight-words";
ReactDOM.render(
<Highlighter
highlightClassName="YourHighlightClass"
searchWords={["and", "or", "the"]}
autoEscape={true}
textToHighlight="The dog is chasing the cat. Or perhaps they're just playing?"
/>,
document.getElementById("root")
);
Install with npm i --save react-highlight-words
安装 npm i --save react-highlight-words
回答by William Liwanag
Try Highlighter.js library here: https://gist.github.com/wliwanag/03d95916c7ba5d17e226
在此处尝试 Highlighter.js 库:https: //gist.github.com/wliwanag/03d95916c7ba5d17e226
It supports: Highlighting of text in child elements. Use words in a text as search key (e.g. sample below will highlight "simply", "1500" etc..)
它支持: 突出显示子元素中的文本。使用文本中的单词作为搜索键(例如,下面的示例将突出显示“简单”、“1500”等...)
To use:
使用:
var searchInput = "simply 1500 bee y";
var textSource = $("#text-container").html();
var htmlSource = $("#html-container").html();
$("#text-result").html(highlightHtml(textSource, searchInput));
$("#html-result").html(highlightHtml(htmlSource, searchInput));
回答by bgun
If you only want the specific text between start/end replaced (instead of every occurrence), it would look something like this:
如果您只想替换开始/结束之间的特定文本(而不是每次出现),它看起来像这样:
function(element, start, end) {
textToHilight = element.innerHTML.substr(start, end);
element.innerHTML = element.innerHTML.substring(0, start) + "<span class='hilight'>" + textToHilight + "</span>" + element.innerHTML.substring(end);
}