Vue实现的输入框自动补全插件:
先说实现的效果:
不想废话,主要用到了以下的几点:
1.子组件需要通过父组件输入的关键字从后端做智能匹配,这里使用
props:父组件向子组件传递参数
$parent.$data:子组件对父组件的参数进行赋值
目的:父子组件通信
2.CSS切换效果,这里主要对生成的下拉列表中的枚举进行选择时,页面的动画效果
3.为了保证点击屏幕中其他位置,使页面弹出的智能提示下拉列表消失。这里使用blur事件,不过控件中同时使用了click事件,为了保证点中下拉列表中的每项的click事件不被输入框的blur事件覆盖,这里给blur事件中添加settimeout方法,以保证click事件能够正常执行!
4.网络传输使用异步,不过这里使用原生的XMLHttpRequest来进行通信,而不使用vue-resource,目的是尽可能的脱离对其他vue的库的依赖
<style>
.transition, .autocomplete, .showAll-transition, .autocomplete ul, .autocomplete ul li a{
transition:all 0.3s ease-out;
-moz-transition:all 0.3s ease-out;
-webkit-transition:all 0.3s ease-out;
-o-transition:all 0.3s ease-out;
}
.autocomplete ul{
font-family: sans-serif;
position: absolute;
list-style: none;
background: #f8f8f8;
margin: 0;
display: inline-block;
min-width: 15%;
margin-top: 10px;
}
.autocomplete ul:before{
content: "";
display: block;
position: absolute;
height: 0;
width: 0;
border: 10px solid transparent;
border-bottom: 10px solid #f8f8f8;
top: -20px
}
.autocomplete ul li a{
text-decoration: none;
display: block;
background: #f8f8f8;
color: #2b2b2b;
padding: 5px;
}
.autocomplete ul li a:hover, .autocomplete ul li.focus-list a{
color: white;
background: #2F9AF7;
}
.showAll-transition{
opacity: 1;
height: 50px;
overflow: hidden;
}
.showAll-enter{
opacity: 0.3;
height: 0;
}
.showAll-leave{
display: none;
}
.autocomplete-person{
margin-left: 7px;
}
</style>
<template>
<input type="text"
:id="id"
:class="class"
:name="name"
:placeholder="placeholder"
v-model="inputmodel"
@input="input(inputmodel)"
@blur="hideAll"
@keydown="keydown"
@focus="focus" />
<div class="autocomplete transition autocomplete-{{ name }}" id="autocomplete-{{ name }}" v-show="showList">
<ul>
<li v-for="data in json"
transition="showAll"
:class="activeClass($index)">
<a href="#"
@click.prevent="$emit('selectList',data)"
@mousemove="mousemove($index)">
<b>{{ data[anchor] }}</b>
</a>
</li>
</ul>
</div>
</template>
<script>
import Vue from 'vue'
//转场效果
Vue.transition('showAll',{});
export default {
props: {
id: String,
class: String,
name: String,
placeholder: String,
//父组件模型名称
model: String,
//JSON数据取值的Key
anchor: {
type: String,
required: true
},
//请求的数据链接
url: {
type: String,
required: true
},
//请求的参数KEY
param: {
type: String,
default: 'q'
},
//拉取的数据个数的限制
limit: {
type: String,
default: 5
}
},
data:function(){
return {
showList: false,
inputmodel:'',
json: [],
focusList: ''
}
},
methods: {
//转化JSON对象
cleanUp:function(data){
return JSON.parse(JSON.stringify(data));
},
input:function(val){
this.showList = true;
//触发调用getData方法
this.$emit('getData',val);
},
//隐藏补全列表
hideAll:function(e){
//为了让blur方法延迟执行,以便能够成功执行click方法
setTimeout(() => {
this.showList = false;
},250);
},
//
focus:function(e){
this.focusList = 0;
},
mousemove:function(i){
this.focusList = i;
},
//键盘移动
keydown:function(e){
let key = e.keyCode;
//如果没有展示的list,则直接返回
if(!this.showList) return;
switch (key) {
case 40: //向上
this.focusList++;
break;
case 38: //向下
this.focusList--;
break;
case 13: //确认
this.$emit('selectList', this.json[this.focusList]);
this.showList = false;
break;
case 27: //退出
this.showList = false;
break;
}
//点中的序号超过数组的长度时,循环到第一个
let listLength = this.json.length - 1;
this.focusList = this.focusList > listLength ? 0 : this.focusList < 0 ? listLength : this.focusList;
},
//更新样式
activeClass:function(i){
return {
'focus-list' : i == this.focusList
};
}
},
events: {
//选中列表中的哪一项
selectList:function(data){
console.log(JSON.stringify(data));
let clean = this.cleanUp(data);
//按照指定的JSON键值显示在模型上
this.inputmodel = clean[this.anchor];
//传递给父组件中的对象
this.$parent.$parent.$data[this.model] = clean;
this.showList = false;
},
//获取数据
getData:function(val){
let self = this;
if(this.url != null){
let ajax = new XMLHttpRequest();
var limit;
if(this.$get('limit') != ''){
this.limit = parseFloat(this.limit);
limit = this.limit != "" ? '&limit=' + this.limit : '';
}else{
limit = '';
}
ajax.open('GET', `${this.url}?${this.param}=${val}${limit}`, true);
ajax.send();
ajax.addEventListener('progress', function (data) {
if(data.lengthComputable){}
});
ajax.addEventListener('loadend', function (data) {
let json = JSON.parse(this.responseText);
self.json = json;
});
}
}
},
created:function(){
//同步从父组件传递过来的值
this.inputmodel = this.$parent.$data[this.model].staffChnName;
}
}
</script>
调用方式:
组件还没有做的足够独立和灵活,笔者也会尽可能的改善,如果有问题的话,希望大家留言我的邮箱
kameleon@126.com
程序员惜程序员,不喜勿喷,心累~