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

在这里提供种实现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>
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一个简单的示例代码,但需要注意的是,此示例代码仅用于参考目的,您需要根据自己的实际需求进行修改和优化。 首先,在Vue项目中安装Element UI库: ``` npm install element-ui -S ``` 然后,在您的Vue组件中引入Element UI的样式和组件: ```vue <template> <div class="login"> <el-form ref="loginForm" :model="form" label-width="80px"> <el-form-item label="用户名" prop="username"> <el-input v-model="form.username" auto-complete="off"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="form.password" auto-complete="off"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login">登录</el-button> </el-form-item> </el-form> </div> </template> <script> import { ElForm, ElFormItem, ElInput, ElButton } from 'element-ui'; export default { name: 'Login', components: { ElForm, ElFormItem, ElInput, ElButton, }, data() { return { form: { username: '', password: '', }, }; }, methods: { login() { this.$refs.loginForm.validate(valid => { if (valid) { // TODO: 发送登录请求 console.log('登录成功'); } }); }, }, }; </script> <style> .login { margin: 50px auto; max-width: 500px; } </style> ``` 在上面的代码中,我们使用了Element UI的`el-form`、`el-form-item`、`el-input`和`el-button`组件实现登录表单。当用户点击“登录”按钮时,我们调用`login`方法,该方法首先调用`validate`方法验证表单输入是否合法,如果合法则向服务器发送登录请求。 需要注意的是,在实际项目中,您还需要编写后端接口来处理登录请求,并且在登录成功后将用户的登录状态保存在本地或服务器端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值