pull/7/head
gyt 3 weeks ago
parent 677cd46203
commit 6fd34ecd5c

@ -7840,8 +7840,8 @@
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
// 函数用于处理 AJAX 请求的响应
function ajaxHandleResponses(s, jqXHR, responses) {
var contents = s.contents,
dataTypes = s.dataTypes,
responseFields = s.responseFields,
@ -7850,14 +7850,14 @@
finalDataType,
firstDataType;
// Fill responseXXX fields
// 遍历 responseFields 并将响应数据存储到 jqXHR 的相应属性中
for (type in responseFields) {
if (type in responses) {
jqXHR[responseFields[type]] = responses[type];
}
}
// Remove auto dataType and get content-type in the process
// 移除自动数据类型,并在过程中获取内容类型
while (dataTypes[0] === "*") {
dataTypes.shift();
if (ct === undefined) {
@ -7865,7 +7865,7 @@
}
}
// Check if we're dealing with a known content-type
// 检查是否是已知的内容类型
if (ct) {
for (type in contents) {
if (contents[type] && contents[type].test(ct)) {
@ -7875,11 +7875,11 @@
}
}
// Check to see if we have a response for the expected dataType
// 检查是否有期望数据类型的响应
if (dataTypes[0] in responses) {
finalDataType = dataTypes[0];
} else {
// Try convertible dataTypes
// 尝试可转换的数据类型
for (type in responses) {
if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
finalDataType = type;
@ -7889,13 +7889,12 @@
firstDataType = type;
}
}
// Or just use first one
// 或者仅使用第一个数据类型
finalDataType = finalDataType || firstDataType;
}
// If we found a dataType
// We add the dataType to the list if needed
// and return the corresponding response
// 如果找到了数据类型
// 如果需要,将数据类型添加到列表中并返回相应的响应
if (finalDataType) {
if (finalDataType!== dataTypes[0]) {
dataTypes.unshift(finalDataType);
@ -7904,10 +7903,9 @@
}
}
// Chain conversions given the request and the original response
// 根据请求和原始响应进行链式转换
function ajaxConvert(s, response) {
// Apply the dataFilter if provided
// 如果提供了数据过滤器,则应用数据过滤器
if (s.dataFilter) {
response = s.dataFilter(response, s.dataType);
}
@ -7918,22 +7916,20 @@
key,
length = dataTypes.length,
tmp,
// Current and previous dataTypes
// 当前和之前的数据类型
current = dataTypes[0],
prev,
// Conversion expression
// 转换表达式
conversion,
// Conversion function
// 转换函数
conv,
// Conversion functions (transitive conversion)
// 转换函数(传递转换)
conv1,
conv2;
// For each dataType in the chain
// 对于链中的每个数据类型
for (i = 1; i < length; i++) {
// Create converters map
// with lowercased keys
// 创建转换器映射,使用小写键
if (i === 1) {
for (key in s.converters) {
if (typeof key === "string") {
@ -7942,21 +7938,20 @@
}
}
// Get the dataTypes
// 获取数据类型
prev = current;
current = dataTypes[i];
// If current is auto dataType, update it to prev
// 如果当前是自动数据类型,将其更新为 prev
if (current === "*") {
current = prev;
// If no auto and dataTypes are actually different
// 如果不是自动数据类型且数据类型不同
} else if (prev!== "*" && prev!== current) {
// Get the converter
// 获取转换器
conversion = prev + " " + current;
conv = converters[conversion] || converters["* " + current];
// If there is no direct converter, search transitively
// 如果没有直接的转换器,进行传递搜索
if (!conv) {
conv2 = undefined;
for (conv1 in converters) {
@ -7975,13 +7970,13 @@
}
}
}
// If we found no converter, dispatch an error
// 如果没有找到转换器,发出错误
if (!(conv || conv2)) {
jQuery.error("No conversion from " + conversion.replace(" ", " to "));
}
// If found converter is not an equivalence
// 如果找到的转换器不是等价的
if (conv!== true) {
// Convert with 1 or 2 converters accordingly
// 相应地使用 1 或 2 个转换器进行转换
response = conv? conv(response) : conv2(conv1(response));
}
}
@ -7996,38 +7991,47 @@
jsre = /(\=)\?(&|$)|\?\?/i;
// Default jsonp settings
// 使用 jQuery.ajaxSetup 配置全局的 AJAX 设置
jQuery.ajaxSetup({
// 定义 jsonp 的参数名
jsonp: "callback",
// 定义 jsonpCallback 函数,生成一个唯一的回调函数名
jsonpCallback: function () {
return jQuery.expando + "_" + (jsc++);
}
});
// Detect, normalize options and install callbacks for jsonp requests
// 使用 jQuery.ajaxPrefilter 对 json 和 jsonp 类型的请求进行预处理
jQuery.ajaxPrefilter("json jsonp", function (s, originalSettings, jqXHR) {
// 检查 s.data 是否为字符串且内容类型是否为 application/x-www-form-urlencoded
var inspectData = (typeof s.data === "string") && /^application\/x-www-form-urlencoded/.test(s.contentType);
var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
// 如果数据类型为 jsonp 或 jsonp 不为 false 且 url 或 data 中包含 jsonp 回调参数
if (s.dataTypes[0] === "jsonp" ||
s.jsonp!== false && (jsre.test(s.url) ||
inspectData && jsre.test(s.data))) {
var responseContainer,
// 获取或生成 jsonpCallback 函数
jsonpCallback = s.jsonpCallback =
jQuery.isFunction(s.jsonpCallback)? s.jsonpCallback() : s.jsonpCallback,
// 存储之前的 jsonpCallback 函数
previous = window[jsonpCallback],
url = s.url,
data = s.data,
replace = "$1" + jsonpCallback + "$2";
if (s.jsonp!== false) {
// 替换 url 中的 jsonp 回调参数
url = url.replace(jsre, replace);
if (s.url === url) {
if (inspectData) {
// 替换 data 中的 jsonp 回调参数
data = data.replace(jsre, replace);
}
if (s.data === data) {
// Add callback manually
// 手动添加 jsonp 回调参数到 url 中
url += (/\?/.test(url)? "&" : "?") + s.jsonp + "=" + jsonpCallback;
}
}
@ -8036,22 +8040,22 @@
s.url = url;
s.data = data;
// Install callback
// 安装回调函数
window[jsonpCallback] = function (response) {
responseContainer = [response];
};
// Clean-up function
// 清理函数
jqXHR.always(function () {
// Set callback back to previous value
// 将回调函数恢复为之前的值
window[jsonpCallback] = previous;
// Call if it was a function and we have a response
// 如果 responseContainer 存在且 previous 是函数,则调用回调函数
if (responseContainer && jQuery.isFunction(previous)) {
window[jsonpCallback](responseContainer[0]);
}
});
// Use data converter to retrieve json after script execution
// 使用数据转换器在脚本执行后获取 json 数据
s.converters["script json"] = function () {
if (!responseContainer) {
jQuery.error(jsonpCallback + " was not called");
@ -8059,26 +8063,28 @@
return responseContainer[0];
};
// force json dataType
// 强制使用 json 数据类型
s.dataTypes[0] = "json";
// Delegate to script
// 委托给 script 类型处理
return "script";
}
});
// Install script dataType
// 使用 jQuery.ajaxSetup 配置 script 数据类型的相关设置
jQuery.ajaxSetup({
accepts: {
// 定义 script 类型可接受的内容类型
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
},
contents: {
// 定义 script 类型的内容匹配正则表达式
script: /javascript|ecmascript/
},
converters: {
// 定义 text 到 script 的数据转换器,执行全局的脚本评估
"text script": function (text) {
jQuery.globalEval(text);
return text;
@ -8087,66 +8093,65 @@
});
// Handle cache's special case and global
// 使用 jQuery.ajaxPrefilter 为 "script" 类型的请求添加预处理
jQuery.ajaxPrefilter("script", function (s) {
// 如果未定义 s.cache则将其设置为 false
if (s.cache === undefined) {
s.cache = false;
}
// 如果是跨域请求
if (s.crossDomain) {
// 将请求类型设置为 GET
s.type = "GET";
// 将全局标志设置为 false
s.global = false;
}
});
// Bind script tag hack transport
// 绑定 script 标签的 hack 传输方式
jQuery.ajaxTransport("script", function (s) {
// This transport only deals with cross domain requests
// 这个传输方式仅处理跨域请求
if (s.crossDomain) {
var script,
// 获取文档的 head 元素
head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
return {
send: function (_, callback) {
// 创建 script 元素
script = document.createElement("script");
// 设置 script 元素为异步加载
script.async = "async";
// 如果设置了脚本字符集,将其设置到 script 元素上
if (s.scriptCharset) {
script.charset = s.scriptCharset;
}
// 设置 script 的 src 属性为请求的 url
script.src = s.url;
// Attach handlers for all browsers
// 为 script 元素添加 onload 和 onreadystatechange 事件处理函数
script.onload = script.onreadystatechange = function (_, isAbort) {
// 如果是中止或者 script 的 readyState 不存在或为 loaded 或 complete 状态
if (isAbort ||!script.readyState || /loaded|complete/.test(script.readyState)) {
// Handle memory leak in IE
// 处理 IE 的内存泄漏问题
script.onload = script.onreadystatechange = null;
// Remove the script
// 移除 script 元素
if (head && script.parentNode) {
head.removeChild(script);
}
// Dereference the script
// 解除对 script 的引用
script = undefined;
// Callback if not abort
// 如果不是中止,调用回调函数
if (!isAbort) {
callback(200, "success");
}
}
};
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
// 使用 insertBefore 代替 appendChild 以避免 IE6 的一个 bug
// 当使用 base 节点时会出现此问题 (#2709 和 #4378)
head.insertBefore(script, head.firstChild);
},
// abort 函数,用于中止请求
abort: function () {
if (script) {
script.onload(0, 1);
@ -8159,23 +8164,28 @@
var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
xhrOnUnloadAbort = window.ActiveXObject ? function() {
// Abort all pending requests
// #5280: Internet Explorer will keep connections alive if we don't abort on unload
// 定义 xhrOnUnloadAbort 函数,用于在页面卸载时中止所有挂起的请求(针对 IE
var xhrOnUnloadAbort = window.ActiveXObject? function() {
// 中止所有挂起的请求
for (var key in xhrCallbacks) {
xhrCallbacks[key](0, 1);
}
} : false,
// 存储 xhr 的唯一标识符
xhrId = 0,
// 存储 xhr 的回调函数
xhrCallbacks;
// Functions to create xhrs
// 创建标准的 XHR 对象
function createStandardXHR() {
try {
return new window.XMLHttpRequest();
} catch (e) {}
}
// 创建 ActiveXHR 对象(用于 IE
function createActiveXHR() {
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
@ -8184,13 +8194,11 @@
// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
// 根据浏览器环境选择创建 XHR 对象的函数,并将其赋值给 jQuery.ajaxSettings.xhr
jQuery.ajaxSettings.xhr = window.ActiveXObject?
/* Microsoft failed to properly
* implement the XMLHttpRequest in IE7 (can't request local files),
* so we use the ActiveXObject when it is available
* Additionally XMLHttpRequest can be disabled in IE7/IE8 so
* we need a fallback.
*/
// Microsoft failed to properly implement the XMLHttpRequest in IE7 (can't request local files),
// so we use the ActiveXObject when it is available
// Additionally XMLHttpRequest can be disabled in IE7/IE8 so we need a fallback.
function() {
return!this.isLocal && createStandardXHR() || createActiveXHR();
} :
@ -8198,6 +8206,7 @@
createStandardXHR;
// Determine support properties
// 扩展 jQuery.support 对象,判断浏览器对 ajax 和 cors 的支持情况
(function (xhr) {
jQuery.extend(jQuery.support, {
ajax:!!xhr,
@ -8206,84 +8215,79 @@
})(jQuery.ajaxSettings.xhr());
// Create transport if the browser can provide an xhr
// 如果浏览器支持 xhr则创建传输对象
if (jQuery.support.ajax) {
jQuery.ajaxTransport(function (s) {
// Cross domain only allowed if supported through XMLHttpRequest
// 仅当通过 XMLHttpRequest 支持跨域时才允许跨域请求
if (!s.crossDomain || jQuery.support.cors) {
var callback;
return {
send: function (headers, complete) {
// Get a new xhr
// 获取一个新的 xhr 对象
var xhr = s.xhr(),
handle,
i;
// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
// 打开请求连接
// 传递空用户名会在 Opera 上触发登录弹窗 (#2865)
if (s.username) {
xhr.open(s.type, s.url, s.async, s.username, s.password);
} else {
xhr.open(s.type, s.url, s.async);
}
// Apply custom fields if provided
// 应用自定义字段(如果提供)
if (s.xhrFields) {
for (i in s.xhrFields) {
xhr[i] = s.xhrFields[i];
}
}
// Override mime type if needed
// 覆盖 MIME 类型(如果需要)
if (s.mimeType && xhr.overrideMimeType) {
xhr.overrideMimeType(s.mimeType);
}
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
// 对于跨域请求,由于预检条件比较复杂,我们通常不设置该头
// 对于同域请求,如果未提供该头则设置
if (!s.crossDomain &&!headers["X-Requested-With"]) {
headers["X-Requested-With"] = "XMLHttpRequest";
}
// Need an extra try/catch for cross domain requests in Firefox 3
// 在 Firefox 3 中进行跨域请求时需要额外的 try/catch
try {
// 遍历 headers 对象,为 xhr 设置请求头
for (i in headers) {
xhr.setRequestHeader(i, headers[i]);
}
} catch (_) {}
// Do send the request
// This may raise an exception which is actually
// handled in jQuery.ajax (so no try/catch here)
// 发送请求
// 这里可能会引发异常,实际上会在 jQuery.ajax 中处理,所以这里没有 try/catch
xhr.send((s.hasContent && s.data) || null);
// Listener
// 监听器函数
callback = function (_, isAbort) {
var status,
statusText,
responseHeaders,
responses,
xml;
// Firefox throws exceptions when accessing properties
// of an xhr when a network error occured
// Firefox 在网络错误时访问 xhr 的属性会抛出异常
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
try {
// Was never called and is aborted or complete
// 如果 callback 存在且 (是中止状态或者 xhr 的 readyState 为 4)
if (callback && (isAbort || xhr.readyState === 4)) {
// Only called once
// 只调用一次
callback = undefined;
// Do not keep as active anymore
// 不再保持活跃状态
if (handle) {
xhr.onreadystatechange = jQuery.noop;
if (xhrOnUnloadAbort) {
@ -8291,163 +8295,175 @@
}
}
// If it's an abort
// 如果是中止操作
if (isAbort) {
// Abort it manually if needed
// 如果需要,手动中止请求
if (xhr.readyState!== 4) {
xhr.abort();
}
} else {
// 获取响应状态码
status = xhr.status;
// 获取所有响应头
responseHeaders = xhr.getAllResponseHeaders();
responses = {};
// 获取响应的 XML 数据
xml = xhr.responseXML;
// Construct response list
// 构建响应列表
if (xml && xml.documentElement /* #4958 */) {
responses.xml = xml;
}
// When requesting binary data, IE6-9 will throw an exception
// on any attempt to access responseText (#11426)
// 当请求二进制数据时IE6-9 尝试访问 responseText 会抛出异常 (#11426)
try {
responses.text = xhr.responseText;
} catch( _ ) {
}
} catch (_) {}
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
// Firefox 访问跨域请求的 statusText 时会抛出异常
try {
statusText = xhr.statusText;
} catch (e) {
// We normalize with Webkit giving an empty statusText
// 标准化处理Webkit 会给出空的 statusText
statusText = "";
}
// Filter status for non standard behaviors
// 对非标准行为过滤状态
// If the request is local and we have data: assume a success
// (success with no data won't get notified, that's the best we
// can do given current implementations)
// 如果请求是本地的且有数据:假设请求成功
// (无数据的成功请求不会被通知,这是在当前实现下能做到的最好处理)
if (!status && s.isLocal &&!s.crossDomain) {
status = responses.text? 200 : 404;
// IE - #1450: sometimes returns 1223 when it should be 204
// IE - #1450: 有时应返回 204 却返回 1223
} else if (status === 1223) {
status = 204;
}
}
}
} catch (firefoxAccessException) {
// 如果不是中止操作
if (!isAbort) {
complete(-1, firefoxAccessException);
}
}
// Call complete if needed
// 如果需要,调用 complete 函数
if (responses) {
complete(status, statusText, responses, responseHeaders);
}
};
// if we're in sync mode or it's in cache
// and has been retrieved directly (IE6 & IE7)
// we need to manually fire the callback
// 如果是同步模式或者在缓存中且直接获取到IE6 和 IE7
// 我们需要手动触发回调
if (!s.async || xhr.readyState === 4) {
callback();
} else {
handle = ++xhrId;
if (xhrOnUnloadAbort) {
// Create the active xhrs callbacks list if needed
// and attach the unload handler
// 如果需要,创建活跃的 xhrs 回调列表并添加 unload 处理器
if (!xhrCallbacks) {
xhrCallbacks = {};
jQuery(window).unload(xhrOnUnloadAbort);
}
// Add to list of active xhrs callbacks
// 添加到活跃的 xhrs 回调列表
xhrCallbacks[handle] = callback;
}
// 设置 xhr 的 onreadystatechange 事件处理函数为 callback
xhr.onreadystatechange = callback;
}
},
// abort 函数,用于中止请求
abort: function () {
if (callback) {
callback(0, 1);
}
}
};
}
});
}
// 存储元素的默认显示属性
var elemdisplay = {},
// 存储 iframe 元素
iframe, iframeDoc,
// 用于匹配 toggle、show 或 hide 的正则表达式
rfxtypes = /^(?:toggle|show|hide)$/,
// 用于匹配数字和单位的正则表达式
rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
// 存储定时器 ID
timerId,
// 存储不同类型动画涉及的属性数组
fxAttrs = [
// height animations
// 高度相关动画涉及的属性
["height", "marginTop", "marginBottom", "paddingTop", "paddingBottom"],
// width animations
// 宽度相关动画涉及的属性
["width", "marginLeft", "marginRight", "paddingLeft", "paddingRight"],
// opacity animations
// 透明度相关动画涉及的属性
["opacity"]
],
// 存储当前动画的时间
fxNow;
// 扩展 jQuery.fn 对象
jQuery.fn.extend({
show: function (speed, easing, callback) {
var elem, display;
// 如果指定了速度(包括速度为 0
if (speed || speed === 0) {
// 使用 animate 函数,根据 genFx 生成的显示属性进行动画显示操作,并指定速度、缓动和回调
return this.animate(genFx("show", 3), speed, easing, callback);
} else {
// 遍历元素集合
for (var i = 0, j = this.length; i < j; i++) {
elem = this[i];
if (elem.style) {
// 获取元素的显示样式
display = elem.style.display;
// Reset the inline display of this element to learn if it is
// being hidden by cascaded rules or not
// 如果元素没有存储 "olddisplay" 数据且显示样式为 "none"
if (!jQuery._data(elem, "olddisplay") && display === "none") {
// 重置元素的显示样式为空字符串
display = elem.style.display = "";
}
// Set elements which have been overridden with display: none
// in a stylesheet to whatever the default browser style is
// for such an element
// 如果元素的显示样式为空且 jQuery.css 显示为 "none" 或元素不在文档元素中
if ((display === "" && jQuery.css(elem, "display") === "none") ||
!jQuery.contains(elem.ownerDocument.documentElement, elem)) {
// 存储元素的默认显示样式
jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
}
}
}
// Set the display of most of the elements in a second loop
// to avoid the constant reflow
// 第二个循环设置元素的显示样式,避免频繁重排
for (i = 0; i < j; i++) {
elem = this[i];
if (elem.style) {
display = elem.style.display;
// 如果元素的显示样式为空或为 "none"
if (display === "" || display === "none") {
// 将元素的显示样式设置为存储的 "olddisplay" 数据或空字符串
elem.style.display = jQuery._data(elem, "olddisplay") || "";
}
}
}
// 返回 jQuery 对象本身
return this;
}
},
}
});
hide: function( speed, easing, callback ) {
// 如果指定了速度(包括速度为 0
if ( speed || speed === 0 ) {
// 使用 animate 函数,根据 genFx 生成的隐藏属性进行动画隐藏操作,并指定速度、缓动和回调
return this.animate( genFx("hide", 3), speed, easing, callback);
} else {
@ -8455,70 +8471,84 @@
i = 0,
j = this.length;
// 遍历元素集合
for ( ; i < j; i++ ) {
elem = this[i];
if ( elem.style ) {
// 获取元素的显示样式
display = jQuery.css( elem, "display" );
// 如果元素当前显示样式不为 "none" 且元素没有存储 "olddisplay" 数据
if ( display!== "none" &&!jQuery._data( elem, "olddisplay" ) ) {
// 存储元素的当前显示样式
jQuery._data( elem, "olddisplay", display );
}
}
}
// Set the display of the elements in a second loop
// to avoid the constant reflow
// 第二个循环设置元素的显示样式为 "none"
// 避免频繁的重排
for ( i = 0; i < j; i++ ) {
if ( this[i].style ) {
this[i].style.display = "none";
}
}
// 返回 jQuery 对象本身
return this;
}
},
// Save the old toggle function
// 保存旧的 toggle 函数
_toggle: jQuery.fn.toggle,
toggle: function( fn, fn2, callback ) {
var bool = typeof fn === "boolean";
// 如果 fn 和 fn2 都是函数
if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
// 应用旧的 toggle 函数
this._toggle.apply( this, arguments );
} else if ( fn == null || bool ) {
// 遍历元素集合
this.each(function() {
var state = bool? fn : jQuery(this).is(":hidden");
// 根据元素状态进行显示或隐藏操作
jQuery(this)[ state? "show" : "hide" ]();
});
} else {
// 使用 animate 函数,根据 genFx 生成的切换属性进行动画切换操作,并指定速度、缓动和回调
this.animate(genFx("toggle", 3), fn, fn2, callback);
}
// 返回 jQuery 对象本身
return this;
},
}
fadeTo: function( speed, to, easing, callback ) {
// 过滤出隐藏的元素,将其不透明度设置为 0显示它们回到之前的状态并执行动画
return this.filter(":hidden").css("opacity", 0).show().end()
.animate({opacity: to}, speed, easing, callback);
},
animate: function( prop, speed, easing, callback ) {
// 使用 jQuery.speed 函数生成动画的速度、缓动和回调等配置信息
var optall = jQuery.speed( speed, easing, callback );
// 如果传入的 prop 是空对象,对每个元素调用 optall.complete 函数并传入 false 作为参数
if ( jQuery.isEmptyObject( prop ) ) {
return this.each( optall.complete, [ false ] );
}
// Do not change referenced properties as per-property easing will be lost
// 扩展一个新的对象存储 prop避免修改原有的引用防止丢失每个属性的缓动设置
prop = jQuery.extend( {}, prop );
function doAnimation() {
// XXX 'this' does not always have a nodeName when running the
// test suite
// 在测试套件中,'this' 可能并不总是有 nodeName 属性
// 如果 optall.queue 为 false标记元素
if ( optall.queue === false ) {
jQuery._mark( this );
}
@ -8530,23 +8560,25 @@
parts, start, end, unit,
method;
// will store per property easing and be used to determine when an animation is complete
// 存储每个属性的缓动信息,并用于判断动画是否完成
opt.animatedProperties = {};
// first pass over propertys to expand / normalize
// 第一次遍历属性,进行扩展和规范化处理
for ( p in prop ) {
name = jQuery.camelCase( p );
if ( p!== name ) {
// 将转换后的属性名作为键,存储原属性值,并删除原属性键
prop[ name ] = prop[ p ];
delete prop[ p ];
}
if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
// 使用 cssHooks 的 expand 方法扩展属性值
replace = hooks.expand( prop[ name ] );
delete prop[ name ];
// not quite $.extend, this wont overwrite keys already present.
// also - reusing 'p' from above because we have the correct "name"
// 并非完全的 jQuery.extend不会覆盖已有的键
// 这里复用上面的 'p',因为我们有正确的 "name"
for ( p in replace ) {
if (! ( p in prop ) ) {
prop[ p ] = replace[ p ];
@ -8554,6 +8586,7 @@
}
}
}
}
for ( name in prop ) {
val = prop[ name ];

Loading…
Cancel
Save