移动端下拉刷新和加载更多实现

758 阅读2分钟

前言

前几天在捣鼓我那 H5 应用,之前打算不依赖组件库,所以把移动端相关的一些功能实现了,在此记录一下实现下拉刷新的过程。

实现原理

一图以蔽之:

image.png

简要概述:

  • 下拉触发
  • 手势释放时小于最小触发阈值 minConditionH,直接回弹
  • 否则容器设置偏移,并成功触发下拉
  • 偏移大于最大偏移阈值 maxConfitionH,则容器不再偏移
  • 触发下拉成功后,请求数据,数据请求成功,则显示成功文案,否则显示失败文案,并在一秒后回弹

代码实现

下拉 DOM 结构,采用 unocss 设置样式

  <div
    ref="container"
    class="relative h-full"
    @touchstart="touchstart"
    @touchmove="touchmove"
    @touchend="touchend"
  >
    <div class="absolute w-full center text-color -translate-y-100%">
      {{ text }}
    </div>
    <div class="h-full overflow-y-auto">
      <div v-for="(item, index) in list" :key="index">
        {{ item }}
      </div>
    </div>
  </div>

下拉事件处理程序

const list = ref(Array.from({ length: 1000 }, (_, index) => index))
// 开始下来位置
let startY = 0
// 下拉偏移量
let offsetY = 0
// 大于 minConditionH 才算触发下拉刷新
const minConditionH = 40
// 大于 maxConfitionH 则不做容器偏移
const maxConfitionH = 100
const text = ref('下拉刷新')
const container = ref()

function touchstart(evt: TouchEvent) {
  if (container.value.scrollTop === 0) {
    startY = evt.touches[0].pageY
    text.value = '下拉即可刷新'
  }
}

function touchmove(evt: TouchEvent) {
  const currentPosition = evt.touches[0].pageY
  offsetY = currentPosition - startY
  if (offsetY > minConditionH)
    text.value = '释放刷新'

  else
    text.value = '下拉即可刷新'

  // 限制下拉差值为 maxConfitionH,大于这个不再进行偏移
  if (offsetY < maxConfitionH) {
    container.value.style.transition = 'transform 0s'
    container.value.style.transform = `translateY(${offsetY}px)`
  }
}

function touchend() {
  // 如果下拉差值小于最小触发阈值,则回弹
  if (offsetY >= 0 && offsetY <= minConditionH) {
    container.value.style.transition = 'transform 1s'
    container.value.style.transform = 'translateY(0px)'
    offsetY = 0
    return
  }
  if (offsetY > 40) {
    // 下拉差值大于 最小阈值,则触发刷新
    container.value.style.transform = 'translateY(40px)'
    container.value.style.transition = 'transform 0.5s'
    text.value = '刷新中...'
    // 请求数据,现模拟
    setTimeout(() => {
      // 请求成功,则显示成功
      text.value = '刷新成功'
      // 先停留1s,再返回最初状态
      setTimeout(() => {
        container.value.style.transition = 'transform 0.5s'
        container.value.style.transform = 'translateY(0px)'
      }, 1000)
    }, 2000)
  }
  // 下拉结束后重置差值
  offsetY = 0
}

在线体验

加载更多

利用 composables api 可以非常方便的实现加载更多

import { debounce } from 'lodash-es'

export function useLoadMore(el: HTMLElement, cb: () => void) {
  useEventListener(el, 'scroll', debounce(() => {
    const clientHeight = el.clientHeight
    const scrollTop = el.scrollTop
    const scrollHeight = el.scrollHeight
    const top = Math.ceil(clientHeight + scrollTop)
    if (top >= scrollHeight)
      cb()
  }, 500, { leading: true }))
}

总结

本篇介绍了移动端的 下拉刷新加载更多 实现,接下来继续介绍移动端基本组件实现,欢迎关注!