1. 程式人生 > >Vue 自動補全外掛

Vue 自動補全外掛

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]


程式設計師惜程式設計師,不喜勿噴,心累~