サイト案内

運営してるひと: @sters9

妻と娘と猫と神奈川県に住んでいます。最近は Go, Ruby, Rails, Kubernetes, GCP, Datadog あたりをしていますがもっといろいろやりたい!

サイト案内

開発環境の紹介

プライバシーポリシー

tools.gomiba.co

サイト内検索

アーカイブ

2024/04 (7) 2024/03 (4) 2024/01 (3)

2023/12 (1) 2023/11 (3) 2023/10 (1) 2023/09 (1) 2023/08 (2) 2023/05 (4) 2023/04 (4) 2023/03 (4) 2023/02 (2) 2023/01 (1)

2022/12 (1) 2022/11 (4) 2022/10 (3) 2022/09 (2) 2022/08 (4) 2022/07 (5) 2022/06 (4) 2022/05 (9) 2022/04 (8) 2022/03 (10) 2022/02 (21) 2022/01 (8)

2021/12 (11) 2021/11 (1) 2021/10 (4) 2021/09 (2) 2021/08 (1) 2021/07 (2) 2021/06 (5) 2021/05 (10) 2021/04 (1) 2021/03 (8) 2021/02 (12) 2021/01 (8)

2020/05 (2) 2020/04 (2) 2020/02 (2) 2020/01 (1)

2019/12 (3) 2019/11 (2) 2019/10 (5) 2019/09 (3) 2019/07 (6) 2019/06 (4) 2019/04 (3) 2019/01 (2)

2018/12 (6) 2018/10 (4) 2018/09 (6) 2018/08 (7) 2018/07 (16) 2018/06 (7) 2018/05 (7) 2018/04 (5) 2018/03 (3) 2018/02 (10) 2018/01 (6)

2017/12 (8) 2017/11 (6) 2017/10 (10) 2017/09 (12) 2017/08 (12) 2017/07 (3) 2017/06 (1) 2017/01 (4)

2016/12 (5) 2016/10 (3) 2016/09 (1) 2016/07 (2) 2016/06 (1) 2016/04 (1) 2016/02 (1) 2016/01 (2)

2015/12 (1) 2015/10 (1) 2015/09 (3) 2015/06 (1) 2015/01 (1)

2014/08 (2) 2014/07 (3) 2014/05 (1) 2014/01 (7)

2013/12 (2) 2013/11 (4) 2013/10 (1) 2013/09 (1) 2013/08 (3) 2013/07 (4) 2013/06 (5) 2013/05 (2) 2013/04 (7) 2013/03 (1)

DOMの並び替えアニメーションをしてみたい(追記

この記事は公開されてから1年以上経過しており、最新の内容に追従できていない可能性があります。

(追記ここから)

Enter/Leave とトランジション一覧 — Vue.js

Vue.jsで同じようなやつあるしこれ使ったらええやんという話を聞いた。よさそう。

結果同じような見た目だけど、translateで動かして、そのあとDOMの並びを調整しているっぽい。

データの並び = DOMの並びに完全にリンクしているので、Vueの中でも調整しやすいよね的な感じなのかな。

(追記ここまで)


DOM ががーーーーっとならんだものを並び替えるときにアニメーションできないかなあ、というもの。 うにょーんって動いたら面白いのでは?と思って試してみた。

このページで動く様子が確認できるようにした(動いてるときに再度押すとバグる)

https://gomiba.co/tags

 

そのまま動かそうとすると、移動先の座標がわからず動かせないので、いくつかのステップを通してみた。

  1. 今の表示されている座標を保存
  2. 今の表示されている座標の場所に固定した DOM を生成(この時点ではメモリに乗っているだけで表示されない)
  3. コンテンツを並び替えて新しい座標を計算
  4. 今の表示されている DOM を非表示 2 で作った DOM を表示する(見え方は変わらないが表示されているものを切り変える)
  5. 3 の座標に向けて 2 の DOM を CSS アニメーションで動かす
  6. 終わったころあいで 2 と 3 の DOM を入れ替えて 2 の DOM を捨てる。

要は動かす用の DOM を生成して、動かすだけ動かして、前後は元の DOM のまま、というもの。 パッと思いついたやり方はこれ。

 

ちゃんとやろうとすると、再描画が無茶苦茶大変になって遅くなるとおもうので、何か対策考えないといけなさそう。 透過色まずやめよう、とか。

 

コードはこんな感じ。 ちょっと座標のところが面倒になって jQuery を使っている。が、そんなに難しいことはやっていないので生 DOM でもわりかし簡単にいけるはず。

連打対策は入れてないので、連打するとブラウザ固まる。

const DomSortAnimation = ($target, AnimationTimeSec, AnimationCompleteDelaySec, SortFunction) => {
    // fixed now position
    const targetPositions = $target.map((_, e) => {
        const $t = $(e);
        return $t.position()
    });
    const $newTarget = $target.clone()
    $newTarget.each((i, e) => {
        $(e).css({
            top: targetPositions[i].top,
            left: targetPositions[i].left,
            position: 'absolute',
            display: 'block',
            transition: AnimationTimeSec + 's all ease',
        });
    });

    // calculate new position
    const targetContents = $target.toArray()
        .sort(SortFunction)
        .map((a) => {
            return {
                html: a.innerHTML,
                href: a.href
            }
        });

    $target.each((i, e) => {
        const $e = $(e);
        $e.html(targetContents[i].html);
        $e.attr({href:targetContents[i].href});
    });

    const newPositions = {};
    $target.each((_, e) => {
        const $e = $(e)
        newPositions[$e.attr('href')] = $e.position();
    })

    // swap DOM
    $newTarget.appendTo($target.parent());
    $target.hide();

    // animation start
    setTimeout(() => {
        $newTarget.each((i, e) => {
            const $e = $(e);
            const pos = newPositions[$e.attr('href')];
            $e.css({
                top: pos.top,
                left: pos.left,
            });
        });
    }, 0);

    // complete animation restore DOM
    setTimeout(() => {
        $newTarget.remove();
        $target.show();
    }, (AnimationTimeSec + AnimationCompleteDelaySec) * 1000);
};
DomSortAnimation(
        $(".c-article-content .c-badge"),
        2,
        0.2,
        (a, b) => {
            const aContent = a.textContent.trim();
            const bContent = b.textContent.trim();
            if(aContent < bContent){
                return -1;
            }else if(aContent > bContent){
                return 1;
            }
            return 0;
        }
    );