什么是一种足够好的方法来编写实时文本搜索和突出显示功能,而不会破坏文本和元素节点的顺序



我使用以下代码来突出显示div中的文本;a"img";否则,它将破坏html输出、图像并破坏网站。

if ($('#block-multiblock-2 input').val().length !== 0) {
$('.group-informacie .field-name-body p').each(function() {
//Handle special characters used in regex
var searchregexp = new RegExp($("#block-multiblock-2 input").val().replace(/[.*+?^${}()|[]\]/g, '\$&'), "gi");
//$& will maintain uppercase and lowercase characters.
$(this).html($(this).html().replace(searchregexp, "<span class='highlight'>$&</span>"));
});
}

我认为问题在于RegExp,它必须以某种方式排除html标记?我尝试插入<gt;我在其他问题中发现了一些角色,但实际上什么都不起作用。

我试图在用户/ceditor保存的文本中进行jquery搜索,其输出有时类似于:

<p><img src="..."/>Some super text <i>here</></p>

因此,它可以包含任何html输出、标题、div、手风琴等。

此方法存储原始元素节点的副本(初始状态(,其中文本搜索和突出显示

随着相关搜索字段的输入值的每次更改,将触发一个全新的搜索过程,并可能在原始元素节点的另一个(始终是新的(副本内进行匹配/突出显示。

每个过程都从收集所有有效的文本节点开始。然后,每个文本节点的textContent通过正则表达式获得split,该正则表达式是根据相关搜索字段的当前输入值创建的。

然后,生成的数组通过(聚合(渲染过程获得reduced,该过程创建高亮显示元素或纯文本节点,同时替换最近/以前处理的节点或附加到后者。。。

// node detection helpers.
function isElementNode(node) {
return (node && (node.nodeType === 1));
}
function isNonEmptyTextNode(node) {
return (
node
&& (node.nodeType === 3)
&& (node.nodeValue.trim() !== '')
&& (node.parentNode.tagName.toLowerCase() !== 'script')
);
}
// dom node render helper.
function insertNodeAfter(node, referenceNode) {
const { parentNode, nextSibling } = referenceNode;
if (nextSibling !== null) {
node = parentNode.insertBefore(node, nextSibling);
} else {
node = parentNode.appendChild(node);
}
return node;
}
// text node reducer functionality.
function collectNonEmptyTextNode(list, node) {
if (isNonEmptyTextNode(node)) {
list.push(node);
}
return list;
}
function collectTextNodeList(list, elmNode) {
return Array.from(
elmNode.childNodes
).reduce(
collectNonEmptyTextNode,
list
);
}
function getTextNodeList(rootNode) {
rootNode = (isElementNode(rootNode) && rootNode) || document.body;
const elementNodeList = Array.from(
rootNode.getElementsByTagName('*')
);
elementNodeList.unshift(rootNode);
return elementNodeList.reduce(collectTextNodeList, []);
}
// highlight functinality.
function createSearchMatch(text) {
const elmMatch = document.createElement('mark');
// elmMatch.classList.add("highlight");
elmMatch.textContent = text;
return elmMatch;
}
function aggregateSearchResult(collector, text, idx, arr) {
const { previousNode, regXSearch } = collector;
const currentNode = regXSearch.test(text)
? createSearchMatch(text)
: document.createTextNode(text);
if (idx === 0) {
previousNode.parentNode.replaceChild(currentNode, previousNode);
} else {
insertNodeAfter(currentNode, previousNode);
}
collector.previousNode = currentNode;
return collector;
}
function highlightSearch(textNode, regXSearch) {
// console.log(regXSearch);
textNode.textContent
.split(regXSearch)
.filter(text => text !== '')
.reduce(aggregateSearchResult, {
previousNode: textNode,
regXSearch,
})
}
function highlightSearchFromBoundContext(/* evt */) {
const { elmSearch, sourceNode, targetNode } = this;
const replacementNode = sourceNode.cloneNode(true);
const searchValue = elmSearch.value.trim();
if (searchValue !== '') {
const regXSearchString = searchValue
// from the OP's original code ... escaping of regex specific characters.
.replace((/[.*+?^${}()|[]\]/g), '\$&')
// additional escaping of whitespace (sequences).
.replace((/s+/g), '\s+');
const regXSearch = RegExp(`(${ regXSearchString })`, 'gi');
getTextNodeList(replacementNode).forEach(textNode =>
highlightSearch(textNode, regXSearch)
);
}
targetNode.parentNode.replaceChild(replacementNode, targetNode);
this.targetNode = replacementNode;
}
// initialize search behavior
function initializeSearchAndHighlight() {
const elmSearch = document
.querySelector('#block-multiblock-2 input[type="search"]');
const elmHighlight = elmSearch && document
.querySelector('.group-informacie .field-name-body');
if (elmHighlight && (elmHighlight.textContent.trim() !== '')) {
const handleChangeEvent = highlightSearchFromBoundContext.bind({
elmSearch,
targetNode: elmHighlight,
sourceNode: elmHighlight.cloneNode(true),
});
const handleChangeEventThrottled = _.throttle(handleChangeEvent, 200);
elmSearch.addEventListener('input', handleChangeEventThrottled);

handleChangeEvent();
}
}
initializeSearchAndHighlight();
p { margin: 7px 0 0 0; }
/*
.as-console-wrapper { max-height: 67px!important; }
*/
<label id="block-multiblock-2">
<span class="label">Highlight search ...</span>
<input
type="search"
placeholder="... type some text"
value="dolor     (sit)     amet"
/>
</label>
<article class="group-informacie">
<section class="field-name-body">
<p>
Lorem ipsum dolor (sit) amet, consetetur sadipscing elitr, ??sed?? diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam [erat], sed diam voluptua.
</p>
<p>
At vero [eos] et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, (no) **sea** takimata sanctus est Lorem ipsum dolor [sit] amet.
</p>
<p>
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<p>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
</p>
</section>
</article>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

促销

我最近回答了一些相关的搜索和突出显示答案,这些答案可能有助于将这种方法与类似问题进行比较。。。

  • 如何在html文档中突出显示文本查询的搜索结果,忽略html标记
  • 如何从DOM中查询文本节点,找到标记模式,用HTML标记替换匹配项,并用新内容替换原始文本节点

最新更新