TypeScriptと単一ファイルコンポーネントを使用しているので適宜読み替え。
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>template</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" media="screen" href="main.css" /> <script defer src="https://cdn.jsdelivr.net/npm/vue"></script> <script defer src="./built/main.js"></script> </head> <body> <div id="app" class="hidden"> <dragfile-component></dragfile-component> </div> </body> </html>
main.ts
コンポーネントを呼び出すのみ。
import Vue from "vue" import dragfileComponent from "./dragfile.vue" const v = new Vue({ el: "#app", components: { dragfileComponent, }, data() { return { } }, methods: { handleTemplate() { // }, }, }) // 画面初期化までは非表示 IE11対策 v.$nextTick(() => { const app = document.getElementById("app") if (app) { app.classList.remove("hidden") } })
main.ts
単一ファイルコンポーネントを使用している。
重要部分はここ。
<template> <div> <div class="draggable" v-bind:class="{ dragover: isDragOver }" @dragleave.prevent="onDragLeave" @dragover.prevent="onDragOver" @drop.prevent="onDrop"> <p>Drag & Drop</p> </div> <ul> <li v-for="fileName in fileNameList" v-bind:key="fileName"> {{ fileName }} </li> </ul> </div> </template> <script lang="ts"> import Vue from "vue" export default Vue.extend({ props: { // }, data() { return { isDragOver: false, fileNameList: [] as string[], } }, /** Vue構築完了時の処理 */ created: function init() { this.msg = "Hello Vue" }, methods: { // ドラッグ範囲に入ったときの挙動 classを変えている onDragOver(event: any) { this.isDragOver = true // console.log(event) }, // ファイルがドロップされたときの挙動 ここでファイルを操作する onDrop(event: any) { this.isDragOver = false console.log(event) const files = event.dataTransfer.files as FileList // tslint:disable-next-line:prefer-for-of for (let i = 0; i < files.length; i++) { console.log(files[i]) this.fileNameList.push(files[i].name) } }, // ドラッグ範囲外に出たときの挙動 classを変えている onDragLeave(event: any) { this.isDragOver = false // console.log(event) }, }, }) </script>
@dragleave, @dragover,@drop がそれぞれのイベント。
.preventを指定すると既存のイベントが無効になる。
呼び出された関数内で操作できないこともない。
main.css
マウスオーバーしたときに背景色を変えている。
.draggable { width: 30%; height: 30%; top: 0; left: 0; right: 0; margin: auto; text-align: center; bottom: 0; position: fixed; border: black dotted 1px; } .dragover { background-color: aquamarine; }
webpack.config.js
VueだけでなくTypeScriptも使用している。
var path = require('path') var webpack = require('webpack') const { VueLoaderPlugin } = require('vue-loader') module.exports = { entry: { index: './16_Vue/1699_DragFile/main.ts', }, output: { path: path.resolve(__dirname, './built'), publicPath: '/built/', filename: 'main.js' }, module: { rules: [ { test: /\.js$/, include: path.resolve("src"), use: [ { loader: "thread-loader", options: { workers: require('os').cpus().length - 1, } } // your expensive loader (e.g babel-loader) ] }, { enforce: 'pre', test: /\.ts$/, loader: 'tslint-loader', exclude: /(node_modules)/, options: { configFile: 'tslint.json' } }, { test: /\.ts$/, exclude: /node_modules|vue\/src/, loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/], transpileOnly: true } }, { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { 'ts': 'ts-loader!tslint-loader', }, // extractCSS: plugin // other vue-loader options go here } } ] }, resolve: { extensions: ['.ts', '.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js' } }, devServer: { historyApiFallback: true, noInfo: true }, externals: { "vue": "Vue", 'element-ui': 'ElementUI' }, cache: true, performance: { hints: false }, devtool: 'source-map', plugins: [ // make sure to include the plugin for the magic new VueLoaderPlugin() ], }
完成イメージ
上記例だと以下のような感じ。
ドロップされたファイルがリスト表示される。
実際に組み込むなら受け取ったファイルをコンポーネントの呼び出し元で受け取れるようにするとなおよし。