Vue關鍵詞搜索高亮


有時候給頁面內容添加一個關鍵詞搜索功能,如果搜索結果能夠像瀏覽器搜索一樣高亮顯示,那找起來就會很明顯體驗會好很多。本文就介紹一下關鍵詞搜索高亮的實現方案。

實現效果大概如下:

可在線預覽:http://wintc.top/laboratory/#/search-highlight。

 

一、實現原理

實現原理很簡單:使用正則匹配出文本內容中的所有關鍵詞,在關鍵詞外包一層內聯標簽,比如span或者font,通過innerhtml渲染文本。使用css控制插入的內聯元素樣式,並且記錄下當前搜索到的結果是第幾個,使用不同的樣式來展示。

比如文本內容是“實現江畔何人初見月?江月何年初照人?”,而關鍵詞是“月”,那替換后的字符串可能變為:

江畔何人初見<font style="background: #ff9632">月</font>?江<font style="background: #ffff00">月</font>何年初照人?

其中匹配的“月”被替換成了<font>月</font>,並且設置font標簽的背景色,使得搜索到的第一個“月”(當前關鍵詞)背景變為橘黃色,而第二個“月”背景變為黃色。

本文基於vue實現了一個組件,並且將組件發布到了npm上,如果你不想自己寫組件,可以直接安裝使用:vue-search-highlight。
接下來會介紹一下組件vue-search-highlight的使用,然后給出Vue中的搜索高亮的代碼實現。

 

二、vue-search-highlight組件使用

組件需要傳入文本content以及關鍵詞keyword,組件會渲染出一個包含content並且關鍵詞被font元素替換的div元素。
組件功能如下:

關鍵詞高亮
關鍵詞匹配總數以及當前關鍵詞的索引(即是第幾個搜索結果)
查找上一個、下一個功能,調用相應函數即可跳到上一個或者下一個

使用方法:

安裝組件,使用npm或者yarn
// 如果使用yarn yarn add vue-search-highlight // 如果使用npm npm add vue-search-highlight​
引入
vue-search-highlight本身是一個組件,在需要搜索高亮的頁面里引入后,像正常的組件一樣使用即可。
import SearchHighlight from 'vue-search-highlight' // 注冊為子組件 components: { 'search-highlight': SearchHighlight },​
props
props 說明 備注
content 需要展示的文本,搜索即在這個文本中進行。  
keyword 關鍵詞  
highlightStyle 關鍵詞高亮的css樣式 非必傳,參照瀏覽器搜索,默認設置背景為黃色#ffff00
currentStyle 當前關鍵詞高亮的CSS樣式 非必傳,參照瀏覽器搜索,默認設置背景為橘黃色#ff9632
 
events
組件有兩個重要的數據,即搜索匹配數量和當前關鍵詞索引,會通過$emit彈射出來,如果需要展示搜索索引和匹配總數(比如 3 / 16),你可以監聽組件的這兩個事件:
事件名 返回值
@current-change 返回值:當前關鍵詞索引。
關鍵詞改變的時候,如果搜索到內容,會返回1,搜索不到則返回0。
@mactch-count-change 返回值:文本匹配關鍵詞總數。
methods
你可以通過ref引用組件,直接調用組件內部的一些方法:
方法名 參數 說明
searchNext 下一個關鍵詞滾動到可視區域
searchLast 上一個關鍵詞滾動到可視區域
scrollTo index 滾動到第index(從1開始)個關鍵詞
 

使用示例:

<search-highlight
  class="search-highlight" ref="search" @current-change="currentChange" @mactch-count-change="matchCountChange" :content="content" :keyword="keyword"> </search-highlight> <script> import SearchHighlight from 'vue-search-highlight' export default { components: { SearchHighlight }, data () { return { currentIdx: 0, matchCount: 0, keyword: '月', content: ` 春江花月夜 [唐] 張若虛 春江潮水連海平,海上明月共潮生。 灧灧隨波千萬里,何處春江無月明! 江流宛轉繞芳甸,月照花林皆似霰; 空里流霜不覺飛,汀上白沙看不見。 江天一色無纖塵,皎皎空中孤月輪。 江畔何人初見月?江月何年初照人? 人生代代無窮已,江月年年望相似。 不知江月待何人,但見長江送流水。 白雲一片去悠悠,青楓浦上不勝愁。 誰家今夜扁舟子?何處相思明月樓? 可憐樓上月徘徊,應照離人妝鏡台。 玉戶簾中卷不去,搗衣砧上拂還來。 此時相望不相聞,願逐月華流照君。 鴻雁長飛光不度,魚龍潛躍水成文。 昨夜閑潭夢落花,可憐春半不還家。 江水流春去欲盡,江潭落月復西斜。 斜月沉沉藏海霧,碣石瀟湘無限路。 不知乘月幾人歸,落月搖情滿江樹。`, } }, methods: { searchNext () { this.$refs.search.searchNext() }, searchLast () { this.$refs.search.searchLast() }, matchCountChange (count) { this.matchCount = count }, currentChange (idx) { this.currentIdx = idx }, checkKeydown (event) { if (event.shiftKey) { this.searchLast() } else { this.searchNext() } } } } </script>

廣州設計公司https://www.houdianzi.com 我的007辦公資源網站https://www.wode007.com

三、組件代碼實現

vue-search-highlight組件代碼如下:

<template> <div class="search-highlight" v-html="contentShow"> </div> </template> <script> const CLASS_NAME = 'search-hightlight' export default { props: { content: { type: String, default: '' }, keyword: { type: String, default: '' }, highlightStyle: { type: String, default: 'background: #ffff00' }, currentStyle: { type: String, default: 'background: #ff9632' } }, data () { return { lightIndex: 0, matchCount: 0 } }, computed: { contentShow () { if (!this.keyword) return this.content let reg = new RegExp(this.keyword, 'g') let stringList = this.content.split(reg) if (!stringList.length) return this.content let content = '' for (let i = 0; i < stringList.length - 1; i++) { let style = i === this.lightIndex ? this.currentStyle : this.highlightStyle content += `${stringList[i]}<fonttoken interpolation">${style}" ${CLASS_NAME}>${this.keyword}</font>` } content += stringList[stringList.length - 1] return content } }, watch: { keyword: { immediate: true, handler () { this.lightIndex = 0 this.getMatchCount() } }, lightIndex: { immediate: true, handler () { this.$emit('current-change', this.lightIndex) } }, matchCount: { immediate: true, handler () { this.$emit('mactch-count-change', this.matchCount) } } }, methods: { scrollTo (index) { this.$nextTick(() => { let list = this.$el.querySelectorAll(`font[${CLASS_NAME}]`) if (list[index]) { this.lightIndex = index list[index].scrollIntoView() } }) }, searchNext () { this.$nextTick(() => { let idx = this.lightIndex >= this.matchCount - 1 ? 0 : this.lightIndex + 1 this.scrollTo(idx) }) }, searchLast () { this.$nextTick(() => { let idx = this.lightIndex <= 0 ? this.matchCount - 1 : this.lightIndex - 1 this.scrollTo(idx) }) }, getMatchCount () { this.$nextTick(() => { let list = this.$el.querySelectorAll(`font[${CLASS_NAME}]`) this.matchCount = list.length }) }, } } </script>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM