基于jquery的自动提示单选框
来源:互联网 发布:stat数据 编辑:程序博客网 时间:2024/05/17 22:54
本文介绍基于jquery 的 自动提示单选组件QuickSelect ,笔者对该组件进行修改支持dwr的用法。
1 QuickSelect :
1.1 数据源:
组件的数据来源方式:data,ajax
data: 简单数据源
<script> $('#ExampleOne_LocalData').quickselect({ maxItemsToShow:10, data:["Aberdeen", "Ada", "Adamsville", ["Addyston", "Addyston", 'closed'], "Adelphi", "Adena", "Adrian", "Akron"]}) // truncated data... </script>
ajax:ajax数据源
<script type="text/javascript"> $(function(){ $('#zip').quickselect({ ajax:'http://www.test.com/aaa.action', /* call to url with json formatted array of data */ match:'substring', autoSelectFirst:false, mustMatch:true, additionalFields:[$('#city'), $('#state')], formatItem:function(data, index, total){return data[0]+", "+data[1]+" "+data[2]} }); }); </script>
组件在输入变化的时候,会发出ajax请求:
http://www.test.com/aaa.action?q=输入框的值
返回的数据作为下拉提示框的数据源
1.2 返回数据结构
下拉提示框 的数据源格式 使用 json 格式
1.2.1 描述与提交的值一致的
[a,b,c,....]
1.2.1 描述与提交的值不一致的
[{value:'1',label:'中国'},{value:'2',label:'美国'}........]
1.3 对 quickselect的扩展
1.3.1增加对javascript的支持
<script type="text/javascript">$(function(){ $("#input").quickselect({ maxItemsToShow:10, finderFunctionStr:'jsfunction', jsfunction:function(q,callback){ var ognl="daoHelper.queryForList(\"SELECT HOSTNAME label,HOSTNASID VALUE FROM t_cfg_host1_info where HOSTNAME like '%"+q+"%'\")"; //var ognl="service.query("+q+")"; ctx.eval(ognl,callback); /* service.query(q,calback); */ /* $.post("demo_ajax_gethint.asp",{suggest:q},callback); */ } }); }); </script>
finderFunctionStr:查询数据源的的方法 值可以是 data(简单数据源),ajax( ajax数据源),jsfunction(对外部javascript支持,此接口比较灵活,可以用于ajax,dwr的扩展)
jsfunction:组件onchange事件时会自动调用的方法
参数:
q :输入框值
callback: jsfunction的回调函数
补充:
ctx.eval(ognl,callback);
service.query(q,calback);
dwr的调用
ctx,service 是dwr中定义的服务 。
eval是ctx的方法
2 源码解读
2.1 组件构成
$input_element :输入框
$result_list :下拉选择提示
$results_mask:遮罩层 ,当输入变化进行查询的时候,等待时出现的层
2.2 组件查询过程解析
当用户输入,监听输入框的keyup事件 ,并与上次的输入的字符进行对比,如果发生变法,则确认为一个change事件
组件监听change事件,通过 finder找出查询数据源的方法,并调用该方法。
方法返回后,数据结构如1.2 所描述,然后更新$result_list 对象,弹出该对象
用户可以输入上下键选择,按enter确认选择,或者用鼠标点击选择。
2.2.1 finder
QuickSelect.finders = { data : function( q,callback){ callback(this.options.data); }, ajax : function( q,callback){ var url = this.options.ajax + "?q=" + encodeURI(q); for(var i in this.options.ajaxParams){ if(this.options.ajaxParams.hasOwnProperty(i)){ url += "&" + i + "=" + encodeURI(this.options.ajaxParams[i]); } } $.getJSON(url, callback); }, dwrexpression:function( ognl,callback){ ctx.eval(ognl,callback); //alert("daoHelper.queryForList(\"SELECT HOSTNAME label, HOSTNASID value FROM t_cfg_host1_info where HOSTNAME like '%"+ognl+"%'\")"); }, jsfunction:function(q,callback){ this.options.jsfunction(q,callback); //ctx.eval(ognl,callback); //alert("daoHelper.queryForList(\"SELECT HOSTNAME label, HOSTNASID value FROM t_cfg_host1_info where HOSTNAME like '%"+ognl+"%'\")"); } };
if(options.finderFunctionStr==='dwrexpression'){ options.finderFunction = QuickSelect.finders[options.finderFunctionStr]; }else if(options.finderFunctionStr==='jsfunction'){ options.finderFunction = QuickSelect.finders[options.finderFunctionStr]; }else{ options.finderFunction = options.finderFunction || QuickSelect.finders[!options.data ? 'ajax': 'data']; // console.log(options.finderFunction); if(options.finderFunction==='data' || options.finderFunction==='ajax' ) options.finderFunction = QuickSelect.finders[options.finderFunction]; // console.log(options.finderFunction); // matchMethod: (quicksilver | contains | startsWith | <custom>). Defaults to 'quicksilver' if quicksilver.js is loaded / 'contains' otherwise. }如果有ajax 或者data属性,
options.finderFunction = QuickSelect.finders[options.finderFunction]如果options.finderFunctionStr==='jsfunction' 则 使用 jsfunctionfinders是定义数据源查找的js方法 。2.2.2 matcher排序,根据输入的值的匹配程度去排序
3附件:源码
// Credit to Anders Retteras for adding functionality preventing onblur event to fire on text input when clicking on scrollbars in MSIE / Opera.// Minified version created at http://jsutility.pjoneil.net/ by running Obfuscation with all options unchecked, and then Compact.// Packed version created at http://jsutility.pjoneil.net/ by running Compress on the Minified version.//update by zhu_min726@126.com ,add the support of the method for javascript and dwr function object(obj){ var s = function(){}; s.prototype = obj; return new s();}var QuickSelect;(function($){ // The job of the QuickSelect object is to encapsulate all the state of a select control and manipulate the DOM and interface events. QuickSelect = function( $input_element, options){ var self = this; $input_element = $($input_element); $input_element.attr('autocomplete', 'off'); self.options = options; // Save the state of the control // AllItems: hash of "index" -> [items], where index is the query that retrieves or filters the results. // clickedLI: just a state variable for IE scrollbars. self.AllItems = {}; var clickedLI = false, activeSelection = -1, hasFocus = false, last_keyCode, previous_value, timeout, ie_stupidity = false, $results_list, $results_mask; if(/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x; if(Number(RegExp.$1) <= 7) ie_stupidity=true; } // Create the list DOM $results_list = $('<div class="'+options.resultsClass+'" style="display:block;position:absolute;z-index:9999;"></div>').hide(); // Supposedly if we position an iframe behind the results list, before we position the results list, it will hide select elements in IE. $results_mask = $('<iframe />'); $results_mask.css({border:'none',position:'absolute'}); if(options.width>0){ $results_list.css("width", options.width); $results_mask.css("width", options.width); } $('body').append($results_list); $results_list.hide(); // in case for some reason it didn't hide before appending it? if(ie_stupidity) $('body').append($results_mask); // Set up all of the methods self.getLabel = function(item){ return item['label']||item['LABEL']||item.label || (typeof(item)==='string' ? item : item[0]) || ''; // hash:item.label; string:item; array:item[0] }; var getValues = function(item){ return item['value']||item['VALUE']||item.values || (item.value ? [item.value] : (typeof(item)==='string' ? [item] : item)) || []; // hash:item.values || item.value; string:item; array:item[1..end] }; var moveSelect = function(step_or_li){ var lis = $('li', $results_list); if(!lis) return; if(typeof(step_or_li)==="number") activeSelection = activeSelection + step_or_li; else activeSelection = lis.index(step_or_li); if(activeSelection < 0) activeSelection = 0; else if(activeSelection >= lis.size()) activeSelection = lis.size() - 1; lis.removeClass(options.selectedClass); $(lis[activeSelection]).addClass(options.selectedClass); if(options.autoFill && self.last_keyCode != 8){ // autoFill value, if option is set and the last user key pressed wasn't backspace // 1. Fill in the value (keep the case the user has typed) $input_element.val(previous_value + $(lis[activeSelection]).text().substring(previous_value.length)); // 2. SELECT the portion of the value not typed by the user (so the next character will erase if they continue typing) var sel_start = previous_value.length, sel_end = $input_element.val().length, field = $input_element.get(0); if(field.createTextRange){ var selRange = field.createTextRange(); selRange.collapse(true); selRange.moveStart("character", sel_start); selRange.moveEnd("character", sel_end); selRange.select(); } else if(field.setSelectionRange){ field.setSelectionRange(sel_start, sel_end); } else if(field.selectionStart){ field.selectionStart = sel_start; field.selectionEnd = sel_end; } field.focus(); } }; var hideResultsNow = function(){ if(timeout){clearTimeout(timeout);} $input_element.removeClass(options.loadingClass); if($results_list.is(":visible")) $results_list.hide(); if($results_mask.is(":visible")) $results_mask.hide(); activeSelection = -1; }; self.selectItem = function(li, from_hide_now_function){ if(!li){ li = document.createElement("li"); li.item = ''; } var label = self.getLabel(li.item), values = getValues(li.item); $input_element.lastSelected = label; $input_element.val(label); // Set the visible value previous_value = label; $results_list.empty(); // clear the results list $(options.additionalFields).each(function(i,input){$(input).val(values[i+1]);}); // set the additional fields' values if(!from_hide_now_function)hideResultsNow(); // hide the results when something is selected if(options.onItemSelect)setTimeout(function(){ options.onItemSelect(li); }, 1); // run the user callback, if set return true; }; var selectCurrent = function(){ var li = $("li."+options.selectedClass, $results_list).get(0); if(li){ return self.selectItem(li); } else { // No current selection - blank the fields if options.exactMatch and current value isn't valid. if(options.exactMatch){ $input_element.val(''); $(options.additionalFields).each(function(i,input){$(input).val('');}); } return false; } }; var repopulate_items = function(items){ // Clear the results to begin: $results_list.empty(); // If the field no longer has focus or if there are no matches, forget it. //alert(hasFocus+"--"+items); //!hasFocus || if( items === null || items.length === 0) return hideResultsNow(); // alert(hasFocus); var ul = document.createElement("ul"), total_count = items.length, // hover functions hf = function(){ moveSelect(this); }, bf = function(){}, cf = function(e){ e.preventDefault(); e.stopPropagation(); self.selectItem(this); }; $results_list.append(ul); // limited results to a max number if(options.maxVisibleItems > 0 && options.maxVisibleItems < total_count) total_count = options.maxVisibleItems; // Add each item: for(var i=0; i<total_count; i++){ var item = items[i], li = document.createElement("li"); $results_list.append(li); $(li).text(options.formatItem ? options.formatItem(item, i, total_count) : self.getLabel(item)); // Save the extra values (if any) to the li li.item = item; // Set the class name, if specified if(item.className) li.className = item.className; ul.appendChild(li); $(li).hover(hf, bf).click(cf); } // Lastly, remove the loading class. $input_element.removeClass(options.loadingClass); return true; }; var itemList; var repopulate = function(q,callback){ var ognl; if(options.finderFunctionStr==='dwrexpression'){ ognl=options.dwrognl.replace('{value}',q); }else{ ognl=q; } queryLabel=q; options.finderFunction.apply(self,[ognl,function(data){ itemList=data; repopulate_items(options.matchMethod.apply(self,[q,data])); callback(); }]); }; var repopulate2 = function(q, callback){ repopulate_items(options.matchMethod.apply(self,[q,itemList])); callback(); }; var show_results = function(){ // pos: get the position of the input field before showing the results_list (in case the DOM is shifted) // iWidth: either use the specified width, or autocalculate based on form element var pos = $input_element.offset(), iWidth = (options.width > 0 ? options.width : $input_element.width()), $lis = $('li', $results_list); // reposition $results_list.css({ width: parseInt(iWidth,10) + "px", top: pos.top + $input_element.height() + 5 + "px", left: pos.left + "px" }); if(ie_stupidity){$results_mask.css({ width: parseInt(iWidth,10) - 2 + "px", top: pos.top + $input_element.height() + 6 + "px", left: pos.left + 1 + "px", height: $results_list.height() - 2+'px' }).show();} $results_list.show(); // Option autoSelectFirst, and Option selectSingleMatch (activate the first item if only item) if(options.autoSelectFirst || (options.selectSingleMatch && $lis.length == 1)) moveSelect($lis.get(0)); }; var onChange = function(){ // ignore if non-consequence key is pressed (such as shift, ctrl, alt, escape, caps, pg up/down, home, end, arrows) if(itemList==null){ return ; } // alert("change"); if(last_keyCode >= 9 && last_keyCode <= 45){return;} // compare with previous value / store new previous value var q = $input_element.val(); if(q == previous_value) return; previous_value = q; // if enough characters have been typed, load/populate the list with whatever matches and show the results list. if(q.length >= options.minChars){ $input_element.addClass(options.loadingClass); // Populate the list, then show the list. repopulate2( q,show_results); } else { // if too short, hide the list. if(q.length === 0 && (options.onBlank ? options.onBlank() : true)) // onBlank callback $(options.additionalFields).each(function(i,input){input.value='';}); $input_element.removeClass(options.loadingClass); $results_list.hide(); $results_mask.hide(); } }; var queryLabel; var onQuery = function(){ //查询事件 var q = $input_element.val(); previous_value=q; $input_element.addClass(options.loadingClass); if(itemList==null){ repopulate(q,show_results); //alert("repopulate"); }else{ if(q.indexOf(queryLabel)>-1){ repopulate2(q,show_results); }else{ repopulate(q,show_results); } //alert("repopulate2"); } }; // Set up the interface events // Mark that actual item was clicked if clicked item was NOT a DIV, so the focus doesn't leave the items. $results_list.mousedown(function(e){if(e.srcElement)clickedLI=e.srcElement.tagName!='DIV';}); $input_element.keyup(function(e){ last_keyCode = e.keyCode;// if(e.keyCode==13){// // } switch(e.keyCode){ case 38: // Up arrow - select prev item in the drop-down e.preventDefault(); moveSelect(-1); break; case 40: // Down arrow - select next item in the drop-down e.preventDefault(); if(!$results_list.is(":visible")){ show_results(); moveSelect(0);!$results_list.is(":visible") }else{moveSelect(1);} break; case 13: // Enter/Return - select item and stay in field // alert($results_list.css('display')); /**var q = $input_element.val(); if(q != previous_value) { onQuery(); }else if($results_list.is(":visible")){ e.preventDefault(); $input_element.select(); var li = $("li."+options.selectedClass, $results_list).get(0); self.selectItem(li); $results_list.hide(); } */ e.preventDefault(); $input_element.select(); var li = $("li."+options.selectedClass, $results_list).get(0); self.selectItem(li); $results_list.hide(); break; case 9: // Tab - select the currently selected, let the onblur happen // selectCurrent(); break; case 27: // Esc - deselect any active selection, hide the drop-down but stay in the field // Reset the active selection IF must be exactMatch and is not an exact match. if(activeSelection > -1 && options.exactMatch && $input_element.val()!=$($('li', $results_list).get(activeSelection)).text()){activeSelection = -1;} $('li', $results_list).removeClass(options.selectedClass); hideResultsNow(); e.preventDefault(); break; default: var q = $input_element.val(); if(q != previous_value) { onQuery(); }else if($results_list.is(":visible")){ e.preventDefault(); $input_element.select(); var li = $("li."+options.selectedClass, $results_list).get(0); self.selectItem(li); $results_list.hide(); } //alert(q); /**if(timeout){clearTimeout(timeout);} timeout = setTimeout(onChange, options.delay);*/ /*if(itemList!=null&& $results_list.is(":visible")){ repopulate2(q,show_results); }*/ break; } }).focus(function(){ // track whether the field has focus, we shouldn't process any results if the field no longer has focus hasFocus = true; }).blur(function(e){ if(activeSelection>-1){selectCurrent();} hasFocus = false; if(timeout){clearTimeout(timeout);} timeout = setTimeout(function(){ hideResultsNow(); // Select null element, IF options.exactMatch and there is no selection. // !! CLEARS THE FIELD IF YOU BLUR AFTER CHOOSING THE ITEM AND RESULTS ARE ALREADY CLOSED! if(options.exactMatch && $input_element.val() != $input_element.lastSelected){self.selectItem(null,true);} }, 200); }); }; QuickSelect.matchers = { quicksilver : function(q,data){var match_query, match_label, self=this; match_query = (self.options.matchCase ? q : q.toLowerCase());self.AllItems[match_query] = []; for(var i=0;i<data.length;i++){ match_label = (self.options.matchCase ? self.getLabel(data[i]) : self.getLabel(data[i]).toLowerCase()); // Filter by match/no-match if(match_label.score(match_query)>0){self.AllItems[match_query].push(data[i]);}} // Sort by match relevancereturn self.AllItems[match_query].sort(function(a,b){ // Normalize a & b a = (self.options.matchCase ? self.getLabel(a) : self.getLabel(a).toLowerCase()); b = (self.options.matchCase ? self.getLabel(b) : self.getLabel(b).toLowerCase()); // Score a & b a = a.score(match_query); b = b.score(match_query); // Compare a & b by score return(a > b ? -1 : (b > a ? 1 : 0)); }); }, contains : function(q,data){var match_query, match_label, self=this; match_query = (self.options.matchCase ? q : q.toLowerCase()); self.AllItems[match_query] = []; for(var i=0;i<data.length;i++){ match_label = (self.options.matchCase ? self.getLabel(data[i]) : self.getLabel(data[i]).toLowerCase()); if(match_label.indexOf(match_query)>-1){self.AllItems[match_query].push(data[i]);} }return self.AllItems[match_query].sort(function(a,b){ // Normalize a & b a = (self.options.matchCase ? self.getLabel(a) : self.getLabel(a).toLowerCase()); b = (self.options.matchCase ? self.getLabel(b) : self.getLabel(b).toLowerCase()); // Get proximities var a_proximity = a.indexOf(match_query); var b_proximity = b.indexOf(match_query); // Compare a & b by match proximity to beginning of label, secondly alphabetically return(a_proximity > b_proximity ? -1 : (a_proximity < b_proximity ? 1 : (a > b ? -1 : (b > a ? 1 : 0)))); }); }, startsWith : function(q,data){var match_query, match_label, self=this; match_query = (self.options.matchCase ? q : q.toLowerCase()); self.AllItems[match_query] = []; for(var i=0;i<data.length;i++){ match_label = (self.options.matchCase ? self.getLabel(data[i]) : self.getLabel(data[i]).toLowerCase()); if(match_label.indexOf(match_query)===0){self.AllItems[match_query].push(data[i]);} }return self.AllItems[match_query].sort(function(a,b){ // Normalize a & b a = (self.options.matchCase ? self.getLabel(a) : self.getLabel(a).toLowerCase()); b = (self.options.matchCase ? self.getLabel(b) : self.getLabel(b).toLowerCase()); // Compare a & b alphabetically return(a > b ? -1 : (b > a ? 1 : 0)); }); } }; QuickSelect.finders = { data : function( q,callback){ callback(this.options.data); }, ajax : function( q,callback){ var url = this.options.ajax + "?q=" + encodeURI(q); for(var i in this.options.ajaxParams){ if(this.options.ajaxParams.hasOwnProperty(i)){ url += "&" + i + "=" + encodeURI(this.options.ajaxParams[i]); } } $.getJSON(url, callback); }, dwrexpression:function( ognl,callback){ ctx.eval(ognl,callback); //alert("daoHelper.queryForList(\"SELECT HOSTNAME label, HOSTNASID value FROM t_cfg_host1_info where HOSTNAME like '%"+ognl+"%'\")"); }, jsfunction:function(q,callback){ this.options.jsfunction(q,callback); //ctx.eval(ognl,callback); //alert("daoHelper.queryForList(\"SELECT HOSTNAME label, HOSTNASID value FROM t_cfg_host1_info where HOSTNAME like '%"+ognl+"%'\")"); } }; $.fn.quickselect = function(options, data){ if(options == 'instance' && $(this).data('quickselect')) return $(this).data('quickselect'); // Prepare options and set defaults. options = options || {}; options.data = (typeof(options.data) === "object" && options.data.constructor == Array) ? options.data : undefined; options.ajaxParams = options.ajaxParams || {}; options.delay = options.delay || 400; if(!options.delay) options.delay = (!options.ajax ? 400 : 10); options.minChars = options.minChars || 1; options.cssFlavor = options.cssFlavor || 'quickselect'; options.inputClass = options.inputClass || options.cssFlavor+"_input"; options.loadingClass = options.loadingClass || options.cssFlavor+"_loading"; options.resultsClass = options.resultsClass || options.cssFlavor+"_results"; options.selectedClass = options.selectedClass || options.cssFlavor+"_selected";// wrap entire thing: .ui-widget// default item: .ui-state-default// active / hover: .ui-state-hover // finderFunction: (data | ajax | <custom>) if(options.finderFunctionStr==='dwrexpression'){ options.finderFunction = QuickSelect.finders[options.finderFunctionStr]; }else if(options.finderFunctionStr==='jsfunction'){ options.finderFunction = QuickSelect.finders[options.finderFunctionStr]; }else{ options.finderFunction = options.finderFunction || QuickSelect.finders[!options.data ? 'ajax': 'data']; // console.log(options.finderFunction); if(options.finderFunction==='data' || options.finderFunction==='ajax' ) options.finderFunction = QuickSelect.finders[options.finderFunction]; // console.log(options.finderFunction); // matchMethod: (quicksilver | contains | startsWith | <custom>). Defaults to 'quicksilver' if quicksilver.js is loaded / 'contains' otherwise. } options.matchMethod = options.matchMethod || QuickSelect.matchers[(typeof(''.score) === 'function' && 'l'.score('l') == 1 ? 'quicksilver' : 'contains')]; if(options.matchMethod==='quicksilver' || options.matchMethod==='contains' || options.matchMethod==='startsWith') options.matchMethod = QuickSelect.matchers[options.matchMethod]; if(options.matchCase === undefined) options.matchCase = false; if(options.exactMatch === undefined) options.exactMatch = false; if(options.autoSelectFirst === undefined) options.autoSelectFirst = true; if(options.selectSingleMatch === undefined) options.selectSingleMatch = true; if(options.additionalFields === undefined) options.additionalFields = $('nothing'); options.maxVisibleItems = options.maxVisibleItems || -1; if(options.autoFill === undefined || options.matchMethod != 'startsWith'){options.autoFill = false;} // if you're not using the startsWith match, it really doesn't help to autoFill. options.width = parseInt(options.width, 10) || 0; // Make quickselects. return this.each(function(){ var input = this, my_options = object(options); if(input.tagName == 'INPUT'){ // Text input: ready for QuickSelect-ing! var qs = new QuickSelect( input, my_options); $(input).data('quickselect', qs); } else if(input.tagName == 'SELECT'){ // Select input: transform into Text input, then make QuickSelect. my_options.delay = my_options.delay || 10; // for selects, we know we're not doing ajax, so we might as well speed up my_options.finderFunction = 'data'; // Record the html stuff from the select var name = input.name, id = input.id, className = input.className, accesskey = $(input).attr('accesskey'), tabindex = $(input).attr('tabindex'), selected_option = $("option:selected", input).get(0); // Collect the data from the select/options, remove them and create an input box instead. my_options.data = []; $('option', input).each(function(i,option){ my_options.data.push({label : $(option).text(), values : [option.value, option.value], className : option.className}); }); // Create the text input and hidden input var text_input = $("<input type='text' class='"+className+"' id='"+id+"_quickselect' accesskey='"+accesskey+"' tabindex='"+tabindex+"' />"); if(selected_option){text_input.val($(selected_option).text());} var hidden_input = $("<input type='hidden' id='"+id+"' name='"+input.name+"' />"); if(selected_option){hidden_input.val(selected_option.value);} // From a select, we need to work off two values, from the label and value of the select options. // Record the first (label) in the text input, the second (value) in the hidden input. my_options.additionalFields = hidden_input; // Replace the select with a quickselect text_input $(input).after(text_input).after(hidden_input).remove(); // add text input, hidden input, remove select. // console.log(my_options); text_input.quickselect(my_options); // make the text input into a QuickSelect. } }); };})(jQuery);
- 基于jquery的自动提示单选框
- 基于jQuery的input输入框下拉提示层(自动邮箱后缀名)
- 基于jQuery的input输入框下拉提示层(自动邮箱后缀名)
- 基于js 的自动提示控件
- MyEclipse支持Jquery的自动提示
- jQuery 制作自动提示的文本框
- Visual Studio 2008 JQuery的自动提示
- jquery自动提示插件autocompite的使用
- 基于Jquery的输入前提示
- 基于jquery的搜索框输入提示
- 基于jquery的数据加载提示插件
- 基于AJAX的输入提示jQuery插件
- 基于Jquery的文本提示控件 poshytip
- 基于jquery的搜索框输入提示
- JQuery实现自动提示
- jquery自动提示
- Myeclipse JQuery自动提示
- jquery邮箱自动提示
- 说说猎豹安全浏览器
- oracle 监听日志清除
- DNS优化的原理和方法
- 汇编的局部变量
- Erlang的Mnesia——为高伸缩性应用准备的数据库管理系统
- 基于jquery的自动提示单选框
- 如何刷新DNS缓存
- jlu 2776 Problem G 并查集
- Anti-fingerprinting techniques
- 毕业设计辛酸路—mini2440 从VM中的Ubuntu nfs启动
- vs2010 快捷键大全
- 自动滚动3
- 二维码的原理
- Linux下安装MySQL