jquery autocomplete实现读取sql数据库自动补全TextBox
时间:2022-03-13 22:33
项目需要这样子一个功能,其他部门提的意见,只好去实现了哦,搞了好久才弄出来,分享一下。
1.前台页面
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default3.aspx.cs" Inherits="Default3" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title></title> <script src="jquery-1.4.1-vsdoc.js" type="text/javascript"></script> <script src="jquery.autocomplete.js" type="text/javascript"></script> <link href="jquery.autocomplete.css" type="text/css" rel="stylesheet" /> <script language="javascript" type="text/javascript"> $(document).ready((function () { $("#txtUser").autocomplete("GetCode.aspx"); } )); </script> </head> <body> <form id="form1" runat="server"> <div> 用户名: <asp:TextBox ID="txtUser" runat="server"></asp:TextBox> </div> </form> </body> </html>
2.GetCode.aspx
前台为空
后台代码:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data; using System.Data.SqlClient; public partial class GetCode : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Request.QueryString["q"] != null) { string key = Request.Params["q"].ToString(); string result = ""; SqlHelp sql = new SqlHelp(); string str = "select top 15 CustomCode from tCustomList where CustomCode like '" + key + "%'"; SqlDataReader dr = sql.ExecuteReader(str); while (dr.Read()) { result += dr["CustomCode"].ToString() + "\n"; } dr.Dispose(); sql.SqlClose(); if (result == "") result = "not exists"; Response.Write(result); } } }
3jquery.autocomplete.js
jQuery.autocomplete = function (input, options) { // Create a link to self var me = this; // Create jQuery object for input element var $input = $(input).attr("autocomplete", "off"); // Apply inputClass if necessary if (options.inputClass) $input.addClass(options.inputClass); // Create results var results = document.createElement("div"); // Create jQuery object for results var $results = $(results); $results.hide().addClass(options.resultsClass).css("position", "absolute"); if (options.width > 0) $results.css("width", options.width); // Add to body element $("body").append(results); input.autocompleter = me; var timeout = null; var prev = ""; var active = -1; var cache = {}; var keyb = false; var hasFocus = false; var lastKeyPressCode = null; // flush cache function flushCache() { cache = {}; cache.data = {}; cache.length = 0; }; // flush cache flushCache(); // if there is a data array supplied if (options.data != null) { var sFirstChar = "", stMatchSets = {}, row = []; // no url was specified, we need to adjust the cache length to make sure it fits the local data store if (typeof options.url != "string") options.cacheLength = 1; // loop through the array and create a lookup structure for (var i = 0; i < options.data.length; i++) { // if row is a string, make an array otherwise just reference the array row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]); // if the length is zero, don't add to list if (row[0].length > 0) { // get the first character sFirstChar = row[0].substring(0, 1).toLowerCase(); // if no lookup array for this character exists, look it up now if (!stMatchSets[sFirstChar]) stMatchSets[sFirstChar] = []; // if the match is a string stMatchSets[sFirstChar].push(row); } } // add the data items to the cache for (var k in stMatchSets) { // increase the cache size options.cacheLength++; // add to the cache addToCache(k, stMatchSets[k]); } } $input .keydown(function (e) { // track last key pressed lastKeyPressCode = e.keyCode; switch (e.keyCode) { case 38: // up e.preventDefault(); moveSelect(-1); break; case 40: // down e.preventDefault(); moveSelect(1); break; case 9: // tab case 13: // return if (selectCurrent()) { // make sure to blur off the current field $input.get(0).blur(); e.preventDefault(); } break; default: active = -1; if (timeout) clearTimeout(timeout); timeout = setTimeout(function () { onChange(); }, options.delay); 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 () { // track whether the field has focus hasFocus = false; hideResults(); }); hideResultsNow(); function onChange() { // ignore if the following keys are pressed: [del] [shift] [capslock] if (lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32)) return $results.hide(); var v = $input.val(); if (v == prev) return; prev = v; if (v.length >= options.minChars) { $input.addClass(options.loadingClass); requestData(v); } else { $input.removeClass(options.loadingClass); $results.hide(); } }; function moveSelect(step) { var lis = $("li", results); if (!lis) return; active += step; if (active < 0) { active = 0; } else if (active >= lis.size()) { active = lis.size() - 1; } lis.removeClass("ac_over"); $(lis[active]).addClass("ac_over"); // Weird behaviour in IE // if (lis[active] && lis[active].scrollIntoView) { // lis[active].scrollIntoView(false); // } }; function selectCurrent() { var li = $("li.ac_over", results)[0]; if (!li) { var $li = $("li", results); if (options.selectOnly) { if ($li.length == 1) li = $li[0]; } else if (options.selectFirst) { li = $li[0]; } } if (li) { selectItem(li); return true; } else { return false; } }; function selectItem(li) { if (!li) { li = document.createElement("li"); li.extra = []; li.selectValue = ""; } var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML); input.lastSelected = v; prev = v; $results.html(""); $input.val(v); hideResultsNow(); if (options.onItemSelect) setTimeout(function () { options.onItemSelect(li) }, 1); }; // selects a portion of the input string function createSelection(start, end) { // get a reference to the input element var field = $input.get(0); if (field.createTextRange) { var selRange = field.createTextRange(); selRange.collapse(true); selRange.moveStart("character", start); selRange.moveEnd("character", end); selRange.select(); } else if (field.setSelectionRange) { field.setSelectionRange(start, end); } else { if (field.selectionStart) { field.selectionStart = start; field.selectionEnd = end; } } field.focus(); }; // fills in the input box w/the first match (assumed to be the best match) function autoFill(sValue) { // if the last user key pressed was backspace, don't autofill if (lastKeyPressCode != 8) { // fill in the value (keep the case the user has typed) $input.val($input.val() + sValue.substring(prev.length)); // select the portion of the value not typed by the user (so the next character will erase) createSelection(prev.length, sValue.length); } }; function showResults() { // get the position of the input field right now (in case the DOM is shifted) var pos = findPos(input); // either use the specified width, or autocalculate based on form element var iWidth = (options.width > 0) ? options.width : $input.width(); // reposition $results.css({ width: parseInt(iWidth) + "px", top: (pos.y + input.offsetHeight) + "px", left: pos.x + "px" }).show(); }; function hideResults() { if (timeout) clearTimeout(timeout); timeout = setTimeout(hideResultsNow, 200); }; function hideResultsNow() { if (timeout) clearTimeout(timeout); $input.removeClass(options.loadingClass); if ($results.is(":visible")) { $results.hide(); } if (options.mustMatch) { var v = $input.val(); if (v != input.lastSelected) { selectItem(null); } } }; function receiveData(q, data) { if (data) { $input.removeClass(options.loadingClass); results.innerHTML = ""; // if the field no longer has focus or if there are no matches, do not display the drop down if (!hasFocus || data.length == 0) return hideResultsNow(); if ($.browser.msie) { // we put a styled iframe behind the calendar so HTML SELECT elements don't show through $results.append(document.createElement('iframe')); } results.appendChild(dataToDom(data)); // autofill in the complete box w/the first match as long as the user hasn't entered in more data if (options.autoFill && ($input.val().toLowerCase() == q.toLowerCase())) autoFill(data[0][0]); showResults(); } else { hideResultsNow(); } }; function parseData(data) { if (!data) return null; var parsed = []; var rows = data.split(options.lineSeparator); for (var i = 0; i < rows.length; i++) { var row = $.trim(rows[i]); if (row) { parsed[parsed.length] = row.split(options.cellSeparator); } } return parsed; }; function dataToDom(data) { var ul = document.createElement("ul"); var num = data.length; // limited results to a max number if ((options.maxItemsToShow > 0) && (options.maxItemsToShow < num)) num = options.maxItemsToShow; for (var i = 0; i < num; i++) { var row = data[i]; if (!row) continue; var li = document.createElement("li"); if (options.formatItem) { li.innerHTML = options.formatItem(row, i, num); li.selectValue = row[0]; } else { li.innerHTML = row[0]; li.selectValue = row[0]; } var extra = null; if (row.length > 1) { extra = []; for (var j = 1; j < row.length; j++) { extra[extra.length] = row[j]; } } li.extra = extra; ul.appendChild(li); $(li).hover( function () { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); }, function () { $(this).removeClass("ac_over"); } ).click(function (e) { e.preventDefault(); e.stopPropagation(); selectItem(this) }); } return ul; }; function requestData(q) { if (!options.matchCase) q = q.toLowerCase(); var data = options.cacheLength ? loadFromCache(q) : null; // recieve the cached data if (data) { receiveData(q, data); // if an AJAX url has been supplied, try loading the data now } else if ((typeof options.url == "string") && (options.url.length > 0)) { $.get(makeUrl(q), function (data) { data = parseData(data); addToCache(q, data); receiveData(q, data); }); // if there's been no data found, remove the loading class } else { $input.removeClass(options.loadingClass); } }; function makeUrl(q) { var url = options.url + "?q=" + encodeURI(q); for (var i in options.extraParams) { url += "&" + i + "=" + encodeURI(options.extraParams[i]); } return url; }; function loadFromCache(q) { if (!q) return null; if (cache.data[q]) return cache.data[q]; if (options.matchSubset) { for (var i = q.length - 1; i >= options.minChars; i--) { var qs = q.substr(0, i); var c = cache.data[qs]; if (c) { var csub = []; for (var j = 0; j < c.length; j++) { var x = c[j]; var x0 = x[0]; if (matchSubset(x0, q)) { csub[csub.length] = x; } } return csub; } } } return null; }; function matchSubset(s, sub) { if (!options.matchCase) s = s.toLowerCase(); var i = s.indexOf(sub); if (i == -1) return false; return i == 0 || options.matchContains; }; this.flushCache = function () { flushCache(); }; this.setExtraParams = function (p) { options.extraParams = p; }; this.findValue = function () { var q = $input.val(); if (!options.matchCase) q = q.toLowerCase(); var data = options.cacheLength ? loadFromCache(q) : null; if (data) { findValueCallback(q, data); } else if ((typeof options.url == "string") && (options.url.length > 0)) { $.get(makeUrl(q), function (data) { data = parseData(data) addToCache(q, data); findValueCallback(q, data); }); } else { // no matches findValueCallback(q, null); } } function findValueCallback(q, data) { if (data) $input.removeClass(options.loadingClass); var num = (data) ? data.length : 0; var li = null; for (var i = 0; i < num; i++) { var row = data[i]; if (row[0].toLowerCase() == q.toLowerCase()) { li = document.createElement("li"); if (options.formatItem) { li.innerHTML = options.formatItem(row, i, num); li.selectValue = row[0]; } else { li.innerHTML = row[0]; li.selectValue = row[0]; } var extra = null; if (row.length > 1) { extra = []; for (var j = 1; j < row.length; j++) { extra[extra.length] = row[j]; } } li.extra = extra; } } if (options.onFindValue) setTimeout(function () { options.onFindValue(li) }, 1); } function addToCache(q, data) { if (!data || !q || !options.cacheLength) return; if (!cache.length || cache.length > options.cacheLength) { flushCache(); cache.length++; } else if (!cache[q]) { cache.length++; } cache.data[q] = data; }; function findPos(obj) { var curleft = obj.offsetLeft || 0; var curtop = obj.offsetTop || 0; while (obj = obj.offsetParent) { curleft += obj.offsetLeft curtop += obj.offsetTop } return { x: curleft, y: curtop }; } } jQuery.fn.autocomplete = function (url, options, data) { // Make sure options exists options = options || {}; // Set url as option options.url = url; // set some bulk local data options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null; // Set default values for required options options.inputClass = options.inputClass || "ac_input"; options.resultsClass = options.resultsClass || "ac_results"; options.lineSeparator = options.lineSeparator || "\n"; options.cellSeparator = options.cellSeparator || "|"; options.minChars = options.minChars || 1; options.delay = options.delay || 400; options.matchCase = options.matchCase || 0; options.matchSubset = options.matchSubset || 1; options.matchContains = options.matchContains || 0; options.cacheLength = options.cacheLength || 1; options.mustMatch = options.mustMatch || 0; options.extraParams = options.extraParams || {}; options.loadingClass = options.loadingClass || "ac_loading"; options.selectFirst = options.selectFirst || false; options.selectOnly = options.selectOnly || false; options.maxItemsToShow = options.maxItemsToShow || -1; options.autoFill = options.autoFill || false; options.width = parseInt(options.width, 10) || 0; this.each(function () { var input = this; new jQuery.autocomplete(input, options); }); // Don't break the chain return this; } jQuery.fn.autocompleteArray = function (data, options) { return this.autocomplete(null, options, data); } jQuery.fn.indexOf = function (e) { for (var i = 0; i < this.length; i++) { if (this[i] == e) return i; } return -1; };
4.jquery-1.4.1-vsdoc.js
?/* * This file has been commented to support Visual Studio Intellisense. * You should not use this file at runtime inside the browser--it is only * intended to be used only for design-time IntelliSense. Please use the * standard jQuery library for all production use. * * Comment version: 1.4.1a */ /*! * jQuery JavaScript Library v1.4.1 * http://jquery.com/ * * Distributed in whole under the terms of the MIT * * Copyright 2010, John Resig * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXpreSS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2010, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Mon Jan 25 19:43:33 2010 -0500 */ (function( window, undefined ) { // Define a local copy of jQuery var jQuery = function( selector, context ) { /// <summary> /// 1: $(expression, context) - 此函数接受一个包含 CSS 选择器的字符串,随后将使用该选择器匹配一组元素。 /// 2: $(html) - 基于提供的原始 HTML 字符串动态创建 DOM 元素。 /// 3: $(elements) - 围绕单个或多个 DOM 元素包装 jQuery 功能。 /// 4: $(callback) - $(document).ready() 的简写形式。 /// 5: $() - 从 jQuery 1.4 开始,如果未向 jQuery()方法传递任何参数,则将返回空的 jQuery 集。 /// </summary> /// <param name="selector" type="String"> /// 1: expression - 要用于搜索的表达式。 /// 2: html - 要动态创建的 HTML 字符串。 /// 3: elements - 将由 jQuery 对象封装的 DOM 元素。 /// 4: callback - 当 DOM 就绪时要执行的函数。 /// </param> /// <param name="context" type="jQuery"> /// 1: context - 要用作上下文的 DOM 元素、文档或 jQuery。 /// </param> /// <returns type="jQuery" /> // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context ); }, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // Use the correct document accordingly with window argument (sandbox) document = window.document, // A central reference to the root jQuery(document) rootjQuery, // A simple way to check for HTML strings or ID strings // (both of which we optimize for) quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, // Is it a simple selector isSimple = /^.[^:#\[\.,]*$/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // Has the ready events already been bound? readyBound = false, // The functions to execute on DOM ready readyList = [], // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwnProperty = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, indexOf = Array.prototype.indexOf; jQuery.fn = jQuery.prototype = { init: function( selector, context ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { doc = (context ? context.ownerDocument || context : document); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = buildFragment( [ match[1] ], [ doc ] ); selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; } // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); if ( elem ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $("TAG") } else if ( !context && /^\w+$/.test( selector ) ) { this.selector = selector; this.context = document; selector = document.getElementsByTagName( selector ); // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return (context || rootjQuery).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return jQuery( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if (selector.selector !== undefined) { this.selector = selector.selector; this.context = selector.context; } return jQuery.isArray( selector ) ? this.setArray( selector ) : jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.4.1", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { /// <summary> /// 当前匹配的元素的数目。 /// 核心部分 /// </summary> /// <returns type="Number" /> return this.length; }, toArray: function() { /// <summary> /// 以数组的形式检索 jQuery 集中包含的所有 DOM 元素。 /// </summary> /// <returns type="Array" /> return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { /// <summary> /// 访问单个匹配的元素。num 用于访问 /// 匹配的第 N 个元素。 /// 核心部分 /// </summary> /// <returns type="Element" /> /// <param name="num" type="Number"> /// 访问处于第 N 个位置的元素。 /// </param> return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { /// <summary> /// 将 jQuery 对象设置为一个元素数组,同时对 /// 堆栈进行维护。 /// 核心部分 /// </summary> /// <returns type="jQuery" /> /// <param name="elems" type="Elements"> /// 元素数组 /// </param> // Build a new jQuery matched element set var ret = jQuery( elems || null ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + (this.selector ? " " : "") + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Force the current matched set of elements to become // the specified array of elements (destroying the stack in the process) // You should use pushStack() in order to do this, but maintain the stack setArray: function( elems ) { /// <summary> /// 将 jQuery 对象设置为一个元素数组。此操作具有十足的 /// 破坏性 - 如果您希望维护 jQuery 堆栈, /// 请务必使用 .pushStack()。 /// 核心部分 /// </summary> /// <returns type="jQuery" /> /// <param name="elems" type="Elements"> /// 元素数组 /// </param> // Resetting the length to 0, then using the native Array push // is a super-fast way to populate an object with array-like properties this.length = 0; push.apply( this, elems ); return this; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { /// <summary> /// 在每个匹配元素的上下文中执行函数。 /// 这意味着每次执行传入的函数 /// (为每个匹配的元素执行一次)时,“this”关键字 /// 将指向特定元素。 /// 此外,在执行该函数时,还会为其传递一个参数, /// 用于表示元素在匹配集中的位置 /// 。 /// 核心部分 /// </summary> /// <returns type="jQuery" /> /// <param name="callback" type="Function"> /// 要执行的函数 /// </param> return jQuery.each( this, callback, args ); }, ready: function( fn ) { /// <summary> /// 绑定一个每当准备好遍历和操作 DOM 时就要执行的函数。 /// </summary> /// <param name="fn" type="Function">当 DOM 就绪时要执行的函数。</param> // Attach the listeners jQuery.bindReady(); // If the DOM is already ready if ( jQuery.isReady ) { // Execute the function immediately fn.call( document, jQuery ); // Otherwise, remember the function for later } else if ( readyList ) { // Add the function to the wait list readyList.push( fn ); } return this; }, eq: function( i ) { /// <summary> /// 将匹配元素集简化为单个元素。 /// 元素在匹配元素集中的位置 /// 从 0 开始,直至 length - 1。 /// 核心部分 /// </summary> /// <returns type="jQuery" /> /// <param name="num" type="Number"> /// pos 希望限制为的元素索引。 /// </param> return i === -1 ? this.slice( i ) : this.slice( i, +i + 1 ); }, first: function() { /// <summary> /// 将匹配元素集精简为集合中的第一个元素。 /// </summary> /// <returns type="jQuery" /> return this.eq( 0 ); }, last: function() { /// <summary> /// 将匹配元素集精简为集合中的最后一个元素。 /// </summary> /// <returns type="jQuery" /> return this.eq( -1 ); }, slice: function() { /// <summary> /// 选择匹配元素的子集。行为方式与内置的 Array 切片方法完全一样。 /// </summary> /// <param name="start" type="Number" integer="true">开始子集的位置(从 0 开始)。</param> /// <param name="end" optional="true" type="Number" integer="true">结束子集的位置(不包括结束元素本身)。 /// 如果省略,则在选择结束时结束</param> /// <returns type="jQuery">切片元素</returns> return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { /// <summary> /// 此成员为内部成员。 /// </summary> /// <private /> /// <returns type="jQuery" /> return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { /// <summary> /// 结束最新的“破坏性”操作,并将匹配元素的列表 /// 还原回以前的状态。执行结束操作之后,匹配元素的列表将还原为 /// 匹配元素的最后状态。 /// 如果前面没有出现过破坏性操作,则将返回一个空集。 /// DOM/遍历部分 /// </summary> /// <returns type="jQuery" /> return this.prevObject || jQuery(null); }, // 仅供内部使用。 // 行为方式与数组的方法类似,而与 jQuery 方法不类似。 push: push, sort: [].sort, splice: [].splice }; // 为 init 函数指定 jQuery 原型以用于以后的实例化 jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { /// <summary> /// 用一个或多个对象扩展另一个对象,并返回已修改的 /// 原始对象。这对于简单继承是一个非常有用的实用工具。 /// jQuery.extend(settings, options); /// var settings = jQuery.extend({}, defaults, options); /// JavaScript 部分 /// </summary> /// <param name="target" type="Object"> /// 要扩展的对象 /// </param> /// <param name="prop1" type="Object"> /// 将合并到第一个对象的对象。 /// </param> /// <param name="propN" type="Object" optional="true" parameterArray="true"> /// (可选)要合并到第一个对象的多个对象 /// </param> /// <returns type="Object" /> // copy reference to target object var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging object literal values or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src : jQuery.isArray(copy) ? [] : {}; // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { /// <summary> /// 运行此函数以将 $ 变量的控制权交还给 /// 任何首先实现它的库。这可帮助确保 /// jQuery 不会与其他库的 $ 对象 /// 冲突。 /// 通过使用此函数,您将只能够使用“jQuery”变量 /// 来访问 jQuery。例如,在执行 /// $("div p") 的位置,您现在必须执行 jQuery("div p")。 /// 核心部分 /// </summary> /// <returns type="undefined" /> window.$ = _$; if ( deep ) { window.jQuery = _jQuery; } return jQuery; }, // 是否准备好使用 DOM? 一旦准备好,请设置为 true。 isReady: false, // 当 DOM 就绪时处理 ready: function() { /// <summary> /// 此方法为内部方法。 /// </summary> /// <private /> // Make sure that the DOM is not already loaded if ( !jQuery.isReady ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 13 ); } // Remember that the DOM is ready jQuery.isReady = true; // If there are functions bound, to execute if ( readyList ) { // Execute all of them var fn, i = 0; while ( (fn = readyList[ i++ ]) ) { fn.call( document, jQuery ); } // Reset the list of functions readyList = null; } // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); } } }, bindReady: function() { if ( readyBound ) { return; } readyBound = true; // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { return jQuery.ready(); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent("onreadystatechange", DOMContentLoaded); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { /// <summary> /// 确定传递的参数是否为函数。 /// </summary> /// <param name="obj" type="Object">要检查的对象</param> /// <returns type="Boolean">如果该参数为函数,则为 true;否则为 false。</returns> return toString.call(obj) === "[object Function]"; }, isArray: function( obj ) { /// <summary> /// 确定传递的参数是否为数组。 /// </summary> /// <param name="obj" type="Object">要测试其是否为数组的对象。</param> /// <returns type="Boolean">如果该参数为函数,则为 true;否则为 false。</returns> return toString.call(obj) === "[object Array]"; }, isPlainObject: function( obj ) { /// <summary> /// Check to see if an object is a plain object (created using "{}" or "new Object"). /// </summary> /// <param name="obj" type="Object"> /// 将检查其是否为纯对象的对象。 /// </param> /// <returns type="Boolean" /> // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { return false; } // Not own constructor property must be Object if ( obj.constructor && !hasOwnProperty.call(obj, "constructor") && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwnProperty.call( obj, key ); }, isEmptyObject: function( obj ) { /// <summary> /// 检查某个对象是否为空(不包含任何属性)。 /// </summary> /// <param name="obj" type="Object"> /// 将检查其是否为空的对象。 /// </param> /// <returns type="Boolean" /> for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw msg; }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { // Try to use the native JSON parser first return window.JSON && window.JSON.parse ? window.JSON.parse( data ) : (new Function("return " + data))(); } else { jQuery.error( "Invalid JSON: " + data ); } }, noop: function() { /// <summary> /// 一个空函数。 /// </summary> /// <returns type="Function" /> }, // 计算全局上下文中的脚本 globalEval: function( data ) { /// <summary> /// 在内部计算全局上下文中的脚本。 /// </summary> /// <private /> if ( data && rnotwhite.test(data) ) { // Inspired by code by Andrea Giammarchi // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html var head = document.getElementsByTagName("head")[0] || document.documentElement, script = document.createElement("script"); script.type = "text/javascript"; if ( jQuery.support.scriptEval ) { script.appendChild( document.createTextNode( data ) ); } else { script.text = data; } // Use insertBefore instead of appendChild to circumvent an IE6 bug. // This arises when a base node is used (#2709). head.insertBefore( script, head.firstChild ); head.removeChild( script ); } }, nodeName: function( elem, name ) { /// <summary> /// 检查指定的元素是否具有指定的 DOM 节点名称。 /// </summary> /// <param name="elem" type="Element">要检查的元素</param> /// <param name="name" type="String">要检查的节点名称</param> /// <returns type="Boolean">如果指定的节点名称与节点的 DOM 节点名称匹配,则为 true;否则为 false</returns> return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { /// <summary> /// 一个泛型迭代器函数,它可用于无缝地 /// 循环访问对象和数组。此函数不同于 /// $().each(),该函数用于以独占方式循环访问 jQuery /// 对象。此函数可用于循环访问任何内容。 /// 该回调具有两个参数: key (对象)或 index (数组)作为 /// 第一个参数,value 作为第二个参数。 /// JavaScript 部分 /// </summary> /// <param name="obj" type="Object"> /// 要循环访问的对象或数组。 /// </param> /// <param name="fn" type="Function"> /// 将针对每个对象执行的函数。 /// </param> /// <returns type="Object" /> var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction(object); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} } } return object; }, trim: function( text ) { /// <summary> /// 移除字符串开始和结尾处的空白。 /// JavaScript 部分 /// </summary> /// <returns type="String" /> /// <param name="text" type="String"> /// 要修整的字符串。 /// </param> return (text || "").replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( array, results ) { /// <summary> /// 将任何内容转换为一个真正的数组。这是一个内部方法。 /// </summary> /// <param name="array" type="Object">要转换为实际数组的任何内容</param> /// <returns type="Array" /> /// <private /> var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; }, merge: function( first, second ) { /// <summary> /// 将两个数组合并在一起并移除所有重复项。 /// 新数组是: 第一个数组中的所有结果, /// 后跟第二个数组中的唯一结果。 /// JavaScript 部分 /// </summary> /// <returns type="Array" /> /// <param name="first" type="Array"> /// 要合并的第一个数组。 /// </param> /// <param name="second" type="Array"> /// 要合并的第二个数组。 /// </param> var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { /// <summary> /// 使用筛选器函数从数组中筛选出项。 /// 将向指定的函数传递两个参数: /// 当前数组项和该项在数组中的索引。 /// 该函数必须返回“true”以将该项保留在数组中, /// 若返回 false 则将移除该项。 /// }); /// JavaScript 部分 /// </summary> /// <returns type="Array" /> /// <param name="elems" type="Array"> /// array 要在其中查找项的数组。 /// </param> /// <param name="fn" type="Function"> /// 要用于处理每一项的函数。 /// </param> /// <param name="inv" type="Boolean"> /// 反转选择 - 选择函数的反函数。 /// </param> var ret = []; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { if ( !inv !== !callback( elems[ i ], i ) ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { /// <summary> /// 将一个数组中的所有项转换为另一个项数组。 /// 针对数组中每一项调用提供给此方法的转换函数, /// 并向该函数传递一个参数: /// 要转换的项。 /// 然后,该函数可以返回转换后的值、“null” /// (以移除相应项)或值数组 - 这些数据将 /// 会修整到完整的数组中。 /// JavaScript 部分 /// </summary> /// <returns type="Array" /> /// <param name="elems" type="Array"> /// array 要转换的数组。 /// </param> /// <param name="fn" type="Function"> /// 要用于处理每一项的函数。 /// </param> var ret = [], value; // 遍历数组,并将每个项转换为 // 一个或多个新值。 for ( var i = 0, length = elems.length; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } return ret.concat.apply( [], ret ); }, // 用于对象的全局 GUID 计数器 guid: 1, proxy: function( fn, proxy, thisObject ) { /// <summary> /// 采用一个函数,并返回一个将始终具有特定范围的新函数。 /// </summary> /// <param name="fn" type="Function"> ///