feat: 1. 更新音乐插件 2. 组件注册插件增加单插件模式
This commit is contained in:
1 parent
4b5b7956c7
commit
38e1b098d2
9 files changed
+316
-41
No files matched your search
@@ -25,7 +25,8 @@ const pluginConfig: registerComponentOption = {
|
||||
}
|
||||
return vFiles[0].name.endsWith('?')
|
||||
},
|
||||
disable: false
|
||||
disable: false,
|
||||
single: true
|
||||
}
|
||||
|
||||
export default pluginConfig
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createApp, Reactive } from "vue";
|
||||
import aplayerListNew from "../src/aplayerListNew.vue";
|
||||
import apType from "../types/ap";
|
||||
|
||||
/**
|
||||
* 对aplayer进行一些自定义的风格优化
|
||||
*/
|
||||
const useAplayerMiao = (ap: Reactive<apType>) => {
|
||||
const container = ap.container as HTMLDivElement;
|
||||
|
||||
// 隐藏旧版歌单
|
||||
const old_listDom = container.querySelector(".aplayer-list") as HTMLDivElement;
|
||||
old_listDom.style.display = "none";
|
||||
|
||||
// 新版歌单
|
||||
const new_list_dom = document.createElement("div");
|
||||
new_list_dom.classList.add("aplayer-list");
|
||||
new_list_dom.style.maxHeight = ap.options.listMaxHeight;
|
||||
|
||||
ap.on("listadd", () => {
|
||||
ap.list.audios.forEach(v => {
|
||||
!v.id && (v.id = Math.random());
|
||||
});
|
||||
});
|
||||
ap.on("listshow", () => {
|
||||
new_list_dom.classList.remove("aplayer-list-hide");
|
||||
});
|
||||
ap.on("listhide", () => {
|
||||
new_list_dom.classList.add("aplayer-list-hide");
|
||||
});
|
||||
|
||||
container.appendChild(new_list_dom);
|
||||
const app = createApp(aplayerListNew, { ap });
|
||||
app.mount(new_list_dom);
|
||||
|
||||
ap.on("destroy", () => {
|
||||
app.unmount();
|
||||
});
|
||||
return app;
|
||||
};
|
||||
|
||||
export default useAplayerMiao;
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<miao-drop-handler @on-virtual-files="handleDropVFiles">
|
||||
<div class="miaoMusic-container">
|
||||
<NScrollbar>
|
||||
<div class="miaoMusic-main">
|
||||
</div>
|
||||
</NScrollbar>
|
||||
<div ref="aplayer" />
|
||||
</div>
|
||||
</miao-drop-handler>
|
||||
@@ -8,40 +12,60 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import miaoDropHandler from '@/components/miaoDropHandler.vue'
|
||||
import useAplayerMiao from './hooks/aplayerMiao';
|
||||
import { VirtualFile } from '@/class/VirtualDirectory';
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { NScrollbar } from 'naive-ui';
|
||||
import 'APlayer/dist/APlayer.min.css';
|
||||
// @ts-ignore
|
||||
import APlayer from 'APlayer';
|
||||
import config from '@/config';
|
||||
import { difference, uniq } from 'lodash';
|
||||
import apType from './types/ap';
|
||||
|
||||
|
||||
const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
|
||||
required: true
|
||||
});
|
||||
|
||||
const MusicList = computed(() => currentFiles.value.map(v => ({
|
||||
watch(()=>currentFiles.value, (value, oldValue) => {
|
||||
ap.list.add(getMusicList(difference(value, oldValue)))
|
||||
})
|
||||
|
||||
const getMusicList = (mp3VFiles: VirtualFile[]) => mp3VFiles.map((v, index) => ({
|
||||
url: `${config.baseUrl}${v.url}`,
|
||||
name: v.name,
|
||||
artist: '???',
|
||||
})));
|
||||
artist: ' ',
|
||||
index
|
||||
}));
|
||||
|
||||
const handleDropVFiles = (files: VirtualFile[]) => {
|
||||
currentFiles.value = [...currentFiles.value, ...files];
|
||||
currentFiles.value = uniq([...currentFiles.value, ...files]);
|
||||
};
|
||||
|
||||
const aplayer = ref<any>(null);
|
||||
|
||||
let ap: any
|
||||
let ap: apType
|
||||
let vueApp: any
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
currentFiles.value = [...currentFiles.value.reverse()]
|
||||
const aplayerOption = {
|
||||
container: aplayer.value,
|
||||
audio: MusicList.value,
|
||||
audio: getMusicList(currentFiles.value),
|
||||
autoplay: true,
|
||||
volume: 1,
|
||||
theme: "#60e8a2"
|
||||
}
|
||||
ap = new APlayer(aplayerOption);
|
||||
ap = reactive<apType>(new APlayer(aplayerOption))
|
||||
vueApp = useAplayerMiao(ap)
|
||||
ap.on('listremove', (...args: any) => {
|
||||
const {index} = args[0] as {index: number}
|
||||
const _name = ap.list.audios[index].name
|
||||
currentFiles.value = currentFiles.value.filter(v=>v.name !== _name)
|
||||
})
|
||||
console.log({ ap, vueApp })
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -53,21 +77,28 @@ onUnmounted(() => {
|
||||
.miaoMusic-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.miaoMusic-main {
|
||||
padding-bottom: 88px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.aplayer {
|
||||
height: calc(100% - 10px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// .aplayer-list {
|
||||
// max-height: none !important;
|
||||
// height: fit-content;
|
||||
// min-height: 0;
|
||||
// ol {
|
||||
// max-height: none !important;
|
||||
// height: fit-content;
|
||||
// }
|
||||
// }
|
||||
flex-direction: column-reverse;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
width: -webkit-fill-available;
|
||||
|
||||
.aplayer-list {
|
||||
max-height: 444px !important;
|
||||
|
||||
ol {
|
||||
max-height: inherit !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,139 @@
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { ChevronUpOutline, ChevronDownOutline, CloseOutline } from '@vicons/ionicons5';
|
||||
import apType, { audioType } from '../types/ap';
|
||||
|
||||
const props = defineProps<{
|
||||
ap: apType
|
||||
}>()
|
||||
|
||||
const refreshKey = ref(Math.random())
|
||||
|
||||
const apTheme = computed(() => props.ap.list.audios[activeAudioIndex.value].theme ?? props.ap.options.theme)
|
||||
|
||||
const activeAudioIndex = computed(() => props.ap.list.index)
|
||||
|
||||
props.ap.on('listswitch', (...args: any) => {
|
||||
// 手动触发更新,不然监听不到
|
||||
props.ap.list.index = args[0].index as number;
|
||||
})
|
||||
|
||||
const refresh = () => {
|
||||
refreshKey.value = Math.random()
|
||||
}
|
||||
|
||||
props.ap.on('listremove', refresh)
|
||||
props.ap.on('listadd', refresh)
|
||||
|
||||
const switchAudio = (index: number) => {
|
||||
if (index === activeAudioIndex.value) {
|
||||
return
|
||||
}
|
||||
props.ap.list.switch(index)
|
||||
}
|
||||
const listRefreshIndex = (curr: audioType) => {
|
||||
for(let index in props.ap.list.audios){
|
||||
if(props.ap.list.audios[index] === curr) {
|
||||
props.ap.list.index = parseInt(index)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const listAudioUp = (index: number) => {
|
||||
const arr = props.ap.list.audios;
|
||||
const len = arr.length
|
||||
const curr = props.ap.list.audios[props.ap.list.index]
|
||||
if (index === 0) {
|
||||
const _item = arr.shift();
|
||||
_item && arr.push(_item);
|
||||
} else {
|
||||
const pre: number = (len - 1 + index) % len;
|
||||
const _pre = arr[index];
|
||||
arr[index] = arr[pre];
|
||||
arr[pre] = _pre;
|
||||
}
|
||||
listRefreshIndex(curr)
|
||||
};
|
||||
|
||||
const listAudioDown = (index: number) => {
|
||||
const arr = props.ap.list.audios;
|
||||
const len = arr.length
|
||||
const curr = props.ap.list.audios[props.ap.list.index]
|
||||
if (index === len - 1) {
|
||||
const _item = arr.pop();
|
||||
_item && arr.unshift(_item);
|
||||
} else {
|
||||
const pre: number = (len + 1 + index) % len;
|
||||
const _pre = arr[index];
|
||||
arr[index] = arr[pre];
|
||||
arr[pre] = _pre;
|
||||
}
|
||||
listRefreshIndex(curr)
|
||||
}
|
||||
const listAudioRemove = (index: number) => {
|
||||
props.ap.list.remove(index)
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
console.log(props.ap)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aplayer-list-control {
|
||||
float: right;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-btn {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-svg {
|
||||
width: 20px;
|
||||
aspect-ratio: 1;
|
||||
transition: all .1s ease;
|
||||
|
||||
&:hover {
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.aplayer svg circle,
|
||||
.aplayer .aplayer-list-new svg path {
|
||||
fill: #ffffff00;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,40 @@
|
||||
export type audioType = {
|
||||
url: string
|
||||
artist: string
|
||||
cover?: string
|
||||
name: string
|
||||
theme?: string
|
||||
id?: number
|
||||
index: number
|
||||
}
|
||||
|
||||
type apType = {
|
||||
list: {
|
||||
audios: audioType[]
|
||||
index: number
|
||||
switch: (index: number) => void
|
||||
remove: (index: number) => void
|
||||
add: (audios: audioType[]) => void
|
||||
refreshAudioIndex: () => void
|
||||
}
|
||||
container: HTMLDivElement
|
||||
on: (event: string, callback: () => void) => void
|
||||
options: {
|
||||
audio: audioType[],
|
||||
autoplay: boolean,
|
||||
"volume": number,
|
||||
"theme": string,
|
||||
"mini": boolean,
|
||||
"fixed": boolean,
|
||||
"mutex": boolean,
|
||||
"lrcType": number,
|
||||
"preload": "auto",
|
||||
"loop": "all",
|
||||
"order": "list",
|
||||
"listMaxHeight": string,
|
||||
"storageName": "aplayer-setting"
|
||||
},
|
||||
destroy: () => {}
|
||||
}
|
||||
|
||||
export default apType
|
||||
Reference in new issue
Block a user