首页 > 解决方案 > 将元素动画到 DOM 中的新位置

问题描述

我有一个容器,里面有未知数量的卡片(从 3 到 8)。

|  --   --   --  |
| CARD CARD CARD |
|  --   --   --  |

当一个被点击时,所有其他人都会消失,点击的卡片需要向左移动。例如,如果单击中间的卡片:

卡片消失

|       --       |
|      CARD      |
|       --       |

卡片向左移动(带有动画

|  --            |
| CARD           |
|  --            |

卡片可以消失,但我觉得我的解决方案不是很好。我无法将卡向左移动。

这是我隐藏卡片的解决方案:

    cards.forEach(card => {
        card.addEventListener('click', () => {
            cards.forEach(card2 => {
                if(card2 != card){
                    card2.style.animation = 'fadeOut 0.2s linear forwards';
                }
            })
        })
    })

但我很不确定如何移动卡。这是卡片容器和卡片本身的 CSS。

.cards{
    height: 100%;
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 50px;
    position: relative;
}
.card{
    height: 100%;
    width: 100%;
    position: relative;
}

这可能与css动画吗?

标签: javascripthtmlcssanimationdom

解决方案


动画元素到它的新位置

要将元素动画到其新位置,请按照以下简单步骤操作:

  1. 计算元素相对于父元素的当前X、Y位置
  2. 隐藏其他元素display: none
  3. 由于元素现在有了一个新位置,而其他元素都消失了 -立即将其捕捉(移动)回它使用 CSStranslate: transform(x, y)X 和 Y的位置。
  4. 使用 CSS设置动画transition0, 0 translate: transform(0, 0),这是在其他元素从视图中隐藏后该元素实际占据的位置。

这是上面列表的一个示例,其中包含一个额外的步骤,即在隐藏它们之前首先淡出其他元素,并且仅对元素进行动画处理:

const animateCards = (card) => {
  const fxHide = `display: none;`;
  const fxFade = `transition: opacity 0.3s; opacity: 0;`;
  const fxMove = `transform: translate(${card.offsetLeft}px, ${card.offsetTop}px);`;
  const fxAnim = `transition: transform 0.5s; transform: translate(0, 0);`;
  let other; // Just to catch a sibling element as reference

  cards.forEach(el => {
    if (el === card) return;
    if (!other) other = el;
    el.addEventListener("transitionend", () => el.style.cssText += fxHide, {once: true});
    el.style.cssText += fxFade;
  });

  other.addEventListener("transitionend", () => {
    card.style.cssText += fxMove;
    setTimeout(() => card.style.cssText += fxAnim, 0);
  }, {once: true});
};

const cards = document.querySelectorAll(".card");
cards.forEach(el => el.addEventListener('click', () => animateCards(el)));
.cards {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 50px;
  position: relative;
}

.card {
  height: 100%;
  position: relative;
  cursor: pointer;
}
<div class="cards">
  <div class="card" style="background-color:#0bf;">1</div>
  <div class="card" style="background-color:#f0b;">2</div>
  <div class="card" style="background-color:#bf0;">3</div>
</div>


推荐阅读