当前位置:Gxlcms > JavaScript > jQuery链式调用与show知识浅析

jQuery链式调用与show知识浅析

时间:2021-07-01 10:21:17 帮助过:14人阅读

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

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

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

  1. (function(window, undefined){
  2. function jQuery(sel){
  3. return new jQuery.prototype.init(sel);
  4. }
  5. jQuery.prototype = {
  6. constructor: jQuery,
  7. init: function(sel){
  8. if(typeof sel === 'string'){
  9. var that = this;
  10. var nodeList = document.querySelectorAll(sel);
  11. Array.prototype.forEach.call(nodeList, function(val, i){
  12. that[i] = val;
  13. })
  14. this.selector = sel;
  15. this.length = nodeList.length;
  16. }
  17. },
  18. show: function(){
  19. Array.prototype.forEach.call(this, function(node){
  20. //if(node.style) continue; //textnode没有style
  21. //删除style上的display:none
  22. var display = node.style.display;
  23. if(display === 'none'){
  24. //dispaly置为空后,css如果有display则css的生效
  25. //否则默认的生效
  26. node.style.display = '';
  27. }
  28. //元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
  29. //或 检测css上的display是否为none
  30. if(node.style.display==='' || isHidden(node)){
  31. //有oldDispaly则设置
  32. if(node.oldDisplay) node.style.display = node.oldDisplay;
  33. //没有则设置为元素默认值或元素当前值
  34. else node.style.display = getDisplay(node);
  35. }
  36. })
  37. //链式调用
  38. return this;
  39. },
  40. hide: function(){
  41. Array.prototype.forEach.call(this, function(node){
  42. if(!isHidden(node)) {
  43. //jQuery使用其cache机制存储信息,这里简化一下
  44. //直接挂载在对应的dom下
  45. node.oldDisplay = getDisplay(node);
  46. node.style.display = 'none';
  47. }
  48. })
  49. return this;
  50. }
  51. }
  52. function getDisplay(node){
  53. var display = window.getComputedStyle(node, null).getPropertyValue('display');
  54. if(display === 'none'){
  55. var dom = document.createElement(node.nodeName);
  56. //插入到body中
  57. document.body.appendChild(dom);
  58. //即可获取到元素display的默认值
  59. var display = window.getComputedStyle(dom, null).getPropertyValue('display');
  60. document.body.removeChild(dom);
  61. }
  62. return display;
  63. }
  64. function isHidden(node) {
  65. //忽略未append进document的元素这种隐藏情况:$('<div>block</div>')未append
  66. return window.getComputedStyle(node, null).getPropertyValue('display') === 'none';
  67. }
  68. jQuery.prototype.init.prototype = jQuery.prototype;
  69. window.$ = jQuery;
  70. })(window);

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

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

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

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

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

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

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

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

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

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

  1. node.oldDisplay = getDisplay(node);

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

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

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

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

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

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

  1. function getDisplay(node){
  2. var display = window.getComputedStyle(node, null).getPropertyValue('display');
  3. if(display === 'none'){
  4. var dom = document.createElement(node.nodeName);
  5. //插入到body中
  6. document.body.appendChild(dom);
  7. //即可获取到元素display的默认值
  8. var display = window.getComputedStyle(dom, null).getPropertyValue('display');
  9. document.body.removeChild(dom);
  10. }
  11. return display;
  12. }

然后,综合这两种情况:

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

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

  1. <style>
  2. #none,#none2{ display: none; }
  3. </style>
  4. <body>
  5. <div id="div">默认值为block</div>
  6. <span id="span">默认值为inline</span>
  7. <div id="div2" style="display:inline-block;">修改为inline-block</div>
  8. <div id="none">通过css隐藏了</div>
  9. <div id="none2" style="display:none">通过css和style隐藏了</div>
  10. </body>

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

  1. show: function(){
  2. Array.prototype.forEach.call(this, function(node){
  3. //if(node.style) continue; //textnode没有style
  4. //删除style上的display:none
  5. var display = node.style.display;
  6. if(display === 'none'){
  7. //dispaly置为空后,css如果有display则css的生效
  8. //否则默认的生效
  9. node.style.display = '';
  10. }
  11. //元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
  12. //或 检测css上的display是否为none
  13. if(node.style.display==='' || isHidden(node)){
  14. //有oldDispaly则设置
  15. if(node.oldDisplay) node.style.display = node.oldDisplay;
  16. //没有则设置为元素默认值或当前值
  17. else node.style.display = getDisplay(node);
  18. }
  19. })
  20. }

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

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

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

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

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

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

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

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

  1. div{ display:none !important; }
  2. <div>大家自己开脑洞,怎么处理吧(⊙0⊙)</div>

人气教程排行