小程序音乐播放器

在哈瓦纳街头俱乐部小程序中,做过音乐播放器感觉不错,记录一下,项目已经是线上的,大家可以到小程序中搜索 哈瓦纳街头俱乐部,

 

 在这里可以看到实际效果

首先就是说的歌词部分,歌词的时间轴,下图这种格式的歌词,定好歌词的时间轴

 

然后下边就是wxml,js,wxss,注释代码上有,我就不做解释了,直接上代码

<!--homeSub/diy/diy.wxml-->
<import src="/pages/temp/temp.wxml" />
<view class="article  {{appData.screenProp}} flexcc">
    <template is="header" data="{{appData,hideBack}}"  />
    <image class="bg" src="{{appData.imgCDN}}images/music/bg.jpg" mode="widthFix"></image>
    <view class="content">
        <swiper class="swiper" bindchange="bindchange">
            <swiper-item class="song">
                <div class="topBanner">
                    <!-- banner -->
                    <!-- <swiper class="topSwiper" indicator-dots="true" indicator-color="rgba(255,255,255,0.4)" indicator-active-color="rgba(255,184,14,1)">
                        <swiper-item wx:for="{{banner}}" wx:key="*this" style="overflow: visible;"> -->
                            <image class="banner" src="{{appData.imgCDN}}images/music/banner.png{{appData.mathNum}}"></image>
                        <!-- </swiper-item>
                    </swiper> -->
                    <view class="dotss">
                        <view class="dot dot1"></view>
                        <view class="dot dot2"></view>
                    </view>
                    <view class="title">
                        <image class="songName" src="{{appData.imgCDN}}images/music/title.png"></image>
                        <image class="name" src="{{appData.imgCDN}}images/music/name.png{{appData.mathNum}}"></image>
                    </view>
                </div>
            </swiper-item>
            <!-- 歌词 -->
            <swiper-item class="lyric">
                <scroll-view class="musicCode" scroll-y enhanced="{{true}}" bounces="{{false}}" show-scrollbar="{{false}}" scroll-top="{{-updistance}}rpx" scroll-with-animation="{{true}}" binddragstart="catchtouchstart" binddragging="binddragging" binddragend="catchtouchend">
                    <view class="datalist">
                        <view class="music_code {{opacity}}  {{activeIndex == index ? 'cTime' : ''}}" wx:for="{{datalist}}" wx:key="*this">{{item.text}}</view>
                    </view>
                </scroll-view>
            </swiper-item>
        </swiper>
        <!-- 进度条 -->
        <view class="musicMenu">
            <view class="currentTime">{{currentTime}}</view>
            <view class="process">
                <slider value="{{slideTime}}" block-size="14" max="{{processWidth}}" block-color="#fff" activeColor="#ffb80e" backgroundColor="#98a4a5" bindchanging="moveProcess1" bindchange="moveChange" />
            </view>
            <view class="allTime">{{allTime}}</view>
        </view>
        <!-- 重新播放,播放暂停,返回 按钮 -->
        <view class="btnBox">
            <view class="again" catchtap="again" hover-class="noPointer" hover-stay-time="1000"><image class="again_btn" src="{{appData.imgCDN}}images/music/again_btn.png"></image></view>
            <view class="play" catchtap="play" hover-class="noPointer" hover-stay-time="1000">
                <image class="play_btn" src="{{appData.imgCDN}}images/music/play_btn.png" hidden="{{isPlay}}"></image>
                <image class="pause_btn" src="{{appData.imgCDN}}images/music/pause_btn.png" hidden="{{!isPlay}}"></image>
            </view>
            <view class="back" catchtap="goBack1" hover-class="noPointer" hover-stay-time="1000"><image class="back_btn" src="{{appData.imgCDN}}images/music/back_btn.png"></image></view>
        </view>
    </view>
    <!-- TODO -->
</view>
const app = getApp();
const { API, beats, icom,  mtj, regeneratorRuntime, promisify } = app;var Flag = true;   //控制歌词滚动
//-------------------------------------------------------初始化-------------------------------------------------------
let $query;
Page({
    data: {
        appData:app.data,
        bgmPlay: false,
        hideBack:false,
        currentTime: "00:00", //当前播放时间
        processWidth: 244,  // 控制进度条最大长度
        slideTime: 0,  // 控制进度条的长度
        allTime:'',   //音乐总时长
        activeIndex: 0,  // 控制歌词滚动的位置
        updistance: 0,  // 控制歌词容器滚动的距离
        isPlay:false,   //播放按钮状态
        // banner:[
        //     {src:"images/music/banner1.png"},
        //     {src:"images/music/banner1.png"},
        // ],
        datalist: [], //歌词
        musicTime:[], //时间轴数组
        time:0,
    }, //页面的初始数据
    async onLoad(option) {
        wx.showLoading({mask:true})
        $query = option;
        console.log('getQueryString', option);
        await app.initApp();
        this.setData({appData:app.data});
        app.tdsdk("arrive_song","",{
            bloc_id: 'page0000028',
            bloc_desc_ch: '到达歌曲页',
            action:'page'
        });
         wx.hideLoading()
        
    },
    // 获取歌词
    getSong(){
        
        let {allTime} = this.data;
        let that = this;
        that.audioCtx.onCanplay(() => {
            // console.log("监听播放状态")
            that.audioCtx.duration;
            setTimeout(() => {
                allTime = that.s_to_hs(that.audioCtx.duration);
                that.setData({
                    allTime
                })
                console.log(allTime,"============allTime")
            }, 1000)
        })
        // 获取歌词
        wx.request({
            url:  app.data.imgCDN + "music/havana_new.txt",
            data: {},
            header: {
                'content-type': 'application/x-www-form-urlencoded;' // 默认值
            },
            success(obj) {
                // console.log(obj)
                var result = obj.data.split("\n").map(r => {
                    var arr = r.trim().substr(1).split("]");
                    return {
                        time: arr[0],
                        text: arr[1]
                    }
                })
                var musicTime = [];
                for (var i of result) {
                    that.makeDurationToSeconds(i.time)
                    musicTime.push(that.makeDurationToSeconds(i.time));
                }
                // console.log(musicTime)
                that.setData({
                    datalist:result,
                    musicTime
                })
                // 监听音乐暂停
                that.audioCtx.onPause(function(){
                    // console.log("音乐暂停")
                    that.setData({
                        isPlay:false,
                        time:that.audioCtx.currentTime
                    })
                })
                // 监听音乐播放
                that.audioCtx.onPlay(function(){
                    // console.log("音乐播放")
                    that.setData({
                        isPlay:true,
                    })
                    Flag = true;
                })
                // 监听音乐播放
                that.audioCtx.onTimeUpdate(function () {
                    let { activeIndex, updistance, datalist, musicTime, slideTime, currentTime } = that.data
                    currentTime = that.s_to_hs(that.audioCtx.currentTime);
                    // console.log(that.audioCtx.currentTime)
                    slideTime = that.audioCtx.currentTime / that.audioCtx.duration * that.data.processWidth
                    that.setData({
                        currentTime,
                        slideTime
                    })
                    if(Flag){
                        for (var i = activeIndex; i < datalist.length; i++) {
                            if (datalist[i].time === currentTime) {
                                if (activeIndex != i) {
                                    updistance = i * (-50);
                                    that.setData({
                                        activeIndex: i,
                                        updistance
                                    })
                                }
                            }
                        }
                    }
                })
                // 监听 音乐自然播放至结束
                that.audioCtx.onEnded(function(){
                    that.setData({
                        activeIndex: 0,  // 控制歌词滚动的位置
                        updistance: 0,  // 控制歌词容器滚动的距离
                        slideTime: 0,  // 控制进度条的长度
                        currentTime:"00:00",//当前播放时间
                        isPlay:false
                    })
                })
                
                that.audioCtx.play();
                that.setData({
                    isPlay:true
                })
            }
        })
        
    },
    // 重新播放
    again(){
        let that = this;
        that.audioCtx.pause();
        setTimeout(()=>{
            that.setData({
                activeIndex: 0,  // 控制歌词滚动的位置
                updistance: 0,  // 控制歌词容器滚动的距离
                slideTime: 0,  // 控制进度条的长度
                currentTime:"00:00",//当前播放时间
                isPlay:true
            })
            that.audioCtx.seek(0);
            that.audioCtx.play();
        },500)
        // console.log(that.data.slideTime,"=====slideTime")
        // console.log(that.data.currentTime,"=====currentTime")
        // console.log(that.data.updistance,"=====updistance")
    },
    // 开始播放
    play(){
        // this.setData({
        //     updistance:500
        // })
        if(this.data.isPlay){
            this.audioCtx.pause();
            this.setData({
                isPlay:false
            })
        }else{
            this.audioCtx.play();
            this.setData({
                isPlay:true
            })
        }
    },
    bindchange(){
        console.log(Flag,"=================Flag");
        if(this.data.isPlay){
            Flag = true;
        }
    },
    // 拖动进度条过程触发的事件
    moveProcess1(e) {
        let {
            value
        } = e.detail;
        let {
            processWidth,
        } = this.data;
    
        if (value >= processWidth) {
            value = processWidth;
        }
        this.audioCtx.pause();
    },
    // 拖动进度条
    moveChange(e) {
        let {
            value
        } = e.detail;
        let {
            processWidth,
            activeIndex,
            musicTime
        } = this.data;
        let time = value * this.audioCtx.duration / processWidth;
        let stime = this.s_to_hs(time);
        var seconds = this.makeDurationToSeconds(stime)
        this.setData({
            isPlay:true
        })
        var findNum = this.findCloseNum(musicTime, seconds);
        var updistance1;
        for (var i = 0; i < musicTime.length; i++) {
            if (findNum === musicTime[i]) {
                updistance1 = (i - 1) * (-50);
                this.setData({
                    activeIndex: i,
                    updistance:updistance1
                })
            }
        }
        this.audioCtx.seek(time);
        this.audioCtx.play();
    },
    // 当手指按下歌词区域时
    catchtouchstart(){
        // console.log("暂停自动滚动")
            // Flag = false;
            
    },
    // 滚动事件
    binddragging(){
        Flag = false
    },
    // 滑动歌词结束
    catchtouchend(){
        // console.log("开始自动滚动")
        let that = this;
        
        setTimeout(()=>{
            Flag = true
        },2000)
    },
    // 返回
    goBack1() {
        wx.navigateBack()
    },
    onReady: function() {
        
    }, //监听页面初次渲染完成
    onShow: function() {
        if(this.audioCtx){
            this.audioCtx.seek(this.data.time);
            this.audioCtx.play();
            this.setData({
                isPlay:true
            })
        }else{
            this.audioCtx = wx.createInnerAudioContext();
            this.audioCtx.src = app.data.imgCDN + "music/havana_new.mp3";
            this.audioCtx.useWebAudioImplement = true;
            this.getSong();
            wx.setInnerAudioOption({
                obeyMuteSwitch:false
            })
        }
        
    }, //监听页面显示
    onHide: function() {
    }, //监听页面隐藏
    onUnload: function() {
        // console.log(this.audioCtx.duration)
        this.audioCtx.pause();
        this.setData({
            isPlay:false
        })
        // this.audioCtx.destroy();
    }, //监听页面卸载
    onPullDownRefresh: function() {}, //页面相关事件处理函数--监听用户下拉动作
    onReachBottom: function() {}, //页面上拉触底事件的处理函数
    onShareAppMessage: function() { //用户点击右上角分享
        return app.setShareData();
    },
    // 秒转换成分
    s_to_hs(value) {
        let result = parseInt(value)
        let h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
        let m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60))
        let s = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60))
        result = `${m}:${s}`
        return result
    },
   // 百分比
   getPercent(num, total) {
       num = parseFloat(num);
       total = parseFloat(total);
       if (isNaN(num) || isNaN(total)) {
           return "-";
       }
       return total <= 0 ? "0%" : (Math.round(num / total * 10000) / 100.00) + "%";
   },
   // js将格式为00:00:00的时间转换成秒钟
   makeDurationToSeconds(time) {
       var str = time;
       var arr = str.split(':');
       // var hs = parseInt(arr[0] * 3600);
       var ms = parseInt(arr[0] * 60);
       var ss = parseInt(arr[1]);
       var seconds = ms + ss;
       return seconds;
   },
   // js数组中查找与目标函数最相近的数值
   findCloseNum(arr, num) {
       var index = 0; // 保存最接近数值在数组中的索引
       var d_value = Number.MAX_VALUE; // 保存差值绝对值,默认为最大数值
       for (var i = 0; i < arr.length; i++) {
           var new_d_value = Math.abs(arr[i] - num); // 新差值
           if (new_d_value <= d_value) { // 如果新差值绝对值小于等于旧差值绝对值,保存新差值绝对值和索引
               if (new_d_value === d_value && arr[i] < arr[index]) { // 如果数组中两个数值跟目标数值差值一样,取大
                   continue;
               }
               index = i;
               d_value = new_d_value;
           }
       }
       return arr[index] // 返回最接近的数值
   },
}) //end page

//-------------------------------------------------------业务逻辑-------------------------------------------------------
/* homeSub/diy/diy.wxss */
.article{background-color: black;}
.bg{width: 100%;}
.content{width: 100%;height: 100%;position: absolute;top:0;}
.content .swiper{width: 100%;height: 1185rpx;}
.content .swiper .song {overflow: visible;}
.content .swiper .song .topBanner{width: 530rpx;height:551rpx;}
/* .swiper .song .topBanner{width: 100%;height: 620rpx;margin-top: 275rpx;} */
.content .swiper .song .banner{width: 530rpx;height: 551rpx;display: block; margin: 275rpx auto 0;}
.swiper .song .topBanner .dotss{width: 65rpx;height: 30rpx;margin: 15rpx auto 0;display: flex;justify-content: space-around;}
.swiper .song .topBanner .dotss .dot{width: 15rpx;height: 15rpx;border-radius: 50%;background: rgba(255,255,255,0.4);}
.swiper .song .topBanner .dotss .dot1{background: rgba(255,184,14,1);}
.swiper .song .topBanner .title{width: 100%;height: 100rpx;margin-top: 70rpx;}
.swiper .song .topBanner .songName{width: 280rpx;height: 45rpx;display: block;margin: auto;}
.swiper .song .topBanner .name{width: 132rpx;height: 25rpx;display: block;margin: 24rpx auto 0;}
.content .musicMenu {
    width: 680rpx;
    height: 20rpx;
    margin: 80rpx auto 0;
    display: flex;
    align-items: center;
    justify-content: space-around;
}
.content .musicMenu .currentTime {
    font-size: 22rpx;
    color: #fff;
    white-space: nowrap;
}
.content .musicMenu .process {
    width: 560rpx;
}
.content .musicMenu .allTime {
    font-size: 22rpx;
    color: #fff;
    white-space: nowrap;
}
.btnBox{width: 412rpx;height: 127rpx;margin: 44rpx auto 0;display: flex;line-height: 127rpx;justify-content: space-between;}
.btnBox image{width: 100%;height: 100%;}
.btnBox .again{width: 77rpx;height: 78rpx;margin-top: 25rpx;}
.btnBox .play{width: 127rpx;height: 127rpx;}
.btnBox .back{width: 79rpx;height: 78rpx;margin-top: 25rpx;}
.lyric{width: 100%;height: 886rpx;margin: auto;}
.musicCode{width: 95%;height: 886rpx;text-align: center;color: white;margin: 300rpx auto 0;-webkit-mask-image: linear-gradient(to bottom,rgba(255,255,255,0) 0,rgba(255,255,255,.6) 15%,rgba(255,255,255,1) 25%,rgba(255,255,255,1) 75%,rgba(255,255,255,.6) 85%,rgba(255,255,255,0) 100%);}
.musicCode .music_code{height:50rpx; line-height: 50rpx;font-size: 30rpx;letter-spacing: 1rpx;transform: scale(0.9);}
.content .cTime {
    transform: scale(1.1);
    color: #ffb80e;
}
.datalist{padding: 300rpx 0;}
.datalist{transform: translate3d(0);will-change: transform;transition: all 1s;}

.content{transform: scale(.9);transform-origin: top;}
.screen189 .content .musicMenu{margin: 86rpx auto 0;}
.screen189 .btnBox{margin: 55rpx auto 0;}
.screen189 .content{transform: scale(1);}
.screen159 .content{transform: scale(.9);}

 

 滑动歌词手指松开两秒后歌词自动滚动到正在播放的位置,感觉比较复杂的还是定位歌词这一部分,路过的大家觉得有的地方可以优化的,欢迎评论

posted @ 2022-06-30 10:21  橙子汁z  阅读(356)  评论(0编辑  收藏  举报