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 相关文章推荐
用 Javascript 验证表单(form)中多选框(checkbox)值
Sep 08 Javascript
20款效果非常棒的 jQuery 插件小结分享
Nov 18 Javascript
jQuery实现伸展与合拢panel的方法
Apr 30 Javascript
jQuery实现点击后标记当前菜单位置(背景高亮菜单)效果
Aug 22 Javascript
jsonp跨域请求数据实现手机号码查询实例分析
Dec 12 Javascript
JavaScript文档碎片操作实例分析
Dec 12 Javascript
JQuery EasyUI学习教程之datagrid 添加、修改、删除操作
Jul 09 Javascript
JavaScript与JQUERY获取元素的宽、高和位置
Feb 26 Javascript
js实现时间轴自动排列效果
Mar 09 Javascript
AngularJS实现的省市二级联动功能示例【可对选项实现增删】
Oct 26 Javascript
解决Vue+Element ui开发中碰到的IE问题
Sep 03 Javascript
JS实现头条新闻的经典轮播图效果示例
Jan 30 Javascript
[原创]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
Views rows style模板重写代码
2011/05/16 PHP
教你如何解密 “ PHP 神盾解密工具 ”
2014/06/20 PHP
PHP数组基本用法与知识点总结
2020/06/02 PHP
js获取图片长和宽度的代码
2009/11/24 Javascript
几个有趣的Javascript Hack
2010/07/24 Javascript
js对象关系图 方便dom操作
2012/03/18 Javascript
Jquery Uploadify多文件上传带进度条且传递自己的参数
2013/08/28 Javascript
利用Keydown事件阻止用户输入实现代码
2014/03/11 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
nodejs教程之环境安装及运行
2014/11/21 NodeJs
jQuery实现仿Alipay支付宝首页全屏焦点图切换特效
2015/05/04 Javascript
浅析jquery如何判断滚动条滚到页面底部并执行事件
2016/04/29 Javascript
AngularJs Javascript MVC 框架
2016/06/20 Javascript
js实现固定宽高滑动轮播图效果
2017/01/13 Javascript
es7学习教程之Decorators(修饰器)详解
2017/07/21 Javascript
使用Vue.js和Flask来构建一个单页的App的示例
2018/03/21 Javascript
jQuery使用动画队列自定义动画操作示例
2018/06/16 jQuery
vue-cli 打包后提交到线上出现 &quot;Uncaught SyntaxError:Unexpected token&quot; 报错
2018/11/06 Javascript
详解Vue.js v-for不支持IE9的解决方法
2018/12/29 Javascript
详解mpvue实现对苹果X安全区域的适配
2019/07/31 Javascript
layui 实现加载动画以及非真实加载进度的方法
2019/09/23 Javascript
Paypal支付不完全指北
2020/06/04 Javascript
手把手带你搭建一个node cli的方法示例
2020/08/07 Javascript
JS算法教程之字符串去重与字符串反转
2020/12/15 Javascript
[01:10:57]Liquid vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python对列表中的各项进行关联详解
2017/08/15 Python
以设计师精品品质提供快速时尚:Mostata
2019/05/10 全球购物
船舶专业个人求职信范文
2014/01/02 职场文书
农业局学习党的群众路线教育实践活动心得体会
2014/03/07 职场文书
学生党员公开承诺书
2014/05/28 职场文书
施工工地安全标语
2014/06/07 职场文书
质量管理标语
2014/06/12 职场文书
2014党员学习兰辉先进事迹思想汇报
2014/09/17 职场文书
人生遥控器观后感
2015/06/11 职场文书
2016年党员创先争优承诺书
2016/03/25 职场文书
SQL Server连接查询的实用教程
2021/04/07 SQL Server