实现一个可左右滑动操作的vue3组件
2023-09-27 14:27:34 时间
为了实现左右滑动能够切换页面,便有了做成组件的想法。
代码实现
监听touchstart
,记录开始位置。
监听touchmove
,记录移动的位置,计算移动的方向,再把值设置给translateX
(计算结果的值要能够跟随手指移动),加入锁定方向,是为禁止斜方向滑动。
监听touchend
,在这里判断是否触发change事件。
<script setup>
import { ref } from "vue";
const props = defineProps({
leftDisabled: {
type: Boolean,
default: false
},
rightDisabled: {
type: Boolean,
default: false
}
});
const emit = defineEmits(["change"]);
// 纵向滑动时禁止水平滑动,水平滑动时禁止纵向滑动;
// 水平滑动结束超过屏幕二分之一时则toggle;
// 最大可滑动不超过屏幕的三分之二;
const startX = ref(0);
const startY = ref(0);
const endX = ref(0);
const endY = ref(0);
const dValueX = ref(0);
const dValueY = ref(0);
const translateX = ref(0);
const horizontalMoved = ref(false);
const verticalMoved = ref(false);
const onTouchStart = (e) => {
startX.value = e.targetTouches[0].pageX;
startY.value = e.targetTouches[0].pageY;
};
const onTouchMove = (e) => {
endX.value = e.targetTouches[0].pageX;
endY.value = e.targetTouches[0].pageY;
dValueX.value = Math.abs(startX.value - endX.value);
dValueY.value = Math.abs(startY.value - endY.value);
const stopRange = window.screen.width - window.screen.width / 3;
// 水平滑动长度大于纵向滑动长度,选择水平滑动
if (dValueX.value > dValueY.value) {
if (verticalMoved.value) {
e.preventDefault();
return;
} else horizontalMoved.value = true;
if (dValueX.value < stopRange) {
if (startX.value > endX.value) {
if (!props.leftDisabled) translateX.value = dValueX.value * -1; // 向左划
} else {
if (!props.rightDisabled) translateX.value = dValueX.value;
}
}
e.preventDefault();
} else {
if (horizontalMoved.value) e.preventDefault();
else verticalMoved.value = true;
}
};
const onTouchEnd = (e) => {
const range = window.screen.width / 2;
if (horizontalMoved.value) {
if (dValueX.value > range) {
if (startX.value > endX.value) {
// console.log("向左划");
if (!props.leftDisabled) handleChange("left");
} else if (startX.value < endX.value) {
// console.log("向右划");
if (!props.rightDisabled) handleChange("right");
}
}
}
horizontalMoved.value = false;
verticalMoved.value = false;
translateX.value = 0;
startX.value = endX.value = 0;
startY.value = endY.value = 0;
};
const handleChange = (value) => emit("change", value);
</script>
<template>
<div
:style="`transition-duration: 200ms; transform: translateX(${translateX}px)`"
>
<slot
:touchstart="onTouchStart"
:touchmove="onTouchMove"
:touchend="onTouchEnd"
></slot>
</div>
</template>
复制代码
如何使用
在onToggleChange
里做路由跳转等其它操作。
<swipe-container @change="onToggleChange">
<template #default="{ touchstart, touchmove, touchend }">
<div
class="list"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"
>
<div
v-for="item in list"
class="card"
></div>
</div>
</template>
</swipe-container>
相关文章
- 【Vue3】通过Teleport实现子组件div显示在整个页面中
- 【Vue3】通过provide和inject实现【祖组件与子组件】数据传参
- vue3中使用element-plus调用message
- 浅析Vue3动态组件怎么进行异常处理
- vue3学习笔记(异步组件,包含defineAsyncComponent、Suspense的使用)
- vue3学习笔记(兄弟组件传参)
- vite+vue3使用tailwindcss
- vue2和vue3插件的区别
- 一、trackingjs初体验-颜色捕获 vue3
- Vue3+elementplus搭建通用管理系统实例六:后台主页搭建下
- vue3在单页面使用
- Vue3响应式原理
- vue3+ts+vite之路由组件的搭建
- Vue3入门到精通-setup
- 浅析vue3在源码、性能和语法上对比vue2做了哪些优化
- Vue3:有关v-model的用法
- vue3:兄弟组件,跨组件传值,事件总线的通信方式(mitt / tiny-emitter)