• vue3接口、数据懒加载,回滚不重复加载


    目标:实现当组件进入可视区域在加载数据或者发送请求。

    背景:父组件为vxe-table构成的组件、子组件为table的某一列,这一列的数据通过接口返回,有多少条表格数据就会请求多少次接口,为了提升性能,所以采用接口懒加载,但是需要在回滚的时候不重复请求或者加载数据

    • 使用 @vueuse/core 中的 useIntersectionObserver 来实现监听进入可视区域行为,但是必须配合vue3.0的组合API的方式才能实现。
    • 对某个板块进行数据懒加载,首先要获取到这个dom元素,然后用useIntersectionObserver来监听这个dom,一旦可视区进入了这个dom元素这里,就可以进行请求数据接口
    • 安装@vueuse/core包,它封装了一些常见的交互逻辑
    • 通过状态机保存在列表上已经加载过了的数据,并打上已经加载过了的标签:isLaded:rue,回滚时就对比传入子组件的row数据的id与存入状态机的数据是否有id相同的一条,并查看是否 已存在isLoaded

    npm i @vueuse/core@4.9.0

    步骤:

    • 理解 useIntersectionObserver 的使用,各个参数的含义
    • 封装 useLazyData 函数,作为数据懒加载公用函数
    • 把 index.vue页面里数据改造成懒加载方式

    页面准备:

    src/hook.ts存放懒加载逻辑的函数

    1. import { useIntersectionObserver } from '@vueuse/core'
    2. import { ref } from 'vue'
    3. /**
    4. * 用于懒加载数据
    5. * @param {*} apiFn 懒加载数据的接口
    6. * @returns target: 需要绑定的DOM对象 result: 结果数据
    7. */
    8. export const useLazyData = (apiFn: Function) => {
    9. const target = ref(null)
    10. const result = ref()
    11. let stopObserver // 保存观察者的停止函数
    12. const { stop } = useIntersectionObserver(target, ([{ isIntersecting }], observerElement) => {
    13. if (isIntersecting) {
    14. stopObserver() // 调用之前保存的停止函数
    15. apiFn().then((data) => {
    16. if (data) {
    17. result.value = data
    18. }
    19. })
    20. }
    21. })
    22. stopObserver = stop // 保存观察者的停止函数
    23. return { target, result,stopObserver }
    24. }

    在状态机中定义好状态机的一切

    1. [RootMutations.LOADED_TEST_DATA](state: RootState, value) {
    2. state.loadedTestData = value
    3. },

    子组件:绑定target,使用懒加载

    1. <section ref="target">
    2. <span>{{ newData?.end_time }}span>
    3. section>
    1. import { defaultProps } from './props'
    2. const props = defineProps(defaultProps)
    3. const emits = defineEmits(['update'])
    4. const { modelValue, endTime } = toRefs(props)
    5. const newData: Ref<App.BatteryTest> = ref(unref(modelValue))
    6. //封装接口请求
    7. const getDeadline = () => {
    8. .test(参数, {
    9. //逻辑代码
    10. })
    11. .then(([res]) => {
    12. if (res?.status === 200) {
    13. nextTick(() => {
    14. newData.value = { ...unref(newData), end_time: dateFormat(res?.data?.Deadline / 1000) + '' }
    15. emits('update', unref(newData))
    16. updateLoadedData() //更新已经加载的数据
    17. })
    18. return dateFormat(res?.data?.Deadline / 1000) + ''//这里返回给hook中定义的useLazyData中的result
    19. }else {
    20. nextTick(() => {
    21. newData.value = { ...unref(newData), end_time: '' }
    22. emits('update', unref(newData))
    23. updateLoadedData() //更新已经加载的数据
    24. })
    25. return ''
    26. }
    27. })
    28. function dateFormat(date: any) {
    29. //转变导出报表记录日期格式
    30. if (date == undefined || date == 0) {
    31. return ''
    32. }
    33. return moment(date * 1000).format('YYYY-MM-DD HH:mm:ss')
    34. }
    35. //更新已经加载的数据isLoaded: true,存入状态机
    36. function updateLoadedData() {
    37. let bbarr = cloneDeep(store.state.loadedTestData)
    38. bbarr.push({ ...unref(newData), isLoaded: true })
    39. store.commit('LOADED_TEST_DATA',bbarr)
    40. }
    41. const { target, result, stopObserver } = useLazyData(getDeadline)
    42. //监听穿入子组件的props数据
    43. watch(
    44. modelValue,
    45. newValue => {
    46. let originArr = cloneDeep(store.state.loadedTestData)
    47. if (originArr.length > 0) {
    48. // 停止观察已经加载的节点
    49. const hasSameId = originArr.some(item => item.id === unref(modelValue)?.id && item.isLoaded)
    50. if (hasSameId) {
    51. stopObserver()
    52. const item = originArr.find(item => item.id === unref(modelValue)?.id && item.isLoaded)
    53. newData.value.end_time = formateEndTime(item.end_time)//重新赋值为原来的数据
    54. }
    55. }
    56. },
    57. { deep: true, immediate: true }
    58. )

    父组件
     

    1. <vxe-column
    2. :key="index"
    3. v-bind.sync="column"
    4. :field="column.prop"
    5. :title="column.label"
    6. width="item.minWidth"
    7. show-overflow
    8. :formatter="column.prop === 'test_state' ? formatTestState : null"
    9. :sortable="column.prop !== 'end_time'"
    10. v-if="column.checked"
    11. >
    12. <template v-else-if="column.prop === 'end_time'" #default="{ row }">
    13. <battary-loading :end-time="row.end_time" :model-value.sync="row" @update="getTableRow">battary-loading>
    14. template>
    15. <vxe-column/>
    16. //在nMounted里面重置为[]
    17. onMounted(() => {
    18. store.commit('LOADED_TEST_DATA',[])
    19. })
    20. //如果有分页,可在分页事件中将OADED_TEST_DATA重新置为空数组

  • 相关阅读:
    开源照片管理服务LibrePhotos
    全新升级!《云原生架构白皮书 2022 版》重磅发布
    万向区块链王允臻:区块链如何助力文旅产业元宇宙?
    CRM 概念:了解Leads、Prospect、MQL 和 SQL 的概念
    灵性·挖掘 4:自我迭代之路
    SQL错题集(二)
    【前端面试题】【交互】
    《uni-app》一个非canvas的飞机对战小游戏实现-敌机模型实现
    MSP430F149用模拟SPI和FM25CL640通信
    网络机顶盒哪个牌子好?横评25款整理网络机顶盒排行榜
  • 原文地址:https://blog.csdn.net/weixin_60886885/article/details/134332704