visible选择器

如今移动端项目在重构阶段,将以前的jQuery所有替换成Zepto了。因为Zepto的精简,以置于以前的jQuery的代码不能运行了,其中visible选择器就是其中一个。既然已经选择了Zepto,那就给Zepto增长visible功能。javascript

分析

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

display是没法继承父元素的,visibility是可以继承父元素,可是父元素采用的是display显示与隐藏。html

参考地址1
参考地址1java

个人想法

既然模块的根元素是用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

jQuery实现

查看了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/

相关文章
相关标签/搜索