SOURCE

console 命令行工具 X clear

                    
>
console
Vue.component('play-list',{
    template: "#play-list",
    props: ['data'],
    data() {
        return {
            start: 0,
            amount: 0,
            ob: null,
            lineHeight: 70
        }
    },
    mounted() {
        this.ob = new ResizeObserver(entries=>{
            let containerHeight = entries[0].contentRect.height;
            let amount = Math.floor(containerHeight / this.lineHeight)+2;
            this.amount = amount;
        });
        this.ob.observe(this.$el);
    },
    computed: {
        visibleLines() {
            if(this.data instanceof Array) {
                let start = this.start;
                let end = this.start + this.amount;
                return this.data.slice(start,end);
            }
            return [];
        },
        totalHeight() {
            if(this.data instanceof Array) {
                return {
                    height: `${this.data.length * this.lineHeight}px`,
                    width: 0
                }
            }
        },
        linesTop() {
            return {
                top: `${this.start * this.lineHeight}px`
            }
        }
    },
    methods: {
        cmpStart(e) {
            let scrollTop = e.target.scrollTop;
            let start = Math.floor(scrollTop / this.lineHeight);
            this.start = start;
        }
    },
    beforeDestroyed() {
        this.ob.unobserve(this.$el);
    }
})
let data = {"song":"嘉宾","songId":1846489646,"album":"嘉宾","albumId":127728498,"albumCover":"https://p1.music.126.net/LoVqPgkI7DwSNZk50gcODg==/109951165994863998.jpg","duration":"04:30","time":270602,"artists":"路飞文","avail":true}
let vm = new Vue({
    el: "#root",
    data: {
        list: []
    }
})
for(let i = 0; i < 1000; ++i) {
    let item = Object.create(data);
    item.artists += i;
    vm.list.push(item);
}
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=, initial-scale=">
	<meta http-equiv="X-UA-Compatible" content="">
	<title></title>
</head>

<body>
	<div id="root">
		<play-list :data="list"></play-list>
	</div>
	<template id="play-list">
		<div class="play-list">
			<div class="row-list scrollbar" @scroll="cmpStart($event)">
				<div class="row-wrapper" :style="linesTop">
					<div class="row" v-for="(item,index) in visibleLines" :key="index">
						<div class="left">
							<div class="song">{{item.song}}</div>
							<div class="artists">{{item.artists}}</div>
						</div>
						<div class="right">
							<div class="duration">{{item.duration}}</div>
						</div>
					</div>
				</div>
                <div class="total-height" :style="totalHeight"></div>
			</div>
		</div>
	</template>
</body>

</html>
* {
    margin: 0;
    padding: 0;
}
.scrollbar {
    overflow: auto !important;
}
.scrollbar::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}
.scrollbar::-webkit-scrollbar-thumb {
    border-radius: 4px;
    background: #ccc;
}
#root {
    width: 250px;
    height: 500px;
    background: #fff;
    box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.play-list {
    position: relative;
    width: 100%;
    height: 100%;
    min-width: max-content;
}
.play-list .row-list {
    position: relative;
    width: 100%;
    height: 100%;
}
.play-list .row-list .row-wrapper {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
}
.play-list .row-list .row {
    position: relative;
    width: 100%;
    height: 70px;
    box-sizing: border-box;
}
.play-list .row-list .row:hover {
    background: #ddd;
}
.play-list .row-list .row .left {
    position: absolute;
    left: 10px;
    top: 10px;
}
.play-list .row-list .row .right {
    position: absolute;
    right: 0;
    bottom: 15px;
    padding-right: 10px;
}
.play-list .row-list .row .song {
    font-size: 14px;
}
.play-list .row-list .row .artists,
 .play-list .row-list .row .duration {
    font-size: 13px;
    color: #999;
}
.play-list .row-list .row .artists {
    padding-top: 10px;
}

本项目引用的自定义外部资源