1.结构

<template>
    <div class="lyricScroll">
        <div class="audio">
            <audio id="audio" src="./common/周传雄-青花1.mp3" controls></audio>
        </div>
        <div class="container" id="container">
            <ul id="ul">
                <li v-for="item in dataArr" :key="item.time">
                    {{ item.word }}
                </li>
            </ul>
        </div>
    </div>
</template>
<script>
import {data} from "./common/data";
export default {
    name: 'lyricScroll',
    data() {
        return {
            dataArr: [],
            doms: {}
        }
    },
    mounted(){
        this.parseLrc()
        this.getDoms()
        this.audioTimeUpdata()
    },
    methods:{
        /**
         * 获取dom
         */
        getDoms(){
            this.doms['audio'] = document.getElementById("audio")
            this.doms['container'] = document.getElementById("container")
            this.doms['ul'] = document.getElementById("ul")
        },
        /**
         * 将字符串转为对象数组[{ time: 0, word: 'x' }]
         */
        parseLrc(){
            let lines = data.split('\n');
            this.dataArr = lines.map(item => {
                return {
                    time: this.parseTime(item.split(']')[0].split("[")[1]),
                    word: item.split(']')[1]
                }
            })
        },
        /**
         * 将时间字符串转为数字(秒)
         * @param {String} timeStr 时间字符串
         * @param {Number} offset 设置时间偏移
         */
        parseTime(timeStr, offset = 0.5){
            let parts = timeStr.split(":");
            return +parts[0] * 60 + +parts[1] - offset
        },
        /**
         * 计算出,在当前播放器播放到第几秒的情况下,应该高亮的歌词下标
         */
        findIndex(){
            let curTime = this.doms.audio.currentTime;
            let nowIndex = this.dataArr.findIndex(item => {
                return item.time > curTime
            })
            return nowIndex != -1 ? nowIndex - 1 : this.dataArr.length - 1
        },
        /**
         * 设置ul的偏移量
         */
        setOffset(){
            let { ul, container } = this.doms
            let liHieght = ul.children[0].clientHeight
            let containerHeight = container.clientHeight
            let ulHeight = ul.clientHeight
            let index = this.findIndex();
            let oldLi = ul.querySelector('.active')
            if(oldLi){
                oldLi.classList.remove('active')
            }
            let offset = liHieght * index + liHieght / 2 - containerHeight / 2
            let resultOffset = offset < 0 ? 0 : (offset > ulHeight ? ulHeight : offset)
            ul.style.transform = `translateY(${-resultOffset}px)`
            ul.children[index].classList.add('active')
        },
        /**
         * 给audio监听时间轴改变事件
         */
        audioTimeUpdata(){
            let { audio } = this.doms
            audio.addEventListener('timeupdate', this.setOffset)
        }
    }
};
</script>

<style lang="less" scoped>
* {
    margin: 0;
    padding: 0;
}

.lyricScroll {
    width: 100%;
    height: 100%;
    background: black;
    display: flex;
    flex-direction: column;
    align-content: center;

    .audio{
        audio{
            width: 400px;
            margin: 0 auto;
            display: block;
        }
    }

    .container {
        flex: 1;
        overflow: hidden;

        ul {
            transition: 0.6s;
            li {
                height: 50px;
                line-height: 50px;
                transition: 0.3s;
                text-align: center;
                font-size: 30px;
                &.active{
                    color: #fff;
                    font-size: 40px;
                }
            }
        }

    }
}</style>

2.效果

歌词滚动效果

Logo

前往低代码交流专区

更多推荐