LoginSignup
8
12

More than 3 years have passed since last update.

【Vue.Draggable】リストやdivタグ以外の要素で、ドラッグアンドドロップで並び替えする方法【Vuetify】

Last updated at Posted at 2020-08-18

環境

$ vue --version
2.9.6

ライブラリの導入と、元のソースコード

今回必要なのは、Nuxt.jsでよくお世話になるUIライブラリVuetifyと、直感的に要素の並び替えができるVue.Draggableを利用させていただきます。

$ yarn add @nuxtjs/vuetify
$ yarn add vuedraggable
nuxt.config.js
  buildModules: [
    '@nuxtjs/vuetify',
  ],

並び替えしたい要素は、JSONplaceholderから取得した記事情報を落とし込んだカードコンポーネントになります。

posts/index.vue
<template>
  <v-app dark>
    <v-container>
      <v-row id="main-area">
        <v-col id="feed-template" class="col-4"  v-for="post in posts" :key=post.id>
          <v-card style="overflow:scroll; height:30vh;">
            <v-card-title>
              <nuxt-link :to="'/posts/' + post.id" class="feed-title">{{ post.title }}</nuxt-link>
            </v-card-title>
            <v-card-text class="feed-body">
              <ul class="feed-items">
                <li class="feed-list">
                    {{ post.body }}
                </li>
              </ul>
            </v-card-text>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
  </v-app>
</template>

<script>
import axios from 'axios'
import draggable from 'vuedraggable'

export default {
  components: {
    draggable
  },
  data () {
    return {
      posts: []
    }
  },
  mounted () {
    axios.get('https://jsonplaceholder.typicode.com/posts').then(res => this.posts = res.data)
  }
}
</script>

さあ、並び替えする要素を囲んでみよう(失敗例)

<v-app>
  <draggable v-model="posts">
    <v-container>
      <v-row id="main-area">
        <v-col id="feed-template" class="col-4"  v-for="post in posts" :key=post.id>
  // 省略
  </draggable>
</v-app>

v-modelで、配列名を指定した<draggable>タグを囲んで使う。
ただ、これだと要素全体が移動対象になってしまう。。。

<v-app>
  <v-container>
    <v-row id="main-area">
      <draggable v-model="posts" draggable=".item">
        <v-col id="feed-template" class="col-4"  v-for="post in posts" :key=post.id>
  // 省略
      </draggable>
    </v-row>
  </v-container>
</v-app>

これでもダメ。
<draggable>タグの位置をずらしたり、新たな属性を追加したり、、、、試行錯誤した結果。

https://mebee.info/2019/12/03/post-4508/

この記事より、こんな書き方が。

<div id="app">
  <draggable v-model="list" element="ul" :options="{animation:500}">
    <li v-for="item in list" :key="item.id">{{ item.name }}</li>
  </draggable>
</div>

ほお!元あったタグ名をelement属性に設定しておく必要があるんですね!

カード毎に要素の入れ替えを行う方法(成功例)

つまり、元あったタグを、<draggable>タグで置き換えるイメージで書いていく。
最終的なソースコードはこちら。

posts/index.vue
<template>
  <v-app dark>
    <v-container>
      <draggable v-model="posts" element="v-row">
        <v-col class="col-4 feed-template" v-for="post in posts" :key=post.id>
          <v-card style="overflow:scroll; height:30vh;">
            <v-card-title>
              <nuxt-link :to="'/posts/' + post.id" class="feed-title">{{ post.title }}</nuxt-link>
            </v-card-title>
            <v-card-text class="feed-body">
              <ul class="feed-items">
                <li class="feed-list">
                  {{ post.body }}
                </li>
              </ul>
            </v-card-text>
          </v-card>
        </v-col>
      </draggable>
    </v-container>
  </v-app>
</template>

<script>
import axios from 'axios'
import draggable from 'vuedraggable'

export default {
  components: {
    draggable
  },
  data () {
    return {
      posts: []
    }
  },
  mounted () {
    axios.get('https://jsonplaceholder.typicode.com/posts').then(res => this.posts = res.data)
  }
}
</script>

カードコンポーネントが、自由に移動できるようになった!!

追記

サーバーを立ち上げると、こんな警告が。

 WARN  Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props

どうやら「elementは廃止されるので、tag属性にするように」とのこと。

      <draggable v-model="posts" tag="v-row">

これだけでおk

8
12
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
8
12