⽤vue实现⼀个搜索框组件
⼀、需求描述
实现⼀个搜索框:
1、输⼊关键字,按键抬起后可以实现查询功能;
2、下拉列表展⽰搜索结果,搜索结果中关键字要⽤特殊颜⾊突出显⽰,默认选中搜索结果的第⼀项;
3、可以按上下键切换选中项,按回车输出选中项;
4、单击组件之外的地⽅可以收起下拉列表;
⼆、分析
⽤到的插件 pinyin-match:
⽀持拼⾳全拼、简拼和汉字模糊匹配。
调⽤match⽅法,匹配成功返回数组([匹配到第⼀个字符的下标,匹配到最后⼀个字符的下标]),失败返回false。
三、代码实现
<template>
<div class="search-wrapper"@click.stop>
<div class="search-input":class="{'is-focus':isFocus}">
<!-- 搜索输⼊框 -->
<input type="text"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
autofocus
v-model="value"
ref='searchInput'
spellcheck="false"
placeholder="搜索..."
@click="changeInput"
@keyup="clickSearch"
@keydown.down.prevent="navigateOptions('next')"
@keydown.up.prevent="navigateOptions('prev')">
<!-- 搜索放⼤镜图标 -->
<div class="search-icons">
<i class="el-icon-close"v-show="value"@click="clearSearchValue"></i>
<i class="el-icon-search"v-show="!value"@click="clickSearch"></i>
</div>
</div>
<!-- 搜索下拉列表 -->
<div class="search-list">
<div class="search-result"ref="ul">
<ul v-for="item in result">
<li class="select-li":class="{'is-selected': item.isSelected}"@click="clickResultItem(item)">
<img class="user-avatar"src="../../images/avatar.png">
<div class="user-name">
<span>{{item.keyword[0]}}<span class="keyword">{{item.keyword[1]}}</span>{{item.keyword[2]}}</span>
</div>
</li>
</ul>
<!-- 查询结果为空时候 -->
<div class="result-null"v-if="value && result.length == 0">
没有结果
</div>
</div>
</div>
</div>
</template>
<script>
const PinyinMatch =require('pinyin-match');
export default{
name:'SearchInput',
name:'SearchInput',
data(){
return{
isFocus:false,//搜索框是否获取了焦点
value:'',//输⼊的搜索关键字borderbox
result :[],//全部搜索结果
curIndex:0,//选中的搜索结果的下标
selectItem:{},//选中的搜索结果
userList:[
{name:'安其拉',id:'a1'},
{name:'安琪',id:'a2'},
{name:'陈仙仙', id:'c1'},
{name:'成⼩龙', id:'c2'},
{name:'程野', id:'c3'},
{name:'丁⼩明', id:'d1'},
{name:'丁⼩龙', id:'d2'},
{name:'丁⼩野', id:'d3'},
{name:'冯⼩明', id:'f1'},
{name:'冯⼩龙', id:'f2'},
{name:'冯⼩野', id:'f3'},
{name:'⾼⼩明', id:'g1'},
{name:'⾼⼩龙', id:'g2'},
{name:'⾼⼩野', id:'g3'},
{name:'⾼⼩阳', id:'g4'},
{name:'郭⼩名', id:'g5'},
{name:'黄⼩明', id:'h1'},
{name:'黄⼩龙', id:'h2'},
{name:'黄⼩野', id:'h3'},
{name:'郝⼩阳', id:'h4'},
{name:'郝⼩名', id:'h5'},
{name:'李⼩明',id:'l1'},
{name:'李⼩龙',id:'l2'},
{name:'李⼩野',id:'l3'},
{name:'李⼩阳',id:'l4'},
{name:'李⼩⼀',id:'l5'},
{name:'李⼩⼆',id:'l6'},
{name:'李⼩三',id:'l7'},
{name:'李⼩四',id:'l8'},
{name:'李⼩五',id:'l9'},
]
}
},
mounted(){
let that =this;
document.body.addEventListener('click',()=>{//单击组件之外时收起下拉列表 that.isFocus =false;
that.value ="";
},false);
},
methods:{
changeInput(){//单击搜索框时获取焦点
this.isFocus =true;
},
clearSearchValue(){//清空输⼊的查询条件
if(this.value){
this.value ="";//搜索关键字
this.curIndex =0;//选中的搜索结果的下标
this.selectItem ={};//选中的搜索结果
this.$refs.searchInput.focus();//输⼊查询条件清空后获取焦点
}
},
clickSearch(){//查询
de =="ArrowDown"|| de =="ArrowUp"){//上下键
return;
}
de =="Enter"&&this.selectItem){
this.clickResultItem(this.selectItem);//有搜索结果时按下enter直接选中第⼀项return;
}
this.curIndex =0;//选中的搜索结果的下标
this.selectItem ={};//选中的搜索结果
if(im()){
for(let i =0; i <this.userList.length; i++){//根据所有⼈员名字匹配
let name =this.userList[i].name;
let search = PinyinMatch.match(name,this.value);
if(search && search.length >0){
this.userList[i].keyword =KeyWord(name, search);
this.userList[i].isSelected =false;
this.userList[i].isSelected =false;
}
}
sult &&sult[0]){
this.curIndex =0;//选中的搜索结果的下标
this.selectItem =sult[0];//选中的搜索结果
}
}else{
this.$refs.searchInput.focus();//没有输⼊查询条件焦点不应该失去
}
},
getKeyWord(name, search){//关键字
let keyword =[];
keyword[0]= name.substring(0, search[0]);
if(search[0]== search[1]){
keyword[1]= name.charAt(search[0]);//匹配到的作为关键字
keyword[2]= name.substring(search[0]+1);
}else{
keyword[1]= name.substring(search[0], search[1]+1);//匹配到的作为关键字 keyword[2]= name.substring(search[1]+1);
}
return keyword;
},
clickResultItem(data){//单击下拉列表中的选项
alert('您选择了'+ data.name);
},
navigateOptions(direction){//搜索结果上下键选择
let resultLength =sult.length;
if(resultLength ==0|| resultLength ==1){
return;
}
let lastIndex =this.curIndex;
if(direction ==='next'){//向下
this.curIndex++;
if(this.curIndex === resultLength){
this.curIndex =0;
}
}
if(direction ==='prev'){//向上
this.curIndex--;
if(this.curIndex <0){
this.curIndex = resultLength -1;
}
}
if(lastIndex < resultLength){
}
if(-1<this.curIndex < resultLength){
this.selectItem =sult[this.curIndex];
this.selectItem.isSelected =true;
/
/ sult[this.curIndex].isSelected = true;
this.$sult,this.curIndex,this.selectItem)
}
},
resetScrollTop(){//设置滚动条的位置
let maxShowCount =this.$refs.ul.clientHeight /50;
let diff =this.curIndex - maxShowCount;
diff +=4;
this.$refs.ul.scrollTop = diff *(50)+60;
},
}
}
</script>
<style src="./index.scss"lang="scss"></style>
index.scss
.search-wrapper{
background-color:rgb(235, 148, 148);
height: 580px;
width:325px;
overflow: hidden;
border-radius: 3px;
font-family:'Microsoft YaHei';
font-family:'Microsoft YaHei';
box-sizing: border-box;
padding: 10px;
.search-input{
position: relative;
input{
width: 100%;
height: 35px;
box-sizing: border-box;
border: 0;
border-radius: 3px;
margin: 0;
padding: 0px 40px 0px 10px;
outline: 0;
font-size: 14px;
color: #E5EAEE;
// background-color: #209df7;
background-color: #fff;
}
input::-webkit-input-placeholder{
color: #E5EAEE;
}
.search-icons{
position: absolute;
top: 7px;
right: 10px;
color: #209df7;
font-size: 17px;
}
}
.is-focus{
overflow: visible !important;
input{
color: #222 !important;
// border: 1px solid #fff !important;
// background-color: #fff !important;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2), 0 1px 15px hsla(0, 0%, 100%, .3)!important; }
.search-icons{
.el-icon-close{
color: #111;
background-color: #d8d8d8;
border-radius: 50%;
padding: 2px;
box-sizing: border-box;
font-size: 15px;
cursor: pointer;
}
.el-icon-close:hover{
color: #fff;
background-color: #209df7;
}
}
}
.search-list{
height: 480px;
margin-top: 8px;
border: 0 none;
border-radius: 3px;
box-shadow: 0 0 6px rgba(0, 0, 0, .15);
background-color: #fff;
.search-result{
height: 100%;
overflow-x: hidden;
overflow-y: auto;
ul, li{
ul, li{
margin: 0px;
padding: 0px;
}
li{
list-style-type: none;
}
.select-li{
cursor: pointer;
padding: 8px 10px;
overflow: hidden;
border-bottom: 1px solid #ebebeb;
.user-avatar{
border-radius: 50%;
float: left;
width: 40px;
height: 40px;
background-size: cover;
}
.user-name{
width: 200px;
float: left;
margin-left: 15px;
line-height: 40px;
.keyword{
color: #008cee;
}
}
}
.select-li:hover{
background-color: #e5f0fa;
}
.is-selected{
background-color:rgba(140, 197, 255, 0.46) }
}
.result-null{
margin-top: 100px;
text-align: center;
font-size: 20px;
}
}
}
::-webkit-scrollbar{
width: 6px;
height: 6px;
}
/*滑动轨道*/
::-webkit-scrollbar-track-piece{
background-color: transparent;
-webkit-border-radius: 6px;
}
// 下⾯是滑块
/*竖向滚动条*/
::-webkit-scrollbar-thumb:vertical{
height: 5px;
background-color:rgb(161, 161, 161);
-webkit-border-radius: 6px;
}
/*横向滚动条*/
::-webkit-scrollbar-thumb:horizontal{
width: 5px;
background-color:rgb(143, 144, 145);
-webkit-border-radius: 6px;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论