Vue 自动补全插件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuexueenen/article/details/52389977

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>


调用方式:



组件还没有做的足够独立和灵活,笔者也会尽可能的改善,如果有问题的话,希望大家留言我的邮箱

[email protected]


程序员惜程序员,不喜勿喷,心累~

猜你喜欢

转载自blog.csdn.net/xuexueenen/article/details/52389977