vue如何实现一个auto-complete组件

版权声明: https://blog.csdn.net/weixin_41826907/article/details/80458489

在这里提供种实现auto-complete组件的思路
auto-complete的效果
这里写图片描述
一、通过vue指令来实现auto-complete

<template>
  <div>
    <div class="search">
      <input class="search__input" @click.stop @focus="focus" placeholder="搜索" @keyup.13="search" v-model="keyWord" type="text" />
      <i @click="search" class="search__icon iconfont icon-ICONbiaozhun_fuzhi-"></i>
      <transition name="slide">
        <nav-drap
          v-clickOut="hideDrap"
          @checkMenuItem="checkMenuItem"
          v-if="showDrap"
          :list="webMap"
          class="nav-drap" />
      </transition>
    </div>
  </div>
</template>

<script>
import NavDrap from '../nav-drap/nav-drap.vue'
export default {
  components: {
    NavDrap
  },
  data () {
    return {
      showDrap: false,
      keyWord: '',
      webMap: [
        {name: 'navBar.scientificResearch'},
        {name: 'navBar.treatmentCenter'},
        {name: 'navBar.personnel'},
        {name: 'navBar.purchase'},
        {name: 'navBar.continuingEducation'}
      ]
    }
  },
  directives: {
    clickOut: {
      bind: (el, binding) => {
        // removeEventListener只能移除对象上的某个具名函数
        function handler (e) {
          if (el.contains(el.target)) return false
          binding.value()
        }
        el.handler = handler
        document.addEventListener('click', el.handler)
      },
      unbind: function (el) {
        document.removeEventListener('click', el.handler)
      }
    }
  },
  methods: {
    search () {
      this.$emit('search', this.keyWord)
    },
    hideDrap () {
      this.showDrap = false
    },
    focus () {
      this.showDrap = true
    },
    checkMenuItem (e) {
      this.keyWord = e
      this.showDrap = false
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~@/assets/scss/variable.scss';
.search {
    border-radius: 20px;
    height: 30px;
    width: 200px;
    background-color: #f2f3f5;
    position: relative;
    &__input {
      display: inline-block;
      background-color: #f2f3f5;
      margin: 0 0 0 12px;
      height: 30px;
      line-height: 30px;
      width: 160px;
      text-decoration: none;
      border: none;
      font-size: $text-size-16;
      color: $text-color-2;
    }
    .nav-drap {
      width: 200px;
      top: 40px;
      left: 0;
    }

    &__icon {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      color: $theme-sub-1;
      font-size: $text-size-sm;
      cursor: pointer;
      &:hover {
        color: $theme;
      }
    }
    :-moz-placeholder { /* Mozilla Firefox 4 to 18 */
    color: $text-color-3;
    }

    ::-moz-placeholder { /* Mozilla Firefox 19+ */
        color: $text-color-3;
    }

    input:-ms-input-placeholder{
        color: $text-color-3;
    }

    input::-webkit-input-placeholder{
        color: $text-color-3;
    }
  }
</style>

二、通过定时器来实现

/**
* 主要利用input的blur、focus事件来控制NavDrap的显示与掩藏
* 需要注意的是,input的blur事件会在checkMenuItem触发之前就发生,所以在点击NavDrap时,input的blur事件已发生,
* 在checkMenuItem事件发生前,NavDrap已消失,所以通过drapClik控制下
* 事件,以保证checkMenuItem能够正常发生
 */
<template>
  <div>
    <div class="search">
      <input class="search__input" @focus="focus" @blur="blur" placeholder="搜索" @keyup.13="search" v-model="keyWord" type="text" />
      <i @click="search" class="search__icon iconfont icon-ICONbiaozhun_fuzhi-"></i>
      <transition name="slide">
        <nav-drap
          @checkMenuItem="checkMenuItem"
          @mouseenter="enter"
          @mouseleave="leave"
          v-if="showDrap"
          :list="webMap"
          class="nav-drap" />
      </transition>
    </div>
  </div>
</template>

<script>
import NavDrap from '../nav-drap/nav-drap.vue'
export default {
  components: {
    NavDrap
  },
  data () {
    return {
      drapClik: true,
      showDrap: false,
      keyWord: '',
      webMap: [
        {name: 'navBar.scientificResearch'},
        {name: 'navBar.treatmentCenter'},
        {name: 'navBar.personnel'},
        {name: 'navBar.purchase'},
        {name: 'navBar.continuingEducation'}
      ]
    }
  },
  methods: {
    search () {
      this.$emit('search', this.keyWord)
    },
    focus () {
      this.showDrap = true
    },
    enter () {
      this.drapClik = false
    },
    leave () {
      this.drapClik = true
    },
    blur () {
      let timer = setInterval(() => {
        if (this.drapClik) {
          this.showDrap = false
          clearInterval(timer)
          this.drapClik = true
        }
      }, 80)
    },
    checkMenuItem (e) {
      this.drapClik = true
      this.keyWord = e
      this.showDrap = false
    }
  }
}
</script>

这里附上nav-drap的代码

<template>
  <div class="drap" @mouseenter="mouseenter" @mouseleave="mouseleave">
    <i class="iconfont icon-yooxi drap__icon"></i>
    <a
      href="javascript:;"
      @click="checkMenuItem(item)"
      v-for="(item, index) in list"
      :key="index"
      :class="{'item-active': currentMenuItem === item.name}"
      class="item"
      >
      {{$t(item.name)}}
    </a>
  </div>
</template>

<script>
export default {
  props: {
    list: {
      type: Array,
      default: function () {
        return []
      }
    },
    currentMenuItem: ''
  },
  methods: {
    checkMenuItem (e) {
      this.$emit('update:currentMenuItem', e.name)
      this.$emit('checkMenuItem', e)
    },
    mouseenter () {
      this.$emit('mouseenter')
    },
    mouseleave () {
      this.$emit('mouseleave')
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~@/assets/scss/variable.scss';
@import '~@/assets/scss/mixins.scss';
.drap {
  width: 170px;
  background-color: #ffffff;
  padding: 10px 0;
  border-radius: 7px;
  position: absolute;
  z-index: 30;
  box-shadow: 0 1px 1px 1px $text-color-3;/*no*/
  &__icon{ position: absolute;
    top: -12px;
    font-size: 14px;
    left: 16px;
    color: $text-color-3;
  }
  .item {
    display: block;
    font-size: $text-size-xs;
    text-align: center;
    color: $text-color-3;
    // padding: 10px 20px;
    padding: 10px 0;
    &:hover { background-color: $theme-sub-hover;
      color: $text-color-hover;
    }
    @include single
  }
  .item-active {
    background-color: $theme !important;
    color: #ffffff !important;
  }
}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_41826907/article/details/80458489
今日推荐