15
29

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.

画像をドラッグ&ドロップでアップロードして並び替え

Last updated at Posted at 2019-06-27

画像をドラッグ&ドロップでアップロード

画像をドラッグ&ドロップで並び替える
方法をご紹介します!

用途

webサイトとかで、施設に画像を結びつけて、かつ、それをソート順で表示したいとかあるときに使えるよ。

ついでに画像も削除できます。
ついでに画像に説明文も登録できます。

画像のドラッグ&ドロップでアップロードと並び替え.png

参考サイト

https://codepen.io/malkafly/pen/gbVYZb
↑ほぼこれを丸パクリです。ありがとうございます!!!

使うプラグイン

  • みんな大好きDropzoneJS
  • jQuey UIのSortable
    私はここからyarnで追加しました

コード

html側

<form method="post" action="/api/v1/facility-image/upload/" id="my-awesome-dropzone" class="image-upload-area dropzone">
    <input type="hidden" name="client_id" value="{{ $facility->id }}"></div>
</form>
    
<ul class="visualizacao sortable dropzone-previews"></ul>
<div class="preview" style="display:none;">
    <li>
        <div>
            <div class="dz-preview dz-file-preview">
                <img class="facility-image" data-dz-thumbnail />
                <input type="text" class="caption">
                <button type="button" class="btn btn-info caption-button" data-image-id="">説明文登録</button>
                <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
                <div class="dz-error-message"><span data-dz-errormessage></span></div>
            </div>
        </div>
    </li>
</div>

javascript側

import Dropzone from 'dropzone'

require('es-jquery-sortable')

let myDropzone = {}

dropzoneSetting()

//画像の並び替え
$(document).ready(function(){
    let group = $('.sortable').sortable({
        group: 'sortable',
        onDrop: function($item, container, _super) {
            var data = group.sortable('serialize').get()
            _super($item, container)

            //DB上の並び順を更新する
            axios.post('/api/v1/facility-image/update-order/', {
                    data: data,
                })
                .catch((error) => {
                    swal('', '並び順の更新に失敗しました', 'error')
                    console.log(error)
                })
        }
    })
})

/**
 * dropzone.jsの処理
 * 
 */
async function dropzoneSetting() {
    Dropzone.autoDiscover = false

    //最大ファイルアップロードサイズ
    let maxFileSize = 3

    //企業ID
    let clientId = $('#client-id').data('clientId')

    myDropzone = new Dropzone('.image-upload-area', {
        url: '/api/v1/facility-image/upload/',
        params: {
            client_id: clientId,
        },
        dictDefaultMessage: 'ここにファイルをドラッグ&ドロップ、または、クリックしてファイルを選択',
        dictRemoveFile: '',
        dictCancelUpload: '',
        dictFileTooBig: 'ファイルサイズは' + maxFileSize + 'MBまで',
        dictInvalidFileType: 'JPEG,PNGのみ可能',
        addRemoveLinks: true,
        maxFilesize: maxFileSize,
        acceptedFiles: 'image/*',
        parallelUploads: 1,
        uploadMultiple: false,
        previewsContainer: '.visualizacao', 
        previewTemplate : $('.preview').html(),
        renameFile: (file) => {
            let fileName = new Date().getTime() + '_' + file.size

            let extension = file.name.split('.').pop()
            return fileName + '.' + extension
        },
    })

    //アップロードに失敗した場合
    myDropzone.on('error', async function(file, errorMessage) {
        //ファイル数が多い場合
        if(errorMessage === '最大8ファイルまでしか添付できません') {
            myDropzone.removeFile(file)
            swal('', errorMessage, 'warning')
        } else if(errorMessage === 'セッションが切れました。もう一度ログインしてください。') {
            await swal('', 'セッションが切れました。もう一度ログインし直してください。', 'warning')
            location.replace(location.href)
        }
    })
    
    //画像を削除したときに、サーバー上のファイルも削除する
    myDropzone.on("removedfile", function(file) {
        let imageId = file.imageId

        //画像ID
        axios.get('/api/v1/facility-image/delete-by-image-id/' + imageId)
            .catch((error) => {
                console.log(error)
            })
    })

    //既存の画像が表示されたときに情報を追加する
    myDropzone.on("addedfile", function(file) {
        $('.dz-preview').each(function() {
            let imageId = $(this).children('.caption-button').data('imageId')

            //画像IDが設定されていない場合のみ追加する
            if(!imageId) {
                let imageId = file.imageId

                //今回追加した画像の場合は飛ばす
                if(!imageId) {
                    return
                }

                $(this).children('.caption-button').data('imageId', imageId)

                let caption = file.caption
                $(this).children('.caption').val(caption)

                $(this).parents('li').data('imageId', imageId)
            }
        })
    })

    //新しい画像がアップロードされたときに、画像IDを追加する
    myDropzone.on("success", function(file, response) {
        $('.dz-preview').each(function() {
            let existImageId = $(this).children('.caption-button').data('imageId')

            //画像IDが設定されていない場合のみ追加する
            if(!existImageId) {
                let imageId = response
                $(this).children('.caption-button').data('imageId', imageId)
                $(this).parents('li').data('imageId', imageId)
            }
        })
    })

    //すでに保存されている画像を表示する
    $('.exist-image').each(function() {
        let path = $(this).data('path')
        let info = {
            name: '',
            size: '',
            imageId: $(this).data('id'),
            caption: $(this).data('caption')
        }
        myDropzone.emit("addedfile", info)

        if(path) {
            myDropzone.emit("thumbnail", info, path)
        } else {
            let base64 = 'data:' + $(this).data('type') + ';base64,' + $(this).data('binary')
            myDropzone.emit("thumbnail", info, base64)
        }

        myDropzone.emit("complete", info)
    })

    //画像の説明文を登録
    $(document).on('click', '.caption-button', function() {
        let input = $(this).prev()

        axios.post('/api/v1/facility-image/save-caption/', {
                caption: input.val(),
                image_id: $(this).data('imageId'),
            })
            .then(() => {
                swal('', '説明文を登録しました', 'success')
            })
            .catch((error) => {
                swal('', '説明文の登録に失敗しました', 'error')
                console.log(error)
            })
    })
}

#まとめ
php側(私はLaravel使用しています)は、自分で実装してくださいね。
cssも自分で書いてね。

全然コードの説明してなくて、すみません。
いや、こういうの毎回やろうと思ったときに、過去のソースひっぱってくるの大変なので、Qiitaに置きました...

15
29
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
15
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?