业务需求
背景:
如上图所示,此el-table列表数据接口包含包括测试结束时间以及测试状态在内的数据,根据测试状态判定:1、非测试中:测试结束时间采用的是列表接口返回的测试结束时间数据。2、测试中:测试结束时间采用的是另外一个专门用来返回测试结束时间的携带每一条从行获取的参数的接口deadline接口的返回值
此时,如果不加以控制,再pagesize过大时,就会一次性请求太多次deadline接口。
所以,采用@vueuse/core
为我们提供的 useIntersectionObserver
方法,实现滚动到相应位置的可视区域时再请求可视区域的deadline接口
落地代码
@vueuse/core
为我们提供的 useIntersectionObserver
方法
0、安装vueUse:
npm i @vueuse/core
1、封装hooks 新建hooks.ts文件
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
/**
* 用于懒加载数据
* @param {*} apiFn 懒加载数据的接口
* @returns target: 需要绑定的DOM对象 result: 结果数据
*/
export const useLazyData = (apiFn) => {
// 需要
// 1. 被观察的对象
// 2. 不同的API函数
const target = ref(null)
const result = ref([])
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
if (isIntersecting) {
stop()
// 调用API获取数据
apiFn().then(data => {
if(data){
result.value = data.result
}
})
}
}
)
// 返回--->数据(dom,后台数据)
return { target, result }
}
2、该表格列表的测试结束时间列采用了插槽
<el-table-column v-else-if="column.prop === 'end_time'" v-bind="column">
<template v-slot="{ row }">
<battaryLoading :endTime="row.end_time" :modelValue="row" :class="['endTimeClass',endTimeBreathLight(row.end_time)]"></battaryLoading>
</template>
</el-table-column>
3、直接进入battaryLoading 组件,绑定ref为target(如果没有封装组件就在需要懒加载的元素上绑定即可)
<template>
<div>
<!-- 测试中 state = 1 -->
<section v-if="modelValue?.test_state === 1" ref="target">
<!-- loading -->
<section v-if="isLoading">
<AppSvgIcon class="animate-spin h-20 w-20" iconName="icon-battery-loading"></AppSvgIcon>
<span class="text-gray-700 text-14 ml-3">Loading</span>
</section>
<section v-else class="flex items-center">
<span>{{ newData?.end_time }}</span> <span v-if="newData?.end_time" class="bg-[#FFF7ED] rounded text-[#EA580C] px-4 ml-5">预计</span>
</section>
</section>
<!-- 非测试中 -->
<section v-else>
{{ $filters.formatDatetime(endTime) }}
</section>
</div>
</template>
4、引入封装的 useLazyData hook
import { useLazyData } from './hook.ts'
5、封装api请求,并调用hook,传入api
//封装api
const payLoad = {
//请求参数
}
const getDeadline = () => {
return api('DataCheck/deadline')
.test(payLoad, {
showErrorMessage: false,
})
.then(([res]) => {
if (res?.status === 200) {
isLoading.value = false
nextTick(() => {
newData.value = { ...unref(newData), end_time: parseTime(res?.data?.Deadline) + '' }
})
} else {
nextTick(() => {
newData.value = { ...unref(newData), end_time: '' }
})
}
})
.catch(e => {
console.error(e)
})
.finally(() => {
setTimeout(() => {
isLoading.value = false
}, 3000)
})
}
//解构出调用了hook并传了参数return出来的target, result
const { target, result } = useLazyData(getDeadline)
!!!注意:此时存在一个问题,当切换页码大小或者点击头部的刷新刷新表格数据,而非刷新浏览器时,表格不会再次刷新dom,useIntersectionObserver 不会再次执行
解决方案:改变页码大小,刷新表格时强制刷新el-table的dom
<el-table :key="tableKey"/>
//在刷新表格的方法中
function handlerRefresh() {
getTests()
tableKey.value= +new Date()//改变key
}
//在监听分页中
watch([() => pagination.currentPage, () => pagination.pageSize], () => {
getTests().then(() => {
tableKey.value= +new Date()//改变key
})
})
参考:vue强制更新dom
参考: vue 第三方方法 useIntersectionObserver 实现数据懒加载_vue 懒加载第三方依赖_新时代农民工Top的博客-CSDN博客
此时就完美了,表格滚动条滚动到哪儿,需要懒加载的接口才会被触发