How to calculate the amount of flexbox items in a row?

后端 未结 11 1867
北荒
北荒 2020-12-04 12:12

A grid is implemented using the CSS flexbox. Example:

The number of rows in this example is 4 because I fixed the container width for demo purposes. But, in

11条回答
  •  情歌与酒
    2020-12-04 12:53

    To support moving up, down, left, and right, you don't need to know how many boxes there are in a row, you just need to calculate if there is a box above, below, left, or right of the active box.

    Moving left and right is simple as you've noticed - just check if the active box has a previousSiblingElement or nextSiblingElement. For up and down, you can use the current active box as an anchor point and compare it to the other box's getBoundingClientRect()s, a DOM method which returns the geomoetry of an element relative to the browser viewport.

    When trying to move up, start at the anchor and count down through the items towards 0. When moving down, start at the anchor and count until the end of the number of items. This is because when moving up, we only care about boxes before the active box, and when going down we only care about boxes after it. All we need to look for is a box that has the same left position with a higher or lower top position.

    Below is an example which listens for a keydown event on window and will move the active state according to which arrow key was pressed. It could definitely be made more DRY, but I've divided up the the four cases so you can see the exact logic in each. You can hold the arrow keys down so the box moves continuously and you can see it's very performant. And I've updated your JSBin with my solution here:http://jsbin.com/senigudoqu/1/edit?html,css,js,output

    const items = document.querySelectorAll('.item');
    
    let activeItem = document.querySelector('.item.active');
    
    function updateActiveItem(event) {
      let index;
      let rect1;
      let rect2;
    
      switch (event.key) {
        case 'ArrowDown':
          index = Array.prototype.indexOf.call(items, activeItem);
          rect1 = activeItem.getBoundingClientRect();
    
          for (let i = index; i < items.length; i++) {
            rect2 = items[i].getBoundingClientRect();
    
            if (rect1.x === rect2.x && rect1.y < rect2.y) {
              items[i].classList.add('active');
              activeItem.classList.remove('active');
              activeItem = items[i];
              return;
            }
          }
          break;
    
        case 'ArrowUp':
          index = Array.prototype.indexOf.call(items, activeItem);
          rect1 = activeItem.getBoundingClientRect();
    
          for (let i = index; i >= 0; i--) {
            rect2 = items[i].getBoundingClientRect();
    
            if (rect1.x === rect2.x && rect1.y > rect2.y) {
              items[i].classList.add('active');
              activeItem.classList.remove('active');
              activeItem = items[i];
              return;
            }
          }
          break;
    
        case 'ArrowLeft':
          let prev = activeItem.previousElementSibling;
    
          if (prev) {
            prev.classList.add('active');
            activeItem.classList.remove('active');
            activeItem = prev;
          }
          break;
    
        case 'ArrowRight':
          let next = activeItem.nextElementSibling;
    
          if (next) {
            next.classList.add('active');
            activeItem.classList.remove('active');
            activeItem = next;
          }
          break;
    
        default:
          return;
      }
    }
    
    window.addEventListener('keydown', updateActiveItem);
    .grid {
      display: flex;
      flex-wrap: wrap;
      align-content: flex-start;
      background-color: #ffffd;
      padding: 10px 0 0 10px;
    }
    
    .item {
      width: 50px;
      height: 50px;
      background-color: red;
      margin: 0 10px 10px 0;
    }
    
    .active.item {
      outline: 5px solid black;
    }
      

提交回复
热议问题