【山竹记账前端-vue】7.滑动手势封装 useSwipe Hook
大纲链接 §
[toc]
1. 重构拆分组件 ⇧
拆分组件
@/views/WelcomeView.tsx
- 注意原本纯函数式写法不支持
vue组件生命周期钩子函数- 在纯函数组建中使用生命周期钩子的话会报警告
[Vue warn]:onMounted is called when there is no active component instance to be associated with.Lifecycle injection APIs can only be used during execution of setup().
在拆分的组件
@/modules/welcome/MainSwiper.tsx中改为使用defineComponent用法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23import { defineComponent } from 'vue' import { WelcomeHeader } from '@/modules/welcome/WelcomeHeader.tsx' import { WelcomeSkipper } from '@/modules/welcome/WelcomeSkipper.tsx' import { MainSwiper } from '@/modules/welcome/MainSwiper.tsx' import s from '@/views/WelcomeView.module.scss' export const WelcomeView = defineComponent( () => { return () => ( <div class={s.wrapper}> <WelcomeHeader /> <MainSwiper /> <WelcomeSkipper /> </div> ) }, { props: {}, name: 'WelcomeView', }, )
@/modules/welcome/WelcomeHeader.tsx
|
|
@/modules/welcome/WelcomeSkipper.tsx
|
|
@/modules/welcome/MainSwiper.tsx
|
|
@/modules/welcome/MainSwiper.scoped.scss
|
|
@/views/WelcomeView.module.scss
|
|
2. 实现思路与为 useSwipe 搭框架 ⇧
支持滑动事件
- 使用 Hooks,即使用 Composition Api 实现
- 只支持在手机端触控滑动,不管 PC 鼠标事件
@/hooks/useSwipe.ts
|
|
引入到
@src/modules/welcome/MainSwiper.tsx
|
|
- 声明
const mainRef = useTemplateRef<HTMLElement>('mainRef') - 关联
<main ref="mainRef">
3. 监听 Touch / Pointer 事件 ⇧
思路
onMounted组件挂载后再监听事件- 手指先按下 对应
ontouchstart - 手指滑动 对应
ontouchmove - 手指松开 对应
ontouchend
- 手指先按下 对应
- 移动方向判定:手指按下的瞬间,记录一个坐标;在移动时,记录一个坐标,并对比大小
- y 坐标轴向下,x 坐标轴向右
- 松开时y坐标比按下时y坐标大,则向下移动
- 松开时x坐标比按下时x坐标大,则向右移动
@/hooks/useSwipe.ts
|
|
- 坐标数据类型
type Point = {x: number; y: number} - 记录开始按下的坐标
const start = ref<Point>() - 记录松开的坐标
const end = ref<Point>() - 只处理单指点击的情况
e.touches[0] - 记录是否在移动
const isSwiping = ref(false) - 计算移动距离:<开始坐标 - 结束坐标>
x: end.x - start.xy: end.y - start.y- 使用计算属性做缓存
- 根据
start和end计算方向:- 先判断 x、y 绝对值距离更大的一方作为主要方向
- 再根据 x、y 和 0 比较结果返回方向字符串
- 使用计算属性做缓存
- 回调函数
onStart- 记录开始位移坐标,清空上一次结束坐标位移
- 将是否滑动状态设置为 true
- 回调函数
onMove- 记录当前位移坐标为结束坐标
- 回调函数
onEnd- 清空开始坐标和结束坐标
- 将是否滑动状态设置为 false
- 声明终止控制器
const aborter = new AbortController()- 声明监听事件选项
const opt = { signal: aborter.signal }
- 声明监听事件选项
onMounted组件挂载后再监听事件,添加三个回调,并提供参数选项opt终止信号onUnmounted组件卸载,终止控制器取消监听事件aborter.abort()
参考
4. 滑动切换路由 + 重构 ⇧
统一编码规范之 ref 模板引用-泛型传参和默认值 ⇧
- 由于纯函数式写法不支持
vue组件生命周期钩子函数,而已注册的ref必须在组件挂载后才可以获取 - 所以不支持
FunctionalComponent
推荐使用 ✅
|
|
不推荐使用 ❌
|
|
在返回的节点标签上注册
|
|
参考
获取当前路由实例跳转 ⇧
- 获取
const router = useRouter() - 跳转
router.push('/welcome/2') - 判断仅当正在滑动,并且方向向左时,执行跳转
@/modules/welcome/MainSwiper.tsx
|
|
先完成两个欢迎页面跳转哈希表映射跳转逻辑
@/modules/welcome/MainSwiper.tsx
- 使用
useRoute()获取当前路由信息中的name属性
需要在路由表中添加各个路由的
name属性,修改@/router/routes.ts
|
|
@/modules/welcome/MainSwiper.tsx
|
|
滑动事件连续触发,滑动一下就跳转到最后一页了
- 需要添加Touch 事件节流控制
滑动触发 Touch 事件,使用节流控制 ⇧
@/shared/throttle.ts
|
|
使用节流控制滑动事件
@/modules/welcome/MainSwiper.tsx
|
|
根据路由名称对应跳转哈希表进行跳转 ⇧
@/modules/welcome/MainSwiper.tsx
|
|
如果不想用户回退,路由跳转方法使用
replace代替push即可
添加配置选项,包含6个钩子函数,自定义3个滑动动作前后逻辑,添加阻止默认行为 ⇧
手势向左左滑,浏览器默认有一个左滑空白的弹性动画占据部分页面
- 在
useSwipe中的onStart的逻辑中调用e.preventDefault()来阻止 - 但阻止逻辑并不是每一个事件逻辑都会需要的,可以通过参数传入来控制是否需要
- 提供一个选项
useSwipe(elementRef: ref<HTMLElement>, options?: EventOptions) - 但
preventDefault会影响所有子节点的事件默认行为,暂时不配置,仅实现useSwipe选项配置
@/hooks/useSwipe.ts
|
|
5. 选看:TS 类型体操 ⇧
@/shared/throttle.ts
|
|
或者声明一个函数泛型
F,使用Parameters<F>1 2 3 4 5 6 7 8 9 10 11 12 13 14export const throttle = <F extends (...args: unknown[]) => any>(fn: F, delay: number = 500) => { let timer: NodeJS.Timeout | null = null let result: ReturnType<F> return (...args: Parameters<F>) => { if (timer) { return result } result = fn(...args) timer = setTimeout(() => { timer = null }, delay) return result } }
6. 选看:对比同行的代码,VueUse 社区的实现 usePointerSwipe 和 useSwipe ⇧
安装
@vueuse/core
|
|
使用
usePointerSwipe
- 引入
import { usePointerSwipe } from '@vueuse/core' - 替换
const { isSwiping, direction } = usePointerSwipe(mainRef)即可
使用
useSwipe
- 引入
import { useSwipe } from '@vueuse/core' - 替换
const { isSwiping, direction } = useSwipe(mainRef)即可
总结 ⇧
- 纯函数式写法不支持
vue组件生命周期钩子函数,包括使用了生命周期钩子的自定义封装的钩子函数 - 使用
AbortController可卸载事件监听 - 使用
e.preventDefault()可阻止手机默认的整个页面弹性滑动效果
参考文章
1~3
4~5
相关文章
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名