阅读 54

虚拟滚动实现 (纯小白只是记录一下笔记)

--图片--

首先我们应该理解什么是虚拟滚动
1.虚拟滚动的概念是只渲染当前父盒子高度的元素 其他不做渲染 (防止大数据渲染卡死) 我实现方法是通过从源数据截取的方式的方法实现的
2.实现原理 设置子元素单个的高度(itemHeight) 设置所有数据(data)记录当前滚动的距离(scrollTop)
3.计算出总高度 itemHeihgt * data
4.计算出开始索引(first) scrollTop / itemHeight
5.计算出结束索引(last) first + el.clientHeight / itemHeight
6.最后截取数据 data.slice(first,last) 下面是我实现的代码


<template>
  <div class="scroll_wrap" ref="wrapEl" @scroll="handleScroll">
    <div class="scroll_view" :style="getViewStyle">
      <div
        style="height: 40px; background: red"
        v-for="(item, i) in newData"
        :key="i"
      >
        <slot name="default" :item="item"></slot>
      </div>
    </div>
  </div>
</template>

<script>
import {
  computed,
  defineComponent,
  onMounted,
  reactive,
  ref,
  unref,
} from "vue";
export default defineComponent({
  name: "VitrualScroll",
  props: {
    data: Array,
  },
  setup(props) {
    const state = reactive({
      first: 0,
      last: 0,
      scrollTop: 0,
    });
    const wrapEl = ref(null);
    const newData = ref([]);

    const itemHeight = 40;
    const sumHeight = Math.ceil(props.data.length * itemHeight);

    const getViewStyle = computed(() => {
      return {
        height: sumHeight + "px",
        "padding-top":
          Math.floor(state.scrollTop / itemHeight) * itemHeight + "px",
      };
    });
    function handleScroll() {
      onScroll();
    }

    const getFirst = () => {
      return Math.floor(state.scrollTop / itemHeight);
    };
    const getLast = () => {
      return (
        state.first + Math.ceil(unref(wrapEl).clientHeight / itemHeight) + 1
      );
    };

    function onScroll() {
      state.scrollTop = unref(wrapEl).scrollTop;
      state.first = getFirst();
      state.last = getLast();
      newData.value = props.data.slice(state.first, state.last);
    }

    onMounted(() => {
      onScroll();
    });

    return {
      handleScroll,
      wrapEl,
      newData,
      getViewStyle,
    };
  },
});
</script>
<style scoped>
.scroll_wrap {
  height: 300px;
  overflow-y: auto;
  width: 300px;
  margin: auto;
}

.scroll_view {
  box-sizing: border-box;
}
</style>


复制代码
文章分类
前端
文章标签