[javascript]手写一个懒加载组件

参考一下vantui里的List组件,实现一个印象中的懒加载功能(之所以说是印象中呢主要是vant打不开鸭,全凭记忆中的功能来摸索了);

不是我想重复造轮子,是我想自定义一些些功能。。。

逻辑 主要是监听滚动条 计算设置好的滚动条到底部的高度来异步加载数据,期间异步加载尚未结束时不会重复执行加载操作,所以应该是用了节流。

废话不多说,开始coding

先声明一个组件 就叫他LazyLoad吧

  <div class="lazy-load-ctx" ref="scrollRef">
    <div class="scroll-ctx" ref="scrollCtxRef">
      <slot name="child"></slot>
      <div v-show="props.finish" class="not-data">没有更多数据了~</div>
    </div>
  </div>

ts 这里用了vue3的setup语法糖 定义了传过来的参数以及一个onLoad异步加载数据的方法

const props = defineProps({
  finish: {// 数据完全加载完成
    type: Boolean,
    default: false,
  },
  loading: {// 正在加载中
    type: Boolean,
    default: false,
  },
  offset: {// 距离底部的高度
    type: Number,
    default: 300,
  },
  height: {// 整个滚动容器的高度
    type: String,
    default: "100%",
  },
});
const emit = defineEmits(["onLoad"]);

const scrollRef = ref(null);
const scrollCtxRef = ref(null);

css

.lazy-load-ctx {
  height: v-bind("props.height");
  overflow-y: auto !important;
  .scroll-ctx {
    height: auto;
  }
  .not-data {
    text-align: center;
  }
}

声明一个节流函数

function throttle<T>(cb: (e: T) => void) {
  let state = false;
  return (e: T) => {
    if (state) return;
    cb(e);
    state = true;

    setTimeout(() => {
      state = false;
    }, 100);
  };
}

页面挂载的时候给容器添加滚动监听事件 首次进来的时候触发onload加载数据的方法;我这里还监听了鼠标滚轮事件,防止数据量小的时候没有撑开容器高度导致无滚动条接连无法触发滚动监听(好像有点多余,Orz)

onMounted(() => {
  emit("onLoad");
  const dom = scrollRef.value as HTMLDivElement;
  dom.addEventListener("scroll", throttle<Event>(onScroll));
  dom.addEventListener("wheel", throttle<WheelEvent>(addEventWheel));
});

onScroll函数
获取滚动条到底部的高度

function onScroll(e: Event) {
  // 正在加载或者加载完所有数据了停止执行
  if (props.finish || props.loading) return;
  if (e.target instanceof HTMLDivElement) {
    const { scrollHeight, scrollTop, offsetHeight } = e.target;
    const scrollBottom = scrollHeight - scrollTop - offsetHeight;
    if (scrollBottom < props.offset) {
      // 超过了300开始加载数据喔
      emit("onLoad");
    }
  }
}

hasScroll函数
判断页面有无滚动条

function hasScroll() {
  return document.body.offsetHeight < (scrollCtxRef.value as HTMLDivElement).offsetHeight;
}

addEventWheel函数
监听鼠标滚轮事件

function addEventWheel(e: WheelEvent) {
  const state = hasScroll();
  // 当前有尚未加载完的数据并且无滚动条且是向下滚动且非加载状态
  if (!props.finish && !state && e.deltaY > 0 && !props.loading) {
    emit("onLoad");
  } else return;
}

最后页面卸载的时候记得去清除监听事件
我这里用了节流函数去监听事件,由于用了闭包,每次节流函数都返回了随机的字符,而移除监听事件必须得和添加监听事件的名称一致 导致了现在正常是无法去移除监听事件的,需要对节流函数做一下修改 这里有改造节流函数

onUnmounted(() => {
  const dom = scrollRef.value as HTMLDivElement;
  // dom.removeEventListener("scroll", throttle<Event>(onScroll));
});

大致功能就是这样 vue/react拿来改改就能用了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值