import { IconMusic } from "@/assets/icons"; import { isWeixinBrowser } from "@/controllers/wxController"; import { useEditor } from "@/modules/editor"; import { PauseCircleOutlined, PlayCircleOutlined, SoundOutlined, } from "@ant-design/icons-vue"; import { css } from "@linaria/core"; import { Button, Dropdown, Slider } from "ant-design-vue"; import { Howl } from "howler"; import { nanoid } from "nanoid"; import { isPc } from "@queenjs/utils"; import { defineComponent, reactive, ref, watch, onUnmounted, onMounted, } from "vue"; import { bool, number } from "vue-types"; import { MusicOptions } from "./localMusic"; declare const WeixinJSBridge: any; export const PageMusic = defineComponent({ setup() { const { store, helper, controls, actions } = useEditor(); const rootComp = helper.findRootComp(); const volume = rootComp?.value.volume != undefined ? rootComp?.value.volume : 0.3; const state = reactive({ playStatus: false, duration: 0, currentTime: 0, muted: true, volume: volume, }); let audioKey = nanoid(); let audioBgm = ref(); const initAudioBgm = () => { audioBgm.value = null; const curAudio = MusicOptions.find((e) => { return e.value == rootComp?.value.music; }); const src = curAudio?.src || ""; audioBgm.value = new Howl({ src: [src], loop: store.isEditMode ? false : true, preload: true, HTML5: true, volume: volume, }); controls.mediaCtrl.setMediasInstance(audioKey, audioBgm.value); audioBgm.value.on("load", () => { state.duration = audioBgm.value.duration(); if (!store.isEditMode) { if (isWeixinBrowser()) { WeixinJSBridge.invoke( "getNetworkType", {}, () => { playAudio(true); }, false ); } else { playAudio(true); } } }); audioBgm.value.on("loaderror", () => { console.log("音频加载失败"); }); audioBgm.value.on("playerror", () => { console.log("音频播放失败"); }); audioBgm.value.on("play", () => { controls.mediaCtrl.pauseOtherMedia(audioKey); if (!state.playStatus) { state.playStatus = true; } playStep(); }); audioBgm.value.on("pause", () => { audioRest(); }); audioBgm.value.on("end", () => { if (store.isEditMode) { audioRest(); } }); setTimeout(() => { checkAutoPlay(); }, 500); }; const checkAutoPlay = () => { const duration = audioBgm.value.duration(); if (duration) { state.duration = duration; } if (!audioBgm.value || store.isEditMode) { return; } let playing = audioBgm.value.playing(); if (!playing) { playAudio(true); } }; const playStep = () => { if (!audioBgm.value) { return; } let playing = audioBgm.value.playing(); if (!playing) { return; } let seek = audioBgm.value.seek(); state.currentTime = seek; requestAnimationFrame(playStep); }; const playAudio = async (status: boolean) => { if (!audioBgm.value) { return; } if (status) { audioBgm.value.play(); } else { audioRest(); } let playing = audioBgm.value.playing(); if (status && playing) { state.playStatus = true; return; } state.playStatus = false; }; watch( () => rootComp?.value.music, () => { audioRest(); initAudioBgm(); } ); onMounted(() => { initAudioBgm(); }); onUnmounted(() => { audioRest(); audioBgm.value = null; controls.mediaCtrl.removeMedia(audioKey); }); const seekChange = (v: number) => { state.currentTime = v; audioBgm.value && audioBgm.value.seek(v); }; const volumeChange = (v: number) => { state.volume = v; if (rootComp) { actions.updateCompData(rootComp, "value.volume", v); } audioBgm.value && audioBgm.value.volume(v); }; const audioRest = () => { if (!audioBgm.value) { return; } let playing = audioBgm.value.playing(); if (playing) { audioBgm.value.pause(); } state.playStatus = false; state.currentTime = 0; audioBgm.value.seek(0); }; return () => { const music = rootComp?.value.music; return (
{store.isEditMode ? ( ) : (
{ playAudio(!state.playStatus); }} >
)}
); }; }, }); const AudioPlayer = defineComponent({ props: { volume: number(), playStatus: bool(), currentTime: number(), duration: number(), }, emits: ["status", "seekChange", "volumeChange"], setup(props, { emit }) { const audioControl = (playStatus: boolean) => { emit("status", playStatus); }; const seekChange = (v: any) => { emit("seekChange", v); }; const volumeChange = (v: any) => { emit("volumeChange", v); }; const formatTime = (secs?: number) => { if (!secs) { return "00:00"; } secs = Math.round(secs); const minutes = Math.floor(secs / 60) || 0; const seconds = secs - minutes * 60 || 0; return ( String(minutes).padStart(2, "0") + ":" + String(seconds).padStart(2, "0") ); }; const volumeSlider = () => { return (
); }; return () => { return (
{!props.playStatus ? ( ) : ( )}
{formatTime(props.currentTime)}/{formatTime(props.duration)}
); }; }, }); const VolumeSliderStyle = css` margin-bottom: -4px; padding: 8px 4px; background-color: #303030; border-radius: 4px; box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.2); /* slider style */ .ant-slider-disabled { opacity: 0.7; } .ant-slider-step { background-color: rgba(255, 255, 255, 0.27); } .ant-slider-track { border-radius: 4px; background-color: rgba(255, 255, 255, 1); } .ant-slider:not(.ant-slider-disabled):hover { .ant-slider-handle { background-color: @inf-primary-color; &:not(.ant-tooltip-open) { border-color: #fff; } } } .ant-slider { &.ant-slider-disabled { .ant-slider-handle { background-color: #bbb; opacity: 0.8; } } } .ant-slider-handle { width: 14px; height: 8px; border-radius: 2px; border-color: #fff; background-color: #fff; } .ant-slider-handle-click-focused { border-color: #fff; background-color: @inf-primary-color; } `; const MusicEditStyle = css` flex: 1; `; const AudioPlayerStyle = css` width: 100%; display: flex; align-items: center; /* slider style */ .ant-slider-disabled { opacity: 0.7; } .ant-slider-step { background-color: rgba(255, 255, 255, 0.27); } .ant-slider-track { border-radius: 4px; background-color: rgba(255, 255, 255, 1); } .ant-slider:not(.ant-slider-disabled):hover { .ant-slider-handle { background-color: @inf-primary-color; &:not(.ant-tooltip-open) { border-color: #fff; } } } .ant-slider { &.ant-slider-disabled { .ant-slider-handle { background-color: #bbb; opacity: 0.8; } } } .ant-slider-handle { width: 8px; border-radius: 2px; border-color: #fff; background-color: #fff; } .ant-slider-handle-click-focused { border-color: #fff; background-color: @inf-primary-color; } `; const MusicStyle = css` top: 10px; right: 10px; z-index: 999; .music_button { width: 48px; height: 48px; display: inline-flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.5); font-size: 28px; border-radius: 24px; cursor: pointer; &.rotating { animation: myRotate 5s linear infinite; } } @keyframes myRotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } `;