一、方法一

描述:列表懒加载+节流
效果图:
在这里插入图片描述
实现:
组件:LazyLoading

<template>
  <div class="lazy-list">
    <slot></slot>
  </div>
</template>
<script>
export default {
  name: "LazyLoading",
  data() {
    return {};
  },
  methods: {
    // 懒加载
    handleScroll(event) {
      // 标准浏览器中:定义一个形参event,但当事件触发的时候,并没有给event赋实际的值,
      // 则浏览器会把”事件“的对象赋给这个形参e,这时这个e是个系统级的对象:事件;
      const scrollDistance =
        // 正文全文高
        event.target.scrollHeight -
        // 被卷去的高
        event.target.scrollTop -
        // 可见区域的宽度
        event.target.clientHeight;
      // 滚动条距离底部小于等于0证明已经到底了,可以请求接口了
      if (scrollDistance <= 0) {
        this.$emit("onButtomBy");//到底了
      }
    },

    // 节流
    throttle(fn, wait) {
      let context, args;
      let previous = 0;
      return function () {
        let now = +new Date();
        context = this;
        args = arguments; // 取throttle执行作用域的this
        if (now - previous > wait) {
          fn.apply(context, args); // 用apply指向调用throttle的对象,相当于throttle.fn(args);
          previous = now;
        }
      };
    },

    throttleFun(event) {
      this.throttle(this.handleScroll(event), 1000);
    },
  },
  mounted() {
    // 注册 滚动事件
    window.addEventListener("scroll", this.throttleFun, true);
  },
};
</script>

<style >
.lazy-list {
  /* 注意:懒加载必须设置 列表容器的高度哈 */
  /* height: calc(100% - 200px); */
  height: 100%;
  overflow: auto;
}
</style>

注意: 如果 懒加载组件 是被包裹在 keep-alive 下的话,会被缓存,需要在 deactivated 钩子中对 scroll 事件 进行解绑
参考:https://blog.csdn.net/qq_24930411/article/details/107252548

deactivated() {
  window.removeEventListener("scroll", this.throttleFun, true);
},

列表页面引用懒加载组件:
import LazyLoading from "./LazyLoading.vue";

<template>
  <div class="refresh-list-extend-con">
    <lazy-loading @onButtomBy="onButtomBy">
      <div v-for="(item, index) in listBody" :key="index" class="item-con">
        <div class="item"></div>
      </div>
    </lazy-loading>
  </div>
</template>
<script>
import LazyLoading from "./LazyLoading.vue";
export default {
  name: "HomeList",
  components: {
    LazyLoading,
  },
  data() {
    return {
      listBody: [{}, {}, {}, {}, {}, {}, {}, {}],
      pages: 1, // 数据总页数
      current: 1, // 当前页数
      onOff: false, // 节流标识
    };
  },
  methods: {
    // 加载数据
    loadTaksData() {
      // todo 调用接口获取数据给 items 对象赋值
      let params = {
        current: this.current,
        size: 8,
      };
      console.log("接口参数为:", params);
      /* // 调用接口的方法
      this.xxxx(params).then((res)=>{
        console.log('接口返回的数据为:', res);
          this.items = res.body.records;
        // todo 接口返回后需要将 节流标识 设置为 this.onOff = false
        this.onOff = false;
        // todo 当前页数和总页数在第一次请求数据就要保存起来
        this.pages = res.body.pages;
      })
      */

      // 临时数据
      this.listBody = [{}, {}, {}, {}, {}, {}, {}, {}]; //当前页数据
      this.pages = 4; //总页数
      this.onOff = false;
    },
    // 到底了
    onButtomBy() {
      //这个开关是为了避免请求数据中 再次被请求
      if (this.onOff) return;
      this.onOff = true;
      //当前页数小于总页数 就请求
      if (this.current < this.pages) {
        this.current += 1;
        this.loadTaksData();
      }
    },
  },
  created() {
    this.loadTaksData();
  },
};
</script>
<style>
.refresh-list-extend-con {
  width: 300px;
  height: 300px;
  border: 1px solid #ccc;
  overflow-y: auto;
}
.item-con .item {
  width: 100px;
  height: 50px;
  background: #f5f5f5;
  margin: 10px 0;
}
</style>

打印参数如下:
在这里插入图片描述

二、 方法二

描述:一个简单的适用于 Vue 的下拉刷新,触底加载组件

效果图:

在这里插入图片描述

实现:

组件: RefreshList 代码:

<template>
  <div
    class="list-warp-template"
    @touchstart="handlerStart"
    @touchend="handlerEnd"
    @touchmove="handlerMove"
    @scroll="handlerScroll"
    ref="listWrapRef"
  >
    <div class="top-refresh" :style="{ height: refresh.height + 'px' }">
      <div v-show="refresh.height > 30">
        {{ refreshLoading ? "刷新中" : "松开刷新" }}
      </div>
    </div>
    <div class="main-list">
      <slot></slot>
    </div>
    <div class="bottom-loading" v-show="bottomLoading">加载中</div>
  </div>
</template>
<script>
let timer = null;
export default {
  name: "RefreshList",
  props: {
    refreshLoading: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      position: 0,
      startInit: 0,
      bottomLoading: false,
      refresh: {
        height: 0,
      },
    };
  },
  created() {},
  watch: {
    refreshLoading(val) {
      if (!val) {
        this.refresh.height = 0;
      }
    },
  },
  computed: {},
  mounted() {},
  methods: {
    handlerScroll(e) {
      const eDom = e.target;
      const scrollTop = e.target.scrollTop;
      // 判断是否到底了
      let scrollPosition = eDom.scrollHeight - e.target.offsetHeight;
      if (timer) {
        clearTimeout(timer);
      }

      timer = setTimeout(() => {
        this.bottomLoading = true;
        if (scrollPosition <= scrollTop) {
          this.$emit("on-bottom"); //到底了
        }
      }, 200);
      this.position = scrollTop;
      // 滚动事件,返回当前滚动位置
      this.$emit("on-scroll", scrollPosition);
    },
    // 返回顶部
    handlerBackTop() {
      const dom = this.$refs.listWrapRef;
      dom.scrollTop = 0;
    },
    // 触摸开始
    handlerStart(e) {
      this.startInit = parseInt(e.touches[0].clientY);
    },
    // 滑动中,下拉
    handlerMove(e) {
      if (this.position === 0 && !this.refreshLoading) {
        const Y = parseInt(e.touches[0].clientY);
        const range = Y - this.startInit;
        this.refresh.height = range;
      }
    },
    // 滑动结束
    handlerEnd() {
      if (this.refresh.height >= 30) {
        this.refresh.height = 40;
        this.$emit("on-refresh");
        this.$emit("update:refreshLoading", true);
      } else {
        this.refresh.height = 0;
      }
      this.startInit = 0;
    },
  },
};
</script>

<style >
.list-warp-template {
  display: block;
  /* height: 100vh; */
  height: 100%;
  overflow-y: auto;
}
.top-refresh {
  background-color: #ccc;
  height: 0;
  width: 100%;
  transition: height 0.1s linear;
  overflow: hidden;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.main-list {
  width: 100%;
}

.bottom-loading {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #999;
  width: 100%;
  background-color: #f0f0f0;
}
</style>

列表页面:
引入懒加载组件:import RefreshList from "./refreshList.vue";

<template>
  <div class="refresh-list-con">
    <refresh-list @on-bottom="onBotttom">
      <div v-for="(item, index) in listBody" :key="index" class="item-con">
        <div class="item"></div>
      </div>
    </refresh-list>
  </div>
</template>

<script>
import RefreshList from "./refreshList.vue";

export default {
  name: "HomeRefresh",
  props: {},
  components: {
    RefreshList,
  },
  data() {
    return {
      listBody: [{}, {}, {}, {}, {}, {}, {}, {}],
    };
  },
  methods: {
    // 到底了
    onBotttom() {
      console.log("触底加载...");
    },
  },
  created() {},
};
</script>

<style  scoped>
.refresh-list-con {
  width: 300px;
  height: 300px;
  border: 1px solid #ccc;
  overflow-y: auto;
}

.item-con .item {
  width: 100px;
  height: 50px;
  background: #f5f5f5;
  margin: 10px 0;
}
</style>

备注

1、Vue3 手写一个简单的触底刷新:

利用 addEventListener 来监听视图层的高度,还有滚动条的高度

const handleScroll = () => {
  window.addEventListener("scroll", () => {
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    let windowHeight = document.documentElement.clientHeight || document.body.clientHeight
    let scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight
    if (scrollTop + windowHeight == scrollHeight) {
      console.log("到了底部")
      getOrderList()
    }
  })
}
onMounted(() => {
  handleScroll()
})
onBeforeUnmount(() => {
  window.removeEventListener("scroll", () => {})
})

注意:离开前不要忘记销毁

2、

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐