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()
],
}
完成イメージ
上記例だと以下のような感じ。
ドロップされたファイルがリスト表示される。

実際に組み込むなら受け取ったファイルをコンポーネントの呼び出し元で受け取れるようにするとなおよし。