Appearance
课程表
给标签元素添加全局属性的draggable
属性,就可以使用HTML拖放操作API进行拖动了。
主要使用的是以下事件:
dragstart
事件在用户开始拖动元素或被选择的文本时调用。dragover
事件在可拖动的元素或者被选择的文本被拖进一个有效的放置目标时(每几百毫秒)触发。dragenter
事件在可拖动的元素或者被选择的文本进入一个有效的放置目标时触发。drop
事件在元素或文本选择被放置到有效的放置目标上时触发。为确保drop
事件始终按预期触发,应当在处理 dragover 事件的代码部分始终包含preventDefault()
调用。
原生js实现
语文
数学
英语
地理
政治
历史
体育
星期一 | 星期二 | 星期三 | 星期四 | 星期五 | 星期六 | 星期日 | |
---|---|---|---|---|---|---|---|
上午 | |||||||
下午 | |||||||
对应代码
vue
<script setup lang="ts">
let dragElement: HTMLElement
const onDragstart = (event: DragEvent) => {
const target = event.target as HTMLElement
if (event.dataTransfer && target) {
dragElement = target
// 设置鼠标状态: copy表示复制 move表示移动
event.dataTransfer.effectAllowed = target.dataset.effect as DataTransfer['effectAllowed']
}
}
const onDragover = (event: DragEvent) => {
// 默认是不允许别的元素拖到当前元素上的,这也就会导致onDrop事件不会触发,所以这里需要取消默认行为
event.preventDefault();
}
function clearDropoverStyle() {
document.querySelectorAll('.drop_over').forEach(node => {
node.classList.remove('drop_over')
})
}
function getDropNode(node: HTMLElement): HTMLElement | null {
if (node.dataset?.drop) {
return node
} else {
return node.parentNode ? getDropNode(node.parentNode as HTMLElement) : null
}
}
const onDragenter = (event: DragEvent) => {
// 清除之前的drop_over样式
clearDropoverStyle()
const dropNode = getDropNode(event.target as HTMLElement)
if (dropNode && dropNode.dataset.drop === event.dataTransfer?.effectAllowed) {
dropNode.classList.add('drop_over')
}
}
const onDrop = (event: DragEvent) => {
const dropNode = getDropNode(event.target as HTMLElement)
if (dropNode && dropNode.dataset.drop === event.dataTransfer?.effectAllowed) {
dropNode.classList.remove('drop_over')
if (dropNode.dataset.drop === 'copy') {
dropNode.innerHTML = ''
const cloned = dragElement.cloneNode(true) as HTMLElement
cloned.dataset.effect = 'move'
dropNode.appendChild(cloned)
} else {
// move
dragElement.remove()
}
}
}
</script>
<script setup lang="ts">
let dragElement: HTMLElement
const onDragstart = (event: DragEvent) => {
const target = event.target as HTMLElement
if (event.dataTransfer && target) {
dragElement = target
// 设置鼠标状态: copy表示复制 move表示移动
event.dataTransfer.effectAllowed = target.dataset.effect as DataTransfer['effectAllowed']
}
}
const onDragover = (event: DragEvent) => {
// 默认是不允许别的元素拖到当前元素上的,这也就会导致onDrop事件不会触发,所以这里需要取消默认行为
event.preventDefault();
}
function clearDropoverStyle() {
document.querySelectorAll('.drop_over').forEach(node => {
node.classList.remove('drop_over')
})
}
function getDropNode(node: HTMLElement): HTMLElement | null {
if (node.dataset?.drop) {
return node
} else {
return node.parentNode ? getDropNode(node.parentNode as HTMLElement) : null
}
}
const onDragenter = (event: DragEvent) => {
// 清除之前的drop_over样式
clearDropoverStyle()
const dropNode = getDropNode(event.target as HTMLElement)
if (dropNode && dropNode.dataset.drop === event.dataTransfer?.effectAllowed) {
dropNode.classList.add('drop_over')
}
}
const onDrop = (event: DragEvent) => {
const dropNode = getDropNode(event.target as HTMLElement)
if (dropNode && dropNode.dataset.drop === event.dataTransfer?.effectAllowed) {
dropNode.classList.remove('drop_over')
if (dropNode.dataset.drop === 'copy') {
dropNode.innerHTML = ''
const cloned = dragElement.cloneNode(true) as HTMLElement
cloned.dataset.effect = 'move'
dropNode.appendChild(cloned)
} else {
// move
dragElement.remove()
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
vue
<template>
<div class="container" @dragstart="onDragstart" @dragover="onDragover" @dragenter="onDragenter" @drop="onDrop">
<div class="head" data-drop="move">
<div data-effect="copy" draggable="true" class="item color1">语文</div>
<div data-effect="copy" draggable="true" class="item color2">数学</div>
<div data-effect="copy" draggable="true" class="item color3">英语</div>
<div data-effect="copy" draggable="true" class="item color4">地理</div>
<div data-effect="copy" draggable="true" class="item color5">政治</div>
<div data-effect="copy" draggable="true" class="item color6">历史</div>
<div data-effect="copy" draggable="true" class="item color7">体育</div>
</div>
<div class="content">
<table>
<!-- 列的分组 -->
<colgroup>
<col />
<col />
<col />
<col />
<col />
<col />
<col />
<col />
</colgroup>
<!-- 表头 -->
<thead>
<tr>
<td></td>
<th>星期一</th>
<th>星期二</th>
<th>星期三</th>
<th>星期四</th>
<th>星期五</th>
<th>星期六</th>
<th>星期日</th>
</tr>
</thead>
<!-- 表格 -->
<tbody>
<tr>
<th rowspan="4" class="span">上午</th>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<th rowspan="4" class="span">下午</th>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<template>
<div class="container" @dragstart="onDragstart" @dragover="onDragover" @dragenter="onDragenter" @drop="onDrop">
<div class="head" data-drop="move">
<div data-effect="copy" draggable="true" class="item color1">语文</div>
<div data-effect="copy" draggable="true" class="item color2">数学</div>
<div data-effect="copy" draggable="true" class="item color3">英语</div>
<div data-effect="copy" draggable="true" class="item color4">地理</div>
<div data-effect="copy" draggable="true" class="item color5">政治</div>
<div data-effect="copy" draggable="true" class="item color6">历史</div>
<div data-effect="copy" draggable="true" class="item color7">体育</div>
</div>
<div class="content">
<table>
<!-- 列的分组 -->
<colgroup>
<col />
<col />
<col />
<col />
<col />
<col />
<col />
<col />
</colgroup>
<!-- 表头 -->
<thead>
<tr>
<td></td>
<th>星期一</th>
<th>星期二</th>
<th>星期三</th>
<th>星期四</th>
<th>星期五</th>
<th>星期六</th>
<th>星期日</th>
</tr>
</thead>
<!-- 表格 -->
<tbody>
<tr>
<th rowspan="4" class="span">上午</th>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<th rowspan="4" class="span">下午</th>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
<tr>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
<td data-drop="copy"></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
vue
<style scoped lang="less">
.timetable_item {
.item {
padding: 12px;
user-select: none;
font-weight: bold;
&.color1 {
background-color: crimson;
}
&.color2 {
background-color: blue;
}
&.color3 {
background-color: deeppink;
}
&.color4 {
background-color: darkgoldenrod;
}
&.color5 {
background-color: darkorchid;
}
&.color6 {
background-color: darkseagreen;
}
&.color7 {
background-color: lightskyblue;
}
}
}
.container {
.head {
display: flex;
gap: 12px;
background-color: #ebebef;
padding: 12px 6px;
&.drop_over {
background-color: #ccc;
}
.timetable_item();
}
.content {
overflow: hidden;
table {
margin: 0;
colgroup,
thead,
tbody {
width: 100%;
tr th {
text-align: center;
}
}
tbody {
td {
width: 90px;
height: 60px;
&.drop_over {
background-color: #ccc;
}
.timetable_item();
}
}
}
}
}
</style>
<style scoped lang="less">
.timetable_item {
.item {
padding: 12px;
user-select: none;
font-weight: bold;
&.color1 {
background-color: crimson;
}
&.color2 {
background-color: blue;
}
&.color3 {
background-color: deeppink;
}
&.color4 {
background-color: darkgoldenrod;
}
&.color5 {
background-color: darkorchid;
}
&.color6 {
background-color: darkseagreen;
}
&.color7 {
background-color: lightskyblue;
}
}
}
.container {
.head {
display: flex;
gap: 12px;
background-color: #ebebef;
padding: 12px 6px;
&.drop_over {
background-color: #ccc;
}
.timetable_item();
}
.content {
overflow: hidden;
table {
margin: 0;
colgroup,
thead,
tbody {
width: 100%;
tr th {
text-align: center;
}
}
tbody {
td {
width: 90px;
height: 60px;
&.drop_over {
background-color: #ccc;
}
.timetable_item();
}
}
}
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84