微信小程序---简约音乐播放器

此设计界面比较简陋,请大家海涵。针对初学者的布局与js的结合用法

一、项目效果图:

(1)音乐播放页面

在这里插入图片描述

(2)播放器页面

在这里插入图片描述

(3)播放列表

在这里插入图片描述

(4)文件的创建

在这里插入图片描述

二、WXML的标签运用

(1)标签内容

1.运用到了view、swiper(滑块视图容器)、swiper-item、include(跳转到自己的页面)、image(放置图片)、block(占位符)、slider(滑动选择)、scroll-view(可滚动视图区域)等标签。理解所涉及标签的方法和属性。

(2)代码区域

1.index.wxml

<!-- 上导航部分 -->
<view class="tab">
  <view class="tab-item {{tab==0?'active':''}}" bindtap="changeitem" data-item="0">音乐播放</view>
  <view class="tab-item {{tab==1?'active':''}}" bindtap="changeitem" data-item="1">播放器</view>
  <view class="tab-item {{tab==2?'active':''}}" bindtap="changeitem" data-item="2">播放列表</view>
</view>
<!-- 内容 -->
<view class="content">
<!-- 滑块视图容器 current当前所在滑块的 index-->
  <swiper current="{{item}}" bindchange="changetab">
    <swiper-item>
    <!-- 跳转当前自己的文件 -->
      <include src="info.wxml"></include>
    </swiper-item>
    <swiper-item>
      <include src="play.wxml"></include>
    </swiper-item>
    <swiper-item>
      <include src="playlist.wxml"></include>
    </swiper-item>
  </swiper>
</view>
<!-- 音乐导航底部 -->
<view class="player">
  <image class="player-cover" src="{{play.coverImgUrl}}" />
  <view class="player-info">
    <view class="player-info-title">{{play.title}}</view>
    <view class="player-info-singer">{{play.singer}}</view>
  </view>
  <view class="player-controls">
    <!-- 切换到播放列表 -->
    <image src="http://localhost:3000/images/16.png" bindtap="changePage" data-page="2" />
    <!-- 播放或暂停 -->
    <image wx:if="{{state=='paused'}}" src="http://localhost:3000/images/17.png" bindtap="play" />
    <image wx:else src="http://localhost:3000/images/19.png" bindtap="pause" />
    <!-- 下一曲 -->
    <image src="http://localhost:3000/images/18.png" bindtap="next" />
  </view>
</view>

2.info.wxml

<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}" wx:key="unique">
    <swiper-item>
        <image src="{{item}}" class="slide-imge" style="width: 100%;"></image>
    </swiper-item>
</block>
</swiper>

<view class="content-info-portal">
    <view>
        <image src="http://localhost:3000/images/22.png"></image>
        <text>私人FM</text>
    </view>
    <view>
        <image src="http://localhost:3000/images/20.png"></image>
        <text>每日歌曲推荐</text>
    </view>
    <view>
        <image src="http://localhost:3000/images/21.png"></image>
        <text>云音乐新歌榜</text>
    </view>
</view>
<view class="content-info-list">
    <view class="list-title">推荐歌曲</view>
    <view class="list-inner">
    <view class="list-item">
        <image src="http://localhost:3000/images/05.png"></image><view>流行--歌曲</view>
    </view>
    <view class="list-item">
        <image src="http://localhost:3000/images/06.png"></image><view>经典--歌曲</view>
    </view>
    <view class="list-item">
        <image src="http://localhost:3000/images/07.png"></image><view>民谣--歌曲</view>
    </view>
    <view class="list-item">
        <image src="http://localhost:3000/images/08.png"></image><view>火爆--歌曲</view>
    </view>
    <view class="list-item">
        <image src="http://localhost:3000/images/09.png"></image><view>翻唱--歌曲</view>
    </view>
    <view class="list-item">
        <image src="http://localhost:3000/images/10.png"></image><view>温情--歌曲</view>
    </view>
    </view>
</view>

3.play.wxml

<view class="content-play">
    <!-- 显示音乐信息 -->
    <view class="content-play-info">
        <text>{{play.title}}</text>
        <view>--{{play.singer}}--</view>
    </view>
    <!-- 专题封皮 -->
    <view class="content-play-cover">
        <image src="{{play.coverImgeUrl}}" style="animation-play-state: {{stata}};"></image>
    </view>
    <view class="content-play-progress"></view>
<!-- 播放进度和时间 -->
<view class="content-play-progress">
    <text>{{play.currentTime}}</text>
    <view>
    <!-- 滑动选择器 -->
    <slider bindtap="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#dadada" value="{{play.percent}}"></slider>
    </view>
    <text>{{play.duration}}</text>
</view>
</view>

4.playlist.wxml

<scroll-view class="content-playlist" scroll-y>
  <view class="playlist-item" wx:for="{{playlist}}" wx:key="id" bindtap="change" data-index="{{index}}">
    <image class="playlist-cover" src="{{item.coverImgeUrl}}" />
    <view class="playlist-info">
      <view class="playlist-info-title">{{item.title}}</view>
      <view class="playlist-info-singer">{{item.singer}}</view>
    </view>
    <view class="playlist-controls">
      <text wx:if="{{index==playIndex}}">正在播放</text>
    </view>
  </view>
</scroll-view>

三、WXSS的运用

(1)需要注意样式设置

  • display: flex;-----弹性盒子:水平的主轴(main axis)和垂直的交叉轴(cross axis)
  • flex-direction:[row\column]-----代表排列方向, 决定主轴的方向:
    flex-direction:row // 表示从左到右排列
    flex-direction:row-reverse // 表示从右到左排列
    flex-direction:column //表示从上到下排列
    flex-direction:column-reverse //表示从下到上排列
  • flex-wrap:wrap;-----换行后,使其间距相等
  • justify-content: space-around;-----让排布均匀分布
  • animation: musicStart 0.2s linear forwards;-----动画对象:让其以0.2秒的速度匀速动画
  • @keyframes ------创建动画

(2)代码区域

page{
  display: flex;
  flex-direction: column;
  background: #141b10;
  color: #ccc;
  height: 100%;
}
.tab{
    /* r让他变成伸缩盒子 */
  display: flex;
}
.tab-item{
  flex: 1;
  font-size: 10pt;
  text-align: center;
  line-height: 72rpx;
  height: 72rpx;
  border-bottom: 6rpx solid #eee;
}
/* 激活当前选项 */
.tab-item.active{
  color: #c25b5b;
  border-bottom-color:#c25b5b;
}
.content{
  flex: 1;
}
.content > swiper{
    /* 宽度给其自适应 */
  height: 100%;
}
.player{
  background: #222;
  border-top: 2rpx solid #252525;
  height: 112rpx;
}
.slide-image{
  width: 100%;
  height: 100%;
}
.content-slide-imge{
  height: 30rpx;
  margin-bottom: auto;
}

.content-info-portal{
  display: flex;
  margin-bottom: 15px;
}
.content-info-portal > view{
  flex: 1;
  font-size: 11pt;
  text-align: center;
}
.content-info-portal image{
  width: 120rpx;
  height: 120rpx;
  display: block;
  margin: 20rpx auto;
}
.content-info-list{
  font-size: 11pt;
  margin-bottom: 20rpx;
}
.content-info-list > .list-title{
  margin: 20rpx 35rpx;
}
.content-info-list > .list-inner{
  display: flex;
  flex-wrap: wrap;
  margin: 0 20rpx;
}
.content-info-list > .list-inner > .list-item{
  flex: 1;
}
.content-info-list > .list-inner > .list-item > image{
  display: block;
  width: 200rpx;
  height: 200rpx;
  margin: 0 auto;
  border-radius: 10rpx;
  border: 1rpx solid #555;
}
.content-info-list > .list-inner > .list-item > view{
  width: 200rpx;
  margin: 10rpx auto;
  font-size: 10pt;
}


/* 音乐导航底部 */
.player {
    display: flex;
    align-items: center;
    background: #222;
    border-top: 1px solid #252525;
    height: 112rpx;
  }
  
  .player-cover {
    width: 100rpx;
    height: 100rpx;
    margin-left: 15rpx;
    border-radius: 8rpx;
    border: 1px solid #333;
  }
  
  .player-info {
    flex: 1;
    font-size: 10pt;
    line-height: 38rpx;
    margin-left: 20rpx;
    padding-bottom: 8rpx;
  }
  
  .player-info-singer {
    color: #888;
  }
  
  .player-controls image {
    width: 80rpx;
    height: 80rpx;
    margin-right: 15rpx;
  }
  


/* 播放器页面样式 */
.content-play{
  display: flex;
  /* 让排布均匀分布 */
  justify-content: space-around;
  /* 决定主轴,从上到下排列 还有一个从左到右row,相反则加-reverse*/
  flex-direction: column;
  height: 100%;
  text-align: center;
}
.content-play-info > view{
  color: #888;
  font-size: 11pt;
}
.content-play-cover image{
  animation: rotateImage 10s linear infinite;
  width: 400rpx;
  height: 400rpx;
  border-radius: 50%;
  border: 1px solid #333;
}
@keyframes rotateImage{
  from{
    transform: rotate(0deg);
  }
  to{
    transform: rotate(360deg);
  }
}
.content-play-progress{
  display: flex;
  align-items: center;
  margin: 0 35rpx;
  font-size: 9pt;
  text-align: center;
}
.content-play-progress > view{
  flex: 1;
}
/* 页面结构 */
.playlist-item{
    display: flex;
    align-items: center;
    border-bottom: 1rpx solid #333;
    height: 112rpx;
}
.playlist-cover{
    width: 80rpx;
    height: 80rpx;
    margin-left: 15rpx;
    border-radius: 8rpx;
    border: 1px solid #333;
}
.playlist-info{
    float: 1px;
    font-size: 10pt;
    line-height: 38rpx;
    margin-left: 20rpx;
    padding-bottom: 8rpx;
}
.playlist-info-singer{
    color: #888;
}
.playlist-controls{
    font-size: 10pt;
    margin-right: 20rpx;
    color: #c25b5b;
}

/* 播放和暂停的效果 */
.player-play > image:first-child{
    animation-play-state: running;
}
.player-play > image:last-child{
    animation: musicStart 0.2s linear forwards;
}
.player-pause > image:first-child{
    animation-play-state: paused;
}
.player-pause > image:last-child{
    animation: musicStop 0.2s linear forwards;
}
@keyframes musicStart{
    from{transform: rotate(0deg);}
    to{transform: rotate(20deg);}
}
@keyframes musicStop{
    from{transform: rotate(20deg);}
    to{transform: rotate(0deg);}
}

四、JS的运用

(1)需要注意js的语句设置

  1. 变量的初始化:

data:{
变量:值
}

  1. 数组的创建:

数组名称:[…]

  1. 绑定事件的创建:

绑定设置的名称:function(){ 方法 }

  1. 获取绑定事件的索引的方法:

绑定设置的名称:function(){
this.setData({ console.log(); })
}

(2)代码区域

// index.js
// 获取应用实例
const app = getApp()

Page({
 data:{
     item:0,
     tab:0,
     isPlayingMusic:false,
     playlist:[
        {
        id:0,title:'钢琴曲',singer:'肖邦',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/11.png'
        },
        {
         id:1,title:'奏鸣曲',singer:'莫扎特',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/12.png'
         },
        {
         id:2,title:'欢乐颂',singer:'贝多芬',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/13.png'
         },
         {
         id:3,title:'爱之梦',singer:'李斯特',src:'http://localhost:3000/images/song.mp3',coverImgeUrl:'http://localhost:3000/images/14.png'
        },
   
   ],
   stata:'paused',
   playIndex:0,
   play:{
      currentTime:'00:00',
      duration:'00:00',
      percent: 0,
      title:'',
      singer:'',
      coverImgeUrl:'http://localhost:3000/images/11.png',
   },

     imgUrls:[
        "http://localhost:3000/images/01.png",
        "http://localhost:3000/images/02.png",
        "http://localhost:3000/images/03.png",
        "http://localhost:3000/images/04.png"
    ],
    indicatorDots:true,
    autoplay:true,
    interval:3000,
    duration:500,
 },
 changeitem(e){
   // 获取点击的索引数据
    this.setData({
        // 给这个item赋值
        item:e.target.dataset.item
    })
 },
 changetab(e){
    this.setData({tab:e.detail.current})
 },

 audioCtx:null,
 onReady:function(){
    //  音乐接口
    this.audioCtx = wx.createInnerAudioContext()
    //调用
    this.setMusic(0)
 },
 setMusic(index){
    var music = this.data.playlist[index]
    this.audioCtx.src = music.src
    this.setData({
       playIndex:index,
       'play.title':music.title,
       'play.singer':music.singer,
       'play.coverImgUrl':music.coverImgeUrl,
       'play.currentTime':'00:00',
       'play.duration':'00:00',
       'play.percent':0
    })
 },
//播放
 play: function(){
    this.audioCtx.play()
    this.setData({ state:'running'})
 },
 //暂停
 pause: function(){
    this.audioCtx.pause()
    this.setData({ state:'paused'})
 },
 next: function(){
    //  如果满足,就等于0,不满足就加一
    var index = this.data.playIndex >= this.data.playlist.length - 1?0: this.data.playIndex + 1
   this.setMusic(index)
   if (this.data.state ==='running'){
      this.play()
   }else{
       this.pause()
   }
 },
 //点击下一曲
 changer:function(e){
     this.setMusic(e.Target.dataset.index)
     this.play()
 },
 
 onReady:function(){
    this.audioCtx = wx.createInnerAudioContext()
    var that = this
   //  播放失败检测
   this.audioCtx.onError(function(){
      console.log('播放失败:'+ that.audioCtx.src)
   })
   // 播放完成自动换下一曲
   this.audioCtx.onEnded(function(){
      thta.next()
   })
   // 自动更新播放进度
   this.audioCtx.onPlay(function(){})
   this.audioCtx.onTimeUpdate(function(){//音乐播放,进度更新就触发
      that.setData({
         'play.duration':formatTime(that.audioCtx.duration),//滑动时间
         'play.currentTime':formatTime(that.audioCtx.currentTime),//总时长
         'play.percent':that.audioCtx.currentTime /
                        that.audioCtx.duration * 100
      })
   })
   //  默认选择第一曲
this.setMusic(0)
   // 格式化时间
   function formatTime(time){
      var minute = Math.floor(time / 60) % 60;
      var second = Math.floor(time) % 60
      return (minute < 10 ? '0' + minute: minute) + ':' +
            (second < 10 ? '0' + second : second)
   }
 },
 //进度条到哪,就播放到哪
sliderChange: function(e){
   var second = e.detail.value * this.audioCtx.duration / 100
   this.audioCtx.seek(second)
},

sliderChanging:function(e){
   console.log(e.detail.value)
},
})

五、音频和图片的导入

(1)node的方法用服务端进行导入

1.如果还不会用node的同学,可以跟一下以下教程:
下载地址与教程:https://nodejs.org/en/download/

  • 18
    点赞
  • 111
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半粒糖₩

对自己有帮助的,在相应文章回复

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值