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存放懒加载逻辑的函数

import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
 
/**
 * 用于懒加载数据
 * @param {*} apiFn 懒加载数据的接口
 * @returns target: 需要绑定的DOM对象  result: 结果数据
 */
export const useLazyData = (apiFn: Function) => {
  const target = ref(null)
  const result = ref()
  let stopObserver // 保存观察者的停止函数

  const { stop } = useIntersectionObserver(target, ([{ isIntersecting }], observerElement) => {
    if (isIntersecting) {
      stopObserver() // 调用之前保存的停止函数
      apiFn().then((data) => {
        if (data) {
          result.value = data
        }
      })
    }
  })

  stopObserver = stop // 保存观察者的停止函数

  return { target, result,stopObserver }
}

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

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

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

<section ref="target">
     <span>{{ newData?.end_time }}</span>
 </section>
import { defaultProps } from './props'

const props = defineProps(defaultProps)
const emits = defineEmits(['update'])
const { modelValue, endTime } = toRefs(props)

const newData: Ref<App.BatteryTest> = ref(unref(modelValue))
//封装接口请求
const getDeadline = () => {
.test(参数, {
     //逻辑代码
    })
    .then(([res]) => {
  if (res?.status === 200) {
        nextTick(() => {
         
          newData.value = { ...unref(newData), end_time: dateFormat(res?.data?.Deadline / 1000) + '' }
          emits('update', unref(newData))

          updateLoadedData() //更新已经加载的数据    
        })
        return dateFormat(res?.data?.Deadline / 1000) + ''//这里返回给hook中定义的useLazyData中的result
      }else {
        nextTick(() => {
          newData.value = { ...unref(newData), end_time: '' }

          emits('update', unref(newData))
          updateLoadedData() //更新已经加载的数据
        })

        return ''
      }
})




function dateFormat(date: any) {
  //转变导出报表记录日期格式

  if (date == undefined || date == 0) {
    return ''
  }

  return moment(date * 1000).format('YYYY-MM-DD HH:mm:ss')
}

//更新已经加载的数据isLoaded: true,存入状态机
function updateLoadedData() {

  let bbarr = cloneDeep(store.state.loadedTestData)
  bbarr.push({ ...unref(newData), isLoaded: true })
  store.commit('LOADED_TEST_DATA',bbarr)
}


const { target, result, stopObserver } = useLazyData(getDeadline)
//监听穿入子组件的props数据
watch(
  modelValue,
  newValue => {
   
      let originArr = cloneDeep(store.state.loadedTestData)
      if (originArr.length > 0) {
        // 停止观察已经加载的节点
        const hasSameId = originArr.some(item => item.id === unref(modelValue)?.id && item.isLoaded)
        if (hasSameId) {
          stopObserver()
          const item = originArr.find(item => item.id === unref(modelValue)?.id && item.isLoaded)
          newData.value.end_time = formateEndTime(item.end_time)//重新赋值为原来的数据
        } 
      } 
    
  },
  { deep: true, immediate: true }
)


父组件:
 

            <vxe-column
              :key="index"
              v-bind.sync="column"
              :field="column.prop"
              :title="column.label"
              width="item.minWidth"
              show-overflow
              :formatter="column.prop === 'test_state' ? formatTestState : null"
              :sortable="column.prop !== 'end_time'"
              v-if="column.checked"
            >
              <template v-else-if="column.prop === 'end_time'" #default="{ row }">
                <!-- <battary-loading :end-time="row.end_time" :model-value.sync="row" :class="[endTimeClass, endTimeBreathLight(row.end_time)]"></battary-loading> -->
                <battary-loading :end-time="row.end_time" :model-value.sync="row" @update="getTableRow"></battary-loading>
              </template>
            <vxe-column/>


//在nMounted里面重置为[]
    onMounted(() => {
      
      store.commit('LOADED_TEST_DATA',[])
})
//如果有分页,可在分页事件中将OADED_TEST_DATA重新置为空数组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值