今天我们来聊一聊业务开发中的
触底请求
,其实就是分页的一种,只不过传统
的分页感觉很丑而已,正好我的小博客最近在做触底分页,借此机会来说一说具体
怎么实现
的,以及来带领大家使用一下Vue3
中的新特性hooks
函数。
案例
和我实际开发的功能会有差异,这里我只是想讲明白具体的思路。
一、触底分页思路
我这里就列举我自己实现的这种方式把,就是通过监听scroll
,通过对比滚动卷入的高度(scrollTop
)、窗口的高度(clientHeight
)和滚动条的总高度(scrollHeight
)三者之间插值的计算,来判断是否发起请求。
后续你可能还会判断:如果数据库没有更多的数据我们就不再请求等操作(这里我就不过多讲解了)。
二、Hooks函数
在 Vue 3 中,引入了 Composition API,它是一种新的 API 设计范式,为我们提供了更加灵活和可组合的代码组织方式。使我们的代码写起来更加的舒服,我们今天就来使用一下其中的一个重要概念Hooks。
首先Hooks 是一种函数,以 use
开头,用于封装可复用的逻辑。它们提供了一种在函数组件中复用状态逻辑的方式,使我们能够更好地组织组件代码,将相关的逻辑聚合在一起,实现更高水平的可维护性。
借用知乎大佬的定义:集成定义一些可复用的方法,可以随时被引入和调用以实现高内聚低耦合的目标,应该都能算是hook。
下面我们就结合Hook函数,一起来实现一下触底功能。
三、Hooks具体实现
大家会学到两部分,触底的实现思路和hooks的使用。
3.1 创建文件
在 src
目录下创建 hooks/usePagination.js
,抛出一个函数,我们的所有业务都放在此函数中,并且通过 return
进行返回,我们会使用到一些 Vue
的钩子
(ref, onMounted等),通过 import
进行导入。
import {ref, onMounted, onUnmounted } from 'vue'
export const usePagination = () => {
return {
...
}
}
3.2 编写触底业务函数
这里我用到了三个自己定义的变量loading、currentPage和list
- loading:作用类似于节流,防止我们重复触底,重复请求;
- currentPage:就是当前页码(
默认为1
); - list:来存储我们
http
请求的数据。
我们通过setTimeout
来模拟一下http
请求。
const loading = ref(false)
const loading = ref(false)
const list = ref([])
const scrollBottom = () => {
// 判断是否在请求阶段
if(loading.value) return
// 获取滚动条卷入的高度
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('开始请求');
loading.value = true;
currentPage.value ++
setTimeout(() => {
loading.value = false
// http请求函数
getList(currentPage.value)
}, 2000)
}
}
3.3 http请求函数
请求函数接收两个参数,当前页和每次请求的条数,这个我通过for
循环push
到list
中来模拟。
const getList = (currentPage = 1, currentSize = 10) => {
for (let i = 0; i < currentSize; i ++) {
list.value.push({
id: new Date().getTime(),
})
}
console.log(list.value)
}
3.4 挂载触底函数
当我们组件加载/注销
完成之后挂载/卸载
我们的触底函数。
onMounted(() => {
console.log('事件已挂载');
window.addEventListener('scroll', scrollBottom);
getList();
})
onUnmounted(() => {
console.log('事件已移除');
window.removeEventListener('scroll', scrollBottom);
})
3.5 return数据
返回
我们在组件中需要用到的变量
和函数
export const usePagination = () => {
...
...
return {
currentPage,
list,
getList
}
}
3.6 完整代码
import { ref, onMounted, onUnmounted } from 'vue'
export const usePagination = () => {
const currentPage = ref(1)
const list = ref([])
const loading = ref(false)
// 判断触底
const scrollBottom = () => {
if(loading.value) return
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
// 变量 windowHeight 是可视区的高度
let windowHeight =
document.documentElement.clientHeight || document.body.clientHeight
// 变量 scrollHeight 是滚动条的总高度
let scrollHeight =
document.documentElement.scrollHeight || document.body.scrollHeight
if (scrollTop + windowHeight >= scrollHeight) {
console.log('开始请求');
loading.value = true
currentPage.value ++
setTimeout(() => {
loading.value = false
getList(currentPage.value)
}, 2000)
}
}
// 请求数据
const getList = (currentPage = 1, currentSize = 10) => {
console.log(currentPage)
for (let i = 0; i < currentSize; i ++) {
list.value.push({
id: new Date().getTime(),
})
}
}
onMounted(() => {
console.log('事件已挂载');
window.addEventListener('scroll', scrollBottom)
getList()
})
onUnmounted(() => {
console.log('事件已移除');
window.removeEventListener('scroll', scrollBottom)
})
return {
currentPage,
list,
getList
}
}
四、组件使用
4.1 编写组件模板
我们编写一个列表来渲染我们的list
数组
<template>
<div class="container">
<div class="item" v-for="(item, index) in list" :key="item.id">
我是列表内容{{ index + 1 }}
</div>
</div>
</template>
<style lang="scss" scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
.item {
width: 60%;
height: 150px;
border: 1px solid #000;
margin-bottom: 10px;
}
}
</style>
4.1 引入
通过import
导入hook
函数,执行hook函数,解构
出我们需要的值,如果对解构
不太了解的小伙伴,可以看我往期的文章,勇宝趣学JavaScript ES6第二章(解构赋值)
<script setup>
import { usePagination } from '@/hooks/usePagination';
const { currentPage, list } = usePagination();
</script>
五、效果
效果图晚点时间给小伙伴们呈现,在外边,这台笔记本没有做gif
的工具,先放一个静态的图片给大家泄泄火把
六、总结
今天给大家讲解了一下触底的实现过程以及 Vue3 中hooks的上手体验,希望大家会对 Vue3 有一个更加深刻的认识。
说实话我写不出那些高大上的代码,哈哈哈,希望大家能理解我这个前端小菜鸟。