vue3.0项目中手动封装加载更多数据(常见)
Posted 奥特曼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3.0项目中手动封装加载更多数据(常见)相关的知识,希望对你有一定的参考价值。
技术点 Vue官方工具库 (仅限vue3.0使用)中的 useIntersectionObserver
使用场景:在一些购物平台中,往往都会看见下滑商品的时候当滑倒底部就会去请求最新的数据,和数据懒加载和图片懒加载很类似
一、模拟数字实现
默认数字为60个数字 当滚到第60个数字时模拟请求20个数字
封装组件
npm i @vueuse/core
<template>
<div class="xtx-infinite-loading" ref="container">
<!-- 正在加载数据时显示 -->
<div class="loading" v-if="isLoading">
<span class="img"></span>
<span class="text">正在加载...</span>
</div>
<!-- 数据全部加载完毕时显示 -->
<div class="none" v-if="isFinished">
<span class="text">亲,没有更多了</span>
</div>
</div>
</template>
<script>
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
export default {
name: 'xtxInfiniteLoading',
props: {
// 是否在加载中
isLoading: {
type: Boolean,
default: false
},
// 数据全部加载完毕
isFinished: {
type: Boolean,
default: false
}
},
setup (props, { emit }) {
const container = ref(null)
const { stop } = useIntersectionObserver(container, ([{ isIntersecting }]) => {
if (isIntersecting) {
// 双重 判断 缺一不可
if (props.isFinished === false && props.isLoading === false) {
emit('doLoading')
}
}
})
return { container, stop }
}
}
</script>
<style scoped lang='less'>
.xtx-infinite-loading {
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
.img {
width: 50px;
height: 50px;
background: url('~@/assets/images/load.gif') no-repeat center / contain;
}
.text {
color: #999;
font-size: 16px;
}
}
.none {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
.text {
color: #999;
font-size: 16px;
}
}
}
</style>
分析
变量
isLoading 是否在加载中
isFinished 数据全部加载完毕
DOM:
如果isLoading 为true 显示 加载状态
如果 isFinished 为true 显示 加载完毕
js :
要操作的DOM元素
const container = ref(null)
使用监听
const { stop } = useIntersectionObserver(container, ([{ isIntersecting }]) => {如果当前监听的元素可见
if (isIntersecting) {
// props传递时异步的 双重 判断 缺一不可 当没有加载完毕 并且 没有正在加载
if (props.isFinished === false && props.isLoading === false) {抛出事件给父组件
emit('doLoading')
}
}
})
测试
<template>
<p v-for="i in list" :key="i" style="margin-left:50px"> {{i}} </p>
<xtxInfiniteLoading @doLoading="doLoading" :isLoading="isLoading" :isFinished="isFinished"></xtxInfiniteLoading>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const list = ref(60)
const isLoading = ref(false)
const isFinished = ref(false)
const doLoading = () => {
isLoading.value = true
setTimeout(() => {
list.value += 20
isLoading.value = false
if (list.value >= 100) {
isFinished.value = true
}
}, 1000)
}
return { list, doLoading, isLoading, isFinished }
}
}
</script>
DOM:
循环list中的数据,并且接收子组件传过来的数据
JS
调用子组件抛出来的事件,加载完毕后把正在加载设为false 当list数据大于等于100 把加载完成设为true,也就是说当大于100的时候不再执行
if (props.isFinished === false && props.isLoading === false) { 子组件中判断如果加载和加载完毕都为false才执行
emit('doLoading')
}
项目中例子
封装的组件不用修改,直接在父组件中写代码
<template>
<xtxInfiniteLoading @doLoading="doLoading" :isFinished="isFinished" :isLoading="isLoading" ></xtxInfiniteLoading>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const isLoading = ref(false)
const isFinished = ref(false)
const doLoading = () => {
isLoading.value = true
findSubCategoryGoods(reqParams).then(res => {
//思路①
if (res.result.items.length) {
isFinished.value = false
reqParams.page++
} else {
isFinished.value = true
}
goodList.value.push(...res.result.items)
// 思路②
// isLoading.value = false
// goodList.value.push(...res.result.items)
// reqParams.page++
// if (!res.result.items.length) {
// isFinished.value = true
// }
})
}
return {doLoading, isLoading, isFinished }
}
}
</script>
DOM:当浏览到可视区域 封装的子组件触发事件 给父组件 父组件接受后就回去调用doLoading事件
JS: 触发doLoading事件
1. 先把isLoading 变量设为true代表正在加载
2. 调用请求之后 if判断 如果返回的长度不为0 那么代表后台一直有数据
3. if{ 把isLoading 状态改为false代表加载完了,页数++ }
4.else 代表后台的数据没有了 把isFinished 变量设为true 代表全部执行完了
5.每次调用函数 都把最新的数据添加到 goodList中 注意(一开始获取和添加不是同一个方法 只是同一个API)
以上是关于vue3.0项目中手动封装加载更多数据(常见)的主要内容,如果未能解决你的问题,请参考以下文章
web前端页面水印的实现,防手动删除和修改,支持vue3.0+vite项目