在这里我用两种方式来实现搜索,一种是组件的未拆分,另一种是用组件拆分来实现
一、用组件的未拆封的方式来实现(Vuex来管理数据)
sore中的数据(即Vuex)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
list:[
'html','css','javascript','vue','react','jquery','html5','css3'
]
},
actions: {},
modules: {}
})
Main.vue组件
<template>
<div>
<!-- 搜索的未拆分 -->
<!-- 绑定输入框的值并作筛选 失去焦点的时候让他隐藏 当按下下键的时候执行 当按下上键的时候执行 当按下回车的时候,把值给到输入框 -->
<input type="text" v-model="val" @input="show" @blur="blur" @keydown.down.prevent="down" @keydown.up.prevent="up"
@keydown.enter.prevent="enter">
<!-- 判断鼠标移入的时候,让mouse为true,鼠标离开的时候,让mouse为false -->
<div class="search-list" v-show="isShow" @mouseenter="mouse=true" @mouseleave="mouse=false">
<!-- 当tap与要选中的下标一样的时候,选中背景变颜色 -->
<div v-for="(item,index) in list" :key="index" :class="{'sel':tap==index}" @mouseenter="tap=index" @click="enter">
{{item}}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [], //全部数据
val: '', //输入框的值
isShow: false,//判断是否要展示数据
tap: -1,//在按上键和下键以及那个鼠标移入的时候的下标
mouse: false,//判断鼠标的移入和移出
}
},
methods: {
//键盘输入事件
show() {
// 首先清空原来的数据
this.list = [];
// 拿到下标
this.tap = -1;
// 遍历所有的数据,如果输入框输入的值与list的一样,就添加到list页面上
this.$store.state.list.map(item => {
if (item.includes(this.val)) {
this.list.push(item)
}
});
// 判断list的数据的长度大于0,就展示数据,否则就隐藏
if (this.list.length > 0) {
this.isShow = true
} else {
this.isShow = false
}
},
// 输入框失去焦点
blur() {
if (this.mouse) {
return
}
this.isShow = false;
},
//下方向键
down() {
if (this.tap == this.list.length - 1) {
return
}
this.tap++;
},
// 上方向键
up() {
if (this.tap == -1) {
return
}
this.tap--;
},
// 回车事件
enter() {
this.val = this.list[this.tap];
this.isShow = false;
}
}
}
</script>
<style>
input {
width: 300px;
height: 30px;
font-size: 16px;
}
.search-list {
border: 1px solid #000;
width: 300px;
line-height: 40px;
}
.sel {
background-color: #EEEEEE;
}
</style>
最终的效果
二、用组件的拆封的方式来实现(在这里是获取json数据)
json数据(hot.json)
{
"world":[
"html",
"css",
"javascript",
"vue",
"node",
"jquery",
"html5",
"css3",
"react",
"hello"
]
}
引入axios
先执行指令:cnpm i axios --save
在main.js中引入axios
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import axios from 'axios'
Vue.config.productionTip = false
Vue.prototype.$axios = axios
new Vue({
router,
render: h => h(App)
}).$mount('#app')
在这里要用到子传父
父组件:(Test.vue)
<template>
<div>
<input type="text"
v-model="val"
@input="search"
@keydown.down.prevent="down"
@keydown.up.prevent="up"
@keydown.enter="enter"
/>
<search-list
:list="list"
:tap="tap"
:show="isShow"
@ok="enter"
@menter="mEnter"></search-list>
</div>
</template>
<script>
import SearchList from '../components/SearchList.vue'
export default {
components: {
'search-list': SearchList
},
data() {
return {
word: [], //全部的数据
val: '', //输入框中的数据
list: [], //用于存放符合搜索条件的元素
tap: -1, //被选中的元素下标
isShow: false, //搜索结果默认显示状态
}
},
// 拿到json中的数据
created() {
this.$axios.get('/hot.json')
.then(res => {
this.word = res.data.world;
})
},
methods: {
// 键盘输入事件
search() {
this.list = [];
this.isShow = true;
this.tap = -1;
this.word.map(item => {
if (item.includes(this.val)) {
this.list.push(item);
}
})
},
// 上方向键
up() {
if (this.tap == 0) {
return
}
this.tap--;
},
// 下方向键
down() {
if (this.tap == this.list.length - 1) {
return
}
this.tap++;
},
// 回车事件
enter() {
this.val = this.list[this.tap];
this.isShow = false;
},
mEnter(index) {
this.tap = index;
}
}
}
</script>
<style>
input {
width: 200px;
}
.search-list {
border: 1px solid #999;
width: 200px;
}
.search-list p {
line-height: 30px;
}
.sel {
background-color: #EEEEEE;
}
</style>
子组件:(SearchList.vue)
<template>
<div>
<div class="search-list" v-show="show">
<p v-for="(item,index) in list" :key="index" :class="{'sel':tap==index}" @mouseenter="menter(index)" @click="clickme"
class="search-item">
<span style="font-size: 14px;">{{item}}</span>
</p>
</div>
</div>
</template>
<script>
export default {
props: {
list: {
type: Array
},
tap: {
type: Number
},
show: {
type: Boolean
}
},
methods: {
clickme() {
this.$emit('ok')
},
menter(index) {
this.$emit('menter', index)
}
}
}
</script>
<style scoped="scoped">
.search-item {
border-bottom: 1px solid #eee;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>