feat: 1. 更新音乐插件 2. 组件注册插件增加单插件模式
This commit is contained in:
1 parent
4b5b7956c7
commit
38e1b098d2
9 files changed
+311
-36
No files matched your search
+1
-2
@@ -113,7 +113,6 @@ onMounted(async () => {
|
|||||||
await init(messageProviderRef.value?.alertTip)
|
await init(messageProviderRef.value?.alertTip)
|
||||||
pluginCenter = usePluginCenter()
|
pluginCenter = usePluginCenter()
|
||||||
pluginCenter.usePlugin('miaoDirectory', [rootDirectory], [])
|
pluginCenter.usePlugin('miaoDirectory', [rootDirectory], [])
|
||||||
console.log(rootDirectory.tree)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -138,7 +137,7 @@ provide('rootDirectory', rootDirectory)
|
|||||||
</span>
|
</span>
|
||||||
<div class="tab-point" :style="{ backgroundColor: view.color }"></div>
|
<div class="tab-point" :style="{ backgroundColor: view.color }"></div>
|
||||||
<div class="tab-control">
|
<div class="tab-control">
|
||||||
<n-icon class="tag-control-icon icon" @click="view.switchShow()">
|
<n-icon class="tag-control-icon icon" @click="view.switchShow()" v-if="view.allowCopy">
|
||||||
<EyeOutline v-show="view.visible" class="icon-inner" />
|
<EyeOutline v-show="view.visible" class="icon-inner" />
|
||||||
<EyeOffOutline v-show="!view.visible" class="icon-inner" />
|
<EyeOffOutline v-show="!view.visible" class="icon-inner" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
|
|||||||
+20
-10
@@ -2,6 +2,7 @@ import useVirtualPages from "@/hooks/useVirtualPages";
|
|||||||
import VirtualDirectory, { VirtualFile } from "./VirtualDirectory";
|
import VirtualDirectory, { VirtualFile } from "./VirtualDirectory";
|
||||||
import { ShallowRef, shallowRef } from "vue";
|
import { ShallowRef, shallowRef } from "vue";
|
||||||
import { alertTipType, usePluginHooksType } from "@/types/type";
|
import { alertTipType, usePluginHooksType } from "@/types/type";
|
||||||
|
import VirtualPage from "./VirtualPage";
|
||||||
|
|
||||||
export enum PluginGroup {
|
export enum PluginGroup {
|
||||||
default = "default",
|
default = "default",
|
||||||
@@ -17,6 +18,8 @@ export interface registerComponentOption {
|
|||||||
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
|
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
|
||||||
disable?: boolean;
|
disable?: boolean;
|
||||||
exitConfirm?: boolean;
|
exitConfirm?: boolean;
|
||||||
|
// 若为true,则只会创建一个页面,当存在已创建页面则会直接将VFile和VDir加到curr里面
|
||||||
|
single?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Plugin = {
|
export type Plugin = {
|
||||||
@@ -31,12 +34,7 @@ export type Plugin = {
|
|||||||
// 判断在未禁用时是否可以使用这个组件
|
// 判断在未禁用时是否可以使用这个组件
|
||||||
// 使用组件即调用下面的func
|
// 使用组件即调用下面的func
|
||||||
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
|
filter: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[]) => boolean;
|
||||||
func: (
|
func: (VDirectories: VirtualDirectory[], VFiles: VirtualFile[], hooks: usePluginHooksType, ...args: any[]) => void;
|
||||||
VDirectories: VirtualDirectory[],
|
|
||||||
VFiles: VirtualFile[],
|
|
||||||
hooks: usePluginHooksType,
|
|
||||||
...args: any[]
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class PluginCenter {
|
export default class PluginCenter {
|
||||||
@@ -58,7 +56,7 @@ export default class PluginCenter {
|
|||||||
* 便捷地注册一个组件为插件,触发时直接用新页面打开
|
* 便捷地注册一个组件为插件,触发时直接用新页面打开
|
||||||
*/
|
*/
|
||||||
registerComponent(option: registerComponentOption): void {
|
registerComponent(option: registerComponentOption): void {
|
||||||
const { key, name, getComponent, icon, filter, group = [PluginGroup.default], disable = false, exitConfirm = false } = option;
|
const { key, name, getComponent, icon, filter, group = [PluginGroup.default], disable = false, exitConfirm = false, single = false } = option;
|
||||||
let _component: any;
|
let _component: any;
|
||||||
const views = useVirtualPages();
|
const views = useVirtualPages();
|
||||||
this.register(key, {
|
this.register(key, {
|
||||||
@@ -81,12 +79,19 @@ export default class PluginCenter {
|
|||||||
timeout: 2000
|
timeout: 2000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (single && views.find(_component) !== undefined) {
|
||||||
|
const view = views.find(_component) as VirtualPage;
|
||||||
|
view.currentFiles = [...view.currentFiles, ...VFiles];
|
||||||
|
view.currentDirectories = [...view.currentDirectories, ...VDirectories];
|
||||||
|
} else {
|
||||||
views.push(_component, VDirectories, VFiles, {
|
views.push(_component, VDirectories, VFiles, {
|
||||||
VirtualPageOption: {
|
VirtualPageOption: {
|
||||||
exitConfirm
|
exitConfirm,
|
||||||
|
allowCopy: single === false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +117,13 @@ export default class PluginCenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]) {
|
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]) {
|
||||||
this.pluginsMap[key].func(VDirectories ?? [], VFiles ?? [], {
|
this.pluginsMap[key].func(
|
||||||
|
VDirectories ?? [],
|
||||||
|
VFiles ?? [],
|
||||||
|
{
|
||||||
globalAlertTip: this.globalAlertTip
|
globalAlertTip: this.globalAlertTip
|
||||||
}, ...args);
|
},
|
||||||
|
...args
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ export class VirtualFile {
|
|||||||
stats: stats;
|
stats: stats;
|
||||||
parent: VirtualDirectory;
|
parent: VirtualDirectory;
|
||||||
id: number;
|
id: number;
|
||||||
|
storage: {[key: string]: any} = {};
|
||||||
get path() {
|
get path() {
|
||||||
return `${this.parent.path}${this.name}`;
|
return `${this.parent.path}${this.name}`;
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,6 @@ export class VirtualFile {
|
|||||||
class VirtualDirectory {
|
class VirtualDirectory {
|
||||||
constructor(info: directory, parent?: VirtualDirectory) {
|
constructor(info: directory, parent?: VirtualDirectory) {
|
||||||
this.name = info.name;
|
this.name = info.name;
|
||||||
this.type = "directory";
|
|
||||||
this.stats = info.stats;
|
this.stats = info.stats;
|
||||||
this.parent = parent ?? undefined;
|
this.parent = parent ?? undefined;
|
||||||
this.id = generateId();
|
this.id = generateId();
|
||||||
@@ -60,7 +60,7 @@ class VirtualDirectory {
|
|||||||
// 子目录
|
// 子目录
|
||||||
directories?: VirtualDirectory[];
|
directories?: VirtualDirectory[];
|
||||||
// 没啥意义,标注一下就是了
|
// 没啥意义,标注一下就是了
|
||||||
type: "directory";
|
type: "directory" = 'directory';
|
||||||
// 文件夹创建时间等杂项属性
|
// 文件夹创建时间等杂项属性
|
||||||
stats: stats;
|
stats: stats;
|
||||||
// 父文件夹
|
// 父文件夹
|
||||||
@@ -68,6 +68,8 @@ class VirtualDirectory {
|
|||||||
|
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
storage: {[key: string]: any} = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取相对于根目录的路径的层数
|
* 获取相对于根目录的路径的层数
|
||||||
* 用于目录下文件定位
|
* 用于目录下文件定位
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { reactive, shallowRef } from 'vue'
|
import { Component, reactive, shallowRef } from 'vue'
|
||||||
import VirtualDirectory, { VirtualFile } from './VirtualDirectory'
|
import VirtualDirectory, { VirtualFile } from './VirtualDirectory'
|
||||||
import generateId from '@/hooks/generateId'
|
import generateId from '@/hooks/generateId'
|
||||||
|
|
||||||
export interface VirtualPageOption {
|
export interface VirtualPageOption {
|
||||||
exitConfirm?: boolean
|
exitConfirm?: boolean
|
||||||
|
allowCopy?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewsPushOption {
|
export interface ViewsPushOption {
|
||||||
@@ -44,6 +45,7 @@ export default class VirtualPage {
|
|||||||
this.refreshKey = Math.random()
|
this.refreshKey = Math.random()
|
||||||
this.color = getRandomWebSafeColor()
|
this.color = getRandomWebSafeColor()
|
||||||
this.exitConfirm = initObjects?.option?.exitConfirm ?? false
|
this.exitConfirm = initObjects?.option?.exitConfirm ?? false
|
||||||
|
this.allowCopy = initObjects?.option?.allowCopy ?? true
|
||||||
}
|
}
|
||||||
// 页面使用的组件
|
// 页面使用的组件
|
||||||
component: any
|
component: any
|
||||||
@@ -61,8 +63,10 @@ export default class VirtualPage {
|
|||||||
color: string
|
color: string
|
||||||
// 用于展示的title
|
// 用于展示的title
|
||||||
_title?: string
|
_title?: string
|
||||||
// 关闭时是否需要确认
|
// 关闭时是否需要确认(未实现)
|
||||||
exitConfirm: boolean
|
exitConfirm: boolean
|
||||||
|
// 是否允许复制页面
|
||||||
|
allowCopy: boolean
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
if (this._title) {
|
if (this._title) {
|
||||||
@@ -155,4 +159,11 @@ export class VirtualPages {
|
|||||||
deleteView(index: number) {
|
deleteView(index: number) {
|
||||||
this._views.splice(index, 1)
|
this._views.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回第一个使用此组件的页面
|
||||||
|
*/
|
||||||
|
find(component: Component) {
|
||||||
|
return this._views.find(v=>v.component === component)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,8 @@ const pluginConfig: registerComponentOption = {
|
|||||||
}
|
}
|
||||||
return vFiles[0].name.endsWith('?')
|
return vFiles[0].name.endsWith('?')
|
||||||
},
|
},
|
||||||
disable: false
|
disable: false,
|
||||||
|
single: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export default pluginConfig
|
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>
|
<template>
|
||||||
<miao-drop-handler @on-virtual-files="handleDropVFiles">
|
<miao-drop-handler @on-virtual-files="handleDropVFiles">
|
||||||
<div class="miaoMusic-container">
|
<div class="miaoMusic-container">
|
||||||
|
<NScrollbar>
|
||||||
|
<div class="miaoMusic-main">
|
||||||
|
</div>
|
||||||
|
</NScrollbar>
|
||||||
<div ref="aplayer" />
|
<div ref="aplayer" />
|
||||||
</div>
|
</div>
|
||||||
</miao-drop-handler>
|
</miao-drop-handler>
|
||||||
@@ -8,40 +12,60 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import miaoDropHandler from '@/components/miaoDropHandler.vue'
|
import miaoDropHandler from '@/components/miaoDropHandler.vue'
|
||||||
|
import useAplayerMiao from './hooks/aplayerMiao';
|
||||||
import { VirtualFile } from '@/class/VirtualDirectory';
|
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';
|
import 'APlayer/dist/APlayer.min.css';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import APlayer from 'APlayer';
|
import APlayer from 'APlayer';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
import { difference, uniq } from 'lodash';
|
||||||
|
import apType from './types/ap';
|
||||||
|
|
||||||
|
|
||||||
const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
|
const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
|
||||||
required: true
|
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}`,
|
url: `${config.baseUrl}${v.url}`,
|
||||||
name: v.name,
|
name: v.name,
|
||||||
artist: '???',
|
artist: ' ',
|
||||||
})));
|
index
|
||||||
|
}));
|
||||||
|
|
||||||
const handleDropVFiles = (files: VirtualFile[]) => {
|
const handleDropVFiles = (files: VirtualFile[]) => {
|
||||||
currentFiles.value = [...currentFiles.value, ...files];
|
currentFiles.value = uniq([...currentFiles.value, ...files]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const aplayer = ref<any>(null);
|
const aplayer = ref<any>(null);
|
||||||
|
|
||||||
let ap: any
|
let ap: apType
|
||||||
|
let vueApp: any
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
currentFiles.value = [...currentFiles.value.reverse()]
|
currentFiles.value = [...currentFiles.value.reverse()]
|
||||||
const aplayerOption = {
|
const aplayerOption = {
|
||||||
container: aplayer.value,
|
container: aplayer.value,
|
||||||
audio: MusicList.value,
|
audio: getMusicList(currentFiles.value),
|
||||||
autoplay: true,
|
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(() => {
|
onUnmounted(() => {
|
||||||
@@ -53,21 +77,28 @@ onUnmounted(() => {
|
|||||||
.miaoMusic-container {
|
.miaoMusic-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.miaoMusic-main {
|
||||||
|
padding-bottom: 88px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.aplayer {
|
.aplayer {
|
||||||
height: calc(100% - 10px);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column-reverse;
|
||||||
// .aplayer-list {
|
position: fixed;
|
||||||
// max-height: none !important;
|
bottom: 10px;
|
||||||
// height: fit-content;
|
width: -webkit-fill-available;
|
||||||
// min-height: 0;
|
|
||||||
// ol {
|
.aplayer-list {
|
||||||
// max-height: none !important;
|
max-height: 444px !important;
|
||||||
// height: fit-content;
|
|
||||||
// }
|
ol {
|
||||||
// }
|
max-height: inherit !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</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