如今移动端项目在重构阶段,将以前的jQuery所有替换成Zepto了。因为Zepto的精简,以置于以前的jQuery的代码不能运行了,其中visible选择器就是其中一个。既然已经选择了Zepto,那就给Zepto增长visible功能。javascript
第一反应就是思考经过元素的属性来判断,而后尝试了使用display和visibility来进行判断。可是通过小的测试,是我想的简单了!css
display是没法继承父元素的,visibility是可以继承父元素,可是父元素采用的是display显示与隐藏。html
既然模块的根元素是用display显示与隐藏,那我先就经过类选择器,选到元素。而后再透过递归判断父元素display,直到body元素。git
;(function($) { var _filter = $.fn.filter; function visible(elem) { var $elem = $(elem); if($elem.css('display') === 'none') { return false; }else { if($elem.is('body')) { return true; }else { if(visible($elem.parent())) { return true; } } } } $.fn.filter = function(sel) { if (sel === ":visible") { return $([].filter.call(this, visible)); } return _filter.call(this, sel); }; })(window.Zepto);
本身的实现是能够的,不过自我感受有点饶了,看看能不能透过其它方式来解决。github
查看了jQuery3.0的内部实现,最终调用的是jQuery.expr.filters.visible浏览器
jQuery.expr.filters.visible = function( elem ) { return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); };
jQuery首先的判断元素的offsetWidth和offsetHeight。由于根元素隐藏后,致使其子元素的宽高为0。不占用文档流,这很好理解。ide
getClientRects:获取元素占据页面的全部矩形区域,用于获取元素占据页面的全部矩形区域
与之相关的是getBoundingClientRect。
getBoundingClientRect:用于得到页面中某个元素的左,上,右和下分别相对浏览器视窗的位置学习
而为何要使用这个呢?在官网找到了答案。测试
Breaking change: Behavior of :hidden and :visible
An element is considered now visible if it has a layout box returned from the DOM getClientRects() method,even if that box has a height and/or width of zero. This means that elements such as
or an empty <span> element that don't have height are considered to be visible.
大致的意思是对于一个元素自己宽高都为0,可是占据了稳定流,这是能认为是visible的。好比像 换行br、空的span 标签。
在github上也找到了,对Zepto增长visible的方法。
;(function($){ var _is = $.fn.is, _filter = $.fn.filter; function visible(elem){ elem = $(elem); return !!(elem.width() || elem.height()) && elem.css("display") !== "none"; } $.fn.is = function(sel){ if(sel === ":visible"){ return visible(this); } if(sel === ":hidden"){ return !visible(this); } return _is.call(this, sel); } $.fn.filter = function(sel){ if(sel === ":visible"){ return $([].filter.call(this, visible)); } if(sel === ":hidden"){ return $([].filter.call(this, function(elem){ return !visible(elem); })); } return _filter.call(this, sel); } })(Zepto);
最终我选择了最后一种,功能可以知足现有的需求。
其实Sizzle很强大,这visible选择器只是其九牛一毛,后面能够再学习学习其思想。
原文地址http://xiaoqiang730730.github.io/2016/07/16/visible%E9%80%89%E6%8B%A9%E5%99%A8/