在这里提供种实现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>