vue通用触底加载实现

150 阅读1分钟

vue触底加载更多数据简易版本

<template>
  <div>
    <div class="container" style="overflow-x: auto">
      <div class="scroll-container" ref="scrollContainers">
        <ul class="uls">
          <li
            class="lis"
            :class="active === index ? 'isActive' : ''"
            v-for="(item, index) in list"
            :key="index"
            @click="activeList(index)"
          >
            {{ item }}
          </li>
        </ul>
      </div>
    </div>

    <ul
      class="ul"
      style="height: 200px; overflow-y: scroll"
      ref="scrollContainer"
    >
      <li class="li" v-for="(item, index) in diffExpect.data" :key="index">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, reactive } from "vue";

const list = ref([
  "热点",
  "新闻",
  "神话",
  "小说",
  "杂志",
  "怪志奇谈",
  "武侠传记",
]);
const active = ref(0);
const dataArray = new Array(1000).fill({
  date: "2016-05-03",
  name: "Tom",
  address: "No. 189, Grove St, Los Angeles",
  age: 23,
});

// 监听滚动事件
onMounted(() => {
  scrollContainer.value.addEventListener("scroll", handleScroll);
});

// 滚动容器的引用
const scrollContainer = ref(null);
const diffExpect = reactive({ data: dataArray.slice(0, 8) });
const copyTabData = reactive({ data: dataArray }); // 拷贝一份 tableData 的值
const pageNo = ref(1);
const pageSize = ref(8);
const total = ref(1000); // 这里需要获取总数据的条数
const isHasNextPage = () => {
  return pageNo.value < Math.ceil(total.value / pageSize.value);
};

var throttle = function (func, delay) {
  var prev = Date.now();
  return function () {
    var context = this;
    var args = arguments;
    var now = Date.now();
    if (now - prev >= delay) {
      func.apply(context, args);
      prev = Date.now();
    }
  };
};
let timer = null;
const handleScroll = throttle((event) => {
  const scrollContainer = event.target;
  const scrollHeight = scrollContainer.scrollHeight;
  const scrollTop = scrollContainer.scrollTop;
  const clientHeight = scrollContainer.clientHeight;
  if (
   // 30  li的 margin-bottom: 30px;
    scrollTop + clientHeight + 30 >= scrollHeight &&
    isHasNextPage &&
    !timer
  ) {
    console.log("触底加载");
    pageNo.value += 1;
    timer = setTimeout(() => {
      const concatList = copyTabData.data.slice(
        pageNo.value * pageSize.value,
        pageNo.value * pageSize.value + 8
      );
      diffExpect.data = diffExpect.data.concat(concatList);
      timer = null;
    }, 80);
  }
}, 90);

const reset = () => {
  diffExpect.data = copyTabData.data.slice(0, 8);
  pageNo.value = 0;
};
const scrollContainers = ref(null);
const scrollItemIntoView = (index) => {
  const listItem = scrollContainers.value.getElementsByClassName("lis")[index];
  listItem.scrollIntoView({ behavior: "smooth", inline: "center" });
};
const activeList = (index) => {
  active.value = index;
  scrollItemIntoView(index);
  // 使用参数进行下一步的接口联调
  reset();
  setTimeout(() => {
    scrollContainer.value.addEventListener("scroll", handleScroll);
  }, 500);
};
</script>
<style  scoped>
li {
  list-style: none;
}
.container {
  width: 400px;
  white-space: nowrap;
}
/* 自定义滚动条的样式 */
.container::-webkit-scrollbar {
  width: 3px;
}

.scroll-container {
  scroll-behavior: smooth;
}

.uls {
  display: inline-flex;
  padding: 10px;
}

.lis {
  flex: 0 0 auto;
  padding: 8px;
  background-color: #ccc;
  margin-right: 10px;
}

.isActive {
  background: skyblue;
  color: #fff;
  cursor: pointer;
}

.li {
  list-style: none;
  margin-bottom: 30px;
  color: #e4e4e4;
}
.ul {
  background: skyblue;
}

/* 自定义滚动条的样式 */
.ul::-webkit-scrollbar {
  width: 8px;
  background: rgba(238, 238, 238, 0.2);
}

::-webkit-scrollbar-thumb {
  background-color: dimgrey;
  border-radius: 5px;
  opacity: 0.7;
}

::-webkit-scrollbar-track {
  background-color: #e4e4e4;
  border-radius: 2px;
}
</style>