欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue自定義組件search-box示例詳解

 更新時間:2023年05月17日 14:14:28   作者:longxiaoming  
這篇文章主要介紹了vue自定義組件search-box,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

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: () => {}
    • (注: 上述兩個回調(diào)函數(shù)參數(shù)為currentIndex, currentSelector, lastIndex, lastSelector)
  • events:
    • @search: 檢索時觸發(fā), 參數(shù)為input和total
    • @goto: 跳轉(zhuǎn)時觸發(fā), 參數(shù)為index
    • @close: 關(guān)閉時觸發(fā)
  • methods:
    • clear() 清空檢索框
    • search() 檢索

效果展示

設(shè)計思路

完整代碼見github: https://github.com/lxmghct/my-vue-components在其中的src/components/SearchBox下。

1. 界面

界面上比較簡單, 輸入框、當(dāng)前/總數(shù)、上一個、下一個、關(guān)閉按鈕。

<div class="search-box" :style="boxStyle">
  <input
    v-model="input"
    placeholder="請輸入檢索內(nèi)容"
    class="search-input"
    type="text"
    @input="search"
  >
  <!--當(dāng)前/總數(shù)、上一個、下一個、關(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的核心功能,一共有以下幾個需要解決的問題:

  • 獲取待搜索的容器
    • 為提高組件的通用性,可以通過傳入選擇器列表來獲取容器,如['.container', '#containerId'],使用document.querySelector()獲取容器。

獲取所有文本

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)
    }
}
  • 不能單獨對某個dom節(jié)點獲取文本, 因為某個待搜索詞可能被分割在多個節(jié)點中, 例如<span>hello</span><span>world</span>,所以需要獲取整個容器內(nèi)的所有文本拼接起來, 然后再進(jìn)行檢索。
  • 使用innetText獲取文本會受到樣式影響, 具體見文章最后的其它問題。所以需要遍歷所有節(jié)點將文本拼接起來。
  • 遍歷文本節(jié)點時, 可以用node.nodeType === Node.TEXT_NODE判斷是否為文本節(jié)點。
  • 檢索結(jié)果的保存
    • 由于查找完之后需要實現(xiàn)跳轉(zhuǎn), 所以為方便處理, 將檢索到的結(jié)果所在的dom節(jié)點保存起來, 以便后續(xù)跳轉(zhuǎn)時使用。每個結(jié)果對應(yīng)一個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é)點插入到parent的指定位置
// insertBofore會將節(jié)點從原來的位置移除,導(dǎo)致引錯誤,所以不能用forEach
while (tempNode.firstChild) {
  parent.insertBefore(tempNode.firstChild, textNode)
}
parent.removeChild(textNode)
  • 使用span標(biāo)簽包裹檢索詞, 并設(shè)置樣式, 實現(xiàn)高亮。
  • 為了避免檢索詞被html標(biāo)簽分割, 可以對檢索詞的每個字符都用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長度, 可以改為給span設(shè)置class, 注意這種情況下在style標(biāo)簽設(shè)置的樣式未必有效, 可以采用動態(tài)添加樣式的方式。
  • 將span標(biāo)簽插入到原先文本節(jié)點的位置, 若使用innerHtml直接進(jìn)行替換, 處理起來略有些麻煩??梢钥紤]使用insertBefore和removeChild方法。

跳轉(zhuǎn)
由于結(jié)果對應(yīng)的dom節(jié)點已保存,所以跳轉(zhuǎn)起來比較容易。跳轉(zhuǎn)時修改當(dāng)前高亮的dom節(jié)點的類名, 然后將其滾動到可視區(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é)點
        }
    })
}
  • 由于高亮效果是通過給text節(jié)點添加span標(biāo)簽實現(xiàn), 所以需要將span標(biāo)簽移除, 并替換為原先的文本節(jié)點。
  • 使用insertBeforeremoveChild方法。
  • 替換完節(jié)點后需要調(diào)用normalize()方法, 將相鄰的文本節(jié)點合并為一個文本節(jié)點。

3. 添加對iframe的支持

有時候頁面中可能會包含iframe標(biāo)簽, 如果需要檢索iframe中的內(nèi)容, 直接使用當(dāng)前的document是無法獲取到iframe中的內(nèi)容的, 需要拿到iframe的document對象。

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
}

同一個iframe, 如果src發(fā)生變化, 則需要重新給其生成樣式, 否則樣式會失效。

其他問題

  • 使用svg畫按鈕圖標(biāo)時,雙擊svg按鈕會自動觸發(fā)全選
    • 解決方法: 在svg標(biāo)簽所在容器上添加user-select: none;樣式
  • 使用node.nodeType === Node.TEXT_NODE判斷文本節(jié)點時,會遇到一些空節(jié)點,導(dǎo)致檢索錯誤
    • 解決方法: 在判斷文本節(jié)點時,加上node.textContent.trim() !== ''的判斷, 獲取所有元素的文本時。
    • 后續(xù)修改: 可以不單獨處理這些空的文本節(jié)點, 只要保證所有使用到獲取文本的地方都統(tǒng)一使用或不使用trim()即可。盡量都不使用trim(), 如果隨意使用trim(),可能會導(dǎo)致部分空白字符被誤刪。

到此這篇關(guān)于vue自定義組件——search-box的文章就介紹到這了,更多相關(guān)vue自定義組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論