记jQuery.fn.show的一次踩坑和问题排查
最近很少已经很少用jQuery,因为主攻移动端,常用Zepto,其实很多细节和jQuery并不一样。
最近又无意中接触到了PC的需求和IE6, 使用了jQuery,刚好踩坑了,特意记录一下。
> 本文内容如下:
> - 问题
> - 解决
> - jQuery.fn.show()和jQuery.fn.show(0)到底发生了什么
> - 结语
> - 参考和引用
JavaScript - 前端开发交流群:377786580
问题
最近很少用jQuery,因为主攻移动端,常用Zepto,其实很多细节和jQuery并不一样。以前读过Zepto的源码,所以完全知道zepto.fn.show/zepto.fn.hide到底做了什么。
一直只记得jQuery.fn.show/jQuery.fn.hide方法在后来被改写过,也没怎么去关注过这里,最近又无意中接触到了PC的需求和IE6, 使用了jQuery,刚好踩坑了,特意记录一下。
问题就是有一个<a>标签默认是隐藏的(display:none),做了一些业务逻辑的处理之后呢把这个<a>显示出来(通过jQuery.fn.show),但是这个<a>标签却被加上了新的样式:
<a href="javascript:;" style="display:inline-block;"></a>
查了一下当时调用jQuery.fn.show
的代码:
$('#id').show(0); //给a加上了display:inline-block;
解决
触发这个问题就是因为自己错误的以为jQuery.fn.show/jQuery.fn.hide
会有默认动画时间,于是显示隐藏元素的时候喜欢这样处理:
$('#id').show(0);
$('#id').hide(0);
其实是自己对jQuery.fn.show/jQuery.fn.hide记错了,以前学jQuery的时候就只记得了个jQuery动画有个默认的时间,是300ms。但没记API,其实是:
jQuery的动画系列函数,
slideDown、slideUp、slideToggle、fadeIn、fadeOut、fadeToggle、fadeTo、toggle
都是默认400ms动画时间的,而show/hide
默认是没有动画时间的。
参见jQuery 1.11.0源码:
jQuery.each({
slideDown: genFx("show"),
slideUp: genFx("hide"),
slideToggle: genFx("toggle"),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
jQuery.fn[ name ] = function( speed, easing, callback ) {
return this.animate( props, speed, easing, callback );
};
});
合并动画配置(设置动画默认时间)的代码是jQuery.speed
方法:
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default /*默认动画时间(ms)*/;
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
opt.old = opt.complete;
opt.complete = function() {
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
if ( opt.queue ) {
jQuery.dequeue( this, opt.queue );
}
};
return opt;
};
//...
jQuery.fx.speeds = {
slow: 600,
fast: 200,
// Default speed
_default: 400
};
后来查到问题是给方法传递了一个参数0
导致的问题,把参数去掉即可,改成下面的代码即可:
<script>
$('#id').show();
</script>
<a href="javascript:;" style=""></a>
然后被妹子追问为什么,回答不上来,只记得这俩API后来调整过。
jQuery.fn.show()和jQuery.fn.show(0)到底发生了什么
之后我就觉得有必要再去深入了解下jQuery.fn.show/jQuery.fn.hideAPI了,至少要了解下这俩API现在到底做了什么。
刚开始我仍然天真的以为jQuery.fn.show在不传递参数的情况下会有默认动画时间,直到翻阅源码版本至jQuery 1.4.0发现都对没有参数的情况进行了display的处理,反而是传递了speed
之后会走动画处理。
jQuery.fn.extend({
//$('id').show();
show: function( speed, callback ) {
if ( speed != null ) {
return this.animate( genFx("show", 3), speed, callback);
} else {
//speed===undefined
for ( var i = 0, l = this.length; i < l; i++ ) {
//操作元素的display
var old = jQuery.data(this[i], "olddisplay");
this[i].style.display = old || "";
if ( jQuery.css(this[i], "display") === "none" ) {
var nodeName = this[i].nodeName, display;
if ( elemdisplay[ nodeName ] ) {
display = elemdisplay[ nodeName ];
} else {
var elem = jQuery("<" + nodeName + " />").appendTo("body");
display = elem.css("display");
if ( display === "none" ) {
display = "block";
}
elem.remove();
elemdisplay[ nodeName ] = display;
}
jQuery.data(this[i], "olddisplay", display);
}
}
for ( var j = 0, k = this.length; j < k; j++ ) {
this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
}
return this;
}
},
hide: function( speed, callback ) {
if ( speed != null ) {
return this.animate( genFx("hide", 3), speed, callback);
} else {
for ( var i = 0, l = this.length; i < l; i++ ) {
var old = jQuery.data(this[i], "olddisplay");
if ( !old && old !== "none" ) {
jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
}
}
for ( var j = 0, k = this.length; j < k; j++ ) {
this[j].style.display = "none";
}
return this;
}
}
});
在jQuery 1.11.0代码整理后阅读起来好了很多:
jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = jQuery.fn[ name ];
jQuery.fn[ name ] = function( speed, easing, callback ) { //$('#id').show();
//speed===undefined
return speed == null || typeof speed === "boolean" ?
cssFn.apply( this, arguments ) :
this.animate( genFx( name, true ), speed, easing, callback );
};
});
可以看见当在jQuery 1.11.0中,当speed参数为null、undefined、boolean的时候会进入css直接处理分支,而不会走动画。
所以下面的代码完全走的是不同的分支:
$('#id').show(); //走css处理分支
$('id').show(0); //走animate处理分支
那么<a>上的display:inline-block
从何而来呢?于是搜索了一下inline-block
,发现了这一段代码:
function defaultPrefilter( elem, props, opts ) {
/* jshint validthis: true */
var prop, value, toggle, tween, hooks, oldfire, display, dDisplay,
anim = this,
orig = {},
style = elem.style,
hidden = elem.nodeType && isHidden( elem ),
dataShow = jQuery._data( elem, "fxshow" );
// ...
// height/width overflow pass
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
display = jQuery.css( elem, "display" ); //获取元素样式中的display
dDisplay = defaultDisplay( elem.nodeName ); //获取元素默认的display
if ( display === "none" ) {
display = dDisplay;
}
if ( display === "inline" && jQuery.css( elem, "float" ) === "none" ) {
if ( !support.inlineBlockNeedsLayout || dDisplay === "inline" ) {
//现代浏览器下,当元素默认的display为inline,则调整为inline-block
style.display = "inline-block";
} else {
style.zoom = 1;
}
}
}
// ...
}
defaultPrefilter
方法在jQuery内置的动画对象Animation
中调用,用于修正执行动画前的一些细节。
到了这里再想想动画的一些操作因素,也就可以理解为什么会这样了:
jQuery中的动画操作的无非是位置、透明度、宽高几个点。
有些动画涉及到宽高的改变(例如:jQuery.fn.show/jQuery.fn.hide改变的就是元素的width+height,jQuery.fn.slideDown改变的是height),那么就需要把这些元素设置成可以改变宽高的(行)块级元素。因为行级元素是不能通过css改变宽高的。
而<a>标签默认是inline的,当对它操作width/height(即jQuery.fn.show)的时候,需要把它改成inline-block,让动画对它设置的宽高生效。
结语
至此,问题追查完毕,我也可以好好的跟妹子吹吹牛逼啦~~~~~~~当然除了这个,更多的是自己的反思,想起了之前做的代码里很多时候使用的都是:
$('#id').show(0);
加这一个参数和不加参数光看看源码就知道是天壤之别了,更别提什么性能,IE678套餐可能造成的影响了。
其实问题的根源仍然在于我对代码的了解程度不够,对于当前代码的认知自己竟然觉得满足了。想想刚学js的我可是充满了好奇心各种探索造轮子查资料读源码,随着时间的推移,技术实力和视野逐渐的提升,让自己变得越来越懒惰,越来越容易满足,这样的状态并不好。
任何时候,都应该清楚的知道自己撸的代码到底发生了什么,学无止境,共勉。
JavaScript - 前端开发交流群:377786580
记jQuery.fn.show的一次踩坑和问题排查的更多相关文章
- 【锋利的jQuery】表单验证插件踩坑
和前几篇博文提到的一样,由于版本原因,[锋利的jQuery]表单验证插件部分又出现照着敲不出效果的情况. 书中的使用方法: 1. 引入jquery源文件, 2. 引入表单验证插件js文件, 3. 在f ...
- Spark踩坑记——共享变量
[TOC] 前言 Spark踩坑记--初试 Spark踩坑记--数据库(Hbase+Mysql) Spark踩坑记--Spark Streaming+kafka应用及调优 在前面总结的几篇spark踩 ...
- 基于JQuery可拖动列表格插件DataTables的踩坑记
前言 最近项目中在使用能够拖动列调整列位置顺序的表格插件---DataTables,这也是目前我找到的唯一一种存在有这种功能的插件. 在查找使用方法的过程中发现可用案例并不多,且大多言语不详.本文将全 ...
- jQuery升级踩坑大全
jQuery升级踩坑大全 背景 jQuery想必各个web工程师都再熟悉不过了,不过现如今很多网站还采用了很古老的jQuery版本.其实如果早期版本使用不当,可能会有DOMXSS漏洞,非常建议升级到j ...
- jQuery版本升级踩坑大全
背景 -------------------------------------------------------------------------------- jQuery想必各个web工程师 ...
- jQuery源码-jQuery.fn.attr与jQuery.fn.prop
jQuery.fn.attr.jQuery.fn.prop的区别 假设页面有下面这么个标签,$('#ddd').attr('nick').$('#ddd').prop('nick')分别会取得什么值? ...
- jQuery.fn.attr与jQuery.fn.prop
jQuery.fn.attr与jQuery.fn.prop jQuery.fn.attr.jQuery.fn.prop的区别 假设页面有下面这么个标签,$('#ddd').attr('nick').$ ...
- jQuery升级踩坑之路
1.使用了被废弃的jQuery.browser属性 jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support . 在更 ...
- Vue + TypeScript + Element 搭建简洁时尚的博客网站及踩坑记
前言 本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 . TypeScript 具有类型系统,且是 JavaScript 的超集,TypeScript ...
随机推荐
- ArcGIS API for JavaScript(2)-ArcGIS Server发布要素图层服务
1.前言 上一篇该系列的文章我们主要讲了一下基础Web地图搭建,这篇我们主要讲一下ArcGIS Server发布服务,并且如何调用服务.将自己的数据加载到Web地图当中来,实现Web端浏览数据. 2. ...
- 利用typescript使backbone强类型智能提示
模型类一旦多了没有强类型和智能提示是相当痛苦的,所以. 仅仅用ts定义一个模型类: class Person extends Backbone.Model { defaults = { Name:&q ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + div.aaron input[type="checkb ...
- java Proxy(代理机制)
我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习 ...
- 关于Android多项目依赖在Eclipse中无法关联源代码的问题解决
被Eclipse中Android依赖项目无法关联源代码的问题困扰了许久,网上搜索了一下,终于得到解决,大大提高了开发效率. 问题描述: 项目有A,B两个Android Project组成, B是And ...
- 窥探Swift之协议(Protocol)和委托代理(Delegate)回调的使用
协议与委托代理回调在之前的博客中也是经常提到和用到的在<Objective-C中的委托(代理)模式>和<iOS开发之窥探UICollectionViewController(四) - ...
- preg_match的isU代表什么意义
正则后面的/(.*)/isU ,“isU”参数代表什么意思?这是正则中的修正符.i是同时查找大小写字母,s是圆点(.)匹配所有字符,包括换行符.如果没有设定s,则不包括换行符.U是反转了匹配数量的值 ...
- java 连接数据库之一个完整的函数
第一个参数要查询的列名第二个参数是连接的url第三个参数是用户名第四个参数密码第五个参数是执行的命令. 注意,url格式是 jdbc:mysql://localhost:3306/wechat jdb ...
- [翻译]利用顶点位移的VR畸变校正
文章英文原网址: http://www.gamasutra.com/blogs/BrianKehrer/20160125/264161/VR_Distortion_Correction_using_V ...
- C++运算符重载
C++运算符重载 基本知识 重载的运算符是具有特殊名字的函数,他们的名字由关键字operator和其后要定义的运算符号共同组成. 运算符可以重载为成员函数和非成员函数.当一个重载的运算符是成员函数时, ...