3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【ひとりカレンダー】フロントエンド開発成長日記Advent Calendar 2022

Day 10

svelte-dnd-actionを使ってsvelteでドラッグアンドドロップを実装

Last updated at Posted at 2022-12-10

はじめに

カンバンボードのようなものを作りたく、
ドラッグアンドドロップのツールを探していました。

公式でドラッグアンドドロップのonイベントは用意されていますが、もう少し簡単に実装できないかと思い、
svelte-dnd-actionを使ってみました。

公式の例

svelte-dnd-action導入

$ npm install --save-dev svelte-dnd-action

使い方

まずは参考コードから。

<script lang="ts">
  const myItems = {
    id: 1, name: 'item1',
  }
</script>

<div
  use:dndzone="{{items: myItems, ...otherOptions}}"
  on:consider="{handler}"
  on:finalize="{handler}"
>
  {#each myItems as item(item.id)}
      <div>{item.name}</div>
  {/each}
</div>

<div>タグに注目すると、use:dndzoneon:consideron:finalizeを発見。

<div
  use:dndzone="{{items: myItems, ...otherOptions}}"
  on:consider="{handler}"
  on:finalize="{handler}"
>

この3つをドラッグアンドドロップさせたい範囲に設定することでドラッグアンドドロップを機能させています。

use:dndzone

ドラッグアンドドロップをさせたい配列を指定するメソッド。
otherOptionsには文字通り、オプションを指定する。
オプションは以下の通り

オプション

Name Type 必須 デフォルト
flipDurationMs Number No 0
type String No Internal
dragDisabled Boolean No false
morphDisabled Boolean No false
dropFromOthersDisabled Boolean No false
zoneTabIndex Number No 0
dropTargetStyle Object No {outline: 'rgba(255, 255, 102, 0.7) solid 2px'}
dropTargetClasses Array No []
transformDraggedElement Function No () => {}
autoAriaDisabled Boolean No false
centreDraggedOnCursor Boolean No false

よく使いそうなものを解説していきます。

flipDurationMs

ドラッグされたアイテムが戻るときのアニメーションの秒数。
0または設定しないとアニメーションがないことにできる

0の場合
0.gif

10000の場合(10秒かけて戻る)
10000.gif

type

同じタイプが設定されているdnd-zone同士ではドロップアンドドロップできます。
デフォルトではすべてのdnd-zoneが同じタイプになってます。

dragDisabled

設定するとドラッグアンドドロップを禁止できる

dropFromOthersDisabled

他のdnd-zoneからのドロップを許可するかどうか。
こちらからのドラッグは制限しない。

centreDraggedOnCursor

trueにするとドラッグした際に、アイテムの中心を持つようにアイテムが移動します。

center.gif

カンバンツールっぽいものを実装してみた

以上を使って実装したのがこちら。

UIコンポーネントにはFlowbite-svelteを利用しました。
導入方法は前回の記事で公開しています。

kanban.gif

// handler.ts
export const DndConsider = (e, items) => {
  items = e.detail.items;

  return items
}
export const DndFinalize = (e, items) => {
  items = e.detail.items;

  return items
}
// Dnd.svelte
<script>
  import {flip} from "svelte/animate";
  import {dndzone} from "svelte-dnd-action";
  import { Card } from "flowbite-svelte";
  import { DndConsider, DndFinalize } from "./handler";

  let Aitems = [
      {id: 1, name: "Aitem1"},
      {id: 2, name: "Aitem2"},
      {id: 3, name: "Aitem3"},
      {id: 4, name: "Aitem4"}
  ];

  let Bitems = [
      {id: 5, name: "Bitem1"},
      {id: 6, name: "Bitem2"},
      {id: 7, name: "Bitem3"},
      {id: 8, name: "Bitem4"}
  ];

  const flipDurationMs = 300;
</script>

<div class="flex">
  <div class="w-1/2">
    <h1 class="text-4xl font-bold text-center">配列A</h1>
    <div
      class="box mx-auto"
      use:dndzone="{{items: Aitems, centreDraggedOnCursor: true, flipDurationMs}}"
      on:consider="{e => Aitems = DndConsider(e, Aitems)}"
      on:finalize="{e => Aitems = DndFinalize(e, Aitems)}"
    >
      {#each Aitems as item(item.id)}
        <div class="my-2" animate:flip="{{duration: flipDurationMs}}">
          <Card class="mx-auto">
          {item.name}
          </Card>
        </div>
      {/each}
    </div>
  </div>
  <div class="w-1/2">
    <h1 class="text-4xl font-bold text-center">配列B</h1>
    <div
      class="box mx-auto"
      use:dndzone="{{items: Bitems, centreDraggedOnCursor: true, flipDurationMs}}"
      on:consider="{e => Bitems = DndConsider(e, Bitems)}"
      on:finalize="{e => Bitems = DndFinalize(e, Bitems)}"
    >
      {#each Bitems as item(item.id)}
        <div class="my-2" animate:flip="{{duration: flipDurationMs}}">
          <Card class="mx-auto">
          {item.name}
          </Card>
        </div>
      {/each}
    </div>
  </div>
</div>

<style>
  .box {
    width: 400px;
    border: 1px solid black;
  }
</style>
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?