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/[email protected]

步骤:

  • 理解 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,使用懒加载

{{ newData?.end_time }}
import { defaultProps } from './props'

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

const newData: Ref = 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 }
)


父组件:
 

            
              
            


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

你可能感兴趣的:(javascript,前端,vue.js)