如何检测CSS flex wrap事件

时间:2016-10-13 04:41:00

标签: javascript jquery css flexbox

我有灵活容器,内有物品。如何检测flex wrap事件?我想将一些新的css应用于已经包装的元素。我想通过纯css检测包装事件是不可能的。但它将是非常强大的功能!我可以试着去捕捉"当元素换行到新行/行时,媒体查询的此断点事件。但这是一种可怕的方法。我可以尝试通过脚本来检测它,但它也不是很好。

Look at the picture

我很惊讶,但简单的$(" #lement")。resize()不能检测flex容器的高度或宽度变化,以便将适当的css应用于子元素。 LOL。

我发现只有这个jquery代码的例子才有效 jquery event listen on position changed

但仍然非常糟糕。

6 个答案:

答案 0 :(得分:15)

这是一个潜在的解决方案。您可能需要检查其他陷阱和边缘情况。

基本思路是遍历flex items并测试他们top位置与前一个兄弟姐妹的关系。如果top值更大(因此在页面的下方),则项目已经包装。

函数detectWrap返回已包装的DOM元素数组,可用于根据需要进行样式设置。

该函数可与window.resize一起用于在调整窗口大小时检测包装。由于StackOverflow代码窗口没有调整大小,因此无法在此处工作。

这里有CodePen,可以调整屏幕大小。



var detectWrap = function(className) {
  
  var wrappedItems = [];
  var prevItem = {};
  var currItem = {};
  var items = document.getElementsByClassName(className);

  for (var i = 0; i < items.length; i++) {
    currItem = items[i].getBoundingClientRect();
    if (prevItem && prevItem.top < currItem.top) {
      wrappedItems.push(items[i]);
    }
    prevItem = currItem;
  };
  
  return wrappedItems;

}

window.onload = function(event){
  var wrappedItems = detectWrap('item');
  for (var k = 0; k < wrappedItems.length; k++) {
    wrappedItems[k].className = "wrapped";
  }
};
&#13;
div  {
  display: flex;
  flex-wrap: wrap;
}

div > div {
  flex-grow: 1;
  flex-shrink: 1;
  justify-content: center;
  background-color: #222222;
  padding: 20px 0px;
  color: #FFFFFF;
  font-family: Arial;
  min-width: 300px;
}

div.wrapped {
  background-color: red;
}
&#13;
<div>
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:6)

为此目的在jQuery上略微改进了片段。

wrapped();

$(window).resize(function() {
   wrapped();
});

function wrapped() {
    var offset_top_prev;

    $('.flex-item').each(function() {
       var offset_top = $(this).offset().top;

      if (offset_top > offset_top_prev) {
         $(this).addClass('wrapped');
      } else if (offset_top == offset_top_prev) {
         $(this).removeClass('wrapped');
      }

      offset_top_prev = offset_top;
   });
}

答案 2 :(得分:3)

我已经修改了 sansSpoon 的代码,即使该元素不在页面的绝对顶部也能正常工作。代码笔:https://codepen.io/tropix126/pen/poEwpVd

function detectWrap(node) {
  node.forEach(container => {
    Array.from(container.children).forEach(child => {
      const containerPos = container.getBoundingClientRect().top;
      const childPos = child.getBoundingClientRect().top;
      if (childPos > containerPos) {
        child.classList.add('wrapped');
      } else {
        child.classList.remove('wrapped');
      }
    });
  });
}

请注意,margin-top 不应应用于项目,因为它已被考虑到 getBoundingClientRect 中,并且会触发包装类以应用于所有项目。

答案 3 :(得分:2)

我正在使用类似的方法来确定<li>是否已被<ul>包裹在其显示设置为flex的位置。

ul = document.querySelectorAll('.list');

function wrapped(ul) {

    // loops over all found lists on the page - HTML Collection
    for (var i=0; i<ul.length; i++) {

        //Children gets all the list items as another HTML Collection
        li = ul[i].children;

        for (var j=0; j<li.length; j++) {
            // offsetTop will get the vertical distance of the li from the ul.
            // if > 0 it has been wrapped.
            loc = li[j].offsetTop;
            if (loc > 0) {
                li[j].className = 'wrapped';
            } else {
                li[j].className = 'unwrapped';
            }
        }
    }
}

答案 4 :(得分:1)

我注意到元素通常会相对于第一个元素进行包装。将每个元素的偏移顶部与第一个元素进行比较是一种更简单的方法。这适用于自动换行和自动换行。 (如果元素使用弹性顺序,则可能无效)

var wrappers = $('.flex[class*="flex-wrap"]'); //select flex wrap and wrap-reverse elements

    if (wrappers.length) { //don't add listener if no flex elements
        $(window)
            .on('resize', function() {
                wrappers.each(function() {
                    var prnt = $(this),
                        chldrn = prnt.children(':not(:first-child)'), //select flex items
                        frst = prnt.children().first();

                    chldrn.each(function(i, e) { $(e).toggleClass('flex-wrapped', $(e).offset().top != frst.offset().top); }); //element has wrapped
                    prnt.toggleClass('flex-wrapping', !!prnt.find('.flex-wrapped').length); //wrapping has started
                    frst.toggleClass('flex-wrapped', !!!chldrn.filter(':not(.flex-wrapped)').length); //all are wrapped
               });
            })
            .trigger('resize'); //lazy way to initially call the above
    }
.flex {
    display: flex;
}

.flex.flex-wrap {
    flex-wrap: wrap;
}

.flex.flex-wrap-reverse {
    flex-wrap: wrap-reverse;
}

.flex.flex-1 > * { /*make items equal width*/
    flex: 1;
}

.flex > * {
  flex-grow: 1;
}

.cc-min-width-200 > * { /*child combinator*/
  min-width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="flex flex-1 flex-wrap-reverse cc-min-width-200">
    <div>Hello</div>
    <div>There</div>
    <div>World</div>
</div>

答案 5 :(得分:0)

如果有人想从包装元素开始的地方找到行的最后一个元素,可以使用以下逻辑。它也适用于多行

       window.onresize = function (event) {
            const elements = document.querySelectorAll('.borrower-detail');
            let previousElement = {};
            let rowTop = elements[0].getBoundingClientRect().top;
            elements.forEach(el => el.classList.remove('last-el-of-row'))
            elements.forEach(el => {
                const elementTop = el.getBoundingClientRect().top;

                if (rowTop < elementTop) {
                    previousElement.classList.add('last-el-of-row');
                    rowTop = elementTop;
                }

                previousElement = el;
            })
        };