视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
jQuerysupport源码解读
2020-11-27 20:16:51 责编:小采
文档


jquery support主要是检测浏览器兼容性,支持力度的方法,用于展示不同浏览器各自特性和bug的属性集合。作为一个静态成员,提供给jquery内部函数,告诉他们某些功能是否能用。避免了以往通过检测浏览器版本做修改。
  可以直接调用jQuery.support来检测某些功能,通过查看其源代码我们可以更深入的了解各个浏览器之间的区别。特别是针对IE,还有webkit的bug,都能让我们受益匪浅。

 


兼容各种主流浏览器是JavaScript库的必修课之一,一般来说检测浏览器有两种方法:

  1. 检测navigator.userAgent,用户代理检测法

  2. 检测浏览器的功能特性,即功能特性检测法

而jQuery1.3开始采用的就是功能特性检测法,以下是针对最新的jquery1.9.1版本,添加的注释。

// 浏览器各自特性和bug的属性集合,功能特性检测/支持
jQuery.support = (function () {
 // 声明变量
 var support, all, a,
 input, select, fragment,
 opt, eventName, isSupported, i,
 p = document.createElement("p");

 // Setup
 // 设置class样式
 p.setAttribute("className", "t");
 // 插入HTML
 p.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";

 // Support tests won't run in some limited or non-browser environments
 // 获取元素
 all = p.getElementsByTagName("*");
 a = p.getElementsByTagName("a")[0];

 // 检测是否支持最基本检测
 if (!all || !a || !all.length) {
 return {};
 }

 // First batch of tests
 // 创建select元素
 select = document.createElement("select");

 // 创建option元素并插入到select中
 opt = select.appendChild(document.createElement("option"));

 // 获取input元素
 input = p.getElementsByTagName("input")[0];

 // 设置CSS样式
 // cssText:设置样式
 // 说明:在IE中最后一个分号会被删掉,可以添加一个分号来解决这个问题
 // 例如: Element.style.cssText += ’;width:100px;height:100px;top:100px;left:100px;’
 a.style.cssText = "top:1px;float:left;opacity:.5";

 // support(支持)对象
 support = {
 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
 // 验证一些属性是否支持使用get/setAttribute方法,不支持返回true,支持返回false
 // 通过setAttribute添加class值是否成功来检测,IE6~7支持,其他浏览器不支持
 getSetAttribute:p.className !== "t",

 // IE strips leading whitespace when .innerHTML is used
 // 检测节点类型是否为文本节点 成功返回true,失败返回false
 // 使用innerHTML,IE会自动剔除HTML代码头部的空白符
 leadingWhitespace:p.firstChild.nodeType === 3,

 // Make sure that tbody elements aren't automatically inserted
 // IE will insert them into empty tables
 // 验证是否存在tbody标签,不存在返回true,存在返回false
 // 确保tbody元素不会自动插入(IE6~7会自动插入的空tbody)
 tbody:!p.getElementsByTagName("tbody").length,

 // Make sure that link elements get serialized correctly by innerHTML
 // This requires a wrapper element in IE
 // 验证innerHTML插入链接元素是否可被序列化,成功则返回true,失败返回false
 // 所谓序列化是指:可被读取的一种存储标准,在IE6~8中返回false。
 htmlSerialize:!!p.getElementsByTagName("link").length,

 // Get the style information from getAttribute
 // (IE uses .cssText instead)
 // 验证getAttribute("style")是否返回元素的行内样式,成功返回true,失败返回false
 // 在IE6~8中为false,因为他用cssText代替
 style:/top/.test(a.getAttribute("style")),

 // Make sure that URLs aren't manipulated
 // (IE normalizes it by default)
 // 验证getAttribute("href")返回值是否原封不动,成功返回true,失败返回false
 // 在IE6~7中会返回false,因为他的URL已常规化。
 hrefNormalized:a.getAttribute("href") === "/a",

 // Make sure that element opacity exists
 // (IE uses filter instead)
 // Use a regex to work around a WebKit issue. See #5145
 // 验证浏览器是否能正确解析opacity,成功返回true,失败返回false
 // 在IE6~8中返回false,因为他用alpha滤镜代替。
 opacity:/^0.5/.test(a.style.opacity),

 // Verify style float existence
 // (IE uses styleFloat instead of cssFloat)
 // 验证cssFloat是否存在,成功返回true,失败返回false
 // 在IE6~8中返回false,他用styleFloat代替
 cssFloat:!!a.style.cssFloat,

 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
 // 验证checkbox的默认value是否为'on',成功返回true,失败返回false
 // safair默认为'' 空字符串
 checkOn:!!input.value,

 // Make sure that a selected-by-default option has a working selected property.
 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
 // 验证创建的select元素的第一个option元素是否会默认选中, 成功返回true,失败返回false
 // FF,Chrome返回true,IE6~10返回false
 // 注意:option元素的父元素不一定是select,也有可能是optgroup
 optSelected:opt.selected,

 // Tests for enctype support on a form (#6743)
 // 验证创建form的enctype属性是否存在,存在返回true,不存在返回fasle(IE6~9,均存在)
 // enctype:设置表单的MIME编码,默认编码格式是application/x-www-form-urlencoded,不能用于文件上传;multipart/form-data,才能完整的传递文件数据
 enctype:!!document.createElement("form").enctype,

 // Makes sure cloning an html5 element does not cause problems
 // Where outerHTML is undefined, this still works
 // 验证是否支持html5节点复制,成功返回ture,失败返回false
 // 失败:复制节点cloneNode(true).innerHTML返回一个空字符串
 html5Clone:document.createElement("nav").cloneNode(true).outerHTML !== "<:nav></:nav>",

 // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
 // 验证页面和浏览器是否以W3C CSS盒式模型来渲染,而非怪异模式下。IE6~7的怪癖模式会返回false
 boxModel:document.compatMode === "CSS1Compat",

 // Will be defined later
 // 稍后将定义
 deleteExpando:true,
 noCloneEvent:true,
 inlineBlockNeedsLayout:false,
 shrinkWrapBlocks:false,
 reliableMarginRight:true,
 boxSizingReliable:true,
 pixelPosition:false
 };

 // Make sure checked status is properly cloned
 // 检测单选框选中状态能否正确克隆
 // 在IE6~9中会返回false,无法正确克隆
 // (1) 设置checkbox的checked为true
 input.checked = true;
 // (2) cloneNode克隆(复制)一份checkbox,获取他的checked值
 support.noCloneChecked = input.cloneNode(true).checked;

 // Make sure that the options inside disabled selects aren't marked as disabled
 // (WebKit marks them as disabled)
 // 检测select元素设置为disabled后,其所有option子元素是否也会被设置为disabled
 // (1)禁用下拉列表
 select.disabled = true;
 // (2)获取下拉列表子元素的disabled是否为true
 // 测试:IE FF Chrome Safair Opera 的opt.disabled都为false,说明option不会被设置为disabled
 // 其他:部分webkit会被设置为disabled,需要老版本的chrome支持。
 support.optDisabled = !opt.disabled;

 // Support: IE<9
 // 检测是否能删除附加在DOM Element 上的属性或数据
 // 在IE6~7中返回false,若事先声明这个属性,那么在IE8返回true,否者返回false
 try {
 delete p.test;
 } catch (e) {
 support.deleteExpando = false;
 }

 // Check if we can trust getAttribute("value")
 // 检测input元素被设置为radio类型后,是否仍然保持原先的值 保持成功返回true,失败返回false
 // 在IE6~9和opera中返回false,其他返回true
 input = document.createElement("input");
 input.setAttribute("value", "");
 support.input = input.getAttribute("value") === "";

 // Check if an input maintains its value after becoming a radio
 input.value = "t";
 input.setAttribute("type", "radio");
 //IE返回on
 support.radioValue = input.value === "t";

 // #11217 - WebKit loses check when the name is after the checked attribute
 // 先“选中”然后在“名称”,顺序要点,在老版本的chroem16和safair 下有兼容问题
 input.setAttribute("checked", "t");
 input.setAttribute("name", "t");
 // 创建一个文档碎片
 fragment = document.createDocumentFragment();

 // 将input元素插入到碎片中
 fragment.appendChild(input);

 // Check if a disconnected checkbox will retain its checked
 // value of true after appended to the DOM (IE6/7)
 // 检测(使用setAttribute)被添加到DOM中的checkbox是否仍然保留原先的选中状态 成功返回true,失败返回false
 // 在IE6~7中,返回false
 // 其他:(1) safair下 若先未设置"名称",返回true
 // 其他:(2) safair下 若设置"名称",则返回false
 support.appendChecked = input.checked;

 // WebKit doesn't clone checked state correctly in fragments
 // 检测fragment中的checkbox的选中状态能否被复制 成功返回true,失败返回false
 // 在IE6~7中 失败返回false
 // 其他:(1) safair下 若先设置"名称"后"选中"返回true
 // 其他:(2) safair下 若先设置"选中"后"名称"返回false
 support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;

 // Support: IE<9
 // Opera does not clone events (and typeof p.attachEvent === undefined).
 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
 // 检测克隆 DOM Element 是否会连同Element一起克隆(复制),成功返回false,失败返回true
 // IE6~8克隆会复制事件,标准浏览器返回false
 // (1)IE的注册事件
 if (p.attachEvent) {
 p.attachEvent("onclick", function () {
 support.noCloneEvent = false;
 });
 // (2)克隆DOM Element并执行onclick事件
 p.cloneNode(true).click();
 }

 // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
 // 检测(嗅探)事件是否支持
 // 其他: IE6~7不支持submitBubbles和changeBubbles,支持focusinBubbles. IE8~9均支持
 for (i in { submit:true, change:true, focusin:true }) {
 p.setAttribute(eventName = "on" + i, "t");
 //eventName in window 低版本iE6~7浏览器检测,返回false
 //高版本IE8~9浏览器检测
 support[i + "Bubbles"] = eventName in window || p.attributes[eventName].expando === false;
 }
 //IE9的问题,对于克隆的元素清除掉其background时,其原型的background也会被清除
 p.style.backgroundClip = "content-box";
 p.cloneNode(true).style.backgroundClip = "";
 // 检测原型的background是否被清除
 support.clearCloneStyle = p.style.backgroundClip === "content-box";

 // Run tests that need a body at doc ready
 // 页面加载完成之后开始执行
 jQuery(function () {
 var container, marginp, tds,
 // 声明保存一种样式(目的是重置样式)
 pReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
 // 获取body元素
 body = document.getElementsByTagName("body")[0];

 if (!body) {
 // Return for frameset docs that don't have a body
 // 框架的页面没有body元素,返回空值
 return;
 }
 // 创建DOM Element元素(p)
 container = document.createElement("p");
 // 设置 p 样式
 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
 // 将p插入到body第一行
 body.appendChild(container).appendChild(p);

 // Support: IE8
 // Check if table cells still have offsetWidth/Height when they are set
 // to display:none and there are still other visible table cells in a
 // table row; if so, offsetWidth/Height are not reliable for use when
 // determining if an element has been hidden directly using
 // display:none (it is still safe to use offsets if a parent element is
 // hidden; don safety goggles and see bug #4512 for more information).
 // 插入table表格
 p.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
 // 获取TD
 tds = p.getElementsByTagName("td");
 // 检测none状态下,offsetHeight值是否正确,正确返回true,失败返回false
 // 在IE6~8下返回false
 // (1)设置TD[0]样式
 tds[0].style.cssText = "padding:0;margin:0;border:0;display:none";
 // (2)检测TD[0]的内容高度是否为0
 isSupported = (tds[0].offsetHeight === 0);
 // 检测TD初始化,相邻的td的隐藏,offsetHeight值是否正确,正确返回true,失败返回false
 // 在IE6~8返回false
 // 设置TD[0]display(显示)初始化,相邻的td隐藏
 tds[0].style.display = "";
 tds[1].style.display = "none";

 // Support: IE8
 // Check if empty table cells still have offsetWidth/Height
 support.reliableHiddenOffsets = isSupported && (tds[0].offsetHeight === 0);

 // Check box-sizing and margin behavior
 // 清理p子元素
 p.innerHTML = "";
 // 设置盒模型以及margin等行为
 p.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
 // 检测是否符盒模型(通过offsetWidth来判断)
 // 在IE6~7中返回false 返回值为6
 support.boxSizing = (p.offsetWidth === 4);

 // 字面翻译:body偏移不是因为margin影响 (未验证)
 support.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== 1);

 // Use window.getComputedStyle because jsdom on node.js will break without it.
 // 未来判断(向上检测)
 // 判断是否支持getComputedStyle方法
 // getComputedStyle:获取当前元素所有最终使用的CSS属性值,返回的是一个CSS样式声明对象
 if (window.getComputedStyle) {
 // 检测图层定位(像素位置)是否有误,正确返回false 错误返回true
 support.pixelPosition = (window.getComputedStyle(p, null) || {}).top !== "1%";
 // 检测盒模型是否可靠
 support.boxSizingReliable = (window.getComputedStyle(p, null) || { width:"4px" }).width === "4px";

 // Check if p with explicit width and no margin-right incorrectly
 // gets computed margin-right based on width of container. (#3333)
 // Fails in WebKit before Feb 2011 nightlies
 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
 // 为处理某个BUG存在,块级元素margin right兼容问题
 // webkit 返回错误的值
 // 创建一个p元素
 marginp = p.appendChild(document.createElement("p"));
 // 样式声明或(重置)
 marginp.style.cssText = p.style.cssText = pReset;
 marginp.style.marginRight = marginp.style.width = "0";
 p.style.width = "1px";

 support.reliableMarginRight =
 !parseFloat((window.getComputedStyle(marginp, null) || {}).marginRight);
 }
 // FF不支持zoom 检测IE6~7 版本
 if (typeof p.style.zoom !== core_strundefined) {
 // Support: IE<8
 // Check if natively block-level elements act like inline-block
 // elements when setting their display to 'inline' and giving
 // them layout
 p.innerHTML = "";
 p.style.cssText = pReset + "width:1px;padding:1px;display:inline;zoom:1";
 // 检测IE6~7下,块元素在display:inline并拥有layout属性,是否会按inline-block显示
 support.inlineBlockNeedsLayout = (p.offsetWidth === 3);

 // Support: IE6
 // Check if elements with layout shrink-wrap their children
 // 检测父元素拥有layout属性和固定的width/height,是否会被子元素撑大。成功返回true失败,返回false
 // 在IE6中返回true,(值是7)
 p.style.display = "block";
 p.innerHTML = "<p></p>";
 p.firstChild.style.width = "5px";
 support.shrinkWrapBlocks = (p.offsetWidth !== 3);

 if (support.inlineBlockNeedsLayout) {
 // Prevent IE 6 from affecting layout for positioned elements #11048
 // Prevent IE from shrinking the body in IE 7 mode #12869
 // Support: IE<8
 body.style.zoom = 1;
 }
 }
 // 移除container元素 垃圾回收,避免内存泄露
 body.removeChild(container);

 // Null elements to avoid leaks in IE
 container = p = tds = marginp = null;
 });
 // IE下,创建DOM Element对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的
 // 不需要的DOM Element,需要做结束清理
 // 释放dom元素占用的内存
 // 释放DOM Element对象,垃圾清理,内存回收
 // Null elements to avoid leaks in IE
 all = select = fragment = opt = a = input = null;
 // 返回结果
 return support;
})();


http://jsdashi.com/development/316.html

下载本文
显示全文
专题