jQuery链式调用与show知识浅析


Posted in Javascript onMay 11, 2016

上篇文章给大家介绍了jQuery的框架,有关jquery的基础知识可以参考下。

jQuery使用许久了,但是有一些API的实现实在想不通。下面将使用简化的代码来介绍,主要关注jQuery的实现思想。

相较于上一篇,代码更新了:21~78

(function(window, undefined){
function jQuery(sel){
return new jQuery.prototype.init(sel);
}
jQuery.prototype = {
constructor: jQuery,
init: function(sel){
if(typeof sel === 'string'){
var that = this;
var nodeList = document.querySelectorAll(sel);
Array.prototype.forEach.call(nodeList, function(val, i){
that[i] = val;
})
this.selector = sel;
this.length = nodeList.length;
}
},
show: function(){
Array.prototype.forEach.call(this, function(node){
//if(node.style) continue; //textnode没有style
//删除style上的display:none
var display = node.style.display;
if(display === 'none'){
//dispaly置为空后,css如果有display则css的生效
//否则默认的生效
node.style.display = '';
}
//元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
//或 检测css上的display是否为none
if(node.style.display==='' || isHidden(node)){
//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或元素当前值
else node.style.display = getDisplay(node);
}
})
//链式调用
return this;
},
hide: function(){
Array.prototype.forEach.call(this, function(node){
if(!isHidden(node)) {
//jQuery使用其cache机制存储信息,这里简化一下
//直接挂载在对应的dom下
node.oldDisplay = getDisplay(node);
node.style.display = 'none';
}
})
return this;
}
}
function getDisplay(node){
var display = window.getComputedStyle(node, null).getPropertyValue('display');
if(display === 'none'){
var dom = document.createElement(node.nodeName);
//插入到body中
document.body.appendChild(dom);
//即可获取到元素display的默认值
var display = window.getComputedStyle(dom, null).getPropertyValue('display');
document.body.removeChild(dom);
}
return display;
}
function isHidden(node) {
//忽略未append进document的元素这种隐藏情况:$('<div>block</div>')未append
return window.getComputedStyle(node, null).getPropertyValue('display') === 'none';
}
jQuery.prototype.init.prototype = jQuery.prototype;
window.$ = jQuery;
})(window);

先拿hide函数热身一下。如上篇提到的,jQuery会将获取到的nodeList处理成数组,所以一上来,我们用forEach处理数组里的每一个node节点。

接下来,我们只需要将每一个节点的style.display置为'none'即可隐藏。很简单,对吧?(⊙0⊙) 。oldDisplay和return this先不管?( ̄? ̄)?

hide: function(){
Array.prototype.forEach.call(this, function(node){
if(!isHidden(node)) {
//jQuery使用其cache机制存储信息,这里简化一下
//直接挂载在对应的dom下
node.oldDisplay = getDisplay(node);
node.style.display = 'none';
}
})
return this;
}

其中isHidden是判断该元素是否隐藏:已经隐藏的元素就没必要再去处理了,直接跳过

function isHidden(node) {
//忽略未append进document的元素这种隐藏情况:$('<div>block</div>')未append
return window.getComputedStyle(node, null).getPropertyValue('display') === 'none';
}

--------------------------

接下来,来个稍繁琐的show。先抛出一个问题来引发一系列问题:

hide某个元素只需要将display:none,那么show呢?

display:block不就行了吗?这样确实可以将元素显示出来。但是万一元素原来的值是display:inline呢?

那在hide处保存原来的值不就行了吗?就像以下的代码:

node.oldDisplay = getDisplay(node);

要是执行show前没有不执行hide呢?比如下面这种情况,不就没有oldDisplay了吗(⊙0⊙)

<style>
div{ display:none; }
</style>
<div>display:none</div>$('div').show()

好,关键的地方到了:我们获取元素display的默认值就可以了吧?比如div默认是block,span默认是inline。

思路有了,那么接下来的问题是:如何获取元素display的默认值

嘿嘿嘿,想不到吧?这里需要用点小技巧,大体思路如下:通过nodeName创建一个新的标签,再获取。

有个地方可以再优化一下,getDisplay获取到元素display默认值后,可以使用jQuery的cache机制存起来(实际上jQuery也是这么做了)。

function getDisplay(node){
var display = window.getComputedStyle(node, null).getPropertyValue('display');
if(display === 'none'){
var dom = document.createElement(node.nodeName);
//插入到body中
document.body.appendChild(dom);
//即可获取到元素display的默认值
var display = window.getComputedStyle(dom, null).getPropertyValue('display');
document.body.removeChild(dom);
}
return display;
}

然后,综合这两种情况:

//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或元素当前值
else node.style.display = getDisplay(node);

以为这样就结束了?NO,show函数的情况还是挺复杂的,我们大致要应对这几种情况:

<style>
#none,#none2{ display: none; }
</style>
<body>
<div id="div">默认值为block</div>
<span id="span">默认值为inline</span>
<div id="div2" style="display:inline-block;">修改为inline-block</div>
<div id="none">通过css隐藏了</div>
<div id="none2" style="display:none">通过css和style隐藏了</div>
</body>

最终,show函数变成了这鬼样ψ(?_?)。大致思路如下:

jQuery链式调用与show知识浅析

show: function(){
Array.prototype.forEach.call(this, function(node){
//if(node.style) continue; //textnode没有style
//删除style上的display:none
var display = node.style.display;
if(display === 'none'){
//dispaly置为空后,css如果有display则css的生效
//否则默认的生效
node.style.display = '';
}
//元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
//或 检测css上的display是否为none
if(node.style.display==='' || isHidden(node)){
//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或当前值
else node.style.display = getDisplay(node);
}
})
}

--------------------------

链式调用就是类似这种情况:

$('div').show().hide().css('height','300px').toggle()

实现起来非常简单,只要在每个函数后面return this即可

--------------------------

有同学说:喂!这个show,hide不对吧?是不是漏了时间参数? 用setTimeOut自己实现吧~>_<~+。

本节最主要是让大家知道jQuery需要考虑的情况非常多(很多脏活)。即时简化了代码,依然还是这么长。

写完后,发现show还有一种情况没考虑:

div{ display:none !important; }
<div>大家自己开脑洞,怎么处理吧(⊙0⊙)</div>
Javascript 相关文章推荐
特殊字符、常规符号及其代码对照表
Jun 26 Javascript
iframe的onload在Chrome/Opera中执行两次Bug的解决方法
Mar 17 Javascript
JS字符串累加Array不一定比字符串累加快(根据电脑配置)
May 14 Javascript
解析JavaScript中的标签语句
Jun 19 Javascript
JavaScript事件类型中UI事件详解
Jan 14 Javascript
全面解析JavaScript中的valueOf与toString方法(推荐)
Jun 14 Javascript
JavaScript暂停和继续定时器的实现方法
Jul 18 Javascript
jQuery3.0中的buildFragment私有函数详解
Aug 16 Javascript
深入学习js瀑布流布局
Oct 14 Javascript
ES6中Class类的静态方法实例小结
Oct 28 Javascript
微信小程序canvas分享海报功能
Oct 31 Javascript
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
[原创]Javascript 实现广告后加载 可加载百度谷歌联盟广告
May 11 #Javascript
Extjs4.0 ComboBox如何实现三级联动
May 11 #Javascript
javascript简单判断输入内容是否合法的方法
May 11 #Javascript
解析JavaScript面向对象概念中的Object类型与作用域
May 10 #Javascript
JavaScript根据CSS的Media Queries来判断浏览设备的方法
May 10 #Javascript
JavaScript中的原型prototype完全解析
May 10 #Javascript
简单解析JavaScript中的__proto__属性
May 10 #Javascript
You might like
PHP运行出现Notice : Use of undefined constant 的完美解决方案分享
2012/03/05 PHP
基于PHP Socket配置以及实例的详细介绍
2013/06/13 PHP
PHP用星号隐藏部份用户名、身份证、IP、手机号等实例
2014/04/08 PHP
php过滤表单提交的html等危险代码
2014/11/03 PHP
VSCode+PHPstudy配置PHP开发环境的步骤详解
2020/08/20 PHP
动态载入/删除/更新外部 JavaScript/Css 文件的代码
2010/07/03 Javascript
JQuery的ajax获取数据后的处理总结(html,xml,json)
2010/07/14 Javascript
ExtJs 表单提交登陆实现代码
2010/08/19 Javascript
js动态移动滚动条至底部示例代码
2014/04/24 Javascript
使用AngularJS中的SCE来防止XSS攻击的方法
2015/06/18 Javascript
js实现带圆角的两级导航菜单效果代码
2015/08/24 Javascript
浅谈node.js中async异步编程
2015/10/22 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
2016/09/06 Javascript
关于js函数解释(包括内嵌,对象等)
2016/11/20 Javascript
Bootstrap table表格简单操作
2017/02/07 Javascript
JavaScript中利用构造器函数模拟类的方法
2017/02/16 Javascript
详解vee-validate的使用个人小结
2017/06/07 Javascript
vue项目实现表单登录页保存账号和密码到cookie功能
2018/08/31 Javascript
Javascript中绑定click事件的四种方式介绍
2018/10/26 Javascript
前端路由&amp;webpack基础配置详解
2019/06/10 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
2019/07/10 jQuery
Vue+Vuex实现自动登录的知识点详解
2020/03/04 Javascript
vue中的.$mount('#app')手动挂载操作
2020/09/02 Javascript
Windows和Linux下Python输出彩色文字的方法教程
2017/05/02 Python
opencv改变imshow窗口大小,窗口位置的方法
2018/04/02 Python
pycharm执行python时,填写参数的方法
2018/10/29 Python
django框架用户权限中的session缓存到redis中的方法
2019/08/06 Python
python爬虫模拟浏览器访问-User-Agent过程解析
2019/12/28 Python
TensorFlow实现保存训练模型为pd文件并恢复
2020/02/06 Python
如何解决tensorflow恢复模型的特定值时出错
2020/02/06 Python
利物浦足球俱乐部官方网上商店:Liverpool FC Official Store
2018/01/13 全球购物
俄罗斯有趣和原创礼物网上商店:MagicMag
2019/08/01 全球购物
大型营销活动计划书
2014/04/28 职场文书
乡镇八一建军节活动方案
2014/08/24 职场文书
写给同事的离职感言
2015/08/04 职场文书
基于redis+lua进行限流的方法
2022/07/23 Redis