uni-app中实现音乐播放器

这篇具有很好参考价值的文章主要介绍了uni-app中实现音乐播放器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

uni-app中实现音乐播放器

1、主要利用的是uni-app中提供的uni.createInnerAudioContext()来进行实现;

2、代码示例

(1)主页面代码展示

<template>
  <view class="music-layout">
    <view class="tn-flex">
      <view class="left-content">
        <view class="left-pic-layout">
          <img :src="bgUrl" :class="isPlay ? 'img-rotate' : ''">
          <view class="small-circle"></view>
        </view>
        <view class="like-layout">
          <text class="tn-icon-like-fill" v-if="musicDetail.liked" @click="onLikeMusic(false, musicDetail)"></text>
          <text class="tn-icon-like" v-else @click="onLikeMusic(true, musicDetail)"></text>
        </view>
      </view>
      <view class="right-content">
        <view class="song-name-layout">
          <view>{{ musicDetail.bsmb002 }}</view>
          <view v-if="isPlay"><PlayerAnimation></PlayerAnimation></view>
        </view>
        <view class="progress-layout">
          <text>{{ formatTime(musicCurrentTime) }}</text>
          <tn-slider
              :min="0"
              :max="musicTotalTime"
              class="progress"
              v-model="musicCurrentTime"
              inactiveColor="#EAEAEA"
              activeColor="#FF3370"
              :blockWidth="1"
              :lineHeight="4">
          </tn-slider>
          <text>{{formatTime(musicTotalTime)}}</text>
        </view>
        <view class="actions-layout">
          <view class="toggle-type-layout" @click="handleToggleType">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-black-icon.png" v-if="toggleType == 1" >
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-black-icon.png" v-else-if="toggleType == 2">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-black-icon.png" v-else>
          </view>
          <view class="action-center">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/previous-icon.png" class="previous-icon" @click="handlePreviousPlay">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/play-icon.png" v-if="isPlay" class="player-icon" @click="handlePlay(false)">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/stop-icon.png" v-else class="player-icon" @click="handlePlay(true)">
            <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/next-icon.png" class="next-icon" @click="handleNextPlay">
          </view>
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/music-list.png" class="music-list-icon" @click="handleMusicListShow">
        </view>
      </view>
    </view>
    <view class="add-music" @click="handleAddWisk">
      点这里添加您的音乐心愿单~
    </view>
  </view>
</template>

<script>

import { formatTime } from '@/utils/util'; // 代码在下方对应文件中
import PlayerAnimation from "../../../components/player-animation/player-animation.vue"; // 播放效果动画(代码在下方对应文件中)
import { musicList, saveCollect, cancleCollect } from "@/api/fetusMovement"; // 接口
import { mediaUrl } from '@/utils/env'; // 静态资源地址前缀

export default {
  components: {
    PlayerAnimation
  },
  data() {
    return {
      isPlay: false, // 是否播放
      toggleType: 1, // 播放顺序 (1:循环;2:单曲循环;3:随机)
      musicDetail : { }, // 音乐详情
      current: null, // 当前播放的是哪首
      currentSrc: '', // 当前音乐路径
      musicPlayCtx: null, // 音频上下文
      musicCurrentTime: 0, // 音乐当前播放进度
      musicTotalTime: 100, // 音乐总的时间
      musicList: [], // 音乐列表
      bgUrl: 'http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/tjyy_bg.png',
      timers: null,
      openId: ''
    }
  },
  watch: {
    currentSrc: {
      handler() {
        if(this.musicPlayCtx) {
          this.musicPlayCtx.destroy();
        }
        this.musicPlayCtx = uni.createInnerAudioContext();
        this.musicPlayCtx.obeyMuteSwitch = false;
        this.musicCurrentTime = 0;
        this.musicPlayCtx.src = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        this.musicTotalTime = this.musicDetail.bsmb009;
        if(this.isPlay){
          this.handleAudioPlay();
        }
      },
      immediate: true,
      deep: true,
    }
  },
  mounted() {
    this.openId = getApp().globalData.openId;
    this.getMusicList();
  },
  methods: {
    // 打开音乐列表
    getMusicList() {
      musicList(this.openId).then(res => {
        if (res.success) {
          this.musicList = res.result;
          this.current = 0;
          this.musicDetail = this.musicList[this.current];
          this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        }
      })
    },
    // 播放列表弹窗显示
    handleMusicListShow() {
      const { isPlay, toggleType, musicList, current} = this;
      this.$emit('handleMusicListShow', {
        bool: true,
        isPlay,
        toggleType,
        musicList,
        current
      });
    },
    formatTime,
    // 处理播放
    handlePlay(bool) {
      this.isPlay = bool;
      if(bool) {
        this.musicPlayCtx.seek(this.musicCurrentTime + 1);
        this.handleAudioPlay();
      } else {
        this.musicPlayCtx.stop();
      }
    },
    // 播放
    handleAudioPlay() {
      this.musicPlayCtx.play();
      if(this.timers) {
        clearTimeout(this.timers);
      }
      this.timers = setTimeout(() => {
        console.log(this.musicPlayCtx.paused);
      }, 200);
      // 播放完成
      this.musicPlayCtx.onEnded(() => {
        if(this.toggleType == 1) {
          this.handleNextPlay(); // 列表循环
        } else if(this.toggleType == 2) {
          this.musicPlayCtx.play(); // 单曲循环
        } else {
          this.current = Math.floor(Math.random() * this.musicList.length);
          this.musicDetail = this.musicList[this.current];
          this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        }
      })
      // 更新播放时间
      this.musicPlayCtx.onTimeUpdate(() => {
        this.onTimeUpdate();
      })
      // 播放出现错误
      this.musicPlayCtx.onError(() => {
        this.onError();
      })
    },
    // 下一首
    handleNextPlay() {
      this.isPlay = true;
      if(this.current < this.musicList.length - 1) {
        uni.showToast({
          title: '即将播放下一首',
          icon: 'none'
        })
        this.current ++;
        this.musicDetail = this.musicList[this.current];
        this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        return
      }
      uni.showToast({
        title: '已经为最后一首了',
        icon: 'none'
      })
    },
    // 上一首
    handlePreviousPlay() {
      this.isPlay = true;
      if(this.current) {
        this.current --;
        uni.showToast({
          title: '即将播放上一首',
          icon: 'none'
        })
        this.musicDetail = this.musicList[this.current];
        this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
        return;
      }
      uni.showToast({
        title: '已经为第一首了',
        icon: 'none'
      })
    },
    // 播放类型
    handleToggleType(parmas) {
      if(parmas) {
        this.toggleType = parmas;
        const { isPlay, toggleType, musicList, current} = this;
        this.$emit('handleMusicListShow', {
          bool: true,
          isPlay,
          toggleType,
          musicList,
          current
        });
        return;
      }
      this.toggleType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;
    },
    // 切换音乐
    handleMusicChange(index) {
      this.isPlay = true;
      this.musicDetail = this.musicList[index];
      this.current = index;
      this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);
      this.handleMusicListShow();
    },
    // 加载失败
    onError() {
      uni.showToast({
        title: '音频加载失败',
        icon: 'none'
      })
    },
    // 时间更新
    onTimeUpdate() {
      if (this.musicPlayCtx.currentTime > 0 && this.musicPlayCtx.currentTime <= 1) {
        this.musicCurrentTime = 1;
      } else if (this.musicCurrentTime !== Math.floor(this.musicPlayCtx.currentTime)) {
        this.musicCurrentTime = Math.floor(this.musicPlayCtx.currentTime);
      }
    },
    // 喜欢
    onLikeMusic(bool, item) {
      this.musicDetail.liked = bool;
      if (bool) {
        //收藏
        saveCollect({
          bsmId: item.id,
          openId: this.openId
        }).then(res => {
          if (res.success) {
            uni.showToast({
              title: '收藏成功',
              icon: 'none'
            })
            this.getMusicList()
          }
        })
      } else {
        //取消收藏
        cancleCollect({
          bsmId: item.id,
          openId: this.openId,
          id: item.collectId
        }).then(res => {
          if (res.success) {
            uni.showToast({
              title: '已取消收藏',
              icon: 'none'
            })
            this.getMusicList()
          }
        })
      }
    },
    // 心愿歌单
    handleAddWisk() {
      uni.navigateTo({
        url: '/toolsPages/fetusMovement/addWish'
      })
    }
  },
  // 销毁
  destroyed() {
    if(this.musicPlayCtx) this.musicPlayCtx.destroy();
    if(this.timers) clearTimeout(this.timers);
  }
}
</script>

<style scoped lang="scss">

.music-layout {
  position: relative;
  width: 690rpx;
  padding: 20rpx 30rpx;
  background: #FFFFFF;
  border-radius: 30rpx;
  backdrop-filter: blur(16px);
}

.left-content {
  width: 130rpx;
  .like-layout {
    margin-top: 20rpx;
    > text {
      color: #FF3370;
      font-size: 40rpx;
    }
  }
}

.left-pic-layout {
  position: relative;
  width: 100rpx;
  height: 100rpx;
  border-radius: 50%;
  overflow: hidden;
  img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
  }
  .small-circle{
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 20rpx;
    height: 20rpx;
    background-color: white;
    border-radius: 50%;
  }
}

.right-content {
  flex: 1;
  margin-left: 30rpx;
}

.song-name-layout {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 32rpx;
  color: #323A59;
  line-height: 40rpx;
  height: 40rpx;
  text {
    color: rgba(115, 121, 141, 1);
  }
}

.progress-layout {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 25rpx 0 0 2rpx;
  font-size: 26rpx;
  color: #73798D;
  line-height: 36rpx;
  .progress {
    display: flex;
    align-items: center;
    flex: 1;
    margin: 0 20rpx;
  }
}

.actions-layout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 25rpx 0 0 4rpx;
  .toggle-type-layout {
    > img {
      width: 30rpx;
      height: 26rpx;
    }
  }

  .action-center {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex: 1;
    margin: 0 86rpx;
  }

  .previous-icon, .next-icon {
    width: 30rpx;
    height: 32rpx;
  }

  .player-icon {
    width: 42rpx;
    height: 42rpx;
  }

  .music-list-icon {
    width: 30rpx;
    height: 30rpx;
  }
}

.img-rotate {
  transform-origin: center center;
  animation: rotate 5s infinite linear; /* 实现旋转动画效果 */
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.add-music {
  margin-top: 20rpx;
  text-align: center;
  font-size: 20rpx;
  color: #999999;
  text-decoration: underline #999999;
}
</style>

(2)utils中util.js文件代码

function fixedZero(val) {
    return val * 1 < 10 ? `0${val}` : val;
}

const formatTime = (time) =>  {
    const minutes = 60;
    const m = Math.floor(time / minutes);
    const s = Math.floor(time % 60);
    return `${fixedZero(m)}:${fixedZero(s)}`;
}

(3)components中player-animation文件夹player-animation.vue文件代码

<template>
    <view class="loading">
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
      <view class="item"></view>
    </view>
</template>

<script>
export default {
  name: "player-animation"
}
</script>

<style scoped>
/* 设置位置 */
.loading {
  height: 24rpx;
  display: flex;
  align-items: center;
}

.item {
  height: 24rpx;
  width: 2rpx;
  background: #FF3370;
  margin: 0 3rpx;
  border-radius: 10rpx;
  animation: loading 2s infinite;
}

/* 设置动画 */
@keyframes loading {
  0% {
    height: 0;
  }

  50% {
    height: 24rpx;
  }

  100% {
    height: 0;
  }
}

/* 为每一个竖条设置延时 */
.item:nth-child(2) {
  animation-delay: 0.2s;
}

.item:nth-child(3) {
  animation-delay: 0.4s;
}

.item:nth-child(4) {
  animation-delay: 0.6s;
}

.item:nth-child(5) {
  animation-delay: 0.8s;
}

</style>

(4)播放器列表弹窗代码

<template>
  <tn-popup v-model="show"
            safeAreaInsetBottom
            mode="bottom"
            height="1200rpx"
            @close="handleClose">
    <view class="music-container">
      <view class="header-layout">
        <view class="header-left">
          胎教音乐列表<text>({{ musicLst.length }}首)</text>
        </view>
        <view class="header-right" @click="() => handleToggle()">
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-icon.png" v-if="toggleType == 1" >
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-icon.png" v-else-if="toggleType == 2">
          <img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-icon.png" v-else>
          顺序播放
        </view>
      </view>
      <scroll-view scroll-y style="height: 1050rpx;">
        <view class="music-list">
          <view :class="['music-item', current  == index && isPlay ? 'active' : '']"
                v-for="(item, index) in musicLst"
                :key="index"
                @click="handleItemClick(index)">
            <view class="name">{{item.bsmb002}}</view>
            <PlayerAnimation v-if="current == index && isPlay"></PlayerAnimation>
          </view>
        </view>
      </scroll-view>
    </view>
  </tn-popup>

</template>

<script>
import PlayerAnimation from "../../../components/player-animation/player-animation.vue";
export default {
  props: {
    musicLst : {
      type: Array,
      default: []
    },
    current: {
      type: Number,
      default: 0
    },
    toggleType:{
      type:Number,
      default: 1
    },
    isPlay:{
      type:Boolean,
      default: false
    }
  },
  components: {
    PlayerAnimation
  },
  data() {
    return {
      show: false
    }
  },
  methods: {
    // 切换歌曲
    handleItemClick(index) {
      this.$emit('handleMusicChange', index);
    },
    // 关闭
    handleClose() {
      this.show = false;
    },
    // 播放类型切换
    handleToggle() {
      const playType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;
      this.$emit('handleToggleType', playType);
    },
  }
}
</script>

<style scoped lang="scss">
.music-container {
  padding: 0 30rpx 0;
  .header-layout {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 10rpx;
    height: 90rpx;
  }
  .header-left {
    display: flex;
    align-items: center;
    font-size: 32rpx;
    font-weight: 500;
    color: #333333;
    line-height: 44rpx;
    text {
      font-size: 24rpx;
      font-weight: 400;
      color: #666666;
      line-height: 34rpx;
    }
  }
  .header-right {
    display: flex;
    align-items: center;
    height: 56rpx;
    background: linear-gradient(135deg, #FF74A2 0%, #FF3370 100%);
    border-radius: 28rpx;
    padding: 0 12rpx;
    font-size: 26rpx;
    color: white;
    img {
      margin-right: 10rpx;
      width: 26rpx;
      height: 26rpx;
    }
  }
}

.music-list {
  font-size: 28rpx;
  color: #333333;
  line-height: 40rpx;

  .music-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 0;
    font-size: 28rpx;
    color: #333333;
    line-height: 40rpx;
  }
}

.active {
  color: #FF3370;
}

</style>

3、实现也面向效果展示

(1)播放器
uni-app中实现音乐播放器,uni-app
(2)播放器弹窗
uni-app中实现音乐播放器,uni-app
4、实现该功能过程所遇到的问题总结

(1)当一首歌曲播完之后,进度条不更新问题,在网上查看到的方法都是说:该问题是存在的一个bug,解决的方案是我们再代码中要主动的调用paused()方法

this.timers = setTimeout(() => {
    console.log(this.musicPlayCtx.paused);
}, 200);

(2)当点击暂停播放后,音乐从头播放的问题,解决方案:利用seek()方法使其跳转到指定位置

 this.musicPlayCtx.seek(this.musicCurrentTime + 1);

(3)音乐播放器的地址,含有中文名称,在模拟器上面可以正常播放,手机上面不可以,解决方案:需要将该地址进行编码,编译成编译器可以识别地址

this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);

5、以上代码可以直接粘贴复制到项目即可使用文章来源地址https://www.toymoban.com/news/detail-790737.html

到了这里,关于uni-app中实现音乐播放器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • APP推荐:推荐一款免费无广告的本地音乐播放器,手机听歌必备

    目录 一、软件简介 二、软件特色 三、软件使用 四、软件下载 相信很多朋友都喜欢听歌,今天给大家推荐一款非常棒的手机本地音乐APP——糖醋音乐,完全无广告、免费听歌,大家只需要把自己需要的歌曲下载到你的手机就可以愉快的听歌了,并且不需要手机联网省点、省

    2024年02月05日
    浏览(45)
  • Android 音乐播放器

    ◼ 音乐播放器 . ◼ 要求 : Activity 编程、 ListView 编程、 SeekBar 编程、 ExoPlayer 编程( 播放 、 暂停 、 停止 、 上一首 、 下一首 ),音乐文件放在 assets/music 目录下,界面自拟. ◼ 期望最终效果: ◼ 分别对应 activity_music_list.xml 、 activity_my_music_player.xml 的视图. ◼ 点击列表任

    2024年02月03日
    浏览(55)
  • 开源音乐播放器!

    导读 音乐是生活的一部分。维基百科关于音乐发展历史的文章有这样一段不错的描述说:“全世界所有的人们,包括哪怕是最孤立、与世隔绝的部落,都会有自己的特色音乐……”好吧,我们开源人就构成了一个部落。我建议我们的“音乐形式”应该包括开源音乐播放器。

    2024年02月08日
    浏览(39)
  • FPGA开发:音乐播放器

    相关阅读  FPGA开发专栏 https://blog.csdn.net/weixin_45791458/category_12388695.html?spm=1001.2014.3001.5482         FPGA开发板上的蜂鸣器可以用来播放音乐,只需要控制蜂鸣器信号的方波频率、占空比和持续时间即可。         简谱上的4/4表示该简谱以4分音符为一拍,每小节4拍,简谱上应该

    2024年02月14日
    浏览(38)
  • 学习笔记(1)——粤嵌gec6818实现电子相册,音乐播放器,视频播放器。

    (1)设计一个初始界面,并且设置电子相册,音乐播放器,视频播放器三个触摸按键。 (2)电子相册——能够实现相册的幻灯片功能,实现相册左右滑动切换相片。 (3)音乐播放器实现——切歌,播放和暂停功能。 (4)视频播放器实现——播放、暂停、音量大小、快进倒

    2024年02月11日
    浏览(57)
  • STM32之音乐播放器

    CPU: STM32F103ZE 屏幕: 3.5寸TFTLCD屏 音频解码器: VS1053 SD卡、外扩Sram   VS1053b 是单片 Ogg Vorbis/MP3/AAC/WMA/MIDI 音频解码器,及 IMA ADPCM 编码器和用户加载的 OggVorbis 编码器。   支持: MP3/WMA/OGG/WAV/FLAC/MIDI/AAC 等音频格式的解码,并支持: OGG/WAV 音频格式的录音,支持高低音调节

    2023年04月09日
    浏览(34)
  • QT 离线音乐播放器

            今天刚做完一个简单的智能家居项目,里面包含了一个比较简单的音乐播放器,为了加深一下对这个东西印象,所以把操作流程以及一些用到的类和方法记录一下。 目录 1.UI界面制作 2.加入播放器类 3.播放器初始化 4.功能控件         4.1 播放、暂停、切换歌曲    

    2023年04月24日
    浏览(39)
  • Python轻松实现音乐播放器

    来个新玩意就是教大家如何用python来制作一个音乐播放器 希望对大家有所帮助哈哈 你们也可以尝试自己做做 先给你们展示展示最简单的,只需要九行代码 知识点和所需模块 python基础知识 requests库 time pygame tkinter 线程 环境 windows pycharm 2021.2 python 3.8 ok,直接说上完整代码 !

    2024年02月11日
    浏览(50)
  • 微信小程序--音乐播放器

    说明: 这个项目旨在练习组件以及页面的设计。页面和交互的实现可能有多种方式,这里只为了对组件和项目的结构进行熟悉了解。后续会有更加完善的项目。 由于涉及到mp3外链导入音乐,预览二维码在外链失效时会出错,这里不放预览二维码了;另预览二维码存在有效时

    2024年02月09日
    浏览(42)
  • .netcore音乐播放器 musicPlayer

    html音乐播放器 .net core mvc 音乐播放器 支持上传本地音乐到云端 支持通过文件夹创建歌单(不需要数据库和其他数据存储) 通过歌单分类 播放歌曲 支持播放暂停 上一首 下一首切换 支持显示歌曲列表 歌单切换 展示歌曲根据歌单名去获取歌曲显示 功能 版权原因 或者想创建自己

    2024年02月20日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包