JavaScript kullanarak metin nasıl vurgulanır


103

Birisi bir web sayfasındaki metni vurgulayabilen bir javascript işlevi konusunda bana yardımcı olabilir mi? Ve şart, arama durumunda yaptığımız gibi metnin tüm tekrarlarını vurgulamak gibi, yalnızca bir kez vurgulamaktır.


4
Fonksiyonun kodunu gönderirseniz size yardımcı olabiliriz. Bizden sizin için böyle bir işlev oluşturmamızı isterseniz ... bu daha az olasıdır. Kendi başına bir şeyler yapmalısın. Bir şeyler yapmaya başlayın ve sıkışıp kaldığınızda geri gelin.
Felix Kling

7
EVET Nasıl Sorulur'u okudum ve kendi başıma bir şeyler yaptım ama takılıp kaldım ve bu yüzden sordum. Android üzerinde çalışıyorum ve javasript hakkında çok az bilgim var, bu yüzden kendi başıma yapamıyorum. Daha önce, işi yapan ancak belirli sınırlamalar olmadan farklı bir javascript kullanıyordum. Bu soruyu sorarken doğru kelimeleri kullanmamış olabilirim ve bunun için üzgünüm ama lütfen aksini düşünmeyin.
Ankit

1
Bu eklenti ilginizi çekebilir: github.com/julmot/jmHighlight . Anahtar kelimeleri ayrı ayrı veya bir terim olarak vurgulayabilir, özel öğeniz ve sınıf adınızla eşleşmeyi vurgulayabilir ve ayrıca aksan işaretlerini arayabilir. Üstte, eşleşmeleri aramak için bağlamı filtrelemenize izin verir.
dostum

1

Yanıtlar:


107

Jquery vurgulama efektini kullanabilirsiniz .

Ancak ham javascript koduyla ilgileniyorsanız, sahip olduğum şeye bir bakın Basitçe kopyalayıp bir HTML'ye yapıştırın, dosyayı açın ve "vurgulayın" düğmesine tıklayın - bu "tilki" kelimesini vurgulamalıdır. Performans açısından bunun küçük metin ve tek bir tekrar için işe yarayacağını düşünüyorum (belirttiğiniz gibi)

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>

Düzenlemeler:

Kullanma replace

Bu cevabın biraz popülerlik kazandığını görüyorum, üzerine ekleyebileceğimi düşündüm. Değiştirmeyi de kolayca kullanabilirsiniz

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

Veya birden çok kez geçtiğinde (soruyla ilgili değildir, ancak yorumlarda sorulmuştur), basitçe globaldeğiştirme normal ifadesini eklemeniz yeterlidir .

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

Umarım bu meraklı yorumculara yardımcı olur.

HTML'yi tüm web sayfasıyla değiştirme

HTML'yi bir web sayfasının tamamı için değiştirmek için innerHTML, belgenin gövdesine başvurmalısınız .

document.body.innerHTML


Cevabınız için çok teşekkürler, ancak javascript'in kendisinde rengi nasıl belirleyeceğimi de söyleyebilir misiniz
Ankit

Sen yerini alabilir "<span class='highlight'>"ile "<span style='color: " + color + ";'>"olduğu gibi, renk olması gereken bir şeyvar color = "#ff0000";
Yaniro

ya bir kelimenin tüm sayfadaki tüm geçtiği yerleri vurgulamak istersem? @guy mograbi
Naqvi

4
Basit bir "değiştir" kullanmak kötü bir fikirdir . Nedenini burada açıkladım: stackoverflow.com/a/32758672/3894981
ahbap

2
Bu harika bir fikir değil çünkü bu HTML etiketlerini / niteliklerini / vb. Vurgulamaya çalışacak. Örneğin, şu durumda ne olurdu: <img src="fox.jpg" /> Şuna benzeyen geçersiz HTML alırsınız: <img src="<span class='highlight'>fox</span>.jpg" /> İyi değil
dcporter7

51

Burada sunulan çözümler oldukça kötü.

  1. Normal ifadeyi kullanamazsınız çünkü bu şekilde html etiketlerinde arama / vurgulama yaparsınız.
  2. Normal ifadeyi kullanamazsınız çünkü UTF * ile düzgün çalışmaz (latin / İngilizce olmayan karakterler içeren herhangi bir şey).
  3. Sadece bir innerHTML.replace yapamazsınız, çünkü karakterlerin özel bir HTML gösterimi olduğunda bu işe yaramaz, örneğin &amp;& &lt;için, <için, &gt;için> için, &auml;için için, &ouml;için &uuml;için ü &szlig;için için için, vb.

Ne yapmak gerekiyor:

Döngü HTML dokümanının yoluyla olsun, tüm metin düğümleri bulmak textContentile vurgulamak metin konumunu almak indexOf(opsiyonel ile toLowerCaseküçük harf duyarsız olması gerekiyorsa) önce, ekleme herşeyi indexofolarak textNode, komuta vurgu açıklıklı eşleşti Metin, ve metin düğümünün geri kalanı için tekrarlayın (vurgu dizesi dizede birden çok kez ortaya çıkabilir textContent).

İşte bunun kodu:

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

};

O zaman bunu şu şekilde kullanabilirsiniz:

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

İşte örnek bir HTML belgesi

<!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>

Bu arada, bir veritabanında arama yaparsanız LIKE,
mesela WHERE textField LIKE CONCAT('%', @query, '%')[sen, tam metin-arama veya lucene kullanmalıdır yapmaması gereken hangi], o zaman, bu şekilde her kaçış karakteri \ ve bir SQL kaçış deyimi ekleyebilir LIKE ifadeleri olan özel karakterler bulacaksınız.

Örneğin

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

ve @query'nin değeri, '%completed%'ancak'%\c\o\m\p\l\e\t\e\d%'

(test edilmiştir, SQL-Server ve PostgreSQL ve ESCAPE'yi destekleyen diğer tüm RDBMS sistemleriyle çalışır)


Revize edilmiş bir daktilo versiyonu:

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 

Kullanım:

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

Harika cevap .. Yöntem abartılı gibi görünüyor, ama özlü! Kesinlikle benim durumumda olduğu gibi bu yöntem ile bir hız testi yaparak ilgilenen olacak sonuçları (orada olarak DOM içine yüklenen tembel CAN bu yöntem tembel yüke yüksek bir gecikme eklemek istiyorum eğer meraklı, sonuçların binlerce olun).
Pogrindis

6
Üzgünüm ama hiçbir argümanınız doğru değil. 1. Kesinlikle bir RegExp kullanabilirsiniz, sadece HTML değeri içinde değil, bir öğenin metin değerini aramalısınız. 2. Mark.js'de uygulandığı gibi, RegExp'i aksan karakterlerle kesinlikle kullanabilirsiniz . 3. HTML gösterimleri, DOM tarayıcısındaki gerçek karakterlere dönüştürülecektir, böylece onları kesinlikle kullanacaksınız!
dostum

1
@julmot; 1'e: Bu, her öğeyi yinelemeniz gerektiği anlamına geliyor, ben de tam olarak bunu yapıyorum. Biçimlendirmeyi kaybetmeyi önemsemediğiniz sürece, bu durumda oldukça yavaş olacak document.body.innerText içinde arama yapabilirsiniz. 3. DOM'da değil, bir metin öğesinin innerText veya textContent özelliğinde. Bu da yine metin öğeleri arasında yineleme yapmanız gerektiği anlamına gelir; regEx AFAIK ile yapılamaz. 2: mark.js'yi bilmiyorum, ancak jQuery.each yapan her şeyden kaçınırdım, çünkü bu çok yavaş.
Stefan Steiger

1
@StefanSteiger 1. O zaman, RegExp ile arama yapamayacağımızı söylediği için karar ilişkinizi düzeltmelisiniz, bu doğru değil 2. jQuery.each kullanmıyor. Seni böyle düşündüren nedir? 3. Bu, en azından Firefox'ta doğru değil. &auml;örneğin kullanılırken bile gerçek karaktere dönüştürülecektir innerHTML.
ahbap

1
Merhaba @StefanSteiger Aslında, çözümlerinizi kullanıyorum. Bu mükemmel. Ancak, eğer II'nin iki açıklığı olan ve bir açıklığı Diploma MSBTE gibi verilere sahip olan bir P'ye sahipse ve ikinci yayılma 2012 verisine sahipse gibi bir sorun var. Şimdi vurgulamak istediğim dize Diploma MSBTE 2012 ise, tüm bu dizenin çalışmadığını kontrol ettim, Eşleşecek her şey bir aralıkta mevcutsa çalışır, ancak metin içeriği diff etiketlerinde ise o zaman İşe yaramıyor. Lütfen bunun hakkında bir şeyler söyleyebilir misin?
ganeshk

42

Kendi kendine vurgulama işlevi kullanmak neden kötü bir fikirdir?

Kendi vurgulama işlevinizi sıfırdan oluşturmaya başlamanın muhtemelen kötü bir fikir olmasının nedeni, kesinlikle başkalarının halihazırda çözdüğü sorunlarla karşılaşacak olmanızdır. Zorluklar:

  • Sen baştan DOM olaylarını tahrip ve aşırı DOM rejenerasyonu tetikleme olmadan Kibritlerini vurgulamak için HTML elemanları ile metin düğümlerini kaldırmak gerekir (örneğin durum olurdu innerHTML)
  • Vurgulanan öğeleri kaldırmak istiyorsanız, HTML öğelerini içerikleriyle birlikte kaldırmanız ve ayrıca daha fazla arama için bölünmüş metin düğümlerini birleştirmeniz gerekir. Bu gereklidir, çünkü her vurgulayıcı eklentisi eşleşmeler için metin düğümlerinde arama yapar ve anahtar kelimeleriniz birkaç metin düğümüne bölünürse bulunmazlar.
  • Eklentinizin düşünmediğiniz durumlarda çalıştığından emin olmak için testler oluşturmanız da gerekecektir. Ve çapraz tarayıcı testlerinden bahsediyorum!

Kulağa karmaşık mı geliyor? Bazı öğeleri vurgulama, aksan eşleme, eş anlamlı eşleme, iframe içinde arama, ayrılmış sözcük arama vb. Gibi bazı özellikleri göz ardı etmek istiyorsanız, bu giderek daha karmaşık hale gelir.

Mevcut bir eklentiyi kullanın

Mevcut, iyi uygulanmış bir eklenti kullanırken, yukarıda belirtilen şeyler için endişelenmenize gerek yok. Makale vurgulayıcı eklentileri 10 jQuery metin popüler vurgulayıcı eklentileri karşılaştırır SitePoint.

Mark.js'ye bir göz atın

mark.js , saf JavaScript ile yazılmış bir eklentidir, ancak jQuery eklentisi olarak da mevcuttur. Aşağıdaki seçeneklerle diğer eklentilerden daha fazla fırsat sunmak için geliştirilmiştir:

  • anahtar kelimeleri tam terim yerine ayrı ayrı arayın
  • harita aksan işaretleri (Örneğin "justo" da "just" "ile eşleşirse)
  • özel öğeler içindeki eşleşmeleri yoksay
  • özel vurgulama öğesi kullan
  • özel vurgulama sınıfı kullan
  • özel eş anlamlıları eşle
  • iframe'lerin içinde de ara
  • bulunamadı terimleri almak

DEMO

Alternatif olarak bu kemanı görebilirsiniz .

Kullanım örneği :

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

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

GitHub'da ücretsiz ve geliştirilmiş açık kaynaklıdır ( proje referansı ).


4
Tek başına metni vurgulamak, jQuery'yi dahil etmem için yeterince iyi bir neden değil.
Roy

10
@Roy Bunu kalbe aldım. İyi haber, v6.0.0 itibariyle mark.js jQuery bağımlılığından feragat etti ve artık isteğe bağlı olarak jQuery eklentisi olarak kullanılmasını sağlıyor.
dostum

Aşağıdakiler dışında tümü doğrudur: 1. nokta mümkün değildir, çünkü kayıtlı olay işleyicileri alamazsınız ve yapabilseniz bile anonim işlevleri ayarlayamazsınız ... 2.: mark.js de iki etiket arasında metin bulmaz, örn. <span> </span> e bulamayacak ... 3: Henüz test etmediğiniz bir tarayıcı (yeni sürüm dahil) geldiğinde, bozulabilir. Kaç tane test yazarsan yaz, bu her zaman doğrudur. 17kb'de, işaretler yaptığı şey için çok büyük.
Stefan Steiger

@StefanSteiger'den hangi noktalardan bahsediyorsunuz? Bu bilgi olmadan ilk noktaya kadar bir şey söyleyemezsin. Ancak ikinci yorum yanlıştır, mark.js acrossElementsseçeneği kullanarak etiketler arasındaki eşleşmeleri bulabilir . Ve üçüncü yoruma; mark.js sunduğu işlevlere kıyasla büyük değil. Ve hayır, mark.js test edildiğinden, örneğin Chrome 30'un başlatılması ve tarayıcılar arası birim testleri ile tüm yeni sürümlerde ve gelecek sürümlerde hiçbir zaman sorun olmadığından, gelecekte bir şeyin bozulma olasılığı düşüktür.
dostum

@dude: İlk paragraftan sonraki üç nokta. Ah, tamam, baktığım demoda bu seçeneği kaçırdım. Bu durumda, biraz mantıklı olabilir. Ama yine de çok büyük buluyorum.
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, SO'ya hoşgeldin. Kodun bir açıklaması güzel olurdu!
Nippey

Başka bir düğüm oluşturmadan metin seçmenin bir yolu olmamalı mı?
Dave Gregory

@ user191433 soru sadece metni seçmekle ilgili değil, aynı zamanda stilleri de uygulamakla ilgili. Bunun için bir düğüme ihtiyacınız var.
Christophe 13

JavaScript'in span.style.backgroundColor = "yellow";CSS'ye çevrildiğine dair hatırlatma / ipucu - style="background-color: yellow;"camelCase ile kesik çizgili gösterim arasındaki ince fark ilk başta beni harekete geçirdi.
MarkHu

1
PS Mohit'in stackoverflow.com/questions/7991474/… adresindeki yanıtı, bu kodun daha akıcı bir varyantıdır. (örneğin, burada yalnızca tanısal / işlevsel olmayan başlangıç ​​ve bitiş değişkenlerini
çıkarmak

8

İşte benim regexp saf JavaScript çözümüm:

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

Vurgulamaya çalıştığım metin bloğu HTML etiketleri içerdiğinde bu benim için mükemmel çalışıyor.
John Chapman

Ayrıca, regexp boru sembolü aracılığıyla birden çok kelimeyi kabul edecek şekilde one|two|three
işlevde ince

Metnin sonunda bir >karakter varsa, metnin yerini almaz . (?!([^<]+)?<)Çalışması için normal ifadeyi kullanarak değiştirin .
Archie Reyes

İstendiği gibi değiştirildi.
Klemen Tušar

Mükemmel! Bu benim için en iyisi
marco burrometo

6

Diğer çözümlerin hiçbiri ihtiyaçlarıma tam olarak uymuyordu ve Stefan Steiger'in çözümü beklediğim gibi çalışmasına rağmen, biraz fazla ayrıntılı buldum.

Benim girişimim şu:

/**
 * 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>

Ayrıca , anahtar kelimeleriniz normal ifadelerde öncelenmesi gereken özel karakterlere sahip olabiliyorsa, kaçış-dizesi-regexp gibi bir şey kullanmanızı tavsiye ederim :

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

Bu benim için iyi çalıştı ama aynı zamanda "
işareti

5

Aynı sorunu yaşıyorum, bir xmlhttp isteği aracılığıyla bir grup metin geliyor. Bu metin html formatlıdır. Her olayı vurgulamalıyım.

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

Sorun şu ki, etiketlerdeki metni vurgulamama gerek yok. Örneğin tilkiyi vurgulamalıyım:

Şimdi bunu şununla değiştirebilirim:

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

Sorunuzu yanıtlamak için: regexp seçeneklerinde g'yi bırakabilirsiniz ve yalnızca ilk geçtiği yer değiştirilecektir, ancak bu yine de img src özelliğindedir ve resim etiketini yok eder:

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

Bu şekilde çözdüm ama daha iyi bir yol olup olmadığını merak ediyordum, normal ifadelerde kaçırdığım bir şey:

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>");
});

Bu, <img src="word">veya ile uğraşmadan benim için çalışan tek normal ifade çözümüydü <a href="word">.
yvesmancera

1
Altın kural: Asla. Kullanın. Düzenli. İfade. To. Dağınıklık. Hakkında. İle. XML.
ScottMcGready

4

Basit TypeScript örneği

NOT: @Stefan ile birçok konuda hemfikir olsam da, sadece basit bir eşleşmenin vurgulanmasına ihtiyacım vardı :

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

Ve sonra asıl sonucu oluşturmak:

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

HTML5'ten beri, <mark></mark>metni vurgulamak için etiketleri kullanabilirsiniz . Bu etiketler arasında bazı metinleri / anahtar kelimeleri kaydırmak için javascript kullanabilirsiniz. Metnin nasıl işaretleneceğine ve işaretinin kaldırılacağına dair küçük bir örnek.

JSFIDDLE DEMO


innerHTMLtehlikeli. Olayları silecek.
dostum

2
Bu aynı zamanda düzgün çalışmaz çünkü örneğin, JSFIDDLE "Lorem" 'a girerseniz, sadece ilk örneğini işaretler.
agm1984

1
Merhabalar, sadece anahtar kelimenin tüm geçtiği yerleri değiştirmeniz gerekiyor. küresel olarak regex ile bir örnek jsfiddle.net/de5q704L/73
kasper Taeymans

2

2019'a hızlı bir şekilde ilerleyin, Web API artık metinleri vurgulamak için yerel olarak desteğe sahip:

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

Ve gitmekte iyisin! anchorNodeseçim başlangıç ​​düğümü, focusNodeseçim bitiş düğümüdür. Ve eğer bunlar metin düğümleriyse, offsetilgili düğümlerdeki başlangıç ​​ve bitiş karakterinin dizinidir. İşte belgeler

Canlı bir demoları bile var


oh bu harika. basitçe şu şekilde kullanın: selection.setBaseAndExtent (istenilenDüğüm, 0, istenilenDüğüm, 1); ihtiyacınız olan tek düğümü vurgulamak için. ve Gutenberg ile çalışır
tonyAndr

1

Ben de merak ediyordum, bu yazıda öğrendiklerimi deneyebilirsin .

Kullandım:

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>

burada da deneyebilirsiniz: http://henriquedonati.com/projects/Extension/extension.html

xc


1

Sayfa yüklenirken de vurgulanmasını istiyorsanız, yeni bir yol var.

sadece ekle #:~:text=Highlight%20These

bu bağlantıya erişmeyi dene

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


-1

Range türünde surroundContents () yöntemini kullanma . Tek argümanı, bu Aralığı saracak bir öğedir.

function styleSelected() {
  bg = document.createElement("span");
  bg.style.backgroundColor = "yellow";
  window.getSelection().getRangeAt(0).surroundContents(bg);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.