likes
comments
collection
share

写一个音乐播放器3--歌曲播放进度条与歌词滚动同步

作者站长头像
站长
· 阅读数 72

前言

实现的是拖动或点击进度条,歌词随之滚动到指定位置,做到与歌曲播放同步。

进度条可参考写一个音乐播放器1--歌曲播放进度条歌词滚动可参考写一个音乐播放器2--歌词高亮滚动

实现

采用原生audio来实现歌曲播放

html布局部分

盒子布局依旧与前面一致

  • 采用原生audio来实现音乐播放功能;

  • 进度条主体是由一个类名为progress-bar的父盒子包裹一个类名为blue-bar的子盒子,其中父盒子为底部灰色进度条,子盒子为已播放的蓝色进度条;

  • 类名为circle的span盒子为进度条白色拖拽点cTime为已播放时间,dTime为总时间,采用固定定位。

  • 采用无序列表ulv-for实现歌词布局,一行一句歌词,默认中间行为当前播放歌词,高亮显示它。

<audio ref="player" autoplay ></audio> 

//歌词部分 
<div class="detail">   
    <div class="song-title">     
        <p ref="song">歌名</p>    
        <p ref="singer">歌手</p>   
    </div>   
    <div class="wrapper">    
        <ul ref="ul" class="content">     
            <li v-for="(item,index) of ms" :key=item.index>{{item.c}}</li>   
        </ul>   
    </div> 
</div> 

//进度条 
<div class="bar">   
    <div class="progressbar" @click="playMusic" ref="runfatbar">
        <div class="greenbar" ref="runbar" >   
            <span class="yuan"></span>   
        </div>   
    </div> 
</div>

//时间 
<div class="time-text">{{cTime}}</div> 
<div class="right-time time-text">{{dTime}}</div>

SCSS样式部分

歌词部分
//歌词部分
.detailposition: absolute;   
    top1rem;   
    bottom2.6rem;   
    left0;   
    right0;   
    text-align: center;   
    color#26a2ff;    
    .song-title {    
        width100%;     
        height2rem;  
        p {      
            width100%;       
            line-height: .8rem;       
            font-size18px;       
            color#FFD700;        
            margin-top: .1rem;       
            text-align: center;
        }
    }
    .wrapper {    
        overflow: hidden;     
        position: absolute;     
        top2rem;     
        right0;     
        left0;     
        height545px;
        ul {      
            line-height32px;       
            width100%;       
            padding-bottom1rem; 
            li {        
                font-size16px;         
                transition-duration1200ms;  
            }
            .lineHigh {        
                color#FFD700;
            }
        }
    }
}
进度条部分
//进度条部分 
<style scoped lang="scss">
.bar {
    width80%;   
    height: .3rem;   
    position: fixed;   
    bottom2.5rem;
    margin-left10%;
    .progress-bar {
        width100%;     
        height: .1rem;     
        margin-top: .1rem;     
        border-radius: .2rem;
        background-color#999999;
        .blue-bar {      
            height: .1rem;
            position: absolute;       
            top: .1rem;       
            left0;
            border-radius: .2rem; 
            background-color#1296db;
            .circle {
                width: .2rem;         
                height: .2rem;  
                position: absolute;         
                top: -.05rem;         
                right: -0.01rem;         
                border-radius10px;
                background-color#fff;
            }
        }
    }     
}      
</style>
时间部分
//时间部分
.time {    
    position: fixed;   
    bottom2.5rem;   
    font-size13px;   
    line-height: .5rem; 
}
.all-time {   
    right0;   
}

逻辑部分

这里对每一行进行了解释,便于通篇理解。

data () {     
    return {       
        lineNo0,       
        Cpos7,       
        offset: -32,       
        ms: [],     
        }   
    }, 
    mounted () {     
        const music = this.$refs.player  // 音频所在对象
        const musicBar = this.$refs.runbar  // 颜色进度条所在对象
        const musicWidth = this.$refs.runfatbar.offsetWidth // 底部进度条总宽              // 监听颜色进度条是否触摸拖动结束
        musicBar.addEventListener('touchend'() => {
            const touwidth = (musicBar.offsetWidth / musicWidth) // 计算进度条所在比例
            music.currentTime = music.duration * touwidth // 通过所在比例赋值给音频应在的播放时间
            const ulist = this.$refs.ul
            const list = ulist.getElementsByTagName("li");//获取全部歌词 
            for(var i = 0; i <= this.ms.length; i++) {
                if(parseFloat(this.ms[i].t) <= music.currentTime) {
                // 删除之前的高亮样式与设置当前点击部分高亮样式
                    if(this.lineNo < i) {
                        list[this.lineNo].removeAttribute("class");//去掉上面的高亮样式
                        this.lineNo = i
                        list[this.lineNo].className = "lineHigh";//高亮显示当前行
                        list[this.lineNo-1].removeAttribute("class");//去掉下面的高亮样式
                    }else {
                        this.lineNo = i
                        list[this.lineNo].className = "lineHigh";//高亮显示当前行
                    }                  
                    // 进行播放         
                    music.play()         
                    this.$refs.icon.innerHTML = ("");       
                }       
            }            
        }) 
    }, 
    methods: {     
    // 点击进度条事件     
    playMusic (e) {       
        const music = this.$refs.player // 音频所在对象
        const barWidth = e.pageX / this.$refs.runfatbar.offsetWidth // 计算点击位置相对父元素总宽的比例
        this.$refs.runbar.style.width = `${barWidth * 100}%` // 进度条应所在的比例总宽
        music.currentTime = music.duration * barWidth // 计算点击时应播放所在的时间
        const ulist = this.$refs.ul
        const list = ulist.getElementsByTagName("li");
        for(var i = 0; i <= this.ms.length; i++) {
            if(parseFloat(this.ms[i].t) <= music.currentTime) {         
                // 删除之前的高亮样式与设置当前点击部分高亮样式
                if(this.lineNo < i) {
                    list[this.lineNo].removeAttribute("class");//去掉上面的高亮样式
                    this.lineNo = i
                    list[this.lineNo].className = "lineHigh";//高亮显示当前行
                }else {
                    list[this.lineNo-1].removeAttribute("class");//去掉下面的高亮样式
                    this.lineNo = i
                    list[this.lineNo].className = "lineHigh";//高亮显示当前行
                }
                // 进行播放         
                music.play()         
                this.$refs.icon.innerHTML = ("");       
            }       
        }     
    }, 
}

最后

不知道是否复杂化,欢迎提出建议鸭。

写一个音乐播放器3--歌曲播放进度条与歌词滚动同步
转载自:https://juejin.cn/post/7132078096663969822
评论
请登录