原理是通过touchstart
touchmove
touchend
三个事件配合transform
属性实现
<div ref="mattersContent" @touchstart='touchStart' @touchmove='touchMove' @touchend='touchEnd' :style="{transform: 'translateX('+translateX+'px)',transition: transition+'s',white-space: 'nowrap'}">
<div :style="{width:'100%',height:'200px'}">1111</div>
<div :style="{width:'100%',height:'200px'}">2222</div>
</div>
在touchstart
事件中需要特别注意的是需要保存当前触发时的transform
的值特别是translateX
的值,因为不是每次触发按下事件都是没有进行滑动过的,只要进行了过滑动计算距离就不能单单是clientX距离页面的绝对距离了 需要配合上上一次的transform
才能实现正常的滑动
data() {
return {
isFirst:false,
x: 0,
y: 0,
_x: 0,
_y: 0,
translateX: 0,
startTranslate:0,
transition:0,
},
}
methods: {
touchStart(e) {
// this.x this.y 按下时 触点位置
// transition每次点击时 清除过渡时间
// this.startTranslate是当前按下时的translateX的值 需要这个变量的原因是可能当前位置是有过translate移动的 如果不加上相当于每次都是translateX(0)
this.transition = 0
this.x = e.touches[0].clientX;
this.y = e.touches[0].clientY;
console.log('touchStart',this.x,this.y)
this.startTranslate = this.translateX
},
touchMove(e) {
// this._x this._y 移动时 触点位置
this._x = e.touches[0].clientX
this._y = e.touches[0].clientY
// console.log('touchMove',this._x,this._x)
// disY disX计算是不是左右滑动
let disY = Math.abs(this._y - this.y)
let disX = Math.abs(this._x - this.x)
if (this.isFirst) {
this.isFirst = false;
//判断方向
if (disY > disX) {
this.isHori = false;
}
if (disY < disX) {
this.isHori = true;
}
}
//判断方向 决定是否阻止默认行为
if (this.isHori) {
e.preventDefault();
e.stopPropagation()
} else {
return;
}
// 每一次触发都要移动时间 就改变一次translate
this.translateX = this._x - this.x + this.startTranslate;
// console.log('this.translateX = this._x - this.x + this.translateX;', this._x , this.x ,this.translateX,this._x - this.x + this.translateX)
},
touchEnd(e) {
this.isFirst = true
if (!this.isHori) return;
let mattersContentWidth = this.$refs.mattersContent.offsetWidth;
if (e.changedTouches.length == 1) {
this._x = e.changedTouches[0].clientX;
// 移动时的x 减去 初始位置的x 就是移动的距离 负为左滑 正为右滑
this.disX = this._x - this.x;
console.log(this.disX, 'this.disX')
// console.log((mattersContentWidth / 2), 'mattersContentWidth/2');
// 只有滑动距离大于整个宽的一半距离才进行切换
if (Math.abs(this.disX) > (mattersContentWidth / 2)) {
if (this.disX < 0) {
console.log('左滑',mattersContentWidth);
// transform直接累加一个宽 这里需要注意根据自己能滑动的次数判断 如果多的话用累加 += 要设上边界值
this.translateX = - mattersContentWidth
this.transition = 0.2
}
else {
console.log('右滑',this.startTranslate, mattersContentWidth,this.startTranslate + mattersContentWidth,this.startTranslate >= mattersContentWidth ? this.startTranslate - mattersContentWidth : 0);
this.transition = 0.2
// 右滑时 如果当前点下时保存的startTranslate大于宽说明可以右滑 否者说明已经是最边上了 直接为0
this.translateX = Math.abs(this.startTranslate) >= mattersContentWidth ? this.startTranslate + mattersContentWidth : 0
}
} else{
// 没有大于整个宽的一半 恢复按下时初始位置的startTranslate
console.log('没有超过临结值 不变',this.startTranslate);
this.transition = 0.2
this.translateX = this.startTranslate
}
}
}
}