feat: 歌单支持拖动排序

This commit is contained in:
539943419 committed 2024-09-27 15:03:43 +08:00
1 parent 38e1b098d2
commit 55381df4f6
8 files changed
+117 -29

No files matched your search

+1
View File
@@ -36,6 +36,7 @@
"sass": "^1.77.8",
"vue": "3.5.0",
"vue-codemirror": "^6.1.1",
"vue-draggable-plus": "^0.5.3",
"xgplayer": "^3.0.20",
"xgplayer-subtitles": "^3.0.20"
},
+21
View File
@@ -80,6 +80,9 @@ importers:
vue-codemirror:
specifier: ^6.1.1
version: 6.1.1(codemirror@6.0.1(@lezer/common@1.2.1))(vue@3.5.0(typescript@5.5.4))
vue-draggable-plus:
specifier: ^0.5.3
version: 0.5.3(@types/sortablejs@1.15.8)
xgplayer:
specifier: ^3.0.20
version: 3.0.20(core-js@3.38.1)
@@ -523,6 +526,9 @@ packages:
resolution: {integrity: sha512-TRdIPqdsvKmPla44kVy4jv5Nt5vjMfVjbIEke1CRULIrwKNRC4lIiZvNYDJvbUMNCFPNIUcOKhXTyMJrX18IMA==}
deprecated: This is a stub types definition. pdfjs-dist provides its own type definitions, so you do not need this installed.
'@types/sortablejs@1.15.8':
resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==}
'@vicons/ionicons5@0.12.0':
resolution: {integrity: sha512-Iy1EUVRpX0WWxeu1VIReR1zsZLMc4fqpt223czR+Rpnrwu7pt46nbnC2ycO7ItI/uqDLJxnbcMC7FujKs9IfFA==}
@@ -1207,6 +1213,15 @@ packages:
codemirror: 6.x
vue: 3.x
vue-draggable-plus@0.5.3:
resolution: {integrity: sha512-dwKDzZ8io3y7k2iuIwVwiGrdiq5C0S7Et7nt5Gz5KjpBS9MtZGFP+L4FJPWGSLYleOT8HmVuCXTZYjGet7wC0g==}
peerDependencies:
'@types/sortablejs': ^1.15.0
'@vue/composition-api': '*'
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-tsc@2.0.29:
resolution: {integrity: sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==}
hasBin: true
@@ -1682,6 +1697,8 @@ snapshots:
- encoding
- supports-color
'@types/sortablejs@1.15.8': {}
'@vicons/ionicons5@0.12.0': {}
'@vitejs/plugin-vue@5.1.2(vite@5.4.0(@types/node@22.1.0)(sass@1.77.8))(vue@3.5.0(typescript@5.5.4))':
@@ -2466,6 +2483,10 @@ snapshots:
codemirror: 6.0.1(@lezer/common@1.2.1)
vue: 3.5.0(typescript@5.5.4)
vue-draggable-plus@0.5.3(@types/sortablejs@1.15.8):
dependencies:
'@types/sortablejs': 1.15.8
vue-tsc@2.0.29(typescript@5.5.4):
dependencies:
'@volar/typescript': 2.4.0-alpha.18
+4 -4
View File
@@ -135,9 +135,9 @@ provide('rootDirectory', rootDirectory)
: view.title
}}
</span>
<div class="tab-point" :style="{ backgroundColor: view.color }"></div>
<div class="tab-control">
<n-icon class="tag-control-icon icon" @click="view.switchShow()" v-if="view.allowCopy">
<div class="tab-point" :style="{ backgroundColor: view.color }"></div>
<n-icon class="tag-control-icon icon" @click="view.switchShow()">
<EyeOutline v-show="view.visible" class="icon-inner" />
<EyeOffOutline v-show="!view.visible" class="icon-inner" />
</n-icon>
@@ -148,7 +148,7 @@ provide('rootDirectory', rootDirectory)
view.currentFiles,
index + 1
)
">
" v-if="view.allowCopy">
<CopyOutline />
</n-icon>
<n-icon class="tag-control-icon icon" @click="deleteView(index)">
@@ -241,7 +241,7 @@ $tag-width: 170px;
height: 5px;
aspect-ratio: 1;
border-radius: 66px;
margin-left: 5px;
margin-right: 5px;
}
.tab-control {
+18
View File
@@ -12,6 +12,13 @@ import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import config from '@/config'
import useDataBus from '@/hooks/useDataBus'
const props = defineProps({
disable: {
type: Boolean,
default: false
}
})
const dataBus = useDataBus()
const { uploadSizeLimit } = config
@@ -57,8 +64,16 @@ const removeDirectory = async (files: File[]) => {
}
}
}
const check = (event: DragEvent) => [
...(event.dataTransfer?.files ?? []),
...(dataBus.get('dragData_vFiles') ?? []),
...(dataBus.get('dragData_vDirectory') ?? [])
].length !== 0
const handleDragOver = async (event: DragEvent) => {
if (props.disable || check(event) === false) {
return
}
event.preventDefault()
if (showMask.value === 1) {
return
@@ -71,6 +86,9 @@ const handleDragLeave = async () => {
}
const handleDrop = async (event: DragEvent) => {
if (props.disable || check(event) === false) {
return
}
showMask.value = 0
event.preventDefault()
event.stopPropagation()
+4
View File
@@ -17,6 +17,10 @@ export default function useDataBus() {
const value = dataStorage[key];
dataStorage[key] = undefined;
return value;
},
get(key: string | number) {
const value = dataStorage[key];
return value;
}
};
}
@@ -2,10 +2,15 @@ import { createApp, Reactive } from "vue";
import aplayerListNew from "../src/aplayerListNew.vue";
import apType from "../types/ap";
type aplayerMiaoOption = {
onDragItemStart?: () => void,
onDragItemEnd?: () => void,
}
/**
* 对aplayer进行一些自定义的风格优化
*/
const useAplayerMiao = (ap: Reactive<apType>) => {
const useAplayerMiao = (ap: Reactive<apType>, options?: aplayerMiaoOption) => {
const container = ap.container as HTMLDivElement;
// 隐藏旧版歌单
@@ -30,7 +35,7 @@ const useAplayerMiao = (ap: Reactive<apType>) => {
});
container.appendChild(new_list_dom);
const app = createApp(aplayerListNew, { ap });
const app = createApp(aplayerListNew, { ap, ...(options ?? {}) });
app.mount(new_list_dom);
ap.on("destroy", () => {
@@ -45,6 +45,8 @@ const handleDropVFiles = (files: VirtualFile[]) => {
const aplayer = ref<any>(null);
const disableDropReceiver = ref(false)
let ap: apType
let vueApp: any
@@ -59,7 +61,14 @@ onMounted(() => {
theme: "#60e8a2"
}
ap = reactive<apType>(new APlayer(aplayerOption))
vueApp = useAplayerMiao(ap)
vueApp = useAplayerMiao(ap, {
onDragItemStart: () => {
disableDropReceiver.value = true
},
onDragItemEnd: () => {
disableDropReceiver.value = false
},
})
ap.on('listremove', (...args: any) => {
const {index} = args[0] as {index: number}
const _name = ap.list.audios[index].name
@@ -1,33 +1,43 @@
<template>
<ol :style="{ maxHeight: ap.options.listMaxHeight }" :key="refreshKey">
<li v-for="(audio, index) in ap.list.audios" :class="activeAudioIndex == index ? 'aplayer-list-light' : ''"
class="aplayer-list-new" @click="switchAudio(index)" :key="audio.id">
<span class="aplayer-list-cur" :style="{ backgroundColor: apTheme }"></span>
<span class="aplayer-list-index">{{ index + 1 }}</span>
<span class="aplayer-list-title">{{ audio.name }}</span>
<span class="aplayer-list-author" v-show="audio.artist">{{ audio.artist }}</span>
<div class="aplayer-list-control">
<div class="aplayer-list-control-btn" @click.stop="listAudioUp(index)">
<ChevronUpOutline class="aplayer-list-control-btn-svg" />
</div>
<div class="aplayer-list-control-btn" @click.stop="listAudioDown(index)">
<ChevronDownOutline class="aplayer-list-control-btn-svg" />
</div>
<div class="aplayer-list-control-btn" @click.stop="listAudioRemove(index)">
<CloseOutline class="aplayer-list-control-btn-svg" />
</div>
</div>
</li>
<ol :style="{ maxHeight: ap.options.listMaxHeight }" :key="refreshKey" >
<VueDraggable v-model="ap.list.audios" @start="onDragStart" @end="onDragEnd" item-key="id" handle=".aplayer-list-control-btn-reorder">
<!-- <template #item="{ element, index }"> -->
<li v-for="(element, index) in ap.list.audios" :class="activeAudioIndex == index ? 'aplayer-list-light' : ''"
class="aplayer-list-new" @click="switchAudio(index)" :key="element.id">
<span class="aplayer-list-cur" :style="{ backgroundColor: apTheme }"></span>
<span class="aplayer-list-index">{{ index + 1 }}</span>
<span class="aplayer-list-title">{{ element.name }}</span>
<span class="aplayer-list-author" v-show="element.artist">{{ element.artist }}</span>
<div class="aplayer-list-control">
<div class="aplayer-list-control-btn" @click.stop="listAudioUp(index)" v-if="false">
<ChevronUpOutline class="aplayer-list-control-btn-svg" />
</div>
<div class="aplayer-list-control-btn" @click.stop="listAudioDown(index)" v-if="false">
<ChevronDownOutline class="aplayer-list-control-btn-svg" />
</div>
<div class="aplayer-list-control-btn" @click.stop="listAudioRemove(index)">
<CloseOutline class="aplayer-list-control-btn-svg" />
</div>
<div class="aplayer-list-control-btn aplayer-list-control-btn-reorder">
<ReorderFourOutline class="aplayer-list-control-btn-svg" />
</div>
</div>
</li>
<!-- </template> -->
</VueDraggable>
</ol>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { ChevronUpOutline, ChevronDownOutline, CloseOutline } from '@vicons/ionicons5';
import { ChevronUpOutline, ChevronDownOutline, CloseOutline, ReorderFourOutline } from '@vicons/ionicons5';
import { VueDraggable } from 'vue-draggable-plus'
import apType, { audioType } from '../types/ap';
const props = defineProps<{
ap: apType
onDragItemStart: () => void,
onDragItemEnd: () => void
}>()
const refreshKey = ref(Math.random())
@@ -97,7 +107,21 @@ const listAudioDown = (index: number) => {
const listAudioRemove = (index: number) => {
props.ap.list.remove(index)
}
const {onDragStart, onDragEnd} = (() => {
let curr: audioType
return {
onDragStart: () => {
curr = props.ap.list.audios[props.ap.list.index]
},
onDragEnd: () => {
listRefreshIndex(curr)
}
}
})()
// const onDragEnd = (_e: any) => {
// const curr = props.ap.list.audios[props.ap.list.index]
// listRefreshIndex(curr)
// }
onMounted(() => {
console.log(props.ap)
@@ -105,6 +129,12 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.aplayer-list-new {
height: fit-content !important;
.aplayer-list-cur {
height: calc( 100% - 8px ) !important;
}
}
.aplayer-list-control {
float: right;
height: 32px;
@@ -136,4 +166,4 @@ onMounted(() => {
.aplayer .aplayer-list-new svg path {
fill: #ffffff00;
}
</style>
</style>