[JS]アニメーション付きで要素の上下を入れ替える

Pocket

Javascript を使って要素の上下を入れ替えるには insertBefore() を使います。
ただしこれだけでは瞬時に入れ替わるため、アニメーションを付けたい場合は先に CSS の translateY() で見かけ上の位置を入れ替えたあとで insertBefore() を使います。

DEMO

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="card mb-3">
            <div class="card-header">
                <button type="button" class="btn btn-default btn-up">
                    <i class="fas fa-caret-up"></i>
                </button>
                <button type="button" class="btn btn-default btn-down">
                    <i class="fas fa-caret-down"></i>
                </button>
            </div>
            <div class="card-body">
                Card A
            </div>
        </div>
    
        <div class="card mb-3">
            <div class="card-header">
                <button type="button" class="btn btn-default btn-up">
                    <i class="fas fa-caret-up"></i>
                </button>
                <button type="button" class="btn btn-default btn-down">
                    <i class="fas fa-caret-down"></i>
                </button>
            </div>
            <div class="card-body">
                Card B
            </div>
        </div>
    </div>
    <script>
    document.addEventListener('DOMContentLoaded', function(){
        var cards = document.querySelectorAll('.card');
        
        var swapCards = function(card1, card2){
            var duration = 300;

            if(!card2 || !card2.classList.contains('card')) return;

            var orgDuration1 = card1.style.transitionDuration;
            var orgDuration2 = card2.style.transitionDuration;

            card1.style.transitionDuration = duration + 'ms';
            card2.style.transitionDuration = duration + 'ms';

            var diff = card2.offsetTop - card1.offsetTop;

            if(diff > 0){
                var spacing = card2.offsetTop - (card1.offsetTop + card1.offsetHeight);
                card1.style.transform = "translateY(" + (card2.offsetHeight + spacing) + "px)";
                card2.style.transform = "translateY(" + (-diff) + "px)";
            } else {
                var spacing = card1.offsetTop - (card2.offsetTop + card2.offsetHeight);
                card1.style.transform = "translateY(" + (diff) + "px)";
                card2.style.transform = "translateY(" + (card1.offsetHeight + spacing) + "px)";
            }
            setTimeout(function(){
                card1.style.transitionDuration = orgDuration1;
                card2.style.transitionDuration = orgDuration2;
                card1.style.transform = "translateY(0)";
                card2.style.transform = "translateY(0)";

                if(diff < 0){
                    card1.parentNode.insertBefore(card1, card2);
                } else {
                    card1.parentNode.insertBefore(card2, card1);
                }
            }, duration);
        };

        cards.forEach(function(card){
            card.querySelector(".btn-up").addEventListener('click', function(){
                swapCards(card, card.previousElementSibling);
            });
            card.querySelector(".btn-down").addEventListener('click', function(){
                swapCards(card, card.nextElementSibling);
            });
        });
    });
    </script>
</body>
</html>

Similar Posts:




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です