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/

相關文章
相關標籤/搜索