2013-10-31 54 views
4

我想使用jQuery選擇並返回搜索到的文本。jQuery高亮顯示標籤中元素的文本片段

問題是;部分文本可能位於<span>或其他內聯元素中,因此在本文中搜索'waffles are tasty'時:'I'm not sure about <i>cabbages</i>, but <b>waffles</b> <span>are</span> <i>tasty</i>, indeed.',您不會得到任何匹配,而文本對於人員不會中斷。

讓我們用這個HTML爲例:

<div id="parent"> 
    <span style="font-size: 1.2em"> 
    I 
    </span> 
    like turtles 
    <span> 
    quite a 
    </span> 
    lot, actually. 

    <span> 
    there's loads of 
    </span> 
    tortoises over there, OMG 

    <div id="child"> 
    <span style="font-size: 1.2em"> 
     I 
    </span> 
    like turtles 
    <span> 
     quite a 
    </span> 
    lot, actually. 

    TURTLES! 
    </div> 
</div> 

有了這個(或類似)的JavaScript:

$('div#parent').selectText({query: ['i like', 'turtles', 'loads of tortoises'], caseinsensitive: true}).each(function() { 
    $(this).css('background-color', '#ffff00'); 
}); 
//The (hypothetical) SelectText function would return an array of wrapped elements to chain .each(); on them 

你會想產生這樣的輸出:(沒有評論,很明顯)

<div id="parent"> 
    <span style="font-size: 1.2em"> 
    <span class="selected" style="background-color: #ffff00"> 
     I 
    </span> <!--Wrap in 2 separate selection spans so the original hierarchy is disturbed less (as opposed to wrapping 'I' and 'like' in a single selection span)--> 
    </span> 
    <span class="selected" style="background-color: #ffff00"> 
    like 
    </span> 
    <span class="selected" style="background-color: #ffff00"> <!--Simple match, because the search query is just the word 'turtles'--> 
    turtles 
    </span> 
    <span> 
    quite a 
    </span> 
    lot, actually. 

    <span> 
    there's 
    <span class="selected" style="background-color: #ffff00"> 
     loads of 
    </span> <!--Selection span needs to be closed here because of HTML tag order--> 
    </span> 
    <span class="selected" style="background-color: #ffff00"> <!--Capture the rest of the found text with a second selection span--> 
    tortoises 
    </span> 
    over there, OMG 

    <div id="child"> <!--This element's children are not searched because it's not a span--> 
    <span style="font-size: 1.2em"> 
     I 
    </span> 
    like turtles 
    <span> 
     quite a 
    </span> 
    lot, actually. 

    TURTLES! 
    </div> 
</div> 

(假設的)SelectText函數會將所有選定的文本包含在<span class="selected">標籤,而不管搜索部分是否位於其他內聯元素,如<span>,「'等。它不搜索子<div>的內容,因爲它不是內聯元素。

有沒有這樣做的jQuery插件? (在span標籤中包裝搜索查詢並返回它們,無視發現文本的一部分是否可能位於其他內聯元素中?)

如果不是,那麼將如何創建這樣的函數? This function有點像我在找的東西,但是當找到的文本的部分嵌套在其他內聯元素中時,它不會返回所選跨度和斷點的數組。

任何幫助將不勝感激!

+0

ID都是唯一的,所以你可能不希望包裹在所有選定的文本' '標籤,也許是一個班級?至於這個問題 - 爲什麼不通過所有的文本節點? –

+0

對,忘了這個,讓我把它改成課。 這可能是一個好的開始,但是我怎麼會告訴文本/內聯節點的哪些部分應該被包裝,以及*他們應該如何包裝? – mickdekkers

+1

http://stackoverflow.com/questions/5886858/full-text-search-in-html-ignoring-tags –

回答

4

小菜一碟!見this

摺疊符號:

$.each(
    $(...).findText(...), 
    function(){ 
     ... 
    } 
); 

在網上表示法:

$(...).findText(...).each(function(){ 
     ... 
    } 
); 
+0

哇。我推測正則表達式在這種情況下將是不切實際的,但該死的,這是優雅的。這個實現確實有兩個問題。 1.如果您查看[此示例](http://jsfiddle.net/SoullessWaffle/JCxMy/2/),我在其中搜索完整字符串,您可以看到它沒有被檢測到,因爲正則表達式在有一些地方。 2.如果你看看你原來的例子,在'我喜歡'和'海龜'之間,有一個空間會被突出顯示兩次,因爲它已經在「選定」範圍內,但由於某種原因被另一個包裹而「喜歡」即使他們是兄弟姐妹。 – mickdekkers

+0

沒問題! http://jsfiddle.net/JCxMy/5/ –

+0

再次感謝。我看到你在搜索查詢中的'I'和''ve'之間插入了一個空格。它現在可以檢測到它,但HTML仍然有一個空間,原本沒有一個空間。這是爲什麼發生?它是EmulateSelection的正則表達式還是'makeRegexp'的正則表達式?順便說一句,[這](http://gyazo.com/edd067fa03555fe769603b6848230f35)是我在問題二中描述的;由於某種原因,即使它已經處於選擇範圍內,也會單獨突出顯示這些空間。這是一個小問題,可以通過檢查元素是否在正則表達式的替換函數的選擇範圍內來解決。 – mickdekkers

3

三個選項:

  • 使用瀏覽器內置的這個方法。對於該發現,IE具有TextRange及其findText()方法;其他瀏覽器(除Opera之外,上次我檢查過,很久以前)都有window.find()。但是,在某些時候,這並不理想,因此需要window.find()may be killed off without being replaced。要突出顯示,您可以使用document.execCommand()
  • 使用我的Rangy庫。這裏有一個演示:http://rangy.googlecode.com/svn/trunk/demos/textrange.html
  • 構建自己的代碼來搜索DOM中的文本內容並對其進行設計。

前兩個選項中詳細介紹上這樣的回答:

https://stackoverflow.com/a/5887719/96100

+0

你的Rangy圖書館似乎正在做我正在尋找...有什麼辦法可以使用它在一個jQuery函數中,並返回搜索結果跨度數組進一步鏈接? – mickdekkers

+0

@SoullessWaffle:在應用「selected」類後,可以在選擇範圍內調用getNodes()。類似'var spansWithClass = rangy.getSelection()。getRangeAt(0).getNodes([1],function(el){return $(el).hasClass(「selected」);})' –

+0

我有一個小小的麻煩解讀了這個例子的確切含義,因爲大多數這些函數似乎沒有很好的記錄(除非我在錯誤的地方查找),例如我可以找到getNodes的唯一參考是[this page](http://www.day.com/maven/jsr170/javadocs/jcr-2.0/javax/jcr/Node.html#getNodes()),它使我困惑略。 – mickdekkers

0

我寫了一個草案爲fiddle。主要步驟:

我做了一個jQuery插件

$.fn.selectText = function(params){ 
    var phrases = params.query, 
     ignorance = params.ignorecase; 
     wrapper = $(this); 
    . . . 
    return(wrapper); 
}; 

現在我可以調用選擇爲$(...).selectText({query:["tortoise"], ignorance: true, style: 'selection'});

我知道你想要的功能調用後有迭代器,但在你的情況下,這是不可能的,因爲迭代器必須返回有效的jQuery選擇器。例如: word <tag>word word</tag> word是無效的選擇器。

消毒包裝的內容後,對於每個搜索makeRegexp()作出個人正則表達式。

每一塊搜索HTML源的去emulateSelection()然後wrapWords()

主要思想是在<span class="selection">...</span>包各單片短語不是標籤分開的,但沒有分析節點的整個樹。

注:

它與HTML標籤<b><i>...工作NOT。你必須在它的正則表達式字符串中進行更正。 我不保證它會與Unicode一起使用。但是,誰知道......

+0

'單詞單詞單詞單詞'確實不是一個有效的選擇器...將返回個人''s(不需要單詞,只是包含結果的跨度)在一個數組中不起作用? AFAIK這是如何jQuery做到這一點(數組中的html對象,如果有多個)... 我可能會使用這樣的東西作爲主函數的包裝,謝謝。 – mickdekkers

+0

但是怎麼樣'word word word'情況?這絕對是非jquery,非樹形包裝的情況。 –

+0

我不確定我完全理解這個例子。 – mickdekkers

1

因爲我剛碰巧正在做一個類似的事情,如果你想看到我的解釋「選項3」的開始,我想我會分享這一點,其主要特點是遍歷所有文本節點,而不改變現有的標籤。尚未在任何不尋常的瀏覽器上進行測試,因此不會對此進行任何保證!

function DOMComb2 (oParent) { 
    if (oParent.hasChildNodes()) { 
     for (var oNode = oParent.firstChild; oNode; oNode = oNode.nextSibling) { 
      if (oNode.nodeType==3 && oNode.nodeValue) { // Add regexp to search the text here 
       var highlight = document.createElement('span'); 
       highlight.appendChild(oNode.cloneNode(true)); 
       highlight.className = 'selected'; 
       oParent.replaceChild(highlight, oNode); 

       // Or, the shorter, uglier jQuery hybrid one-liner 
       // oParent.replaceChild($('<span class="selected">' + oNode.nodeValue + '</span>')[0], oNode); 
      } 
      if (oNode.tagName != 'DIV') { // Add any other element you want to avoid 
       DOMComb2(oNode); 
      } 
     } 
    } 
} 

然後貫穿東西的jQuery也許搜索選擇:

$('aside').each(function(){ 
    DOMComb2($(this)[0]); 
}); 

當然,如果你有你的旁白中的旁白,奇怪的事情可能會發生。

+0

我喜歡這個,非常實用。雖然有一個問題;當它找到匹配時,它將選擇整個文本節點,而不僅僅是找到的部分,因爲它需要創建新的文本節點(可能使用'textNode.splitText()')將結果與其餘部分文本,這將與遍歷混亂。我也不知道這將如何實施,因爲我從來沒有真正搞亂遞歸之前。我也不確定我將如何實現部分匹配,因爲...(例如,繼續) – mickdekkers

+0

(續)例如:您想要搜索'青蘋果',但不是'蘋果';如果結果正在等待在這個HTML中找到:如果你(作爲一個人)要看這個,你可以看到文本是絕對在那裏,空間和一切,如果你忽略span標籤。一種可能的方法是開始搜索完整的字符串,但是如果在當前文本節點中沒有找到,那麼'str.slice(0, - 1)'搜索字符串(刪除最後一個字符),並且只搜索最後一個字符txtNode(cont。) – mickdekkers

+0

(cont。)的幾個字符......因爲您只查找搜索字符串的第一部分,該字符串只位於文本節點的最後部分。重複'str.slice(0, - 1)',如果找到匹配則中斷,然後在下面的同級節點(或子節點,等等)中查找其餘的('originalstr.substr(str.length-1)取決於當前文本節點之後的第一個文本節點),如果文本節點的第一個文本字符與該文本節點的第一個文本字符相同,則選擇該文本的一部分(以及之前遍歷的節點中的文本部分), '如果不是'則繼續正常穿越。 – mickdekkers

0

我的理解(改編自Mozilla的開發參考網站 https://developer.mozilla.org/en-US/docs/Web/API/Node DOMComb功能),我們談論像$.each($(...).searchText("..."),function (str){...});迭代器。

檢查大衛·赫伯特·勞倫斯詩:

<div class="poem"><p class="part">I never saw a wild thing<br /> 
sorry for itself.<br /> 
A small bird will drop frozen dead from a bough<br /> 
without ever having felt sorry for itself.<br /></p></div> 

事實上,在渲染之後,瀏覽器會明白這樣的:

<div class="poem"> 
<p class="part"> 
<br>I never saw a wild thing</br> 
<br>sorry for itself.</br> 
<br>A small bird will drop frozen dead from a bough</br> 
<br>without ever having felt sorry for itself.</br> 
</p> 
</div> 

例如,我在尋找一句話:"wild thing sorry for"。因此,我不得不highligt的exerpt:

wild thing</br><br>sorry for 

我不能把它包裝這樣<span>wild thing</br><br>sorry for</span>,然後通過一些臨時ID =創建jQuery選擇「搜索-XXXXXX」,並將其返回 - 這是錯的HTML。我可以換不同的文本是這樣的:

<span search="search-xxxxx">wild thing</span></br><br><span search="search-xxxxx">sorry for</span> 

然後我不得不調用一些功能,並返回jQuery的陣列選擇的:

return($("[search=search-xxxxx]")); 

現在我們有兩個「成果」:一)「野生東西「; b)「對不起」。它真的是你想要的嗎?

OR

你必須寫你自己each()功能像另一個插件的jQuery:

$.fn.eachSearch = function(arr, func){ 
    ... 
}; 

其中ARR會不會選擇器的陣列,但陣列選擇陣列的,如:

arr = [ 
    {selector as whole search}, 
    {[{selector as first part of search]}, {[selector as second part of search]}}, 
    ...  
] 
+0

第一個例子類似於我想要的;一個可以在元素上調用的jQuery函數,並且[返回所選元素的包裝集合](http://stackoverflow.com/a/1302443/1233003),以便稍後可以鏈接那些選定的元素。即'$('div.poem')。selectText({ignorecase:true,query:['thing sorry','small bird','sorry']})。each(function(){$(this)。 css('background-color','#ffff00');});' – mickdekkers