Đánh dấu một từ với jQuery


101

Về cơ bản, tôi cần đánh dấu một từ cụ thể trong một khối văn bản. Ví dụ: giả sử tôi muốn đánh dấu từ "dolor" trong văn bản này:

<p>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer dolor ullamcorper libero.
    Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

Làm cách nào để chuyển đổi ở trên thành một thứ như thế này:

<p>
    Lorem ipsum <span class="myClass">dolor</span> sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer <span class="myClass">dolor</span> ullamcorper
    libero. Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

Điều này có khả thi với jQuery không?

Chỉnh sửa : Như Sebastian đã chỉ ra , điều này hoàn toàn có thể xảy ra nếu không có jQuery - nhưng tôi hy vọng có thể có một phương thức jQuery đặc biệt cho phép bạn thực hiện các bộ chọn trên chính văn bản. Tôi đã sử dụng jQuery rất nhiều trên trang web này, vì vậy giữ mọi thứ được gói gọn trong jQuery sẽ giúp mọi thứ gọn gàng hơn một chút.


Điều này cũng có thể được quan tâm: jquery.info/The-plugin-SearchHighlight
Eikern 23/09/08

Này, tôi đã viết một plugin thực hiện chính xác điều này - nó giống như plugin Johann Burkard mà mlarsen đã đăng, nhưng hoạt động với biểu thức chính quy thay vì chuỗi. Hãy kiểm tra trên github và vui lòng cho tôi biết nếu bạn cần thêm các tính năng khác.

3
Trong trường hợp bạn cần một phiên bản khoan dung của plugin đánh dấu jQuery: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör

1
Thay vì tô sáng các từ bằng a <span>, cách sử dụng sẽ đúng hơn <mark>, nói theo ngữ nghĩa.
Jose Rui Santos

Xin chào, tôi lên máy bay muộn nhưng đây là một đoạn mã khác giúp đánh dấu và lọc văn bản dựa trên thẻ. Hy vọng rằng sẽ giúp đỡ một ai đó jQuery Plugin for nổi bật văn bản và Filtering
Jaspreet Chahal

Câu trả lời:


85

Thử đánh dấu: plugin jQuery làm nổi bật văn bản JavaScript .! Cảnh báo - Mã nguồn có sẵn trên trang này chứa tập lệnh khai thác tiền điện tử, hãy sử dụng mã bên dưới hoặc xóa tập lệnh khai thác khỏi bản tải xuống trên trang web. !

/*

highlight v4

Highlights arbitrary terms.

<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>

MIT license.

Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>

*/

jQuery.fn.highlight = function(pat) {
 function innerHighlight(node, pat) {
  var skip = 0;
  if (node.nodeType == 3) {
   var pos = node.data.toUpperCase().indexOf(pat);
   if (pos >= 0) {
    var spannode = document.createElement('span');
    spannode.className = 'highlight';
    var middlebit = node.splitText(pos);
    var endbit = middlebit.splitText(pat.length);
    var middleclone = middlebit.cloneNode(true);
    spannode.appendChild(middleclone);
    middlebit.parentNode.replaceChild(spannode, middlebit);
    skip = 1;
   }
  }
  else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
   for (var i = 0; i < node.childNodes.length; ++i) {
    i += innerHighlight(node.childNodes[i], pat);
   }
  }
  return skip;
 }
 return this.length && pat && pat.length ? this.each(function() {
  innerHighlight(this, pat.toUpperCase());
 }) : this;
};

jQuery.fn.removeHighlight = function() {
 return this.find("span.highlight").each(function() {
  this.parentNode.firstChild.nodeName;
  with (this.parentNode) {
   replaceChild(this.firstChild, this);
   normalize();
  }
 }).end();
};

Cũng thử phiên bản "cập nhật" của tập lệnh gốc .

/*
 * jQuery Highlight plugin
 *
 * Based on highlight v3 by Johann Burkard
 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
 *
 * Code a little bit refactored and cleaned (in my humble opinion).
 * Most important changes:
 *  - has an option to highlight only entire words (wordsOnly - false by default),
 *  - has an option to be case sensitive (caseSensitive - false by default)
 *  - highlight element tag and class names can be specified in options
 *
 * Usage:
 *   // wrap every occurrance of text 'lorem' in content
 *   // with <span class='highlight'> (default options)
 *   $('#content').highlight('lorem');
 *
 *   // search for and highlight more terms at once
 *   // so you can save some time on traversing DOM
 *   $('#content').highlight(['lorem', 'ipsum']);
 *   $('#content').highlight('lorem ipsum');
 *
 *   // search only for entire word 'lorem'
 *   $('#content').highlight('lorem', { wordsOnly: true });
 *
 *   // don't ignore case during search of term 'lorem'
 *   $('#content').highlight('lorem', { caseSensitive: true });
 *
 *   // wrap every occurrance of term 'ipsum' in content
 *   // with <em class='important'>
 *   $('#content').highlight('ipsum', { element: 'em', className: 'important' });
 *
 *   // remove default highlight
 *   $('#content').unhighlight();
 *
 *   // remove custom highlight
 *   $('#content').unhighlight({ element: 'em', className: 'important' });
 *
 *
 * Copyright (c) 2009 Bartek Szopka
 *
 * Licensed under MIT license.
 *
 */

jQuery.extend({
    highlight: function (node, re, nodeName, className) {
        if (node.nodeType === 3) {
            var match = node.data.match(re);
            if (match) {
                var highlight = document.createElement(nodeName || 'span');
                highlight.className = className || 'highlight';
                var wordNode = node.splitText(match.index);
                wordNode.splitText(match[0].length);
                var wordClone = wordNode.cloneNode(true);
                highlight.appendChild(wordClone);
                wordNode.parentNode.replaceChild(highlight, wordNode);
                return 1; //skip added node in parent
            }
        } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
            for (var i = 0; i < node.childNodes.length; i++) {
                i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
            }
        }
        return 0;
    }
});

jQuery.fn.unhighlight = function (options) {
    var settings = { className: 'highlight', element: 'span' };
    jQuery.extend(settings, options);

    return this.find(settings.element + "." + settings.className).each(function () {
        var parent = this.parentNode;
        parent.replaceChild(this.firstChild, this);
        parent.normalize();
    }).end();
};

jQuery.fn.highlight = function (words, options) {
    var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
    jQuery.extend(settings, options);

    if (words.constructor === String) {
        words = [words];
    }
    words = jQuery.grep(words, function(word, i){
      return word != '';
    });
    words = jQuery.map(words, function(word, i) {
      return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    });
    if (words.length == 0) { return this; };

    var flag = settings.caseSensitive ? "" : "i";
    var pattern = "(" + words.join("|") + ")";
    if (settings.wordsOnly) {
        pattern = "\\b" + pattern + "\\b";
    }
    var re = new RegExp(pattern, flag);

    return this.each(function () {
        jQuery.highlight(this, re, settings.element, settings.className);
    });
};

Có hai giải pháp và chúng được chứa trong một tệp. Tôi đã thêm chúng ở trên. Ít nhất, trong trường hợp xấu nhất, chúng sẽ luôn có sẵn ở đây trong lịch sử chỉnh sửa.
Erick Robertson

highlight v4 bị lỗi một chút. Có một bản sửa lỗi trên trang chủ của Burkard: johannburkard.de/blog/programming/javascript/… Trong trường hợp này, không nên sao chép mã ở đây; liên kết trỏ đến phiên bản mới nhất (bây giờ :)).
Lerin Sonberg

Nhân tiện, thẻ <mark> -tag có lẽ tốt hơn thẻ <span> ở đây.
unitario

1
Nếu bạn đang tìm kiếm nhỏ và nhẹ, plugin jquery nổi bật thực sự là lựa chọn tốt nhất của bạn. Nó tuyệt vời trong việc đánh dấu và xóa vùng sáng phù hợp với văn bản nhất định. Nếu bạn cần biểu thức chính quy hoặc hỗ trợ khác; tuy nhiên, hãy kiểm tra mark.js hoặc bất kỳ phần mở rộng và fork nào cho phần đánh dấu được liên kết đến từ trang đánh dấu. Tôi sử dụng highlight cho bản thân hơn những người khác vì tính năng nhẹ được đánh giá cao.
Greg

3
QUAN TRỌNG: Johann Burkard đã đưa một tập lệnh khai thác vào nguồn được cung cấp trên trang web của anh ấy !!!!!!
Lukars

42
function hiliter(word, element) {
    var rgxp = new RegExp(word, 'g');
    var repl = '<span class="myClass">' + word + '</span>';
    element.innerHTML = element.innerHTML.replace(rgxp, repl);
}
hiliter('dolor');

2
Bạn không muốn sử dụng innerHTML vì nó đã được Microsoft giới thiệu vào những năm 80 và sau đó lại bị Microsoft loại bỏ như thường lệ. Mặc dù hầu hết các trình duyệt đều hỗ trợ nó, nhưng nó là tất cả mọi thứ ngoại trừ W3C standart.
Steve K

21
Bạn nên sử dụng cái gì thay vì innerHTML?
Kebman

15
@Sir Ben Benji: Tôi nghĩ rằng bạn đang nhầm lẫn giữa innerHTML với innerText (giải pháp thay thế do Microsoft phát triển cho textContent, thực sự không phù hợp với thông số kỹ thuật). innerHTML có thể đã bắt đầu như một tiện ích mở rộng của Microsoft nhưng không có cách nào bị "bỏ"; nó được hỗ trợ bởi mọi trình duyệt chính kể từ đầu những năm 2000 và là một phần của HTML5 (đầu năm 2008): w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml Nó vẫn có mặt trong phiên bản mới nhất sửa đổi tại w3.org/TR/DOM-Parsing . Xem thêm w3.org/TR/html5/references.html#refsDOMPARSING
Jay Dansand

1
Không phải là một giải pháp thực sự tốt. Tôi vừa mới sử dụng cái này nhưng nếu tôi tìm kiếm ví dụ 'person', nó cũng thay thế tất cả các lớp và phần tử html bằng 'person' trong đó. Và chữ thường và chữ hoa cũng không được tích hợp. var rgxp = new RegExp ("(\\ b" + word + "\\ b)", "gim"); đã sửa điều đó nhưng vẫn còn, tôi nghĩ mã không nên thay thế các phần tử html.
Richard Lindhout

32

Tại sao sử dụng chức năng đánh dấu tự tạo là một ý tưởng tồi

Lý do tại sao có lẽ là một ý tưởng tồi nếu bắt đầu xây dựng chức năng đánh dấu của riêng bạn từ đầu là vì bạn chắc chắn sẽ gặp phải những vấn đề mà người khác đã giải quyết. Những thách thức:

  • Bạn sẽ cần phải xóa các nút văn bản có các phần tử HTML để làm nổi bật các kết quả phù hợp của mình mà không phá hủy các sự kiện DOM và kích hoạt tái tạo DOM lặp đi lặp lại (ví dụ như trường hợp này innerHTML)
  • Nếu bạn muốn xóa các phần tử được đánh dấu, bạn sẽ phải xóa các phần tử HTML cùng với nội dung của chúng và cũng phải kết hợp các nút văn bản đã tách để tìm kiếm thêm. Điều này là cần thiết vì mọi plugin đánh dấu đều tìm kiếm bên trong các nút văn bản để tìm các kết quả phù hợp và nếu từ khóa của bạn sẽ được chia thành nhiều nút văn bản thì chúng sẽ không được tìm thấy.
  • Bạn cũng sẽ cần xây dựng các bài kiểm tra để đảm bảo plugin của bạn hoạt động trong các tình huống mà bạn chưa nghĩ đến. Và tôi đang nói về các bài kiểm tra trên nhiều trình duyệt!

Nghe có vẻ phức tạp? Nếu bạn muốn một số tính năng như bỏ qua một số yếu tố khỏi đánh dấu, ánh xạ dấu phụ, ánh xạ từ đồng nghĩa, tìm kiếm bên trong iframe, tìm kiếm từ được phân tách, v.v. thì điều này càng trở nên phức tạp hơn.

Sử dụng một plugin hiện có

Khi sử dụng một plugin hiện có, được triển khai tốt, bạn không phải lo lắng về những thứ đã nêu ở trên. Bài viết 10 plugin đánh dấu văn bản jQuery trên Sitepoint sẽ so sánh các plugin highlighter phổ biến. Điều này bao gồm các phần bổ trợ của câu trả lời từ câu hỏi này.

Hãy xem mark.js

mark.js là một plugin được viết bằng JavaScript thuần túy, nhưng cũng có sẵn dưới dạng plugin jQuery. Nó được phát triển để cung cấp nhiều cơ hội hơn các plugin khác với các tùy chọn:

  • tìm kiếm các từ khóa riêng lẻ thay vì cụm từ hoàn chỉnh
  • dấu phụ trên bản đồ (Ví dụ: nếu "justo" cũng phải khớp với "justò")
  • bỏ qua các kết quả phù hợp bên trong các phần tử tùy chỉnh
  • sử dụng phần tử tô sáng tùy chỉnh
  • sử dụng lớp đánh dấu tùy chỉnh
  • từ đồng nghĩa tùy chỉnh bản đồ
  • cũng tìm kiếm bên trong iframe
  • nhận các điều khoản không tìm thấy

BẢN GIỚI THIỆU

Ngoài ra, bạn có thể xem trò chơi này .

Ví dụ sử dụng :

// Highlight "keyword" in the specified context
$(".context").mark("keyword");

// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);

Nó miễn phí và được phát triển mã nguồn mở trên GitHub ( tham khảo dự án ).


11

Đây là một biến thể bỏ qua và giữ nguyên trường hợp:

jQuery.fn.highlight = function (str, className) {
    var regex = new RegExp("\\b"+str+"\\b", "gi");

    return this.each(function () {
        this.innerHTML = this.innerHTML.replace(regex, function(matched) {return "<span class=\"" + className + "\">" + matched + "</span>";});
    });
};

6
Điều này hoạt động đối với văn bản thuần túy, nhưng nó dường như không loại trừ các thẻ và thuộc tính. tức là Tìm kiếm "lass" khi bạn có thuộc tính lớp trên div trong innerHTML của mình.
Jonathan

Hàm này được gọi như thế nào?
jiy

innerHTMLlà ác, xem câu trả lời của tôi ở đây. Ngoài ra, \\bkhông hoạt động cho các ký tự unicode. Hơn nữa, chức năng này bỏ sót hầu hết mọi thứ, ví dụ như tìm kiếm bên trong các phần tử con lồng nhau.
dude

3

Bạn có thể sử dụng chức năng sau để đánh dấu bất kỳ từ nào trong văn bản của mình.

function color_word(text_id, word, color) {
    words = $('#' + text_id).text().split(' ');
    words = words.map(function(item) { return item == word ? "<span style='color: " + color + "'>" + word + '</span>' : item });
    new_words = words.join(' ');
    $('#' + text_id).html(new_words);
    }

Đơn giản chỉ cần nhắm mục tiêu phần tử chứa văn bản, chọn từ để tô màu và màu tùy chọn.

Đây là một ví dụ :

<div id='my_words'>
This is some text to show that it is possible to color a specific word inside a body of text. The idea is to convert the text into an array using the split function, then iterate over each word until the word of interest is identified. Once found, the word of interest can be colored by replacing that element with a span around the word. Finally, replacing the text with jQuery's html() function will produce the desired result.
</div>

Cách sử dụng ,

color_word('my_words', 'possible', 'hotpink')

nhập mô tả hình ảnh ở đây

Azle cũng có một chức năng hay cho việc này. Nó sử dụng các lớp vì vậy chỉ cần gán tên lớp cho bất kỳ khối văn bản nào bạn muốn nhắm mục tiêu.

az.style_word("target_class", target_instance, {
     "this_class" : "pink_word",
     "word" : "possible", // list any CSS styling after this line ...
     "color" : "hotpink", 
     "font-weight" : "bold"
})

2

Bạn có thể sử dụng plugin đánh dấu jQuiteLight của tôi, plugin này cũng có thể hoạt động với các biểu thức chính quy.

Để cài đặt bằng kiểu npm :

npm install jquitelight --save

Để cài đặt bằng kiểu bower :

bower install jquitelight 

Sử dụng:

// for strings
$(".element").mark("query here");
// for RegExp
$(".element").mark(new RegExp(/query h[a-z]+/));

Cách sử dụng nâng cao hơn tại đây


@ user3631654 không, đó là một plugin khác. Plugin của tôi có thể hoạt động với RegExp và có tính năng đánh dấu thông minh. Nếu bạn đã bao gồm Plugin bạn đã đề cập trước đây plugin này, bạn có thể lấy nó sử dụngvar oldMark = $.fn.mark.noConflict()
iamawebgeek

Có vẻ như jquery.mark cũng có một phương thức markRegExp()để đánh dấu các biểu thức chính quy tùy chỉnh. Vì vậy, đây không phải là một cuộc tranh cãi.
user3631654

Còn @zazu, ý bạn là gì với "điểm nhấn thông minh"?
user3631654

@ user3631654 nếu bạn bật tính năng đánh dấu thông minh và chuyển từ "hệ quả", nó cũng sẽ đánh dấu từ "hậu quả" và các dạng khác của từ đó, nhưng nếu bạn chuyển "the" hoặc "bla", nó sẽ không nhận "chủ đề" hoặc "đen"
iamawebgeek,

2

JSFiddle

Sử dụng .each (), .replace (), .html (). Đã thử nghiệm với jQuery 1.11 và 3.2.

Trong ví dụ trên, đọc 'từ khóa' cần đánh dấu và nối thẻ span với lớp 'đánh dấu'. Văn bản 'từ khóa' được đánh dấu cho tất cả các lớp đã chọn trong .each ().

HTML

<body>
   <label name="lblKeyword" id="lblKeyword" class="highlight">keyword</label>
   <p class="filename">keyword</p>
   <p class="content">keyword</p>
   <p class="system"><i>keyword</i></p>
</body>

JS

$(document).ready(function() {
   var keyWord = $("#lblKeyword").text(); 
   var replaceD = "<span class='highlight'>" + keyWord + "</span>";
   $(".system, .filename, .content").each(function() {
      var text = $(this).text();
      text = text.replace(keyWord, replaceD);
      $(this).html(text);
   });
});

CSS

.highlight {
    background-color: yellow;
}

1

Bạn cần lấy nội dung của thẻ p và thay thế tất cả các phần dolors trong đó bằng phiên bản được đánh dấu.

Bạn thậm chí không cần phải có jQuery cho việc này. :-)


9
Nhưng nó dễ dàng hơn với jQuery, phải không? ;)
Eikern

7
nó có thể được thực hiện với nokia 6310, bạn thậm chí không cần phải có máy tính cho điều này :-)
okliv

1

Tôi đã viết một hàm rất đơn giản sử dụng jQuery để lặp lại các phần tử bao bọc mỗi từ khóa bằng một lớp .highlight.

function highlight_words(word, element) {
    if(word) {
        var textNodes;
        word = word.replace(/\W/g, '');
        var str = word.split(" ");
        $(str).each(function() {
            var term = this;
            var textNodes = $(element).contents().filter(function() { return this.nodeType === 3 });
            textNodes.each(function() {
              var content = $(this).text();
              var regex = new RegExp(term, "gi");
              content = content.replace(regex, '<span class="highlight">' + term + '</span>');
              $(this).replaceWith(content);
            });
        });
    }
}

Thêm thông tin:

http://www.hawkee.com/snippet/9854/


2
Tính năng này không tìm kiếm trong các phần tử lồng nhau, không có chức năng xóa các điểm nổi bật và không có thông tin giấy phép.
anh bạn

Bạn có phiền giải thích cho tôi biết 'gi' trong "new RegExp (thuật ngữ," gi ")" là gì không?
vuquanghoang

0

Tôi đã tạo một kho lưu trữ về khái niệm tương tự để thay đổi màu sắc của văn bản có màu được html5 nhận dạng (chúng tôi không phải sử dụng các giá trị #rrggbb thực tế và chỉ có thể sử dụng các tên như html5 đã chuẩn hóa khoảng 140 trong số đó)

color.js color.js

$( document ).ready(function() {
	
	function hiliter(word, element) {
		var rgxp = new RegExp("\\b" + word + "\\b" , 'gi'); // g modifier for global and i for case insensitive 
		var repl = '<span class="myClass">' + word + '</span>';
		element.innerHTML = element.innerHTML.replace(rgxp, repl);
			
			};

	hiliter('dolor', document.getElementById('dolor'));
});
.myClass{

background-color:red;
}
<!DOCTYPE html>
<html>
	<head>
		<title>highlight</title>
		
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
	
		 <link href="main.css" type="text/css"  rel="stylesheet"/>
		 
	</head>
	<body id='dolor'>
<p >
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer dolor ullamcorper libero.
    Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>
 <script type="text/javascript" src="main.js" charset="utf-8"></script>
	</body>
</html>


-2

Có thể lấy ví dụ trên không:

jQuery.fn.highlight = function (str, className)
{
    var regex = new RegExp(str, "g");

    return this.each(function ()
    {
        this.innerHTML = this.innerHTML.replace(
            regex,
            "<span class=\"" + className + "\">" + str + "</span>"
        );
    });
};

không thay thế văn bản bên trong các thẻ html như, điều này nếu không sẽ phá vỡ trang.


-2
$(function () {
    $("#txtSearch").keyup(function (event) {
        var txt = $("#txtSearch").val()
        if (txt.length > 3) {
            $("span.hilightable").each(function (i, v) {
                v.innerHTML = v.innerText.replace(txt, "<hilight>" + txt + "</hilight>");
            });

        }
    });
});

Jfiddle đây


hilightlà không có yếu tố HTML hợp lệ
user3631654

Chỉ cần bỏ qua cảnh báo này, <hilight> là phần tử tùy chỉnh của bạn, bạn có thể viết bất cứ thứ gì bạn muốn. Bạn đã thấy trò chơi chưa?
L.Grillo

@nickf kịch bản của tôi làm chính xác những điều tương tự của câu trả lời được chấp nhận
L.Grillo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.