Vue3列表触底请求(上手体验hooks新特性)

今天我们来聊一聊业务开发中的触底请求,其实就是分页的一种,只不过传统的分页感觉很丑而已,正好我的小博客最近在做触底分页,借此机会来说一说具体怎么实现的,以及来带领大家使用一下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 进行导入。

js 复制代码
import {ref, onMounted, onUnmounted } from 'vue'

export const usePagination = () => {

    return {
        ...
    }
}

3.2 编写触底业务函数

这里 我用到了三个自己定义的变量loadingcurrentPagelist

  • loading:作用类似于节流,防止我们重复触底,重复请求;
  • currentPage :就是当前页码(默认为1);
  • list :来存储我们http请求的数据。

我们通过setTimeout来模拟一下http请求。

js 复制代码
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循环pushlist中来模拟。

js 复制代码
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 挂载触底函数

当我们组件加载/注销完成之后挂载/卸载我们的触底函数。

js 复制代码
onMounted(() => {
    console.log('事件已挂载');
    window.addEventListener('scroll', scrollBottom);
    getList();
})

onUnmounted(() => {
    console.log('事件已移除');
    window.removeEventListener('scroll', scrollBottom);
})

3.5 return数据

返回我们在组件中需要用到的变量函数

js 复制代码
export const usePagination = () => {
    ...
    ...
    
    return {
        currentPage,
        list,
        getList
    }
}

3.6 完整代码

js 复制代码
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数组

js 复制代码
<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第二章(解构赋值)

js 复制代码
<script setup>
import { usePagination } from '@/hooks/usePagination';

const { currentPage, list } = usePagination();

</script>

五、效果

效果图晚点时间给小伙伴们呈现,在外边,这台笔记本没有做gif的工具,先放一个静态的图片给大家泄泄火把

六、总结

今天给大家讲解了一下触底的实现过程以及 Vue3 中hooks的上手体验,希望大家会对 Vue3 有一个更加深刻的认识。

说实话我写不出那些高大上的代码,哈哈哈,希望大家能理解我这个前端小菜鸟。

相关推荐
web1478621072310 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478011 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖14 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案122 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_7482548826 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.38 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营42 分钟前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_851 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui