【问题标题】:Detect whether an element has position:fixed (possibly by parent element) via jQuery通过jQuery检测元素是否有位置:固定(可能由父元素)
【发布时间】:2013-10-28 18:04:00
【问题描述】:

更新我想避免遍历所有元素的父元素,依次测试每个元素,但这是迄今为止我设法找到的最佳解决方案,如 this answer .


在事件处理程序中,我想检测目标元素的位置是相对于视口(固定)还是文档(静态、相对或绝对)。

考虑到一个元素的位置可能是固定的,因为它具有“position:fixed”,或者因为它的父元素之一是“position:fixed”,那么检测元素固定位置的有效方法是什么?

例如:

CSS

#one {position:relative; height:10px; width:10px}

#two-wrapper {position:fixed; bottom:0; height:10px; width:10px}
#two {height:10px; width:10px}

HTML

<div id="one" class="trigger-event">element one</div>

<div id="two-wrapper">
    <div id="two" class="trigger-event">element two</div>
</div>

JS

$(document).ready(function(){
    $('.trigger-event').on('mouseenter', function(event){
        var isFixed = .... ????

        if (isFixed) {
            $(event.target).css('background','red'); 
        } else {
            $(event.target).css('background','green'); 
        }
    });
});

【问题讨论】:

    标签: javascript jquery html css css-position


    【解决方案1】:

    这是一个基于遍历元素的父元素的解决方案,依次检查每个元素的 CSS 位置值。

    这是最有效的方法,还是有办法仅通过检查元素本身来检测有效定位?

    http://jsfiddle.net/Q4mSJ/

    CSS

    .trigger-event {background:#ccc}
    
    #one {position:relative; height:50px; width:50px}
    
    #two-wrapper {position:fixed; bottom:0; height:50px; width:50px}
    #two {height:50px; width:50px}
    

    HTML

    <div id="one" class="trigger-event">element one</div>
    
    <div id="two-wrapper">
        <div id="two" class="trigger-event">element two</div>
    </div>
    

    JS

    function elementOrParentIsFixed(element) {
        var $element = $(element);
        var $checkElements = $element.add($element.parents());
        var isFixed = false;
        $checkElements.each(function(){
            if ($(this).css("position") === "fixed") {
                isFixed = true;
                return false;
            }
        });
        return isFixed;
    }
    
    $(document).ready(function(){
        $('.trigger-event').on('mouseenter', function(event){
            var isFixed = elementOrParentIsFixed(event.target);
    
            if (isFixed) {
                $(event.target).css('background','red'); 
            } else {
                $(event.target).css('background','green'); 
            }
        });
    });
    

    【讨论】:

    • 恭喜迟到了,但是 +1 :-) 因为我看到你的函数 elementOrParentIsFixed() 和下面我的几乎一样,只是我的是一个 jquery 插件而不是一个函数。
    • 但是这段代码还需要加载 jQuery 才能通过复制/粘贴来工作,而不需要一个框架来完成这个简单的普通书面任务......所以,肯定不是最好的答案......
    【解决方案2】:

    使用$(selector).offsetParent(),您可以搜索选择器的祖先,而无需加载所有元素的父元素。它仍然需要遍历父元素,但一旦找到具有所选位置(相对、绝对或固定)的最近元素,它将停止。

    http://jsfiddle.net/89y1buz9/11/

    CSS:

    div {
    border: 1px solid #ccc;
    }
    #outer {
        height: 200px;
        width: 120px;
        position: fixed;
        padding-top: 20px;
    }
    #inner {
            width: 95px;
        height: 150px;
        margin: 0px auto;
        position: relative;
    }
    #clickme {
        width: 70px;
        height: 50px;
        cursor: pointer;
        text-align: center;
        line-height: 40px;
        margin: 20px auto;
    }
    

    HTML:

    <div id="outer">
        <div id="inner">
            <div id="clickme">ClickMe</div>
        </div>
    </div>
    

    Javascript:

    function isFixed(ele, posType) {
        var eleCheck = ele.offsetParent(),
            returnVal;
        posType = posType || "fixed";
        if (eleCheck.prop("tagName") === 'HTML') {
            return false;
        }
        returnVal = (eleCheck.css("position") !== posType) ? isFixed(eleCheck): posType;
        return returnVal;
    }
    

    用法: 使用或不使用第二个参数调用它默认搜索固定元素

    $(function () {
        $("#clickme").on("click", function () {
            if (isFixed($(this), "fixed") === "fixed") {
                $(this).css("background", "red");
            } else {
                $(this).css("background", "green");
            }
        });
    });
    

    【讨论】:

      【解决方案3】:

      已更新,见下文...

      我在搜索纯 javascript 解决方案时顺便来了这里……但我希望有人会喜欢我的 jquery 版本。

      这里有两个函数,它们的工作方式略有不同,但性能差异很小。我没有测量它,但根据jsperf "each vs filter" 上的测试,.each()version 稍快。

      不过,我喜欢.filter() 版本,因为它非常简洁明了。

      $.fn.isfixed = function(){
          var el = $(this);
          var all = el.add(el.parents());
          return all.filter(function(){
              return $(this).css("position") === "fixed";
          }).length > 0;
      };
      
      $.fn.isfixed = function(){
          var el = $(this);
          var all = el.add(el.parents());
          var ret = false;
          all.each(function(){
              if ($(this).css("position") === "fixed") {
                  ret = true;
                  return false;
              }
          });
          return ret;
      };
      

      用法为$('path &gt; to &gt; your &gt; element').isfixed() 并返回truefalse

      更新

      这是纯 javascript 版本。事实证明,检测el.style.position(固定/绝对/相对)不起作用,不知道为什么,但window.getComputedStyle(el)... 可以。

      var isfixed = function(elm) {
          var el;
          if (typeof elm === 'object') el = elm[0] || elm;
          else if (typeof elm === 'string') el = document.querySelector(elm);
          while (typeof el === 'object' && el.nodeName.toLowerCase() !== 'body') {
              if (window.getComputedStyle(el).getPropertyValue('position').toLowerCase() === 'fixed') return true;
              el = el.parentElement;
          }
          return false;
      };
      

      它接受三种元素参数:
      作为 javascript 对象:
      var obj = document.querySelector('div#myID &gt; span');

      var obj = document.getElementById('span#someID');

      作为 jquery 对象:
      var obj = $('div#myID &gt; span');

      或仅作为选择器:
      var obj = 'div#myID &gt; span';

      使用简单的isfixed(obj); 并提供布尔值truefalse

      最后是混合解决方案(纯 javascript 作为 jquery 插件)

      $.fn.isfixed = function(){
          var el = this[0];
          while (typeof el === 'object' && el.nodeName.toLowerCase() !== 'body') {
              if (window.getComputedStyle(el).getPropertyValue('position').toLowerCase() === 'fixed') return true;
              el = el.parentElement;
          }
          return false;
      };
      

      用法:$('div#myID &gt; span').isfixed() 如上例所示。
      希望你会喜欢。

      【讨论】:

        【解决方案4】:

        这是我现在用来检测可能嵌套在 position:fixed 父级中的元素的方法。 (基于 another answernull 值存在问题。)

        // Returns true if `node` uses css position:fixed or has a parent that does so.
        function isFixedPosition(node) {
            while (node && node.nodeName.toLowerCase() !== 'body') {
                if (window.getComputedStyle(node).getPropertyValue('position').toLowerCase() === 'fixed')
                    { return true; }
                node = node.parentNode;
            }
            return false; // if got this far
        }
        

        【讨论】:

        • 这是一个很好的香草方式,好主意!我可以建议将toLowerCase 更改为.match(/fixed|sticky/i)
        【解决方案5】:

        我拿了上面的一些例子,做了简单的 js vanilla 代码来获取元素的位置,所以你可以在 jQuery 中使用它,也可以在没有 jQuery 的情况下使用。

        function getStylePosition(element){
          return window.getComputedStyle(element).getPropertyValue('position');
        }
        
        // use it like this
        var element = document.getElementsByTagName('div')[0];
        // js only
        alert(getStylePosition(element));
        
        // jQuery
        alert(getStylePosition($('div')[0]));
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <div style="position:fixed;"></div>

        【讨论】:

        • 这不适用于元素在具有position:fixed 的父元素中具有position:absolute 的情况。
        【解决方案6】:
        $(document).ready(function(){
            $('.trigger-element').on('mouseenter', function(event){
                var position= $(this).css("position");
        
                if (position=="fixed") {
                    $(event.target).css('background','red'); 
                } else {
                    $(event.target).css('background','green'); 
                }
            });
        });
        

        jsFiddle

        【讨论】:

        • 对不起,这似乎只在直接在目标元素上设置“位置:固定”时才有效。当元素是静态的但其父元素是固定的时,它不起作用。
        • 谢谢,我想这是“走回元素的父母”方法的一部分。 .parents() 可以接受选择器参数。有没有一个选择器可以用来过滤只有 position:fixed 的父母?
        • 您可以使用position:absolute 在父级上添加一个类,然后使用.parents() 选择它。但不能对单个 CSS 属性使用选择器。
        • 代码很棒,但答案应该包含为什么代码可以工作。
        猜你喜欢
        • 2013-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-08
        • 2010-12-23
        • 1970-01-01
        相关资源
        最近更新 更多