<template>
  <view class="content">
    <!-- 使用 scroll-view 组件来实现滚动 -->
    <scroll-view
      ref="list"
      :scroll-y="true"
      class="list-container"
      @scroll="handleScroll"
      :scroll-top="state.startOffset"
    >
      <view class="list-phantom" :style="{ height: `${listHeight}${itemSizeUnit}` }"></view>
      <view class="list" :style="{ transform: getTransform }">
        <view
          v-for="(item, index) in visibleData"
          class="list-item"
          :key="index"
          :ref="setItemRef"
          :style="`height:${state.itemHeights[index]}${itemSizeUnit}`"
        >
          <!-- <slot name="cell" :item="item" :index="index"></slot> -->
          <text class="">
            {{ item.name }}
          </text>
        </view>
      </view>
    </scroll-view>
  </view>
</template>
<script setup lang="ts">
import { reactive, onMounted, computed } from 'vue'

const state = reactive({
  listHeight: 0,
  screenHeight: 0, // 屏幕高度即可视区域高度
  startOffset: 0, // 顶部偏移量
  startIndex: 0, // 可视化区域的数据开始下标
  endIndex: 0, // 可视化区域的数据结束下标
  itemHeights: [] as number[], // 用来存储每个列表项的高度
})
const props = defineProps({
  listData: {
    type: Array<{ name: string; id: number }>,
    default: () => [],
  },
  //每项高度
  itemSize: {
    type: Number,
    default: 200,
  },
  itemSizeUnit: {
    type: String,
    default: 'px',
  },
})
// const listHeight = computed(() => {
//   return props.listData.length * props.itemSize
// })

const listHeight = computed(() => {
  // 总高度是所有项高度的总和
  return state.itemHeights.reduce((sum, height) => sum + height, 0) || 0
})

const visibleCount = computed(() => {
  return Math.ceil(state.screenHeight / props.itemSize) || 0
})
const getTransform = computed(() => {
  return `translate3d(0,${state.startOffset}${props.itemSizeUnit},0)`
})
const visibleData = computed(() => {
  return props.listData.slice(state.startIndex, Math.min(state.endIndex, props.listData.length))
})
onMounted(() => {
  init()
})
const init = () => {
  getScreenHeight()

  // 设置初始滚动距离  state.startIndex = 0   如果不是从第一个开始滚动 num为第几个开始  state.startIndex = num  state.startOffset = num * props.itemSize
  //   state.startIndex = 0
  state.startIndex = 0
  state.startOffset = 0
  state.endIndex = state.startIndex + visibleCount.value
}

// 获取屏幕高度即可视化区域高度
const getScreenHeight = () => {
  uni.getSystemInfo({
    success: function (res) {
      state.screenHeight = res.screenHeight
    },
  })
}
// 防抖 节流方法   debounce第三个参数没用  可以删除
const debounce = (fn, delay, _this) => {
  var delay = delay || 200
  var timer = null
  return function () {
    let self = _this
    let args = arguments
    timer && clearTimeout(timer)
    timer = setTimeout(function () {
      timer = null
      fn.apply(self, args)
    }, delay)
  }
}
const handleScroll = debounce(
  (e) => {
    //当前滚动位置
    let scrollTop = e.detail.scrollTop
    //开始索引
    state.startIndex = Math.floor(scrollTop / props.itemSize)
    //结束索引
    state.endIndex = state.startIndex + visibleCount.value
    //顶部偏移量
    state.startOffset = scrollTop - (scrollTop % props.itemSize)
  },
  10,
  '',
)

const itemRefs = ref([])
const setItemRef = (el) => {
  if (el) {
    itemRefs.value.push(el)
  }
}

// 计算每个列表项的高度
const calculateItemHeights = () => {
  state.itemHeights = props.listData.map((_, index) => {
    const refItem = itemRefs.value[index]
    return refItem && refItem.$el ? refItem.$el.offsetHeight : props.itemSize // 如果有真实内容，则获取实际高度；否则，使用默认高度
  })
}

watch(itemRefs.value, () => {
  calculateItemHeights()
})

// 监听插槽内容变化，重新计算列表项高度
</script>
<style lang="scss" scoped>
.content {
  height: 100%;
}
.list-container {
  height: 100%;
  overflow: auto;
  position: relative;
  .list-phantom {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
  }
  .list {
    left: 0;
    right: 0;
    top: 0;
    position: absolute;
    .list-item {
      text-align: center;
      border-bottom: 1px solid #ccc;
    }
  }
}
</style>
