使用VUE搭配HTML5拖曳DOM
基本知識
1. 要拖曳的DOM必須加上draggable屬性
2. 拖曳事件
dragstart 開始拖曳的那一刻
dragenter 拖曳標籤進入目標的那一刻
dragover 拖曳標籤在目標內移動的時候
dragleave 拖曳標籤離開目標的那一刻
drop 拖曳標籤放下的那一刻
dragend 拖曳標籤在drop觸發後觸發
3.不想要觸發拖曳事件可以在目標元素加上此css
pointer-events: none;
4.避免可拖曳標籤可以選取到裡面的子標籤
[draggable="true"] {
/*
To prevent user selecting inside the drag source
*/
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
opacity: 1;
}
範例
<template>
<div class="col-12">
<div class="shadow-sm d-flex bg-white px-3">
<div class="overflow-auto table-box mb-2 w-100">
<table
border="1"
class="table table-hover table-bordered table-striped my-3 w-100"
>
<colgroup>
<col
v-for="(col, key) in catsColumns"
:key="key"
:width="col.width"
>
</colgroup>
<thead>
<tr>
<th
v-for="col in catsColumns"
:key="col.key"
>
<template v-if="col.key === 'multiple'">
全選
<input
id=""
type="checkbox"
name=""
:checked="multipleArray.length === catsData.length && multipleArray.length!==0 "
@change="multipleHandler"
>
</template>
<template v-else>
{{ col.title
}}<i
v-if="col.sort"
class="fas fa-sort ml-1"
@click="sortHandler(col)"
/>
</template>
</th>
</tr>
</thead>
<tbody v-if="catsData.length">
<template
v-for="(row,index) in catsData"
>
<tr
:key="row.id"
class="drag-area"
:class="{'cursor-pointer':candrag}"
:draggable="candrag"
@dragstart="handleDragStart($event, row)"
@dragenter="handleDragEnter($event, row)"
@dragover.prevent="dragOver($event, row)"
@dragleave="handleDragLeave($event, row)"
@drop="handleDrop($event, row,index)"
@dragend="handleDragEnd($event, row)"
>
<td
v-for="(col) in catsColumns"
:key="col.col"
:class="[
{ 'input-table': col.type == 'input' },
{ 'text-left': col.tdAlign == 'left' },
]"
>
<template v-if="col.key === 'options'">
<div
v-if="!candrag"
class="d-flex justify-content-center align-items-center"
>
<i
class="fas fa-edit btn-sm btn btn-outline-primary"
@click="editHandler(row)"
/>
</div>
<div
v-if="candrag"
class="d-flex justify-content-center align-items-center pointer-event-none"
>
<i
class="fas fa-expand-arrows-alt text-primary cursor-pointer pointer-event-none"
/>
</div>
</template>
<template v-else-if="col.key === 'index'">
{{ index + 1 }}
</template>
<template
v-else-if="col.key === 'multiple'"
>
<input
id=""
v-model="multipleArray"
:value="row"
type="checkbox"
name=""
>
</template>
<template v-else-if="col.key === 'enabledPro'">
{{ row[col.key] ? 'Yes' : 'No' }}
</template>
<template v-else-if="col.key === 'enabledPlm'">
{{ row[col.key] ? 'Yes' : 'No' }}
</template>
<template v-else>
<span>
{{
row[col.key] != null && row[col.key] != ""
? row[col.key]
: isNullStr
? isNullStr
: ""
}}</span>
</template>
</td>
</tr>
</template>
</tbody>
<tbody v-else>
<tr draggable="true">
<td
:colspan="catsColumns.length"
class="text-center"
>
<template v-if="isloading">
<div class="spinner-grow spinner-grow-sm text-primary" />
<div class="spinner-grow spinner-grow-sm text-primary mx-2" />
<div class="spinner-grow spinner-grow-sm text-primary" />
</template>
<template v-else>
<span class="font-weight-bold text-danger"> 查無資料 </span>
</template>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
catsData: [{},{},{}],
originCatsData: [],
catsColumns: [
{
title: '功能',
key: 'options',
width: '80px'
},
{
title: 'multiple',
key: 'multiple',
width: '80px'
},
{
title: '序號',
key: 'index',
width: '100px'
},
{
title: '名稱',
key: 'catName'
},
{
title: '有效否(PLM)',
key: 'enabledPlm',
width: '150px'
},
{
title: '有效否(產品)',
key: 'enabledPro',
width: '150px'
}
],
candrag: false,
dragging: null
}
},
methods: {
saveSortHandler () {
const putData = this.catsData.map(cat => {
return { id: cat.id, catSequence: cat.catSequence }
})
apiPutPlmSpecCatesList({
items: putData
}).then(res => {
const { status } = res
if (status === 200 || status === 204) {
this.candrag = false
this.getDataHandler(this.productGroup.productGroup)
}
}).catch(err => {
this.$refs.confirm.show(err.response.data.error.message, '確定')
})
},
cancelSortHandler () {
this.candrag = false
this.catsData = this.originCatsData
},
// 離開目標 e目標
handleDragLeave (e) {
if (!this.candrag) return
if (e.target.parentNode.classList.contains('drag-area')) {
e.target.parentNode.classList.remove('enter')
}
},
// 元素開始被拖動 e元素
handleDragStart (e, item) {
if (!this.candrag) return
this.dragging = item
},
// 進入目標 e目標
handleDragEnter (e, data) {
console.log(e.target.parentNode)
if (!this.candrag) return
if (data === this.dragging) return
if (e.target.parentNode.classList.contains('drag-area')) {
e.target.parentNode.classList.add('enter')
}
},
// 元素在目標中被拖動 e目標
dragOver (e, data) {
if (!this.candrag) return
// console.log(e.target)
// 設定指標樣式
e.dataTransfer.dropEffect = 'move'
},
// 放置目標 e目標
handleDrop (e, item) {
if (!this.candrag) return
if (e.target.parentNode.classList.contains('drag-area')) {
e.target.parentNode.classList.remove('enter')
}
if (item === this.dragging) {
return
}
const newItems = [...this.catsData]
const from = newItems.indexOf(this.dragging)
const to = newItems.indexOf(item)
const originCatSequence = newItems[from].catSequence
newItems[from].catSequence = newItems[to].catSequence
newItems[to].catSequence = originCatSequence
newItems[from] = item
newItems[to] = this.dragging
newItems.forEach((row, index) => {
row.catSequence = index + 1
})
this.catsData = newItems
},
// 放置目標後 e元素
handleDragEnd () {
this.dragging = null
}
}
}
</script>