Cara menyorot teks menggunakan javascript


98

Dapatkah seseorang membantu saya dengan fungsi javascript yang dapat menyorot teks pada halaman web. Dan persyaratannya adalah - menyorot hanya sekali, tidak seperti menyorot semua kemunculan teks seperti yang kita lakukan dalam kasus pencarian.


4
Jika Anda memposting kode fungsi, kami akan dapat membantu. Jika Anda meminta kami untuk membuatkan fungsi seperti itu untuk Anda ... kemungkinannya kecil. Anda harus melakukan sesuatu sendiri. Mulailah melakukan sesuatu dan kembali saat Anda mengalami kebuntuan.
Felix Kling

7
YE Saya telah membaca Cara Meminta & Saya telah melakukan sesuatu sendiri tetapi saya mengalami kebuntuan dan itulah mengapa saya bertanya. Saya bekerja di Android dan memiliki sedikit pengetahuan tentang javasript, itulah sebabnya saya tidak dapat melakukannya sendiri. Sebelumnya saya menggunakan javascript berbeda yang melakukan pekerjaan itu tetapi bukan tanpa batasan tertentu. Saya mungkin tidak menggunakan kata-kata yang tepat saat menanyakan pertanyaan ini dan saya minta maaf untuk itu tetapi tolong jangan memikirkan sebaliknya.
Ankit

1
Plugin ini mungkin menarik bagi Anda: github.com/julmot/jmHighlight . Ini dapat menyoroti kata kunci secara terpisah atau sebagai istilah, dapat menyorot kecocokan dengan elemen khusus dan nama kelas Anda dan juga dapat mencari diakritik. Di atas itu memungkinkan Anda untuk memfilter konteks untuk mencari kecocokan.
Bung

1
Checkout mengikuti cara regex ... stackoverflow.com/a/45519242/2792959

Saya menyiapkan artikel tentang itu di sini, exhesham.com/2017/11/20/…
Hesham Yassin

Jawaban:


101

Anda dapat menggunakan efek sorotan jquery .

Tetapi jika Anda tertarik dengan kode javascript mentah, lihat apa yang saya dapatkan. Cukup salin tempel ke HTML, buka file dan klik "sorot" - ini akan menyorot kata "rubah". Dari segi kinerja, saya pikir ini akan dilakukan untuk teks kecil dan satu pengulangan (seperti yang Anda tentukan)

function highlight(text) {
  var inputText = document.getElementById("inputText");
  var innerHTML = inputText.innerHTML;
  var index = innerHTML.indexOf(text);
  if (index >= 0) { 
   innerHTML = innerHTML.substring(0,index) + "<span class='highlight'>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length);
   inputText.innerHTML = innerHTML;
  }
}
.highlight {
  background-color: yellow;
}
<button onclick="highlight('fox')">Highlight</button>

<div id="inputText">
  The fox went over the fence
</div>

Editan:

Menggunakan replace

Saya melihat jawaban ini mendapatkan popularitas, saya pikir saya bisa menambahkannya. Anda juga dapat dengan mudah menggunakan ganti

"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

Atau untuk beberapa kemunculan (tidak relevan untuk pertanyaan, tetapi diminta dalam komentar) Anda cukup menambahkan globalganti ekspresi reguler.

"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

Semoga ini membantu untuk komentator yang tertarik.

Mengganti HTML ke seluruh halaman web

untuk mengganti HTML untuk seluruh halaman web, Anda harus merujuk ke innerHTMLbadan dokumen.

document.body.innerHTML


Terima kasih banyak atas balasan Anda, tetapi dapatkah Anda juga memberi tahu saya cara menentukan warna di javascript itu sendiri
Ankit

Anda dapat mengganti "<span class='highlight'>"dengan "<span style='color: " + color + ";'>", warna harus sepertivar color = "#ff0000";
Yaniro

bagaimana jika saya ingin menyorot semua kemunculan sebuah kata di seluruh halaman? @guy mograbi
Baqer Naqvi

4
Menggunakan "ganti" sederhana adalah ide yang buruk . Saya telah menjelaskan alasannya di sini: stackoverflow.com/a/32758672/3894981
Bung

2
Ini bukan ide yang bagus karena ini akan mencoba menyorot tag / atribut / dll HTML. Misalnya, apa yang akan terjadi jika: <img src="fox.jpg" /> Anda akan mendapatkan HTML yang tidak valid yang akan terlihat seperti ini: <img src="<span class='highlight'>fox</span>.jpg" /> Tidak bagus
dcporter7

47

Solusi yang ditawarkan di sini cukup buruk.

  1. Anda tidak dapat menggunakan regex, karena dengan cara itu, Anda mencari / menyorot di tag html.
  2. Anda tidak dapat menggunakan regex, karena tidak berfungsi dengan baik dengan UTF * (apa pun dengan karakter non-latin / Inggris).
  3. Anda tidak bisa hanya melakukan innerHTML.replace, karena ini tidak berfungsi ketika karakter memiliki notasi HTML khusus, misalnya &amp;untuk &, &lt;untuk <, &gt;untuk>, &auml;untuk ä, &ouml;untuk ö &uuml;untuk ü&szlig; untuk ß, dll.

Apa yang kamu butuhkan:

Ulangi dokumen HTML, temukan semua node teks, dapatkan textContent, dapatkan posisi teks sorotan dengan indexOf(dengan opsional toLowerCasejika harus peka huruf besar-kecil), tambahkan semuanya sebelumnya indexofsebagai textNode, tambahkan Teks yang cocok dengan rentang sorotan, dan ulangi untuk sisa kode teks (string sorotan mungkin muncul beberapa kali dalam textContentstring).

Ini kode untuk ini:

var InstantSearch = {

    "highlight": function (container, highlightText)
    {
        var internalHighlighter = function (options)
        {

            var id = {
                container: "container",
                tokens: "tokens",
                all: "all",
                token: "token",
                className: "className",
                sensitiveSearch: "sensitiveSearch"
            },
            tokens = options[id.tokens],
            allClassName = options[id.all][id.className],
            allSensitiveSearch = options[id.all][id.sensitiveSearch];


            function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll)
            {
                var nodeVal = node.nodeValue, parentNode = node.parentNode,
                    i, j, curToken, myToken, myClassName, mySensitiveSearch,
                    finalClassName, finalSensitiveSearch,
                    foundIndex, begin, matched, end,
                    textNode, span, isFirst;

                for (i = 0, j = tokenArr.length; i < j; i++)
                {
                    curToken = tokenArr[i];
                    myToken = curToken[id.token];
                    myClassName = curToken[id.className];
                    mySensitiveSearch = curToken[id.sensitiveSearch];

                    finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName);

                    finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch);

                    isFirst = true;
                    while (true)
                    {
                        if (finalSensitiveSearch)
                            foundIndex = nodeVal.indexOf(myToken);
                        else
                            foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase());

                        if (foundIndex < 0)
                        {
                            if (isFirst)
                                break;

                            if (nodeVal)
                            {
                                textNode = document.createTextNode(nodeVal);
                                parentNode.insertBefore(textNode, node);
                            } // End if (nodeVal)

                            parentNode.removeChild(node);
                            break;
                        } // End if (foundIndex < 0)

                        isFirst = false;


                        begin = nodeVal.substring(0, foundIndex);
                        matched = nodeVal.substr(foundIndex, myToken.length);

                        if (begin)
                        {
                            textNode = document.createTextNode(begin);
                            parentNode.insertBefore(textNode, node);
                        } // End if (begin)

                        span = document.createElement("span");
                        span.className += finalClassName;
                        span.appendChild(document.createTextNode(matched));
                        parentNode.insertBefore(span, node);

                        nodeVal = nodeVal.substring(foundIndex + myToken.length);
                    } // Whend

                } // Next i 
            }; // End Function checkAndReplace 

            function iterator(p)
            {
                if (p === null) return;

                var children = Array.prototype.slice.call(p.childNodes), i, cur;

                if (children.length)
                {
                    for (i = 0; i < children.length; i++)
                    {
                        cur = children[i];
                        if (cur.nodeType === 3)
                        {
                            checkAndReplace(cur, tokens, allClassName, allSensitiveSearch);
                        }
                        else if (cur.nodeType === 1)
                        {
                            iterator(cur);
                        }
                    }
                }
            }; // End Function iterator

            iterator(options[id.container]);
        } // End Function highlighter
        ;


        internalHighlighter(
            {
                container: container
                , all:
                    {
                        className: "highlighter"
                    }
                , tokens: [
                    {
                        token: highlightText
                        , className: "highlight"
                        , sensitiveSearch: false
                    }
                ]
            }
        ); // End Call internalHighlighter 

    } // End Function highlight

};

Kemudian Anda bisa menggunakannya seperti ini:

function TestTextHighlighting(highlightText)
{
    var container = document.getElementById("testDocument");
    InstantSearch.highlight(container, highlightText);
}

Berikut ini contoh dokumen HTML

<!DOCTYPE html>
<html>
    <head>
        <title>Example of Text Highlight</title>
        <style type="text/css" media="screen">
            .highlight{ background: #D3E18A;}
            .light{ background-color: yellow;}
        </style>
    </head>
    <body>
        <div id="testDocument">
            This is a test
            <span> This is another test</span>
            äöüÄÖÜäöüÄÖÜ
            <span>Test123&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</span>
        </div>
    </body>
</html>

Ngomong-ngomong, jika Anda mencari di database dengan LIKE,
misalnya WHERE textField LIKE CONCAT('%', @query, '%')[yang seharusnya tidak Anda lakukan, Anda harus menggunakan pencarian teks lengkap atau Lucene], maka Anda dapat keluar dari setiap karakter dengan \ dan menambahkan pernyataan-escape-SQL, dengan cara itu Anda akan menemukan karakter khusus yang merupakan ekspresi LIKE.

misalnya

WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'

dan nilai @query tidak '%completed%' tetapi'%\c\o\m\p\l\e\t\e\d%'

(diuji, berfungsi dengan SQL-Server dan PostgreSQL, dan setiap sistem RDBMS lain yang mendukung ESCAPE)


Sebuah versi skrip yang direvisi:

namespace SearchTools 
{


    export interface IToken
    {
        token: string;
        className: string;
        sensitiveSearch: boolean;
    }


    export class InstantSearch 
    {

        protected m_container: Node;
        protected m_defaultClassName: string;
        protected m_defaultCaseSensitivity: boolean;
        protected m_highlightTokens: IToken[];


        constructor(container: Node, tokens: IToken[], defaultClassName?: string, defaultCaseSensitivity?: boolean)
        {
            this.iterator = this.iterator.bind(this);
            this.checkAndReplace = this.checkAndReplace.bind(this);
            this.highlight = this.highlight.bind(this);
            this.highlightNode = this.highlightNode.bind(this);    

            this.m_container = container;
            this.m_defaultClassName = defaultClassName || "highlight";
            this.m_defaultCaseSensitivity = defaultCaseSensitivity || false;
            this.m_highlightTokens = tokens || [{
                token: "test",
                className: this.m_defaultClassName,
                sensitiveSearch: this.m_defaultCaseSensitivity
            }];
        }


        protected checkAndReplace(node: Node)
        {
            let nodeVal: string = node.nodeValue;
            let parentNode: Node = node.parentNode;
            let textNode: Text = null;

            for (let i = 0, j = this.m_highlightTokens.length; i < j; i++)
            {
                let curToken: IToken = this.m_highlightTokens[i];
                let textToHighlight: string = curToken.token;
                let highlightClassName: string = curToken.className || this.m_defaultClassName;
                let caseSensitive: boolean = curToken.sensitiveSearch || this.m_defaultCaseSensitivity;

                let isFirst: boolean = true;
                while (true)
                {
                    let foundIndex: number = caseSensitive ?
                        nodeVal.indexOf(textToHighlight)
                        : nodeVal.toLowerCase().indexOf(textToHighlight.toLowerCase());

                    if (foundIndex < 0)
                    {
                        if (isFirst)
                            break;

                        if (nodeVal)
                        {
                            textNode = document.createTextNode(nodeVal);
                            parentNode.insertBefore(textNode, node);
                        } // End if (nodeVal)

                        parentNode.removeChild(node);
                        break;
                    } // End if (foundIndex < 0)

                    isFirst = false;


                    let begin: string = nodeVal.substring(0, foundIndex);
                    let matched: string = nodeVal.substr(foundIndex, textToHighlight.length);

                    if (begin)
                    {
                        textNode = document.createTextNode(begin);
                        parentNode.insertBefore(textNode, node);
                    } // End if (begin)

                    let span: HTMLSpanElement = document.createElement("span");

                    if (!span.classList.contains(highlightClassName))
                        span.classList.add(highlightClassName);

                    span.appendChild(document.createTextNode(matched));
                    parentNode.insertBefore(span, node);

                    nodeVal = nodeVal.substring(foundIndex + textToHighlight.length);
                } // Whend

            } // Next i 

        } // End Sub checkAndReplace 


        protected iterator(p: Node)
        {
            if (p == null)
                return;

            let children: Node[] = Array.prototype.slice.call(p.childNodes);

            if (children.length)
            {
                for (let i = 0; i < children.length; i++)
                {
                    let cur: Node = children[i];

                    // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
                    if (cur.nodeType === Node.TEXT_NODE) 
                    {
                        this.checkAndReplace(cur);
                    }
                    else if (cur.nodeType === Node.ELEMENT_NODE) 
                    {
                        this.iterator(cur);
                    }
                } // Next i 

            } // End if (children.length) 

        } // End Sub iterator


        public highlightNode(n:Node)
        {
            this.iterator(n);
        } // End Sub highlight 


        public highlight()
        {
            this.iterator(this.m_container);
        } // End Sub highlight 


    } // End Class InstantSearch 


} // End Namespace SearchTools 

Pemakaian:

let searchText = document.getElementById("txtSearchText");
let searchContainer = document.body; // document.getElementById("someTable");
let highlighter = new SearchTools.InstantSearch(searchContainer, [
    {
        token: "this is the text to highlight" // searchText.value,
        className: "highlight", // this is the individual highlight class
        sensitiveSearch: false
    }
]);


// highlighter.highlight(); // this would highlight in the entire table
// foreach tr - for each td2 
highlighter.highlightNode(td2); // this highlights in the second column of table

Jawaban yang bagus .. Metodenya sepertinya berlebihan, tapi ringkas! Pasti akan tertarik untuk melakukan tes kecepatan dengan metode itu karena dalam kasus saya hasilnya dimuat secara malas ke DOM (karena BISA ada ribuan hasil), penasaran apakah metode ini akan menambahkan latensi tinggi ke pemuatan malas.
Pogrindis

5
Maaf, tapi tidak ada argumen Anda yang benar. 1. Anda benar-benar dapat menggunakan RegExp, Anda tidak boleh mencari di dalam nilai HTML tetapi nilai teks dari suatu elemen. 2. Anda benar-benar dapat menggunakan regexp dengan karakter diakritik, seperti yang diterapkan dalam mark.js . 3. Notasi HTML akan diubah menjadi karakter sebenarnya di DOM browser, jadi Anda juga benar-benar menggunakannya!
Bung

1
@tokopedia Ke 1: Yang berarti Anda perlu mengulangi setiap elemen, itulah yang saya lakukan. Kecuali jika Anda tidak peduli kehilangan pemformatan, dalam hal ini Anda dapat mencari di document.body.innerText, yang akan sangat lambat. 3. Bukan di DOM, tapi di innerText atau properti textContent dari elemen teks. Yang sekali lagi berarti Anda perlu mengulang melalui elemen teks; tidak bisa dilakukan dengan regEx AFAIK. 2: Tidak tahu mark.js, tapi saya akan menghindari semua yang melakukan jQuery.each, karena itu sangat lambat.
Stefan Steiger

1
@StefanSteiger 1. Kemudian Anda harus memperbaiki hubungan keputusan Anda, karena dikatakan bahwa kami tidak dapat mencari dengan RegExp sama sekali, yang tidak benar 2. Itu tidak menggunakan jQuery.each. Apa yang membuatmu berpikir demikian? 3. Ini tidak benar, setidaknya di Firefox. &auml;mis. akan diubah menjadi karakter sebenarnya, bahkan saat menggunakan innerHTML.
Bung

1
Hai @StefanSteiger Sebenarnya, saya menggunakan solusi Anda. Yang ini sempurna. Namun ada beberapa permasalahan seperti, Jika II memiliki P dimana terdapat dua span dan satu span memiliki data seperti Diploma MSBTE dan span kedua memiliki data 2012. Sekarang Jika string yang ingin saya soroti adalah Diploma MSBTE 2012, seluruh string ini maka saya centang ini tidak berfungsi, Jika semua yang akan dicocokkan ada dalam satu rentang maka berfungsi, tetapi jika konten teks ada dalam tag diff maka Tidak bekerja. Bisakah Anda menceritakan sesuatu tentang ini?
ganeshk

41

Mengapa menggunakan fungsi penyorotan buatan sendiri adalah ide yang buruk

Alasan mengapa mungkin ide yang buruk untuk mulai membangun fungsi penyorotan Anda sendiri dari awal adalah karena Anda pasti akan mengalami masalah yang telah diselesaikan orang lain. Tantangan:

  • Anda perlu menghapus simpul teks dengan elemen HTML untuk menyorot kecocokan Anda tanpa merusak peristiwa DOM dan memicu regenerasi DOM berulang kali (yang akan menjadi kasus dengan misalnya innerHTML)
  • Jika Anda ingin menghapus elemen yang disorot, Anda harus menghapus elemen HTML dengan kontennya dan juga harus menggabungkan node teks yang dipisahkan untuk pencarian lebih lanjut. Ini diperlukan karena setiap plugin penyorot mencari kecocokan di dalam node teks dan jika kata kunci Anda akan dipecah menjadi beberapa node teks, kata kunci tersebut tidak akan ditemukan.
  • Anda juga perlu membuat pengujian untuk memastikan plugin Anda berfungsi dalam situasi yang tidak Anda pikirkan. Dan saya berbicara tentang pengujian lintas-browser!

Kedengarannya rumit? Jika Anda menginginkan beberapa fitur seperti mengabaikan beberapa elemen dari penyorotan, pemetaan diakritik, pemetaan sinonim, pencarian di dalam iframe, pencarian kata terpisah, dll. Ini menjadi semakin rumit.

Gunakan plugin yang sudah ada

Saat menggunakan plugin yang sudah ada dan diimplementasikan dengan baik, Anda tidak perlu khawatir tentang hal-hal yang disebutkan di atas. Artikel 10 plugin penyorot teks jQuery di Sitepoint membandingkan plugin penyorot populer.

Silahkan lihat mark.js

mark.js adalah plugin semacam itu yang ditulis dalam JavaScript murni, tetapi juga tersedia sebagai plugin jQuery. Itu dikembangkan untuk menawarkan lebih banyak peluang daripada plugin lain dengan opsi untuk:

  • cari kata kunci secara terpisah, bukan istilah lengkap
  • peta diakritik (Misalnya jika "justo" juga harus cocok dengan "justò")
  • abaikan kecocokan di dalam elemen khusus
  • gunakan elemen penyorotan khusus
  • gunakan kelas penyorotan khusus
  • memetakan sinonim khusus
  • cari juga di dalam iframes
  • menerima istilah tidak ditemukan

DEMO

Atau Anda bisa melihat biola ini .

Contoh penggunaan :

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

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

Ini gratis dan dikembangkan sebagai sumber terbuka di GitHub ( referensi proyek ).


4
Menyoroti teks saja bukanlah alasan yang cukup baik bagi saya untuk menyertakan jQuery.
Roy

10
@ Roy, aku sudah mengingat ini. Kabar baik, mulai v6.0.0 mark.js melepaskan ketergantungan jQuery dan membuatnya sekarang secara opsional untuk menggunakannya sebagai plugin jQuery.
Bung

Semua benar, kecuali: Poin pertama tidak mungkin, karena Anda tidak bisa mendapatkan penangan kejadian terdaftar, dan bahkan jika Anda bisa, Anda tidak dapat menyetel fungsi anonim ... 2nd: mark.js juga tidak menemukan teks di antara dua tag, mis. <span> s </span> tidak akan menemukan ... ke-3: setiap kali ada browser (termasuk versi baru) yang belum Anda uji, browser itu mungkin rusak. Itu selalu benar, tidak peduli berapa banyak tes yang Anda tulis. Pada 17kb, nilai terlalu besar untuk apa yang dilakukannya.
Stefan Steiger

Poin apa yang Anda maksud @StefanSteiger? Tidak bisa mengatakan sesuatu ke poin pertama tanpa informasi itu. Namun, komentar kedua salah, mark.js dapat menemukan kecocokan antar tag, menggunakan acrossElementsopsi. Dan untuk komentar ketiga; mark.js tidak besar dibandingkan dengan fungsionalitas yang ditawarkannya. Dan tidak, tidak mungkin ada sesuatu yang rusak di masa mendatang, karena mark.js telah diuji, misalnya memulai Chrome 30 dan di semua versi yang lebih baru dengan pengujian unit lintas-browser dan tidak pernah ada masalah dengan versi yang akan datang.
Bung

@ Bung: Tiga poin setelah paragraf pertama. Ah, oke, opsi itu hilang di demo yang saya lihat. Dalam hal ini, mungkin masuk akal. Tapi tetap saja, saya merasa terlalu besar.
Stefan Steiger

10
function stylizeHighlightedString() {

    var text = window.getSelection();

    // For diagnostics
    var start = text.anchorOffset;
    var end = text.focusOffset - text.anchorOffset;

    range = window.getSelection().getRangeAt(0);

    var selectionContents = range.extractContents();
    var span = document.createElement("span");

    span.appendChild(selectionContents);

    span.style.backgroundColor = "yellow";
    span.style.color = "black";

    range.insertNode(span);
}

3
Mohit, selamat datang di SO. Beberapa deskripsi kode akan menyenangkan!
Nippey

Bukankah seharusnya ada cara untuk memilih teks tanpa membuat node lain?
Dave Gregory

@ user191433 pertanyaannya bukan hanya tentang memilih teks, tetapi juga menerapkan gaya. Untuk itu Anda membutuhkan node.
Christophe

Pengingat / tip bahwa JavaScript span.style.backgroundColor = "yellow";diterjemahkan ke CSS style="background-color: yellow;"- perbedaan halus antara camelCase dan notasi putus-putus membuat saya tersandung pada awalnya.
MarkHu

1
Jawaban PS Mohit di stackoverflow.com/questions/7991474/… adalah varian yang lebih sederhana dari kode ini. (misalnya menghilangkan variabel awal dan akhir yang hanya bersifat diagnostik / non-fungsional di sini.)
MarkHu

7

Inilah solusi JavaScript murni regexp saya:

function highlight(text) {
    document.body.innerHTML = document.body.innerHTML.replace(
        new RegExp(text + '(?!([^<]+)?<)', 'gi'),
        '<b style="background-color:#ff0;font-size:100%">$&</b>'
    );
}

Ini bekerja dengan sempurna untuk saya ketika blok teks yang saya coba sorot berisi tag HTML.
John Chapman

Anda juga dapat mengubah fungsi untuk menerima banyak kata melalui simbol pipa regexp, misalnyaone|two|three
Klemen Tušar

Ini tidak akan menggantikan teks jika akhir teks memiliki >karakter. Ubah regex (?!([^<]+)?<)agar berfungsi.
Archie Reyes

Dimodifikasi sesuai permintaan.
Klemen Tušar

Sempurna! Ini yang terbaik untuk saya
marco burrometo

5

Saya memiliki masalah yang sama, banyak teks masuk melalui permintaan xmlhttp. Teks ini berformat html. Saya perlu menyoroti setiap kejadian.

str='<img src="brown fox.jpg" title="The brown fox" />'
    +'<p>some text containing fox.</p>'

Masalahnya adalah saya tidak perlu menyorot teks dalam tag. Misalnya saya perlu menyorot rubah:

Sekarang saya bisa menggantinya dengan:

var word="fox";
word="(\\b"+ 
    word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1")
        + "\\b)";
var r = new RegExp(word,"igm");
str.replace(r,"<span class='hl'>$1</span>")

Untuk menjawab pertanyaan Anda: Anda dapat mengabaikan g di opsi regexp dan hanya kemunculan pertama yang akan diganti tetapi ini masih yang ada di properti img src dan menghancurkan tag gambar:

<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span 
class='hl'>fox</span> />

Ini adalah cara saya menyelesaikannya tetapi bertanya-tanya apakah ada cara yang lebih baik, sesuatu yang saya lewatkan dalam ekspresi reguler:

str='<img src="brown fox.jpg" title="The brown fox" />'
    +'<p>some text containing fox.</p>'
var word="fox";
word="(\\b"+ 
    word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1")
    + "\\b)";
var r = new RegExp(word,"igm");
str.replace(/(>[^<]+<)/igm,function(a){
    return a.replace(r,"<span class='hl'>$1</span>");
});

Ini adalah satu-satunya solusi regex yang berhasil untuk saya tanpa mengotak-atik <img src="word">atau <a href="word">.
yvesmancera

1
Aturan emas: Tidak pernah. Menggunakan. Reguler. Ekspresi. Untuk. Kekacauan. Tentang. Dengan. XML.
ScottMcGready

5

Tidak ada solusi lain yang benar-benar sesuai dengan kebutuhan saya, dan meskipun solusi Stefan Steiger berfungsi seperti yang saya harapkan, saya merasa sedikit terlalu bertele-tele.

Berikut adalah usaha saya:

/**
 * Highlight keywords inside a DOM element
 * @param {string} elem Element to search for keywords in
 * @param {string[]} keywords Keywords to highlight
 * @param {boolean} caseSensitive Differenciate between capital and lowercase letters
 * @param {string} cls Class to apply to the highlighted keyword
 */
function highlight(elem, keywords, caseSensitive = false, cls = 'highlight') {
  const flags = caseSensitive ? 'gi' : 'g';
  // Sort longer matches first to avoid
  // highlighting keywords within keywords.
  keywords.sort((a, b) => b.length - a.length);
  Array.from(elem.childNodes).forEach(child => {
    const keywordRegex = RegExp(keywords.join('|'), flags);
    if (child.nodeType !== 3) { // not a text node
      highlight(child, keywords, caseSensitive, cls);
    } else if (keywordRegex.test(child.textContent)) {
      const frag = document.createDocumentFragment();
      let lastIdx = 0;
      child.textContent.replace(keywordRegex, (match, idx) => {
        const part = document.createTextNode(child.textContent.slice(lastIdx, idx));
        const highlighted = document.createElement('span');
        highlighted.textContent = match;
        highlighted.classList.add(cls);
        frag.appendChild(part);
        frag.appendChild(highlighted);
        lastIdx = idx + match.length;
      });
      const end = document.createTextNode(child.textContent.slice(lastIdx));
      frag.appendChild(end);
      child.parentNode.replaceChild(frag, child);
    }
  });
}

// Highlight all keywords found in the page
highlight(document.body, ['lorem', 'amet', 'autem']);
.highlight {
  background: lightpink;
}
<p>Hello world lorem ipsum dolor sit amet, consectetur adipisicing elit. Est vel accusantium totam, ipsum delectus et dignissimos mollitia!</p>
<p>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam, corporis.
  <small>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium autem voluptas perferendis dolores ducimus velit error voluptatem, qui rerum modi?</small>
</p>

Saya juga akan merekomendasikan menggunakan sesuatu seperti escape-string-regexp jika kata kunci Anda dapat memiliki karakter khusus yang perlu di-escape dalam regex:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);

Ini bekerja dengan baik untuk saya tetapi juga membutuhkan cara untuk "menghapus tanda" '
jwzumwalt

4

Contoh TypeScript sederhana

CATATAN: Meskipun saya setuju dengan @Stefan dalam banyak hal, saya hanya membutuhkan sorotan kecocokan sederhana :

module myApp.Search {
    'use strict';

    export class Utils {
        private static regexFlags = 'gi';
        private static wrapper = 'mark';

        private static wrap(match: string): string {
            return '<' + Utils.wrapper + '>' + match + '</' + Utils.wrapper + '>';
        }

        static highlightSearchTerm(term: string, searchResult: string): string {
            let regex = new RegExp(term, Utils.regexFlags);

            return searchResult.replace(regex, match => Utils.wrap(match));
        }
    }
}

Dan kemudian menyusun hasil aktual:

module myApp.Search {
    'use strict';

    export class SearchResult {
        id: string;
        title: string;

        constructor(result, term?: string) {
            this.id = result.id;
            this.title = term ? Utils.highlightSearchTerm(term, result.title) : result.title;
        }
    }
}

3

Sejak HTML5 Anda dapat menggunakan file <mark></mark> tag untuk menyorot teks. Anda dapat menggunakan javascript untuk membungkus beberapa teks / kata kunci di antara tag ini. Berikut ini sedikit contoh cara menandai dan menghapus tanda teks.

JSFIDDLE DEMO


innerHTMLberbahaya. Ini akan menghapus acara.
Bung

2
Ini juga tidak berfungsi dengan baik karena, misalnya, jika Anda memasukkan "Lorem" JSFIDDLE, itu hanya menandai kemunculan pertamanya.
agm1984

1
Yah, Anda hanya perlu mengganti semua kemunculan kata kunci. berikut adalah contoh dengan regex secara global jsfiddle.net/de5q704L/73
kasper Taeymans

2

Maju cepat ke 2019, API Web sekarang memiliki dukungan asli untuk menyorot teks:

const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);

Dan Anda siap berangkat! anchorNodeadalah simpul awal pemilihan, focusNodeadalah simpul akhir pemilihan. Dan, jika mereka adalah node teks, offsetadalah indeks dari karakter awal dan akhir di node masing-masing. Berikut dokumentasinya

Mereka bahkan memiliki demo langsung


oh ini luar biasa. cukup gunakan seperti ini: selection.setBaseAndExtent (diinginkanNode, 0, diinginkanNode, 1); untuk menyorot satu-satunya simpul yang Anda butuhkan. dan berfungsi dengan Gutenberg
tonyAndr

1

Saya juga bertanya-tanya, Anda bisa mencoba apa yang saya pelajari di posting ini .

Saya menggunakan:

function highlightSelection() {
			var userSelection = window.getSelection();
			for(var i = 0; i < userSelection.rangeCount; i++) {
				highlightRange(userSelection.getRangeAt(i));
			}
			
		}
			
			function highlightRange(range) {
			    var newNode = document.createElement("span");
			    newNode.setAttribute(
			       "style",
			       "background-color: yellow; display: inline;"
			    );
			    range.surroundContents(newNode);
			}
<html>
	<body contextmenu="mymenu">

		<menu type="context" id="mymenu">
			<menuitem label="Highlight Yellow" onclick="highlightSelection()" icon="/images/comment_icon.gif"></menuitem>
		</menu>
		<p>this is text, select and right click to high light me! if you can`t see the option, please use this<button onclick="highlightSelection()">button </button><p>

Anda juga dapat mencobanya di sini: http://henriquedonati.com/projects/Extension/extension.html

xc


0

Kami jika Anda juga ingin disorot pada pemuatan halaman, ada cara baru.

tambahkan saja #:~:text=Highlight%20These

coba akses tautan ini

/programming/38588721#:~:text=Highlight%20a%20text


-1

Menggunakan metode surroundContents () pada tipe Range . Argumen satu-satunya adalah elemen yang akan membungkus Range itu.

function styleSelected() {
  bg = document.createElement("span");
  bg.style.backgroundColor = "yellow";
  window.getSelection().getRangeAt(0).surroundContents(bg);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.