vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue自定义组件

vue自定义组件search-box示例详解

作者:longxiaoming

这篇文章主要介绍了vue自定义组件search-box,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

github地址: https://github.com/lxmghct/my-vue-components

组件介绍

效果展示

设计思路

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

1. 界面

界面上比较简单, 输入框、当前/总数、上一个、下一个、关闭按钮。

<div class="search-box" :style="boxStyle">
  <input
    v-model="input"
    placeholder="请输入检索内容"
    class="search-input"
    type="text"
    @input="search"
  >
  <!--当前/总数、上一个、下一个、关闭-->
  <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. 检索与跳转

这部分是search-box的核心功能,一共有以下几个需要解决的问题:

获取所有文本

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)
    }
}

高亮检索词

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])
  }
}
// 将节点插入到parent的指定位置
// insertBofore会将节点从原来的位置移除,导致引错误,所以不能用forEach
while (tempNode.firstChild) {
  parent.insertBefore(tempNode.firstChild, textNode)
}
parent.removeChild(textNode)

跳转
由于结果对应的dom节点已保存,所以跳转起来比较容易。跳转时修改当前高亮的dom节点的类名, 然后将其滚动到可视区域。

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() // 合并相邻的文本节点
        }
    })
}

3. 添加对iframe的支持

有时候页面中可能会包含iframe标签, 如果需要检索iframe中的内容, 直接使用当前的document是无法获取到iframe中的内容的, 需要拿到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发生变化, 则需要重新给其生成样式, 否则样式会失效。

其他问题

到此这篇关于vue自定义组件——search-box的文章就介绍到这了,更多相关vue自定义组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文