- 浏览: 265840 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
DragonKiiiiiiiing:
支持楼主,中国互联网太缺这种无私奉献的人了。您的这本书我已拜读 ...
JAVA NIO 全书 译稿 -
sp42:
非常感谢!热部署帮助很大!
Pure JS (2): 热部署 (利用 JDK 7 NIO 监控文件变化) -
sp42:
其实在我的架构中,我更倾向于 JSP 作为前端模板系统~还是写 ...
Pure JS (5.3):pure.render 的实现(构造window对象,实现服务器端 JQuery Template) -
sp42:
非常不错,楼主做的正是鄙人想做的做的,而且比鄙人的来的成熟、健 ...
OMToolkit介绍(5): 总结 -
cfanllm:
楼主辛苦了,,,谢谢分享啊
JAVA NIO 全书 译稿
jQuery.support
jQuery.support 用于检查浏览器对各项特性的支持。检查项多达 27 个。
首先,让我们用一段代码测试一下 support 中包含的检查项:
<script src='jquery.js'></script> <script> support = $.support; for (key in support) { document.write('support.' + key + ' = ' + support[key] + '<br />'); } </script>
IE 下的输出结果为:
support.leadingWhitespace = false support.tbody = false support.htmlSerialize = false support.style = false support.hrefNormalized = false support.opacity = false support.cssFloat = false support.checkOn = true support.optSelected = false support.getSetAttribute = false support.submitBubbles = false support.changeBubbles = false support.focusinBubbles = true support.deleteExpando = false support.noCloneEvent = false support.inlineBlockNeedsLayout = false support.shrinkWrapBlocks = true support.reliableMarginRight = true support.noCloneChecked = false support.optDisabled = true support.radioValue = false support.checkClone = undefined support.appendChecked = false support.boxModel = false support.reliableHiddenOffsets = false support.ajax = true support.cors = false
FireFox 中的显示结果为:
support.leadingWhitespace = true support.tbody = true support.htmlSerialize = true support.style = true support.hrefNormalized = true support.opacity = true support.cssFloat = true support.checkOn = true support.optSelected = true support.getSetAttribute = true support.submitBubbles = true support.changeBubbles = true support.focusinBubbles = false support.deleteExpando = true support.noCloneEvent = true support.inlineBlockNeedsLayout = false support.shrinkWrapBlocks = false support.reliableMarginRight = true support.noCloneChecked = true support.optDisabled = true support.radioValue = true support.checkClone = undefined support.appendChecked = true support.boxModel = true support.reliableHiddenOffsets = true support.ajax = true support.cors = true
需要注意的是,源代码中 checkClone 的检查是有问题的。这将在后面提到。
接下来,我们就对这些检查项进行逐一的分析。
leadingWhitespace
检查用 innerHTML 赋值时,是否会保留前面的空白符。
IE中为 false , Firefox 中为 true 。
实现方式如下:
$ = function(){ var div = document.createElement( "div" ); div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>"; var support = { leadingWhitespace: (div.firstChild.nodeType === 3) } return { support : support } }();
这段代码中,先创建了一个 div ,之后就用 innerHTML 为 div 赋值,
然后检查 div 的第一个子元素的 nodeType 是否为 3 (表示文本),
是的话则空白字符被保留,否则未被保留。
tbody
检查是否会自动为 table 插入 tbody ,会的话为 false ,不会则为 true 。
IE中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { leadingWhitespace: (div.firstChild.nodeType === 3), tbody: !div.getElementsByTagName("tbody").length } // Other codes ... }();
这段代码在原有基础上为 support 增加了 tbody 属性, 并检查是否能够获取 tbody 标签。
由于 innerHTML 中已经包含了 table 标签,能获取 tbody 标签的话则表示会自动为 table 插入 tbody,否则表示不会自动插入 tbody 。
htmlSerialize
检查link标签能否被正确地序列化。
IE中为 false , FireFox 中为true 。
实现方式如下:
$ = function(){ // Other codes ... var a = div.getElementsByTagName("a")[0]; var support = { // Other codes ... tbody: !div.getElementsByTagName( "tbody" ).length, htmlSerialize: !!div.getElementsByTagName("link").length } return { support : support } }();
这段代码在原有基础上为 support 增加了 htmlSerialize 属性,并检查能否获取 link 标签。
由于 innerHTML 中已经包含了 link 标签,能通过getElementsByTagName 获取 link 标签的话,表示 link 可以被正确地序列化,否则表示 link 标签不能被正确地序列化。
style
检查是否能通过 “style” 属性获取 DOM Element 的样式。
IE中为 false , Firefox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var a = div.getElementsByTagName("a")[0]; var support = { // Other codes ... htmlSerialize: !!div.getElementsByTagName("link").length, style: /top/.test(a.getAttribute("style")) } return { support : support } }();
这段代码先是通过 getElementsByTagName("a") 获取表示链接的 DOM Element,
然后在原有基础上为 support 增加了 style 属性,并检查能否通过 getAttribute("style") 获取样式。
hrefNormalized
检查链接的 “href” 属性能否被正常地序列化。
IE中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... style: /top/.test(a.getAttribute("style")), hrefNormalized: (a.getAttribute("href") === "/a") } return { support : support } }();
这段代码通过 getAttribute("href") 来获取 “href” 属性的值,
能正确获取则表示链接的 “href”属性能够被正确地序列化。
opacity
检查 css 样式中的透明度设置能够被有效支持。
IE 中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... hrefNormalized: (a.getAttribute("href") === "/a"), opacity: /^0.55$/.test(a.style.opacity) } return { support : support } }();
这段代码通过 a.style.opacity 来获取透明度设置,并用正则表达式 /^0.55$/ 进行检查,通过检查表示 css 样式中的透明度能够被有效地支持,否则表示不能。
cssFloat
检查 css 样式中的 float 属性能够被有效支持。
IE 中为 false , FireFox中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... opacity: /^0.55$/.test(a.style.opacity), cssFloat: !!a.style.cssFloat } return { support : support } }();
这段代码通过 a.style.cssFloat 来获取 float 属性,并通过 !! 将属性转为 boolean 值(undefined 将被转为 false ,而其他值将被转为 true)。
checkOn
检查 chebox 的 value 是否为 “on”。
IE 和 FireFox 中都为true,而 Chrome 中则为 false 。
实现方式如下:
$ = function(){ // Other codes ... var a = div.getElementsByTagName("a")[0], input = div.getElementsByTagName("input")[0]; var support = { // Other codes ... cssFloat: !!a.style.cssFloat, checkOn: (input.value === "on") } return { support : support } }();
这段代码先通过 getElementsByTagName("input") 获取 checkbox,然后检查 checkbox 的 value 是否为 “on”。
optSelected
检查 select 中的第一个 option 能否被默认选中。
IE 中为 false , FireFox 中为 true 。
$ = function(){ // Other codes ... var select = document.createElement("select"); var opt = select.appendChild(document.createElement("option")); var support = { // Other codes ... checkOn: (input.value === "on"), optSelected: opt.selected } return { support : support } }();
这段代码先通过 createElement("select") 创建了一个 select,
然后将一个 “option” 添加到了 select 中。
接着在 support 中增加了属性 optSelected,检查 opt.selected 是否为true 。
getSetAttribute
检查能够功过 getAttribute("calssName") 和 setAttribute("className", "...") 来获取和设置 div 的 css class。
实际上只检查 setAttribute("className", "...")。
IE 中为 false , FireFox 中为 true 。
$ = function(){ // Other codes ... div.setAttribute("className", "t"); var support = { // Other codes ... optSelected: opt.selected, getSetAttribute: div.className !== "t" } return { support : support } }();
这段代码通过 div.setAttribute("classsName", "t") 将 div 的 css class 设置为 “t”,然后在 support 中增加 getSetAttribute 属性, 检查 div 的 className 是否为 “t”。
submitBubbles, changeBubbles, focusinBubbles
检查 submit、change、focus 事件是否在“冒泡阶段”触发。实际上只针对 IE 进行检查。因为大多数浏览器(及IE9)使用 addEventListener 附加事件,函数的第三个参数 useCapture (是否在“捕捉阶段”触发事件)既可以为 false ,也可以为 true 。
而 IE (IE9之前)使用 attachEvent 函数附加事件,该函数无法指定在哪个阶段触发事件,一律都为“冒泡阶段”触发。
关于 Bubble Event 的更多内容,可以参考 iteye 里其他相关的文章:
http://www.iteye.com/search?query=bubble+event&type=blog
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... getSetAttribute: div.className !== "t", submitBubbles: true, changeBubbles: true, focusinBubbles: false } if (div.attachEvent) { for(var i in { submit: 1, change: 1, focusin: 1 }) { var eventName = "on" + i; var isSupported = (eventName in div); if (!isSupported) { div.setAttribute(eventName, "return;"); isSupported = ( typeof div[eventName] === "function" ); } support[i + "Bubbles"] = isSupported; } } return { support : support } }();
首先,在 support 中增加 submitBubbles, changeBubbles, focusinBubbles,默认值分别为 true, true, false ,这是针对大多数浏览器的。
然后,针对IE (也就是存在 DOMElement.attachEvent 函数的情况),检查 "onXXX" 事件是否存在,以及能否通过 setAttribute(eventName, xxx)进行设置,可以的话就判断为“冒泡阶段”触发(即只要支持该事件,就判断为“冒泡阶段”触发)。
事实上,jQuery 中的 focusin 事件是在 focus 的基础上进行模拟的,浏览器并不支持该事件,所以 focusinBubbles 总是为 false。
从源代码中的注释来看,似乎还考虑到了跨站脚本攻击:
Short-circuiting here helps us to avoid an eval call (in setAttribute) which can cause CSP to go haywire.
大意是说在这里进行简短的检查(typeof div[eventName] === "function"),而不是直接用 eval 执行事件,可以避免不可控的跨站脚本攻击。(我不确定有没有翻译错)
deleteExpando
检查是否允许删除附加在 DOM Element 上的数据。
IE 中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... focusinBubbles: false, deleteExpando: true } // Other codes ... try { delete div.test; } catch(e) { support.deleteExpando = false; } return { support : support } }();
首先在 support 中增加属性 deleteExpando ,默认值为 true 。
然后尝试删除 div.test ,发生错误则将 deleteExpando 设为 false 。
noCloneEvent
检查复制 DOM Element 时是否会连同 event 一起复制,会则为 false , 不会则为true 。
IE 中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... deleteExpando: true, noCloneEvent: true } // Other codes ... if (!div.addEventListener && div.attachEvent && div.fireEvent) { div.attachEvent( "onclick", function click() { support.noCloneEvent = false; div.detachEvent( "onclick", click ); }); div.cloneNode(true).fireEvent("onclick"); } return { support : support } }();
首先在 support 中增加属性 noCloneEvent , 默认值为 true 。
然后复制 div, 并触发其 “onclick” 事件,触发成功则为将 noCloneEvent 设为 false。
从判断条件来看,依旧是针对 IE 的事件体系的检查。
inlineBlockNeedsLayout, shrinkWrapBlocks
都是针对 offsetWidth 的检查。
inlineBlockNeedsLayout 表示将原本 display 为 block 的 DOM Element 设置为 disylay: inline 时,是否与 inline 形式的 DOM Elemnt 一致( offsetWidth 为 2 )。
IE 8 及之前的浏览器中为 true , FireFox 中为 false 。
shrinkWrapBlocks 表示内部 DOM Element 的样式是否会影响外部 DOM Element 的样式。
IE 6 中为 true , 多数浏览器中为 false 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false } // Other codes ... if ( "zoom" in div.style ) { div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); div.style.display = ""; div.innerHTML = "<div style='width:4px;'></div>"; support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); } return { support : support } }();
首先在 support 中增加这两个属性,然后将 div 的 css 样式中的 display 设为 inline ,并检查 offsetWidth ,以确定 inlineBlockNeedsLayout 的值。
接着在 div 内部增加一个 div, 并将其宽度设为 4px ,并检查 offsetWith 的值,以确定外部的 div 是否会受到影响而收缩。
reliableMarginRight
检查 Margin Right 的计算是否可靠。 各浏览器中都为 true 。
原注释中提到某些老版本的 Webkit 内核的浏览器中为 false 。
实现方式如下:
$ = function(){ // Other codes ... var support = { // Other codes ... shrinkWrapBlocks: false, reliableMarginRight: true } // Other codes ... if ( document.defaultView && document.defaultView.getComputedStyle ) { var marginDiv = document.createElement( "div" ); marginDiv.style.width = "0"; marginDiv.style.marginRight = "0"; div.appendChild( marginDiv ); support.reliableMarginRight = ( parseInt( document.defaultView.getComputedStyle( marginDiv, null ).marginRight, 10 ) || 0 ) === 0; } return { support : support } }();
简单地说,就是将 width 和 marginRight 设为 0 时,获取的 marginRignt 应为 0 。
noCloneChecked
检查复制 checkbox 时是否连选中状态也一同复制,若复制则为 false ,否则为 true 。
实现方式如下:
$ = function(){ // Other codes ... input.checked = true; support.noCloneChecked = input.cloneNode(true).checked; return { support : support } }();
这段代码将 input 的选中状态设为 true ,然后复制 input ,并检查 checked 是否为 true 。
optDisabled
已经被设为 disable 的 select ,其内部的 option 的 disable 不应为 true 。
这个名称有一定的误导性,可能称为 “optNotDisabled” 更合适一些。
在各浏览器上的值都为 true 。
根据原注释,某些老版本的 Webkit 内核的浏览器上,该值为 false 。
实现如下:
$ = function(){ // Other codes ... select.disabled = true; support.optDisabled = !opt.disabled; return { support : support } }();
这段代码先将 select 的状态设为 disable , 然后检查其中的 option 的 disable 的值。
radioValue
检查 input 元素被设为 radio 类型后是否仍然保持原来的值。
IE 中为 false , FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... input = document.createElement("input"); input.value = "t"; input.setAttribute("type", "radio"); support.radioValue = input.value === "t"; return { support : support } }();
这段代码先创建了 input 元素,将 value 设为 “t” ,然后将其类型设置为 “radio”,最后检查器 input 原来的值是否仍然保留。
checkClone
检查 fragment 中的 checkbox 的选中状态是否能被复制,IE 中为 false ,FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... div.innerHTML = ""; input.setAttribute("checked", "checked"); div.appendChild( input ); fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; return { support : support } }();
这段代码创建了一个 fragment ,并将一个处于选中状态的 checkbox 加入,连续复制两遍后检查 checkbox 是否为选中状态。(这里源代码中的实现似乎有问题,没有将 div 的 innerHTML 清空,导致 div 的 firstChild 并非 checkbox,使得 checkclone 在各浏览器中的值均为 undefined 。)
appendChecked
检查被添加到 DOM 中的 checkbox 是否仍然保留原来的选中状态。
IE 中为 false ,FireFox 中为 true 。
实现方式如下:
$ = function(){ // Other codes ... support.appendChecked = input.checked; return { support : support } }();
实际上只是简单地检查之前添加到 fragment 中的 checkbox 的选中状态。
boxModel
检查页面渲染是否符合 W3C Box Model 。
在 IE 中没有 DocType 声明时为 false ,其余情况为 true 。
实现方式如下:
$ = function(){ // Other codes ... div.innerHTML = ""; div.style.width = div.style.paddingLeft = "1px"; body = document.createElement( "body" ); bodyStyle = { visibility: "hidden", width: 0, height: 0, border: 0, margin: 0, background: "none" }; for (var i in bodyStyle ) { body.style[i] = bodyStyle[i]; } body.appendChild(div); document.documentElement.appendChild(body); support.boxModel = div.offsetWidth === 2; body.innerHTML = ""; document.documentElement.removeChild( body ); return { support : support } }();
将 div 的 width 和 paddingLeft 设为 1px ,然后将它添加到 body 中,检查 div 的 offsetWidth 是否为 2 。
reliableHiddenOffsets
检查 hidden 状态下的 offsetWidth 和 offsetHeight 是否正确。
IE 中为 false , FireFox 中为 true 。
实现方式如下(插入到清空 body.innerHTML 之前):
$ = function(){ // Other codes ... div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>"; var tds = div.getElementsByTagName("td"); var isSupported = (tds[0].offsetHeight === 0); tds[0].style.display = ""; tds[1].style.display = "none"; support.reliableHiddenOffsets = isSupported && (tds[0].offsetHeight === 0); body.innerHTML = ""; document.documentElement.removeChild( body ); return { support : support } }();
检查将一个 td 隐藏时, 相邻的 td 的 offsetHeight 是否为 0 。
ajax, cors
检查是否支持 ajax 请求,以及是否支持跨域 ajax。
IE 与 FireFox 中 ajax 均为 true ,IE 中 cors 为 false , FireFox 中 cros 为 false 。
实现方式如下:
$ = function(){ // Other codes ... var xhr = window.ActiveXObject ? !this.isLocal && createStandardXHR() || createActiveXHR() : createStandardXHR(); support.ajax = !!xhr; support.cors = !!xhr && ( "withCredentials" in xhr ) function createStandardXHR() { try { return new window.XMLHttpRequest(); } catch( e ) {} } function createActiveXHR() { try { return new window.ActiveXObject("Microsoft.XMLHTTP"); } catch( e ) {} } return { support : support } }();
尝试创建 ajax 对象,创建成功,则 ajax 为 true ;如果 ajax 对象中包含了 "withCredentials" 属性,则表示支持跨域 ajax。
- jQuery-support.rar (62.9 KB)
- 下载次数: 35
发表评论
-
jQuery Utilities 分类下的函数(或属性)的实现方式分析
2011-05-16 19:25 3157jQuery Utilities 分类下的函数(或属性)的实现 ... -
jQuery.data() 的实现方式
2011-05-13 14:21 10523jQuery.data() 的实现方式 jQuery. ... -
jQuery.unique()的实现方式
2011-05-10 08:18 8469jQuery.unique()的实现方式 jQuery 中的 ... -
jQuery.browser的实现方式
2011-05-07 11:11 38252jQuery.browser的实现方式 j ... -
jQuery.extend()的实现方式
2011-04-30 07:54 7109jQuery.extend()的实现方式 jQuery中的ex ...
相关推荐
当一个插件需要在多个浏览器间保持兼容性时,通过`jQuery.support`的检测结果可以决定是否采用特定的实现策略来兼容那些不支持特定特性的浏览器。 #### 浏览器特性检测 在`jQuery.support`模块中,包含了一系列的...
它可能包括使用`jQuery.support`来检测浏览器特性,以及对CSS3动画的降级处理,以确保在不支持这些特性的浏览器中也能实现平滑的过渡效果。 此外,模态窗口的样式可以通过自定义CSS来进一步调整,以满足项目的视觉...
这款插件通过 AJAX 方式动态加载数据,使得用户在输入过程中可以接收到实时的建议列表,极大地提高了交互体验。然而,对于中文输入的支持在某些浏览器中存在一些问题,特别是在 Firefox 3.0 版本中。 问题在于,...
总的来说,jQuery是Web开发中的一个强大工具,无论是1.8.3还是1.12.4,都可以帮助开发者快速地编写出高效的JavaScript代码,实现复杂的交互和动画效果。选择哪个版本取决于项目的具体需求,包括对浏览器兼容性的要求...
在jQuery的早期版本中,开发者通常使用`$.browser`对象来检测用户使用的浏览器类型和版本,以便针对不同浏览器实现特定的兼容性代码。然而,这种做法并不被推荐,因为它鼓励了浏览器嗅探(browser sniffing),而...
jQuery.support对象用于返回当前浏览器的特性和bug信息,便于开发者进行浏览器兼容性检测。 在数组操作方面,jQuery.extend()和jQuery.fn.extend()函数用于合并对象,jQuery.grep()用于根据过滤函数来过滤数组元素...
通过这些示例,可以学习如何在.NET环境中使用jQuery,实现前后端数据交互。 三、应用实践 1. **DOM操作**:利用jQuery提供的`.find()`, `.children()`, `.append()`, `.prepend()`等方法,可以方便地查找、添加或...
3. **动画优化**:jQuery 1.8.0改进了动画效果的实现,如淡入淡出、滑动等,使得动画更加流畅,同时减少了对CPU的占用。 4. **插件API稳定**:这一版本进一步稳定了插件开发的API,使得第三方插件开发者可以更方便...
对于那些仍需支持老版本IE的应用,可以通过条件注释或使用不同的jQuery版本来实现兼容。例如,在HTML中使用条件注释加载不同版本的jQuery库: ```html <!--[if lt IE 9]> <script src="http://keleyi....
`DataTables` 提供了一系列方法来操作表格,如`fnDraw()`用于重新绘制表格,`fnFilter()`实现过滤功能,`fnSort()`进行排序,`fnPageChange()`改变当前页面。 **4. 事件处理(Event Handling)** 通过绑定各种事件...
在这个标题为"jquery-1.8.0min.js&&jquery-1.8.0.js"的资源包中,包含了两个版本的jQuery库——未压缩版的jquery-1.8.0.js和压缩版的jquery-1.8.0.min.js,它们都是jQuery 1.8.0的实现,供开发者根据需求选择使用。...
7. **优化与兼容性**:为了确保在不同浏览器上的良好表现,代码可能包含了一些浏览器兼容性处理,比如使用`$.support`检测浏览器特性,或者使用`$.fn.jquery`检查jQuery版本,以适应不同的环境。 8. **响应式设计**...
- **网页交互增强**: 利用jQuery实现网页的动态交互,如表单验证、下拉菜单等。 - **响应式设计**: 结合媒体查询,实现不同设备下的适配。 - **页面加载优化**: 使用`.load()`和`.unload()`优化页面加载和卸载...
jQuery API 提供了丰富的函数和方法,帮助开发者实现各种功能。其中一些核心API包括: - **$.fn.extend()**:扩展jQuery对象的方法。 - **$.each()**:遍历对象或数组,执行回调函数。 - **$.ajaxSetup()**:设置...
5. 插件机制(Plugins):由于jQuery的开放性,它有一个庞大的插件社区,这些插件可以扩展jQuery的功能,实现如表单验证、轮播图、图片懒加载等多种复杂功能。 6. 跨浏览器兼容性(Cross-Browser Compatibility):...
这可能包括JavaScript库(如jquery-2.0.3.min.js、doT.js和custom_event.js)和Chrome Web UI APIs(chrome_webui_apis.js),这些都是前端开发中常用的工具和资源。 - `jquery-2.0.3.min.js` 是一个轻量级的...
《jquery技术内幕:深入解析jquery架构设计与实现原理》在分析每个模块时均采用由浅入深的方式,先概述功能、用法、结构和实现原理,然后介绍关键步骤和分析源码实现。让读者不仅知其然,而且知其所以然。事实上,...
在jQuery.Autocomplete插件的源代码(jquery.autocomplete.js)的第199行,插入绑定“input”事件的代码,以调用插件内部的onChange函数,实现当输入内容发生变化时触发查询更新。 示例代码如下: ```javascript ...
同时,考虑到老旧浏览器可能不支持某些CSS3特性,可以使用jQuery的`.support()`方法检测浏览器兼容性,并提供备选方案。 总结,使用jQuery实现炫彩文字特效需要掌握jQuery的基本操作,熟悉CSS3动画和过渡效果,以及...