原生js實現autocomplete插件

        在實際的項目中,能用別人寫好的插件實現相關功能是最好不過,爲了節約時間成本,由於有的項目比較緊急,沒充分時間讓你本身來寫,即使寫了,你還要花大量時間調試兼容性。可是出於學習的目的,你能夠利用閒暇時間,本身動手寫寫,看一些原生js的東西,根據本身的思路作插件,這樣能提升水平。javascript

          說到autotemplete,好多人都用過,引用autotemplete.js,而後就能夠實如今輸入框輸入值的時候提示下拉選項,相似於百度搜索框那種提示功能,下面就來講說本身的思路。java

  1.  爲輸入框添加input事件

      input事件兼容性代碼以下:node

    

    AddEvt:function(ele, evt, fn) {
                if (document.addEventListener) {
                    ele.addEventListener(evt, fn, false);
                } else if (document.attachEvent) {
                    ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
                } else {
                    ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
                }
            }

 

       input事件和其餘的事件不同,低版本的ie不支持input事件,只能用propertychange事件,高版本的ie和w3c標準瀏覽器支持input事件ajax

    2.輸入事件觸發的時候獲取數據數組

        這裏數據有兩種形式,一種是直接設置的對象數組,一種是ajax請求返回數據瀏覽器

        這時候咱們須要一個ajax請求函數,這裏寫了一個get請求閉包

       

get: function(url, paraobj, fn, timeout) {
                var xhr = null;
                try {

                  ////兼容firefox,chrom
                    if (window.XMLHttpRequest) {
                        xhr = new XMLHttpRequest();
                    }

                 //////兼容IE

                 else if (Window.ActiveXObject) {

                        xhr = new ActiveXObject("Msxml2.Xmlhttp");
                    }
                } catch (e) {
                    //TODO handle the exception
                    xhr = new ActiveXObject('Microsoft.Xmlhttp');
                }
                xhr.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        fn.call(this, this.responseText);

                    } else {
                        setTimeout(function() {

                             xhr.abort();
                        }, timeout);
                    }
                };
                var parastr = '';
                parastr += "?";
                for (var prop in paraobj) {
                    parastr += prop + "=" + paraobj[prop] + "&";
                }
                 xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
                 xhr.send();

            }

       

 

    3. ajax請求成功,且有數據的時候建立下拉框並在下拉框中追加選項       ////建立下拉Div
    mvc

       建立下拉框代碼:app

     

 createShowDiv: function() {

            ///若是下拉div已存在,刪除掉
            var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
            var childNodes = parentNode.childNodes;
            var showDiv = document.getElementById(this.config.showdivId);
            if (showDiv) {
                parentNode.removeChild(showDiv);
            }
            //建立下拉Div
            var div = document.createElement('div');
            div.id = this.config.showdivId;
            //設置下拉div樣式
            var style = this.config.style || {
                width: '200px',
                height: 'auto',
                backgroundColor: '#1c5683',
                cursor: 'pointer',
                display: 'block'
            };
for (var prop in style) { div.style[prop] = style[prop]; } this.showdiv = div; }

 

    

      追加選項代碼:dom

     

appendChild: function(data) {
            var self = this;
            var data = data;
            var fragment = document.createDocumentFragment();
            for (var i = 0; i < data.length; i++) {
                var obj = data[i];
                var child = document.createElement('div');
                child.style.width = self.showdiv.style.width;
                child.style.border = '1px';
                child.style.borderStyle = 'solid';
                child.style.borderTopColor = 'white';
                child.setAttribute('key', obj[self.config.valueFiled]);
                child.innerHTML = obj[self.config.textFiled];
                fragment.appendChild(child);
            }
            self.showdiv.appendChild(fragment);
            self.util.insertAfter(self.showdiv, self.autoElement);

            //爲下拉框添加點擊事件
            self.util.AddEvt(self.showdiv, 'click', function(e) {
                var evt = e || window.event;
                var target = evt.srcElement || evt.target;
                var key = target.getAttribute("key");
                var val = target.innerHTML;
                self.autoElement.value = val;
                self.closeDiv();
                self.config.select.call(self, key, val);
            });
        }

 

上面說的是主要的幾步思路,如今看一下怎麼將這些代碼封裝到一個對象中,讓它成爲插件。這時候咱們用到匿名閉包:

 

(function(win) {
	var autocomplete= function() {
		this.Init.apply(this, arguments);

	}

	autocomplete.prototype = {

		////添加相關操做代碼

		Init: {}, ///初始化參數

		Render: {},

		createShowDiv: {}, ///建立下拉div

		appendChild: {}, ///在下拉div裏面追加顯示項

		closeDiv: {}, ////關閉下拉框

		//////工具對象,事件,請求,還有dom節點操做的函數

		util: {

			AddEvt: {}, ///添加事件

			insertAfter: {}, ///在某元素後面追加元素

				get: {} ////  Ajax get請求

		}

	}

	win.Autocomplete= function(paraobj) {
		new autocomplete(paraobj).Render();
	}
})(window)

 

 

主體的代碼添加好了,咱們把具體的實現代碼展現出來:

     

(function(win) {
    var autocomplete = function () {
		this.Init.apply(this, arguments);
	}
    autocomplete.prototype = {
		Init: function() {
			var args = Array.prototype.slice.call(arguments);
			if (args && args.length > 0) {
				var config = args[0];
				var getType = Object.prototype.toString;
				if (config && getType.call(config) == "[object Object]") {
					//				this.config = config;
					this.config = config || {
						id: '', //控件id
						data: [], //數據
						textFiled: '', //顯示的文字的屬性名
						valueFiled: '', //獲取value的屬性名
						style: {}, //顯示的下拉div的樣式設置
						url: '', //ajax請求的url
						paraName:'name',//ajax請求的參數
						select: function() {}, //選擇選項時觸發的事件,
						showdivId: '' //下拉選擇區域的id
					};
				}
			}
		},
		Render: function() {
			var self = this;
			if (self.config) {
				var autoElement = document.getElementById(self.config.id);
				this.autoElement = autoElement;
				if (autoElement) {
					self.util.AddEvt(this.autoElement, 'input', function() {
						try {
						    if (autoElement.value) {
                               ////ajax請求獲取數據的方式
						        if (self.config.url && !self.config.data) {
						            var paraobj = {};
						            paraobj[self.config.paraName] = autoElement.value;
						            self.util.get(self.config.url, paraobj, function (data) {
						                self.createShowDiv();
								        self.appendChild(eval('(' + data + ')'));
									}, 10000);
						        }
                               ////直接設置對象數組的形式
						        else if
                                    (!self.config.url && self.config.data) {
						            self.createShowDiv();
									self.appendChild(self.config.data);
								}

							} else {
						        self.closeDiv();
							}

						} catch (e) {
							//TODO handle the exception
							alert(e);
						}
					});
				}

			}
		},
		////建立下拉Div
		createShowDiv: function() {

			///若是下拉div已存在,刪除掉
			var parentNode = this.autoElement.parentNode || this.autoElement.parentElement;
			var childNodes = parentNode.childNodes;
			var showDiv = document.getElementById(this.config.showdivId);
			if (showDiv) {
				parentNode.removeChild(showDiv);
			}
			//建立下拉Div
			var div = document.createElement('div');
			div.id = this.config.showdivId;
			//設置下拉div樣式
			var style = this.config.style || {
				width: '200px',
				height: 'auto',
				backgroundColor: '#1c5683',
				cursor: 'pointer',
				display: 'block'
			};
			for (var prop in style) {
				div.style[prop] = style[prop];
			}
			this.showdiv = div;
		},
		///在下拉div裏面追加顯示項
		appendChild: function(data) {
			var self = this;
			var data = data;
			var fragment = document.createDocumentFragment();
			for (var i = 0; i < data.length; i++) {
				var obj = data[i];
				var child = document.createElement('div');
				child.style.width = self.showdiv.style.width;
				child.style.border = '1px';
				child.style.borderStyle = 'solid';
				child.style.borderTopColor = 'white';
				child.setAttribute('key', obj[self.config.valueFiled]);
				child.innerHTML = obj[self.config.textFiled];
				fragment.appendChild(child);
			}
			self.showdiv.appendChild(fragment);
			self.util.insertAfter(self.showdiv, self.autoElement);

            //爲下拉框添加點擊事件
			self.util.AddEvt(self.showdiv, 'click', function(e) {
				var evt = e || window.event;
				var target = evt.srcElement || evt.target;
				var key = target.getAttribute("key");
				var val = target.innerHTML;
				self.autoElement.value = val;
				self.closeDiv();
				self.config.select.call(self, key, val);
			});
		},
        ////關閉下拉框
		closeDiv: function () {
		    if (this.showdiv) {
		        this.showdiv.style.display = 'none';
		    }

		}
        ,
		util: {
			///添加事件
			AddEvt: function(ele, evt, fn) {
				if (document.addEventListener) {
					ele.addEventListener(evt, fn, false);
				} else if (document.attachEvent) {
					ele.attachEvent('on' + (evt == "input" ? "propertychange" : evt), fn);
				} else {
					ele['on' + (evt == "input" ? "propertychange" : evt)] = fn;
				}
			},
			///在某元素後面追加元素
			insertAfter: function(ele, targetELe) {
				var parentnode = targetELe.parentNode || targetELe.parentElement;
				if (parentnode.lastChild == targetELe) {
					parentnode.appendChild(ele);
				} else {
					parentnode.insertBefore(ele, targetELe.nextSibling);
				}
			},
			///Get請求
			get: function(url, paraobj, fn, timeout) {
				var xhr = null;
				try {
					if (window.XMLHttpRequest) {
						xhr = new XMLHttpRequest();
					} else if (Window.ActiveXObject) {

						xhr = new ActiveXObject("Msxml2.Xmlhttp");
					}
				} catch (e) {
					//TODO handle the exception
					xhr = new ActiveXObject('Microsoft.Xmlhttp');
				}
				xhr.onreadystatechange = function() {
					if (this.readyState == 4 && this.status == 200) {
						fn.call(this, this.responseText);

					} else {
						setTimeout(function() {

							 xhr.abort();
						}, timeout);
					}
				};
				var parastr = '';
				parastr += "?";
				for (var prop in paraobj) {
					parastr += prop + "=" + paraobj[prop] + "&";
				}
				 xhr.open('get', parastr != "?" ? (url + parastr) : url, true);
				 xhr.send();

			}
		}
	}

    win.AutoComplete = function (paraobj) {
        new autocomplete(paraobj).Render();

	}

})(window)

 

 

下面是使用的代碼

           頁面調用

            

    window.onload = function () {
        AutoComplete({
            id: 'txtTest', //控件id
            url: '/Home/Test4', //數據
            paraName:'name',
            textFiled: 'name', //顯示的文字的屬性名
            valueFiled: 'id', //獲取value的屬性名
            //					style: {}, //顯示的下拉div的樣式設置
            //						url: '', //ajax請求的url
            select: function (val, text) {
                alert(val + '---' + text);
            }, //選擇選項時觸發的事件,
            showdivId: 'showDIv' //下拉選擇區域的id});
        });

    }
 

 

          後臺代碼以下,這裏我用的是mvc

         

        public JsonResult Test4(string   name)
        {
            var list=new  List<Student>();
            list.Add(new Student {  id="1",name="aaaaa"});
            list.Add(new Student { id = "2", name = "aacc" });

            list.Add(new Student { id = "3", name = "aabb" });
            list.Add(new Student { id = "4", name = "bbcc" });

            if (!string.IsNullOrEmpty(name))
            {
                list = list.Where(p => p.name.Contains(name)).ToList();
            }
            return Json(list,JsonRequestBehavior.AllowGet);
        }

 

  如今基本的功能實現和調用講完了,從開始到最後的過程是比較麻煩的,每一個方法都是一步步實現,沒有引用其餘的庫,要考慮到各個瀏覽器的兼容性。若是你有什麼疑問,請留言,我會回覆。

相關文章
相關標籤/搜索