增加音乐,摇一摇,服务等页面

This commit is contained in:
cansnow
2026-02-15 19:41:13 +08:00
parent abd279e7a7
commit 271ec4b9c2
74 changed files with 14021 additions and 2 deletions
+120
View File
@@ -0,0 +1,120 @@
/**
* 秒数转时长 1 → 00:01
*/
export function secondToDuration(second, fixed = 0) {
var sec = (second % 60).toFixed(fixed);
var min = Math.floor(second / 60);
if (min.toString().length < 2) {
min = '0' + min;
}
if (sec < 10) {
sec = '0' + sec;
}
return min + ':' + sec
}
/**
* 判断两个对象是否相等
* @param {Object} o1
* @param {Object} o2
*/
export function objEquals(o1,o2){
if(o1 && o2){
return o1.platform == o2.platform && o1.id == o2.id;
}else{
return false;
}
}
export function isExist(list,obj){
for (let itemIndex in list) {
const item = list[itemIndex];
if (objEquals(item,obj)) {
return true;
}
}
return false;
}
export function findIndex(list,obj){
for (let itemIndex in list) {
const item = list[itemIndex];
if (objEquals(item,obj)) {
return parseInt(itemIndex);
}
}
return -1;
}
export function findObj(list,obj){
const index = findIndex(list,obj);
if(inde != -1){
return list[index];
}
return null;
}
export function isFind(list,obj){
const index = findIndex(list,obj);
if(index != -1){
return true;
}
return false;
}
export function showToast(title,duration = 2000,icon="none",position="bottom"){
uni.showToast({
title,
icon,
duration,
position
});
}
/**
* 格式化歌词
* @param {String} lrcStr 歌词文本
* @param {String} mode 格式 object 对象模式,array 数组模式
*/
export function formatLrc(lrcStr,mode = 'object'){
const reg = /\[\d*:\d*(\.|:)\d*]/g
const timeReg = /\[(\d{2,})\:(\d{2})(?:\.(\d{1,3}))?\]/g; // eslint-disable-line no-useless-escape
let timeResult = [];
let index = 0;
if(mode == 'object'){
let lrcs = {};
lrcStr.split("\n").forEach(item => {
const timeRegAry = item.match(reg);
if (timeRegAry) {
const time = timeRegAry[0];
const min = parseInt(time.match(/\[\d*/i).toString().slice(1))
const sec = parseInt(time.match(/\:\d*/i).toString().slice(1))
const second = min * 60 + sec
const content = item.replace(timeRegAry, "")
lrcs[second] = {
time,
content
};
}
})
return lrcs;
}else{
let lrcs = [];
lrcStr.split("\n").forEach(item => {
const timeRegAry = item.match(reg);
if (timeRegAry) {
const time = timeRegAry[0];
const min = parseInt(time.match(/\[\d*/i).toString().slice(1))
const sec = parseInt(time.match(/\:\d*/i).toString().slice(1))
const second = min * 60 + sec
const content = item.replace(timeRegAry, "")
lrcs.push({
second,
time,
content
});
}
})
return lrcs;
}
}
+134
View File
@@ -0,0 +1,134 @@
const storage_constants = {
searchHistory:'searchHistory',
paramSongList:'paramSongList',
mySongList:'mySongList',
playList:'playList',
playMode:'playMode',
progress:'progress',
playSeconds:'playSeconds',
playDuration:'playDuration',
playIndex:'playIndex',
isFirstRun:'isFirstRun',
recentlyPlayList:'recentlyPlayList'
}
function set(key, value) {
try {
uni.setStorageSync(key, value);
return true;
} catch (e) {
return false;
}
}
function get(key) {
try {
return uni.getStorageSync(key);
} catch (e) {
return null;
}
}
function getDefault(key, defaultVal) {
try {
let val = uni.getStorageSync(key);
if(val || val == 0){
return val;
}else{
val = defaultVal;
return val;
}
} catch (e) {
return defaultVal;
}
}
function getObj(key) {
try {
const val = uni.getStorageSync(key);
if (val) {
return val;
}
return null;
} catch (e) {
return null;
}
}
function getObjDefault(key, defaultVal) {
try {
const val = uni.getStorageSync(key);
if (val) {
return val;
}
return defaultVal;
} catch (e) {
return defaultVal;
}
}
function getArray(key) {
try {
const val = uni.getStorageSync(key);
if (val) {
return val;
}
return [];
} catch (e) {
return [];
}
}
function getArrayDefault(key, defaultVal) {
try {
const val = uni.getStorageSync(key);
if (val) {
return val;
}
return defaultVal;
} catch (e) {
return defaultVal;
}
}
function clearStorage(){
uni.clearStorage();
let item = {
coverImg:"/static/mylike.png",
name:`我喜欢的音乐`,
id:"mylike",
url:null,
singer:"我喜欢的音乐",
desc:null,
platform:'local',
album:null,
list:[]
}
let allSongList = [];
allSongList.push(item);
set(storage_constants.mySongList,allSongList)
}
function remove(key){
uni.removeStorageSync(key);
}
const storage = {
set,
get,
getDefault,
getObj,
getObjDefault,
getArray,
getArrayDefault,
clearStorage,
remove
}
export {
storage,
storage_constants
}
+10
View File
@@ -0,0 +1,10 @@
export const playModeConfig = {
list:{id:'list',icon:'play-list-foreach',name:'列表循环'},
random:{id:'random',icon:'play-random',name:'随机播放'},
single:{id:'single',icon:'play-one-foreach',name:'单曲循环'}
}
export const config = {
playModel:playModeConfig
}
+278
View File
@@ -0,0 +1,278 @@
import Vue from 'vue'
import Store from './store.js'
import {
playModeConfig
} from './config.js';
import {
storage,
storage_constants
} from "./StorageUtil.js"
import * as util from "./BaseUtil.js"
export default {
extends: Store,
data() {},
methods: {
initMusic() {
let audioPlayer = null;
/* #ifdef H5 */
audioPlayer = uni.createInnerAudioContext();
/* #endif */
/* #ifdef APP-PLUS */
audioPlayer = uni.getBackgroundAudioManager();
/* #endif */
audioPlayer.autoplay = false;
audioPlayer.onTimeUpdate((e) => {
this.setPlaySeconds(audioPlayer.currentTime);
let progress = (audioPlayer.currentTime / audioPlayer.duration) * 100;
if (progress) {
this.setProgress(progress);
}
this.updateLrc(false);
});
audioPlayer.onCanplay(() => {
this.setMusicIsReady(true);
})
audioPlayer.onError(()=>{
util.showToast('播放错误,即将播放下一首');
this.next();
})
audioPlayer.onEnded(() => {
if (playModeConfig.single.id == this.playMode.id) {
this.setMusic(this.playIndex, null, () => {
this.play();
this.setPlayState(true);
});
} else if (playModeConfig.random.id == this.playMode.id) {
const index = parseInt((this.playList.length - 1) * Math.random())
this.setMusic(index, null, () => {
this.play();
this.setPlayState(true);
});
} else {
this.next();
}
})
Vue.prototype.audioPlayer = audioPlayer;
Vue.prototype.prev = this.prev;
Vue.prototype.next = this.next;
Vue.prototype.stop = this.stop;
Vue.prototype.pause = this.pause;
Vue.prototype.play = this.play;
Vue.prototype.loadLrc = this.loadLrc;
Vue.prototype.setMusic = this.setMusic;
// Vue.prototype.getMusicPlayUrl = this.musicApi.getPlayUrl;
// Vue.prototype.getLrc = this.musicApi.getLrc;
// Vue.prototype.getMusicOtherInfo = this.musicApi.getMusicOtherInfo
const playMode = storage.get(storage_constants.playMode);
if (!playMode) {
this.setPlayMode(playModeConfig.list);
}
const mySongList = storage.getArrayDefault(storage_constants.mySongList, []);
/**
* 初始化歌词
*/
if (this.playList && this.playIndex >= 0) {
let music = this.playList[this.playIndex];
if (music) {
this.loadLrc(music, () => {
this.updateLrc(true);
});
}
}
},
/**
* 设置音乐
* @param {Object} index
* @param {type} progress
* @param {Object} call
*/
setMusic(index, progress, call) {
if (this.playList && this.playList.length > 0) {
if (index == null) {
index = 0
}
// 停止播放
this.audioPlayer.stop();
// 更新播放状态
this.setPlayState(false);
if (progress) {
// 重置进度条
this.setProgress(progress.progress || 0)
// 重置播放秒数
this.setPlaySeconds(progress.playSeconds || 0)
} else {
// 重置进度条
this.setProgress(0)
// 重置播放秒数
this.setPlaySeconds(0)
}
// 重置总秒数
this.setTotalSeconds(0)
// 音乐状态为未准备
this.setMusicIsReady(false)
let music = this.playList[index];
/* this.getMusicOtherInfo(music,(musicOtherInfo)=>{
music = musicOtherInfo;
}) */
const oldPlayMusic = this.playList[this.playIndex];
if (!util.objEquals(oldPlayMusic, music)) {
// 重置歌词
this.setLrcs([{
time: '[00:00.00]',
content: '歌词加载中'
}]);
this.setLrc({
time: '[00:00.00]',
content: '歌词加载中'
})
}
this.setPlayIndex(index);
// 加载歌词
this.loadLrc(music);
// 获取播放地址
Vue.prototype.getMusicPlayUrl && Vue.prototype.getMusicPlayUrl(music).then(playUrl => {
console.log(`播放地址:${playUrl}`)
this.audioPlayer.src = playUrl;
this.audioPlayer.title = music.name;
this.audioPlayer.singer = music.singer;
this.audioPlayer.coverImgUrl = music.coverImg;
let timer = setInterval(() => {
if (this.musicIsReady) {
this.setTotalSeconds(this.audioPlayer.duration)
if (this.playSeconds > 0) {
this.audioPlayer.seek(this.playSeconds)
}
this.setMusicIsReady(false)
clearInterval(timer);
if (call) {
call();
}
}
}, 200);
})
}
},
getMusicOtherInfo(music, call) {
if (music.loadOtherInfo) {
Vue.prototype.getMusicOtherInfo && Vue.prototype.getMusicOtherInfo(music).then(musicResult => {
call(musicResult)
})
}
},
/**
* 加载歌词
*/
loadLrc(music, call) {
Vue.prototype.getLrc && Vue.prototype.getLrc(music).then(lrcStr => {
if (lrcStr) {
this.setLrcStr(lrcStr)
if (call) {
call();
}
} else {
this.setLrcStr('[00:00.00]无歌词')
}
})
},
/**
* 更新当前歌词
* @param {Object} isInit
*/
updateLrc(isInit) {
if (this.lrcs) {
const sec = parseInt(this.playSeconds);
let index = sec + 1;
let line = this.lrcs[index];
if (line) {
this.setLrc(line);
} else {
if (isInit) {
for (var i = index; i >= 0; i--) {
let initLine = this.lrcs[i];
if (initLine) {
this.setLrc(initLine);
break;
}
}
}
}
}
},
/**
* 播放
*/
play() {
this.audioPlayer.play();
this.setPlayState(true);
const music = this.playList[this.playIndex];
this.pushRecentlyPlayList(music);
},
/**
* 暂停
*/
pause() {
this.audioPlayer.pause();
this.setPlayState(false);
},
/**
* 停止
*/
stop() {
this.audioPlayer.stop();
this.setPlayState(false);
this.setProgress(0);
this.setPlaySeconds(0)
},
/**
* 下一曲
*/
next() {
const length = this.playList.length;
let index = -1;
if (this.playIndex == length - 1) {
index = 0;
} else {
index = this.playIndex + 1;
}
this.setMusic(index, null, () => {
this.play();
this.setPlayState(true);
});
},
/**
* 上一曲
*/
prev() {
const length = this.playList.length;
let index = this.playIndex;
if (index == 0) {
index = length - 1;
} else {
index = index - 1;
}
this.setMusic(index, null, () => {
this.play();
this.setPlayState(true);
});
},
pushRecentlyPlayList(music){
let recentlyPlayList = storage.getArrayDefault(storage_constants.recentlyPlayList, []);
let index = util.findIndex(recentlyPlayList,music);
if(index >= 0){
recentlyPlayList.splice(index,1)
}
recentlyPlayList.splice(0,0,music)
this.setRecentlyPlayList(recentlyPlayList);
this.$forceUpdate()
}
}
}
+70
View File
@@ -0,0 +1,70 @@
/* #ifdef H5 */
const bgAudioManager = uni.createInnerAudioContext();
/* #endif */
/* #ifdef APP-PLUS */
const bgAudioManager = uni.getBackgroundAudioManager();
/* #endif */
bgAudioManager.autoplay = false;
function initPlayer(that){
if(that.currentPlaySong){
that.$u.vuex("currentPlayer",{
playState:false,
progress:0,
musicId:that.currentPlaySong.id,
});
bgAudioManager.title = that.currentPlaySong.songName;
bgAudioManager.singer = that.currentPlaySong.artist;
bgAudioManager.coverImgUrl = that.currentPlaySong.pic;
bgAudioManager.src = that.currentPlaySong.playSrc;
console.log("播放器初始化完成");
bindOnControllerPlay(that);
}
}
function bindOnControllerPlay(that){
let playState=that.currentPlayer.playState;
console.log("that.currentPlayer.progress",that.currentPlayer.progress);
if(playState){
bgAudioManager.pause();
}else{
if(that.currentPlayer.canPlay==false){
initPlayer(that);
return;
}else{
bgAudioManager.play();
that.$u.vuex("currentPlayer.canPlay",true);
}
}
playState=!playState;
console.log("当前播放状态===",playState);
that.$u.vuex("currentPlayer.playState",playState);
that.$u.vuex("currentPlayer.canPlay",true);
bgAudioManager.onTimeUpdate((e) => {
let progress = (bgAudioManager.currentTime / bgAudioManager.duration) * 100;
if (progress) {
that.$u.vuex("currentPlayer.progress",progress);
}
});
bgAudioManager.onError(()=>{
resetPlayer(that);
});
bgAudioManager.onEnded(() => {
resetPlayer(that);
});
}
function resetPlayer(that,player){
bgAudioManager.stop();
that.$u.vuex("currentPlayer.playState",false);
that.$u.vuex("currentPlayer.progress",0);
that.$u.vuex("currentPlayer.canPlay",false);
}
module.exports = {
initPlayer,
bindOnControllerPlay,
resetPlayer,
bgAudioManager
}
+88
View File
@@ -0,0 +1,88 @@
import {
mapState,
mapMutations
} from 'vuex'
import * as util from './BaseUtil.js'
export default {
computed: {
...mapState(['totalSeconds', 'totalDuration', 'playSeconds', 'playDuration', 'progress', 'playState',
'playMode', 'musicIsReady', 'playList', 'playIndex', 'lrcStr', 'lrcs', 'lrc', 'recentlyPlayList'
]),
...mapState(['paramSongList', 'isFirstRun', 'showPlayBar'])
},
methods: {
...mapMutations(['setPlayIndex', 'setTotalSeconds', 'setPlaySeconds', 'setProgress', 'setPlayState',
'setPlayMode', 'setMusicIsReady', 'setPlayList', 'setLrcStr', 'setLrcs', 'setLrc', 'setRecentlyPlayList'
]),
...mapMutations(['setParamSongList', 'setIsFirstRun', 'setShowPlayBar']),
like(music) {
this.songListService.like(music)
this.$forceUpdate();
},
unLike(music) {
this.songListService.unLike(music);
this.$forceUpdate();
},
isLike(music) {
return this.musicService.isLike(music);
},
controllerPlay(type) {
if (type == 'play') {
if (this.playState) {
this.pause();
} else {
if (this.isFirstRun) {
const progress = {
progress: this.progress,
playSeconds: this.playSeconds
}
this.setMusic(this.playIndex, progress, () => {
this.play();
})
} else {
this.play();
}
}
} else if (type == 'next') {
this.next();
} else if (type == 'prev') {
this.prev();
}
},
playMusicByMusic(music) {
let playList = this.playList;
const index = util.findIndex(playList, music);
let playIndex = null;
if (index == -1) {
playList.push(music);
this.setPlayList(playList);
playIndex = playList.length - 1;
} else {
playIndex = index;
}
this.setMusic(playIndex, null, () => {
this.play();
})
},
nextPlay(music) {
const playIndex = this.playIndex;
let playList = this.playList;
const musicIndex = util.findIndex(playList, music);
if (musicIndex != -1) {
if (playList.length - 1 == playIndex) {
playList.push(music);
} else {
let index = playIndex + 1;
playList[musicIndex] = playList.splice(index, 1, playList[musicIndex])[0];
}
} else {
const index = playIndex + 1;
playList.splice(index, 0, music);
}
this.setPlayList(playList);
}
}
}