JS+CSS實現(xiàn)高亮關(guān)鍵詞(不侵入DOM)的方式
之前在做關(guān)鍵詞檢索高亮功能的時候,研究了下目前前端實現(xiàn)高亮的幾種方式,第一就是替換dom
元素實現(xiàn)高亮,第二就是利用瀏覽器新特性Css.highlights
結(jié)合js
選區(qū)與光標與CSS
高亮偽類實現(xiàn),實現(xiàn)功能如下:
一、頁面布局
一個搜索框,其余要檢索關(guān)鍵詞的文字,并且給搜索框添加change
事件
二、實現(xiàn)選區(qū)
利用TreeWalker
遍歷遍歷DOM
結(jié)構(gòu),通過nextNode()
方法,拿到所有文本節(jié)點數(shù)據(jù),保存到數(shù)組里,為接下來的搜索做鋪墊
let wrap = document.querySelector('.content') // 創(chuàng)建 createTreeWalker 迭代器,用于遍歷文本節(jié)點,保存到一個數(shù)組 const treeWalker = document.createTreeWalker(wrap, NodeFilter.SHOW_TEXT); const allTextNodes = []; let currentNode = treeWalker.nextNode(); while (currentNode) { allTextNodes.push(currentNode); currentNode = treeWalker.nextNode(); }
可以看到,到這一步,拿到所有文本節(jié)點數(shù)據(jù)
接下來,我們根據(jù)搜索的結(jié)果,拿到匹配到的dom
節(jié)點內(nèi)容的位置信息這里處理下英文小寫,這里要注意,可能每句話會出現(xiàn)多次關(guān)鍵詞,這里的indexOf
要拼開始檢索的參數(shù),開始檢索的參數(shù)這里記錄下,也就是上一個檢索關(guān)鍵詞的結(jié)尾
let search = document.getElementById('search') search.onchange = event => { let value = event.target.value // 獲取關(guān)鍵詞 let indices = []; // 位置信息 const ranges = allTextNodes .map((el) => { // 英文全部小寫 return { el, text: el.textContent.toLowerCase() }; }) .map(({ text, el }) => { // 拿到匹配到dom節(jié)點的位置信息,并且保存為數(shù)組 while (startPos < text.length) { let startPos = 0 while (startPos < text.length) { const index = text.indexOf(value, startPos); if (index === -1) break indices.push({ el, start: index, end: index + value.length }); startPos = index + value.length; } } }); }
我們可以看下位置信息結(jié)果
接下來,創(chuàng)建選區(qū),進行高亮,這里用到了Highlight
,用法如下:Highlight(range1, range2, range3)
// 根據(jù)搜索詞的位置創(chuàng)建選區(qū) let result = indices.map(item => { let range = new Range(); range.setStart(item.el, item.start); range.setEnd(item.el, item.end); return range }); // 創(chuàng)建高亮對象 const searchResultsHighlight = new Highlight(...result); // 注冊高亮 CSS.highlights.set("search-results", searchResultsHighlight);
添加css highlight
樣式:
.content .item::highlight(search-results) { background-color: #ffff00; color: #000; }
可以看下效果,基本成型,但是當我們切換的時候,上一次的檢索結(jié)果還在,需要清除高亮記錄
// 清除上個高亮 CSS.highlights.clear();
三、完整代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CSS高亮</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } .container { width: 100vw; height: 100vh; padding-top: 20px; } .search { width: 100%; padding: 10px 0; display: flex; align-items: center; justify-content: center; } .search input { width: 500px; height: 35px; border: 1px #999 solid; outline: 0; background-color: #fff; border-radius: 3px; padding-left: 10px; } .content { width: 100%; padding: 30px; } .content .item { width: 100%; font-size: 16px; color: #000; margin-bottom: 10px; line-height: 30px; user-select: none; letter-spacing: 0.5px; } .content .item::highlight(search-results) { background-color: #ffff00; color: #000; } </style> </head> <body> <div class="container"> <div class="search"> <input id="search" type="text" placeholder="輸入關(guān)鍵詞檢索" /> </div> <div class="content"> <div class="item"> 1、朱自清《荷塘月色》片段 路上只我一個人,背著手踱著。這一片天地好像是我的;我也像超出了平常旳自己,到了另一世界里。我愛熱鬧,也愛冷靜;愛群居,也愛獨處。像今晚上,一個人在這蒼茫旳月下,什么都可以想,什么都可以不想,便覺是個自由的人。白天里一定要做的事,一定要說的話,現(xiàn)在都可不理。這是獨處的妙處,我且受用這無邊的荷香月色好了。 曲曲折折的荷塘上面,彌望旳是田田的葉子。葉子出水很高,像亭亭旳舞女旳裙。層層的葉子中間,零星地點綴著些白花,有裊娜(niǎo,nuó)地開著旳,有羞澀地打著朵兒旳;正如一粒粒的明珠,又如碧天里的星星,又如剛出浴的美人。微風(fēng)過處,送來縷縷清香,仿佛遠處高樓上渺茫的歌聲似的。這時候葉子與花也有一絲的顫動,像閃電般,霎時傳過荷塘的那邊去了。葉子本是肩并肩密密地挨著,這便宛然有了一道凝碧的波痕。葉子底下是脈脈(mò)的流水,遮住了,不能見一些顏色;而葉子卻更見風(fēng)致了。 月光如流水一般,靜靜地瀉在這一片葉子和花上。薄薄的青霧浮起在荷塘里。葉子和花仿佛在牛乳中洗過一樣;又像籠著輕紗的夢。雖然是滿月,天上卻有一層淡淡的云,所以不能朗照;但我以為這恰是到了好處——酣眠固不可少,小睡也別有風(fēng)味的。月光是隔了樹照過來的,高處叢生的灌木,落下參差的斑駁的黑影,峭楞楞如鬼一般;彎彎的楊柳的稀疏的倩影,卻又像是畫在荷葉上。塘中的月色并不均勻;但光與影有著和諧的旋律,如梵婀(ē)玲(英語violin小提琴的譯音)上奏著的名曲。 荷塘的四面,遠遠近近,高高低低都是樹,而楊柳最多。這些樹將一片荷塘重重圍住;只在小路一旁,漏著幾段空隙,像是特為月光留下的。樹色一例是陰陰的,乍看像一團煙霧;但楊柳的豐姿,便在煙霧里也辨得出。樹梢上隱隱約約的是一帶遠山,只有些大意罷了。樹縫里也漏著一兩點路燈光,沒精打采的,是渴睡人的眼。這時候最熱鬧的,要數(shù)樹上的蟬聲與水里的蛙聲;但熱鬧是它們的,我什么也沒有。 </div> <div class="item"> 2、魯迅《從百草園到三味書屋》片段 不必說碧綠的菜畦,光滑的石井欄,高大的皂莢樹,紫紅的桑椹;也不必說鳴蟬在樹葉里長吟,肥胖的黃蜂伏在菜花上,輕捷的叫天子(云雀)忽然從草間直竄向云霄里去了。單是周圍的短短的泥墻根一帶,就有無限趣味。油蛉在這里低唱,蟋蟀們在這里彈琴。翻開斷磚來,有時會遇見蜈蚣;還有斑蝥,倘若用手指按住它的脊梁,便會拍的一聲,從后竅噴出一陣煙霧。何首烏藤和木蓮藤纏絡(luò)著,木蓮有蓮房一般的果實,何首烏有擁腫的根。有人說,何首烏根是有象人形的,吃了便可以成仙,我于是常常拔它起來,牽連不斷地拔起來,也曾因此弄壞了泥墻,卻從來沒有見過有一塊根象人樣。如果不怕刺,還可以摘到覆盆子,象小珊瑚珠攢成的小球,又酸又甜,色味都比桑椹要好得遠。 </div> <div class="item"> 3、陳從周《說園》片段 園有靜觀、動觀之分,這一點我們在造園之先,首要考慮。何謂靜觀,就是園中予游者多駐足的觀賞點;動觀就是要有較長的游覽線。二者說來,小園應(yīng)以靜觀為主,動觀為輔,庭院專主靜觀。大園則以動觀為主,靜觀為輔。前者如蘇州網(wǎng)師園,后者則蘇州拙政園差可似之。人們進入網(wǎng)師園宜坐宜留之建筑多,繞池一周,有檻前細數(shù)游魚,有亭中待月迎風(fēng),而軒外花影移墻,峰巒當窗,宛然如畫,靜中生趣。至于拙政園徑緣池轉(zhuǎn),廊引人隨,與“日午畫船橋下過,衣香人影太匆匆”的瘦西湖相仿佛,妙在移步換影,這是動觀。立意在先,文循意出。動靜之分,有關(guān)園林性質(zhì)與園林面積大小。象上海正在建造的盆景園,則宜以靜觀為主,即為一例。 中國園林是由建筑、山水、花木等組合而成的一個綜合藝術(shù)品,富有詩情畫意。疊山理水要造成“雖由人作,宛自天開”的境界。山與水的關(guān)系究竟如何呢?簡言之,模山范水,用局部之景而非縮小(網(wǎng)師園水池仿虎丘白蓮池,極妙),處理原則悉符畫本。山貴有脈,水貴有源,脈源貫通,全園生動。我曾經(jīng)用“水隨山轉(zhuǎn),山因水活”與“溪水因山成曲折,山蹊隨地作低平”來說明山水之間的關(guān)系,也就是從真山真水中所得到的啟示。明末清初疊山家張南垣主張用平岡小陂、陵阜陂阪,也就是要使園林山水接近自然。如果我們能初步理解這個道理,就不至于離自然太遠,多少能呈現(xiàn)水石交融的美妙境界。 </div> <div class="item"> 4、梁實秋《雅舍》片段 “雅舍”最宜月夜——地勢較高,得月較先。看山頭吐月,紅盤乍涌,一霎間,清光四射,天空皎潔,四野無聲,微聞犬吠,坐客無不悄然!舍前有兩株梨樹,等到月升中天,清光從樹間篩灑而下,地下陰影斑斕,此時尤為幽絕。直到興闌人散,歸房就寢,月光仍然逼進窗來,助我凄涼。細雨蒙蒙之際,“雅舍”亦復(fù)有趣。推窗展望,儼然米氏章法,若云若霧,一片彌漫。但若大雨滂沱,我就又惶悚不安了,屋頂濃印到處都有,起初如碗大,俄而擴大如盆,繼則滴水乃不絕,終乃屋頂灰泥突然崩裂,如奇葩初綻,砉然一聲而泥水下注,此刻滿室狼藉,搶救無及。此種經(jīng)驗,已數(shù)見不鮮。 </div> <div class="item"> 5、冰心《圖畫》 信步走下山門去,何曾想尋幽訪勝? 轉(zhuǎn)過山坳來,一片青草地,參天的樹影無際。樹后彎彎的石橋,橋后兩個俯蹲在殘照里的獅子?;剡^頭來,只一道的斷瓦頹垣,剝落的紅門,卻深深掩閉。原來是故家陵闕!何用來感慨興亡,且印下一幅圖畫。 半山里,憑高下視,千百的燕子,繞著殿兒飛。城垛般的圍墻,白石的甬道,黃綠琉璃瓦的門樓,玲瓏剔透。樓前是山上的晚霞鮮紅,樓后是天邊的平原村樹,深藍濃紫。暮靄里,融合在一起。難道是玉宇瓊樓?難道是瑤宮貝闕?何用來搜索詩腸,且印下一幅圖畫。 低頭走著,—首詩的斷句,忽然浮上腦海來?!八脑陆蠠o矮樹,人家都在綠陰中?!焙斡每鄳浭钦l的著作,何用苦憶這詩的全文。只此已描畫盡了山下的人家! </div> <div class="item"> 6、徐志摩《我所知道的康橋》片段 康橋的靈性全在一條河上;康河,我敢說是全世界最秀麗的一條水。河的名字是葛蘭大(Granta),也有叫康河(Kiver Cam)的,許有上下流的區(qū)別,我不甚清楚。河身多的是曲折,上游是有名的拜倫潭——“Byron's Pool”——當年拜倫常在那里玩的;有一個老村子叫格蘭騫斯德,有一個果子園,你可以躺在累累的桃李樹蔭下吃茶,花果會掉入你的茶杯,小雀子會到你桌上來啄食,那真是別有一番天地。這是上游;下游是從騫斯德頓下去,河面展開,那是春夏間競舟的場所。上下河分界處有一個壩筑,水流急得很,在星光下聽水聲,聽近村晚鐘聲,聽河畔倦牛芻草聲,是我康橋經(jīng)驗中最神秘的一種:大自然的優(yōu)美、寧靜,調(diào)諧在這星光與波光的默契中不期然的淹入了你的性靈。 </div> </div> </div> </body> <script> let wrap = document.querySelector('.content') // 創(chuàng)建 createTreeWalker 迭代器,用于遍歷文本節(jié)點,保存到一個數(shù)組 const treeWalker = document.createTreeWalker(wrap, NodeFilter.SHOW_TEXT); const allTextNodes = []; let currentNode = treeWalker.nextNode(); while (currentNode) { allTextNodes.push(currentNode); currentNode = treeWalker.nextNode(); } let search = document.getElementById('search') search.onchange = event => { let value = event.target.value // 清除上個高亮 CSS.highlights.clear(); if (!value) { return } let indices = [] // 位置信息 const ranges = allTextNodes .map((el) => { return { el, text: el.textContent.toLowerCase() }; }) .map(({ text, el }) => { let startPos = 0 while (startPos < text.length) { const index = text.indexOf(value, startPos); if (index === -1) break indices.push({ el, start: index, end: index + value.length }); startPos = index + value.length; } }); // 根據(jù)搜索詞的位置創(chuàng)建選區(qū) let result = indices.map(item => { let range = new Range(); range.setStart(item.el, item.start); range.setEnd(item.el, item.end); return range }); // 創(chuàng)建高亮對象 const searchResultsHighlight = new Highlight(...result); // 注冊高亮 CSS.highlights.set("search-results", searchResultsHighlight); } </script> </html>
四、總結(jié)
以上就是關(guān)于 CSS Custom Highlight API
的使用方法:
- 1. 獲取文字節(jié)點
createTreeWalker()
- 2. 創(chuàng)建選區(qū)
new Range()
- ???????3. 創(chuàng)建高亮
new Highlight()
- ???????4. 自定義樣式
::hightlight()
**
highlight()
自定義樣式只兼容以下:
文本顏色 `color` 背景顏色 `background-color` 文本修飾 `text-decoration` 文本陰影 `text-shadow` 文本描邊 `-webkit-text-stroke` 文本填充 `-webkit-text-fill-color`
以下是兼容性,比較差,目前谷歌只兼容 Chrome 105
以上
以上就是JS+CSS實現(xiàn)高亮關(guān)鍵詞(不侵入DOM)的方式的詳細內(nèi)容,更多關(guān)于JS+CSS高亮關(guān)鍵詞的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js定時器(執(zhí)行一次、重復(fù)執(zhí)行)
這篇文章主要分享一段js代碼,有關(guān)js定時器的小例子,分為執(zhí)行一次的定時器與重復(fù)執(zhí)行的定時器,需要的朋友可以參考下2014-03-03JavaScript樹型數(shù)據(jù)與一維數(shù)組相互轉(zhuǎn)換方式
這篇文章主要介紹了JavaScript樹型數(shù)據(jù)與一維數(shù)組相互轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06