<template>
	<view class="virtual-list" style="position: relative;">
		<movable-area style="position: absolute;right: 0;width: 30px;height: 100%;">
			<movable-view class="action-bar-box" direction="vertical" @change="change" :y="y" :animation="false">
				<view style="border-bottom: #000 solid 2px;width: 100%;"></view>
				<view style="border-bottom: #000 solid 2px;width: 100%;"></view>
			</movable-view>
		</movable-area>
		<scroll-view scroll-y="true" :style="{
				height: scrollHeight + 'px',
				position: 'relative',
				zIndex: 1
			}" @scroll="handleScroll" :scroll-top="scrollTop" :show-scrollbar="false">
			<view class="scroll-bar" :style="{
					height: localHeight + 'px'
				}"></view>
			<view class="list" :style="{
					transform: `translateY(${offset}px)`
				}">
				<view class="item-wrap" v-for="(item, index) in visibleData" :key="index">
					<slot :item="item" :active="active"></slot>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
	export default {
		name: 'VirtualList',
		props: {
			// 所有的items
			items: Array,
			// 可视区域的item数量
			remain: Number,
			// item大小
			size: Number,
			// 当前章节
			active: Number,
			// 可使区域高度
			scrollHeight: Number
		},
		data() {
			return {
				// 起始
				start: 0,
				// 结束
				end: this.remain,
				// list 偏移量
				offset: 0,
				scrollTop: 0,
				y: 0
			};
		},
		created() {
			//当前章节滚动至顶部
			this.scrollTop = this.size * this.active;
		},
		computed: {
			// 预留项
			preCount() {
				return Math.min(this.start, this.remain);
			},
			nextCount() {
				return Math.min(this.items.length - this.end, this.remain);
			},
			// 可视区域的item
			visibleData() {
				const start = this.start - this.preCount;
				const end = this.end + this.nextCount;
				return this.items.slice(start, end);
			},
			localHeight() {
				return this.items.length * this.size;
			}
		},
		methods: {
			change(e) {
				if (e.detail.source !== 'touch') {
					return;
				}
				let y = e.detail.y;
				let scroll = (y / (this.scrollHeight - 40)) * (this.localHeight - this.scrollHeight);
				scroll = scroll < 0 ? 0 : scroll;
				this.scrollTop = scroll;
			},
			handleScroll(ev) {
				const scrollTop = ev.detail.scrollTop;
				this.y = (scrollTop / (this.localHeight - this.scrollHeight)) * (this.scrollHeight - 40);
				// 开始位置
				const start = Math.floor(scrollTop / this.size);
				this.start = start < 0 ? 0 : start;
				// 结束位置
				this.end = this.start + this.remain;
				// 计算偏移
				const offset = scrollTop - (scrollTop % this.size) - this.preCount * this.size;
				this.offset = offset < 0 ? 0 : offset;
			}
		}
	};
</script>

<style scoped>
	.list {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
	}

	.action-bar-box {
		padding: 3px;
		display: flex;
		flex-flow: column;
		justify-content: space-around;
		align-items: center;
		position: absolute;
		right: 0;
		background-color: transparent;
		border-radius: 10rpx;
		box-shadow: 0 0 5px #000;
		width: 20px;
		height: 40px;
		z-index: 2;
	}
</style>