vue3长列表优化-虚拟列表

主要思路:

1.获取单个元素的高度,然后根据所有数据计算总高度,

2.通过滚动事件计算当前元素的索引,来给列表容器动态添加paddingTop

3.如果不设置paddingTop会怎么样:

因为虚拟列表是根据索引使用slice动态截取数据的,当滚动超过第一个元素时,就会触发slice更新数据。数据更新又会触发重新渲染,如果不加paddingTop的话,元素又会从顶部开始排列下来,这是scrollTop又会变为0。(这时慢慢滑的话会出现过了第一个元素又会从第一个元素开始,出现循环的现象。快速滑的则会出现白屏。)

vue3代码

import {
  reactive,
  ref,
  computed,
  onMounted,
  watchEffect,
  nextTick,
} from "vue";

const scrollBox = ref(null);
const items =ref(null);

const state = reactive({
  DataList: [],
  ItemBoxHeight: 0,
  Itemnum: 1,
  startIndex: 0,
});

const getdata = () => {
  let list = [];
  for (let i = 0; i < 100000; i++) {
    list.push({
      src: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Flmg.jj20.com%2Fup%2Fallimg%2F1114%2F042421133312%2F210424133312-1-1200.jpg&refer=http%3A%2F%2Flmg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1669454206&t=bc5099c7f969e3b09cc744604316d025",
      text: `我是${i}号`,
      tid: i,
    });
  }
  state.DataList = list;
};

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

const virtualList = computed(() => {
  let endIndex = state.startIndex + state.Itemnum;
  if (endIndex >= state.DataList.length) endIndex = state.DataList.length;
  return state.DataList.slice(state.startIndex, endIndex);
});

const doscroll = () => {
  const curScrollTop = scrollBox.value.scrollTop;
  if (curScrollTop > state.ItemBoxHeight) {
    const index = ~~(scrollBox.value.scrollTop / state.ItemBoxHeight);
    items.value.style.setProperty(
      "padding-top",
      `${index * state.ItemBoxHeight}px`
    );
    state.startIndex = index;
  } else {
    items.value.style.setProperty("padding-top", "0px");
    state.startIndex = 0;
  }
};

watchEffect(() => {
  if (state.DataList.length > 0) {
    nextTick(() => {
      // 计算每行高度
      state.ItemBoxHeight = items.value.children[0].offsetHeight;
      //计算屏幕内能显示的行数   +5是防止下拉过快出现白屏
      state.Itemnum = ~~(scrollBox.value.clientHeight / state.ItemBoxHeight)+5;
      // 设置列表总高度
      const ListHeight = state.ItemBoxHeight * state.DataList.length;
      items.value.style.setProperty("height", `${ListHeight}px`);
    });
  }
});

HTML代码

1. box-sizing: border-box(这个是重点)。因为padding的缘故。

{{ item.text }}

 CSS

.container {
  height: 600px;
  overflow-y: scroll;
}
.container .item {
  height: 100px;
}
.container .item img {
  width: 100px;
  height: 100%;
}

你可能感兴趣的:(js,前端,javascript,css)