vue自定義組件search-box示例詳解
github地址: https://github.com/lxmghct/my-vue-components
組件介紹
- props:
- value/v-model: 檢索框的值, default: ''
- boxStyle: 檢索框的樣式, default: 'position: fixed; top: 0px; right: 100px;'
- highlightColor: 高亮顏色, default: 'rgb(246, 186, 130)'
- currentColor: 當(dāng)前高亮顏色, default: 'rgb(246, 137, 31)'
- selectorList: 檢索的選擇器列表, default: []
- iFrameId: 檢索的iframe的id, default: null, 若需要搜索iframe標(biāo)簽中的內(nèi)容, 則將該參數(shù)設(shè)為目標(biāo)iframe的id
- beforeJump: 跳轉(zhuǎn)前的回調(diào)函數(shù), default: () => {}
- afterJump: 跳轉(zhuǎn)后的回調(diào)函數(shù), default: () => {}
- (注: 上述兩個(gè)回調(diào)函數(shù)參數(shù)為currentIndex, currentSelector, lastIndex, lastSelector)
- events:
- @search: 檢索時(shí)觸發(fā), 參數(shù)為input和total
- @goto: 跳轉(zhuǎn)時(shí)觸發(fā), 參數(shù)為index
- @close: 關(guān)閉時(shí)觸發(fā)
- methods:
- clear() 清空檢索框
- search() 檢索
效果展示
設(shè)計(jì)思路
完整代碼見(jiàn)github: https://github.com/lxmghct/my-vue-components在其中的src/components/SearchBox下。
1. 界面
界面上比較簡(jiǎn)單, 輸入框、當(dāng)前/總數(shù)、上一個(gè)、下一個(gè)、關(guān)閉按鈕。
<div class="search-box" :style="boxStyle"> <input v-model="input" placeholder="請(qǐng)輸入檢索內(nèi)容" class="search-input" type="text" @input="search" > <!--當(dāng)前/總數(shù)、上一個(gè)、下一個(gè)、關(guān)閉--> <span class="input-append"> {{ current }}/{{ total }} </span> <span class="input-append" @click="searchPrevious"> <div class="svg-container"> <svg width="100px" height="100px"> <path d="M 100 0 L 0 50 L 100 100" stroke="black" fill="transparent" stroke-linecap="round"/> </svg> </div> </span> <span class="input-append" @click="searchNext"> <div class="svg-container"> <svg width="100px" height="100px" transform="rotate(180)"> <path d="M 100 0 L 0 50 L 100 100" stroke="black" fill="transparent" stroke-linecap="round"/> </svg> </div> </span> <span class="input-append" @click="searchClose"> <div class="svg-container"> <svg width="100%" height="100%"> <line x1="0" y1="0" x2="100%" y2="100%" stroke="black" stroke-width="1" /> <line x1="100%" y1="0" x2="0" y2="100%" stroke="black" stroke-width="1" /> </svg> </div> </span> </div>
2. 檢索與跳轉(zhuǎn)
這部分是search-box的核心功能,一共有以下幾個(gè)需要解決的問(wèn)題:
- 獲取待搜索的容器
- 為提高組件的通用性,可以通過(guò)傳入選擇器列表來(lái)獲取容器,如
['.container', '#containerId']
,使用document.querySelector()
獲取容器。
- 為提高組件的通用性,可以通過(guò)傳入選擇器列表來(lái)獲取容器,如
獲取所有文本
if (node.nodeType === Node.TEXT_NODE) { // text node callback(node) } else if (node.nodeType === Node.ELEMENT_NODE) { // element node for (let i = 0; i < node.childNodes.length; i++) { traverseTextDom(node.childNodes[i], callback) } }
- 不能單獨(dú)對(duì)某個(gè)dom節(jié)點(diǎn)獲取文本, 因?yàn)槟硞€(gè)待搜索詞可能被分割在多個(gè)節(jié)點(diǎn)中, 例如
<span>hello</span><span>world</span>
,所以需要獲取整個(gè)容器內(nèi)的所有文本拼接起來(lái), 然后再進(jìn)行檢索。 - 使用
innetText
獲取文本會(huì)受到樣式影響, 具體見(jiàn)文章最后的其它問(wèn)題。所以需要遍歷所有節(jié)點(diǎn)將文本拼接起來(lái)。 - 遍歷文本節(jié)點(diǎn)時(shí), 可以用
node.nodeType === Node.TEXT_NODE
判斷是否為文本節(jié)點(diǎn)。 - 檢索結(jié)果的保存
- 由于查找完之后需要實(shí)現(xiàn)跳轉(zhuǎn), 所以為方便處理, 將檢索到的結(jié)果所在的dom節(jié)點(diǎn)保存起來(lái), 以便后續(xù)跳轉(zhuǎn)時(shí)使用。每個(gè)結(jié)果對(duì)應(yīng)一個(gè)domList。
高亮檢索詞
function createCssStyle (css) { const style = myDocument.createElement('style') style.type = 'text/css' try { style.appendChild(myDocument.createTextNode(css)) } catch (ex) { style.styleSheet.cssText = css } myDocument.getElementsByTagName('head')[0].appendChild(style) }
const tempNode = myDocument.createElement('span') tempNode.innerHTML = textHtml const children = tempNode.children if (children) { for (let i = 0; i < children.length; i++) { domList.push(children[i]) } } // 將節(jié)點(diǎn)插入到parent的指定位置 // insertBofore會(huì)將節(jié)點(diǎn)從原來(lái)的位置移除,導(dǎo)致引錯(cuò)誤,所以不能用forEach while (tempNode.firstChild) { parent.insertBefore(tempNode.firstChild, textNode) } parent.removeChild(textNode)
- 使用span標(biāo)簽包裹檢索詞, 并設(shè)置樣式, 實(shí)現(xiàn)高亮。
- 為了避免檢索詞被html標(biāo)簽分割, 可以對(duì)檢索詞的每個(gè)字符都用span標(biāo)簽包裹, 例如檢索詞為
hello
,則可以將其替換為<span>h</span><span>e</span><span>l</span><span>l</span><span>o</span>
。 - 樣式設(shè)置可以給span設(shè)置background-color, 為了方便修改并減小整體html長(zhǎng)度, 可以改為給span設(shè)置class, 注意這種情況下在style標(biāo)簽設(shè)置的樣式未必有效, 可以采用動(dòng)態(tài)添加樣式的方式。
- 將span標(biāo)簽插入到原先文本節(jié)點(diǎn)的位置, 若使用innerHtml直接進(jìn)行替換, 處理起來(lái)略有些麻煩??梢钥紤]使用insertBefore和removeChild方法。
跳轉(zhuǎn)
由于結(jié)果對(duì)應(yīng)的dom節(jié)點(diǎn)已保存,所以跳轉(zhuǎn)起來(lái)比較容易。跳轉(zhuǎn)時(shí)修改當(dāng)前高亮的dom節(jié)點(diǎn)的類(lèi)名, 然后將其滾動(dòng)到可視區(qū)域。
setCurrent (index) { const lastSelector = this.searchResult[this.currentIndex] ? this.searchResult[this.currentIndex].selector : null const currentSelector = this.searchResult[index] ? this.searchResult[index].selector : null if (this.currentIndex >= 0 && this.currentIndex < this.searchResult.length) { this.searchResult[this.currentIndex].domList.forEach((dom) => { dom.classList.remove(this.currentClass) }) this.searchResult[this.currentIndex].domList[0].scrollIntoView({ behavior: 'smooth', block: 'center' }) } this.currentIndex = index if (this.currentIndex >= 0 && this.currentIndex < this.searchResult.length) { this.searchResult[this.currentIndex].domList.forEach((dom) => { dom.classList.add(this.currentClass) }) } }
移除高亮效果
function convertHighlightDomToTextNode (domList) { if (!domList || !domList.length) { return } domList.forEach(dom => { if (dom && dom.parentNode) { const parent = dom.parentNode const textNode = myDocument.createTextNode(dom.textContent) parent.insertBefore(textNode, dom) parent.removeChild(dom) parent.normalize() // 合并相鄰的文本節(jié)點(diǎn) } }) }
- 由于高亮效果是通過(guò)給text節(jié)點(diǎn)添加span標(biāo)簽實(shí)現(xiàn), 所以需要將span標(biāo)簽移除, 并替換為原先的文本節(jié)點(diǎn)。
- 使用
insertBefore
和removeChild
方法。 - 替換完節(jié)點(diǎn)后需要調(diào)用
normalize()
方法, 將相鄰的文本節(jié)點(diǎn)合并為一個(gè)文本節(jié)點(diǎn)。
3. 添加對(duì)iframe的支持
有時(shí)候頁(yè)面中可能會(huì)包含iframe標(biāo)簽, 如果需要檢索iframe中的內(nèi)容, 直接使用當(dāng)前的document是無(wú)法獲取到iframe中的內(nèi)容的, 需要拿到iframe的document對(duì)象。
const myIframe = document.getElementById(this.iframeId) if (myIframe) { myDocument = myIframe.contentDocument || myIframe.contentWindow.document } else { myDocument = document } if (myIframe && this.lastIframeSrc !== myIframesrc) { const css = `.${this.highlightClass} { background-color: ${this.highlightColor}; } .${this.currentClass} { background-color: ${this.currentColor}; }` createCssStyle(css) this.lastIframeSrc = myIframe.src }
同一個(gè)iframe, 如果src發(fā)生變化, 則需要重新給其生成樣式, 否則樣式會(huì)失效。
其他問(wèn)題
- 使用svg畫(huà)按鈕圖標(biāo)時(shí),雙擊svg按鈕會(huì)自動(dòng)觸發(fā)全選
- 解決方法: 在svg標(biāo)簽所在容器上添加
user-select: none;
樣式
- 解決方法: 在svg標(biāo)簽所在容器上添加
- 使用
node.nodeType === Node.TEXT_NODE
判斷文本節(jié)點(diǎn)時(shí),會(huì)遇到一些空節(jié)點(diǎn),導(dǎo)致檢索錯(cuò)誤- 解決方法: 在判斷文本節(jié)點(diǎn)時(shí),加上
node.textContent.trim() !== ''
的判斷, 獲取所有元素的文本時(shí)。 - 后續(xù)修改: 可以不單獨(dú)處理這些空的文本節(jié)點(diǎn), 只要保證所有使用到獲取文本的地方都統(tǒng)一使用或不使用
trim()
即可。盡量都不使用trim()
, 如果隨意使用trim()
,可能會(huì)導(dǎo)致部分空白字符被誤刪。
- 解決方法: 在判斷文本節(jié)點(diǎn)時(shí),加上
到此這篇關(guān)于vue自定義組件——search-box的文章就介紹到這了,更多相關(guān)vue自定義組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue實(shí)現(xiàn)抽獎(jiǎng)效果Demo
這篇文章主要介紹了vue實(shí)現(xiàn)抽獎(jiǎng)效果Demo,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Vue表單綁定的實(shí)例代碼(單選按鈕,選擇框(單選時(shí),多選時(shí),用 v-for 渲染的動(dòng)態(tài)選項(xiàng))
本文通過(guò)實(shí)例代碼給大家介紹了Vue表單綁定(單選按鈕,選擇框(單選時(shí),多選時(shí),用 v-for 渲染的動(dòng)態(tài)選項(xiàng))的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-05-05vue-cli3項(xiàng)目生產(chǎn)和測(cè)試環(huán)境分包后文件名和數(shù)量不一致解決
這篇文章主要為大家介紹了vue-cli3項(xiàng)目生產(chǎn)和測(cè)試環(huán)境分包后文件名和數(shù)量不一致解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05vue組件實(shí)現(xiàn)移動(dòng)端九宮格轉(zhuǎn)盤(pán)抽獎(jiǎng)
這篇文章主要為大家詳細(xì)介紹了vue組件實(shí)現(xiàn)移動(dòng)端九宮格轉(zhuǎn)盤(pán)抽獎(jiǎng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10vue+element項(xiàng)目中過(guò)濾輸入框特殊字符小結(jié)
這篇文章主要介紹了vue+element項(xiàng)目中過(guò)濾輸入框特殊字符小結(jié),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08vue composition-api 封裝組合式函數(shù)的操作方法
在 Vue 應(yīng)用的概念中,“組合式函數(shù)”(Composables) 是一個(gè)利用 Vue 的組合式 API 來(lái)封裝和復(fù)用有狀態(tài)邏輯的函數(shù),這篇文章主要介紹了vue composition-api 封裝組合式函數(shù)的操作方法,需要的朋友可以參考下2022-10-10elementUI動(dòng)態(tài)表單?+?el-select?按要求禁用問(wèn)題
這篇文章主要介紹了elementUI動(dòng)態(tài)表單?+?el-select?按要求禁用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Vue實(shí)現(xiàn)簡(jiǎn)單圖片切換效果
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)簡(jiǎn)單圖片切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06