Fork me on GitHub

visible选择器

现在移动端项目在重构阶段,将之前的jQuery全部替换成Zepto了。由于Zepto的精简,以置于之前的jQuery的代码不能运行了,其中visible选择器就是其中一个。既然已经选择了Zepto,那就给Zepto增加visible功能。

分析

第一反应就是思考通过元素的属性来判断,然后尝试了使用display和visibility来进行判断。但是经过小的测试,是我想的简单了!

display是无法继承父元素的,visibility是能够继承父元素,但是父元素采用的是display显示与隐藏。

参考地址1
参考地址2

我的想法

既然模块的根元素是用display显示与隐藏,那我先就通过类选择器,选到元素。然后再透过递归判断父元素display,直到body元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
;(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;
}else {
return false;
}
}
}
}

$.fn.filter = function(sel) {
if (sel === ":visible") {
return $([].filter.call(this, visible));
}
return _filter.call(this, sel);
};
})(window.Zepto);

自己的实现是可以的,不过自我感觉有点饶了,看看能不能透过其它方式来解决。

jQuery实现

查看了jQuery3.0的内部实现,最终调用的是jQuery.expr.filters.visible

1
2
3
jQuery.expr.filters.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};

jQuery首先的判断元素的offsetWidth和offsetHeight。因为根元素隐藏后,导致其子元素的宽高为0。不占用文档流,这很好理解。

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 element that don’t have height are considered to be visible.

大体的意思是对于一个元素本身宽高都为0,但是占据了稳定流,这是能认为是visible的。比如像 换行br、空的span 标签。

其它实现

在github上也找到了,对Zepto增加visible的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
;(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选择器/

觉得有点意思,打个赏鼓励博主继续写哈!がんばって
前端-小强 WeChat Pay

微信打赏

前端-小强 Alipay

支付宝打赏