小程序swiper demo
demo的性能太差,仅仅是提供思路,实际应用中需要优化
方案1(需要优化性能、上下滚动)
swiper.js
function swiper(that) {
that.handleStart = handleStart
that.handleMove = handleMove
that.handleEnd = handleEnd
}
/*
* @触摸起点
* @获取起点时间,起点坐标
*/
function handleStart(e){
const { timeStamp } = e // 起点时间
const { clientX, clientY } = e.touches[0] //起点坐标
this.setData({
touching: true,
startX: clientX,
startY: clientY,
startTime: timeStamp
})
}
/*
* @触摸变换
* @坐标轴
* X -> 右, X轴自左向右自增
* Y -> 下, Y轴自上向下自增
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|),终点X坐标 - 起点X坐标 > 0
* > 0;(页面向右滑动,偏移距离增大。偏移距离 = offsetOld + |X|)
* < 0;(页面向左滑动,偏移距离减小。偏移距离 = offsetOld - |X|)
*
*/
function handleMove(e){ // 坐标变换,触摸变换触发页面左右滑动
const { clientX, clientY } = e.touches[0]
let { startX, startY, offsetOld } = this.data
let _X = clientX - startX,
_Y = clientY - startY
if(Math.abs(_X) <= Math.abs(_Y))
return this.setData({ touching: false })
else
this.setData({ offset: offsetOld + _X })
}
/*
* @触摸结束
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|)
*
* @快速滑动: 时间最长小于300ms,最短距离50触发滑动事件 T < 300 && |X| >= 50
* @慢速滑动: T > 300 && |X| >= width/2
* index = 0 终止右移(X > 0),并复原move效果
* index = last 终止左移(X < 0),并复原move效果
*/
function handleEnd(e){ // 坐标变换终止
const { timeStamp, target: { dataset: { index } } } = e // index 小圆点变换状态
const { clientX, clientY } = e.changedTouches[0]
let { list, startX, startY, startTime, width, offset, offsetOld } = this.data
let T = timeStamp - startTime,
_X = clientX - startX,
_Y = clientY - startY,
X = Math.abs(_X),
Y = Math.abs(_Y)
if(X < Y || T < 300 && X < 50 || T >= 300 && X < Math.round(width/2) || index == 0 && _X > 0 || index == list.length - 1 && _X < 0) {
this.setData({
offset: offsetOld
})
}else {
// if(T <= 300) {
// this.setData({ duration: 300 })
// setTimeout(() => {
// this.setData({ duration: 0 })
// }, 300)
// }
if(_X < 0) width = -width
this.setData({
offset: offsetOld + width,
offsetOld: offsetOld + width,
})
}
}
module.exports = swiper
swiper.wxss
.page-swiper{
width:100%;
overflow-x:hidden;
}
.swiper-content{
display:flex;
min-height:100vh;
}
.swiper-content .content-slider{
width:100vh;
position: relative;
top:0;
left:0;
}
.swiper-content .content-slider:nth-child(odd){
background-color:#f5f5f5;
}
.overflow-hidden{
overflow:hidden;
}
index.js
const swiper = require('../../../../util/swiper')
Page({
data: {
list: [
{
page: '',
title: '展览展览'
},
{
page: '',
title: 'VIP专区VIP专区'
},
{
page: '',
title: '购票购票购票'
},
{
page: '',
title: '动态动态动态'
}
],
touching: false, // 触摸后防止抖动
duration: 600, // 延缓动画
offsetOld: 0, // 保留距离状态
offset: 0, // 向左移动的距离
startX: 0, // X轴起点坐标
startY: 0, // Y轴起点坐标
startTime: 0, // 触摸起点时间
width: 375 //默认屏幕宽度
},
/*
* @获取设备宽度
*/
onLoad() {
const res = wx.getSystemInfoSync()
this.setData({ width: res.windowWidth })
swiper(this)
},
})
index.wxml
<view class="page-swiper" bind:touchstart="handleStart" bind:touchmove="handleMove" bind:touchend="handleEnd">
<view class="swiper-content {{touching?'overflow-hidden':''}}" style="width:{{width*list.length}}px;transform: translate3d({{offset ? offset : 0}}px, 0px, 0px);transition-duration: {{duration}}ms;">
<view
class="content-slider"
wx:for-items="{{list}}"
wx:key="{{item}}"
data-index="{{index}}"
>
<scroll-view>
{{item.title}}
</scroll-view>
</view>
</view>
</view>
index.wxss
.page-swiper{
width:100%;
overflow-x:hidden;
}
.swiper-content{
display:flex;
min-height:100vh;
}
.swiper-content .content-slider{
width:100vh;
position: relative;
top:0;
left:0;
}
.swiper-content .content-slider:nth-child(odd){
background-color:#f5f5f5;
}
.swiper-transform {
transform: translate3d(0px, 0px, 0px);
transition-duration: 0ms;
}
实现2(不推荐)
index.js
Page({
data: {
list: [
{
page: '',
title: '展览展览'
},
{
page: '',
title: 'VIP专区VIP专区'
},
{
page: '',
title: '购票购票购票'
},
{
page: '',
title: '动态动态动态'
}
],
offsetOld: 0, // 保留距离状态
offset: 0, // 向左移动的距离
startX: 0, // X轴起点坐标
startY: 0, // Y轴起点坐标
startTime: 0, // 触摸起点时间
width: 375 //默认屏幕宽度
},
/*
* @获取设备宽度
*/
onLoad() {
const res = wx.getSystemInfoSync()
this.setData({ width: res.windowWidth })
},
/*
* @触摸起点
* @获取起点时间,起点坐标
*/
handleStart(e){
const { timeStamp } = e // 起点时间
const { clientX, clientY } = e.touches[0] //起点坐标
this.setData({
startX: clientX,
startY: clientY,
startTime: timeStamp
})
},
/*
* @触摸变换
* @坐标轴
* X -> 右, X轴自左向右自增
* Y -> 下, Y轴自上向下自增
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|),终点X坐标 - 起点X坐标 > 0
* > 0;(页面向右滑动,偏移距离增大。偏移距离 = offsetOld + |X|)
* < 0;(页面向左滑动,偏移距离减小。偏移距离 = offsetOld - |X|)
*
*/
handleMove(e){ // 坐标变换,触摸变换触发页面左右滑动
const { clientX, clientY } = e.touches[0]
let { startX, startY, offsetOld } = this.data
let _X = clientX - startX,
_Y = clientY - startY
if(Math.abs(_X) <= Math.abs(_Y)) return
this.setData({ offset: offsetOld + _X })
},
/*
* @触摸结束
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|)
*
* @快速滑动: 时间最长小于300ms,最短距离50触发滑动事件 T < 300 && |X| >= 50
* @慢速滑动: T > 300 && |X| >= width/2
* index = 0 终止右移(X > 0),并复原move效果
* index = last 终止左移(X < 0),并复原move效果
*/
handleEnd(e){ // 坐标变换终止
const { timeStamp, target: { dataset: { index } } } = e // index 小圆点变换状态
const { clientX, clientY } = e.changedTouches[0]
let { list, startX, startY, startTime, width, offset, offsetOld } = this.data
let T = timeStamp - startTime,
_X = clientX - startX,
_Y = clientY - startY,
X = Math.abs(_X),
Y = Math.abs(_Y)
// if(X < Y) return
if(X < Y || T < 300 && X < 50 || T >= 300 && X < Math.round(width/2) || index == 0 && _X > 0 || index == list.length - 1 && _X < 0) {
this.setData({
offset: offsetOld
})
}else {
if(_X < 0) width = -width
this.setData({
offset: offsetOld + width,
offsetOld: offsetOld + width,
})
}
}
})
index.wxss
.page-swiper{
width:100%;
overflow-x:hidden;
}
.swiper-content{
display:flex;
min-height:100vh;
}
.swiper-content .content-slider{
width:100vh;
position: relative;
top:0;
left:0;
}
.swiper-content .content-slider:nth-child(odd){
background-color:#f5f5f5;
}
.swiper-transform {
transition: all 100ms ease;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
}
index.wxml
<view class="page-swiper" bind:touchstart="handleStart" bind:touchmove="handleMove" bind:touchend="handleEnd">
<view class="swiper-content" style="width:{{width*list.length}}px">
<view
class="content-slider {{startTime ? 'swiper-transform':''}}"
style="left: {{offset}}px"
wx:for-items="{{list}}"
wx:key="{{item}}"
data-index="{{index}}"
>
{{item.title}}
</view>
</view>
</view>
抽象为工具 swiper.js
function swiper(that) {
that.handleStart = handleStart
that.handleMove = handleMove
that.handleEnd = handleEnd
}
/*
* @触摸起点
* @获取起点时间,起点坐标
*/
function handleStart(e){
const { timeStamp } = e // 起点时间
const { clientX, clientY } = e.touches[0] //起点坐标
this.setData({
startX: clientX,
startY: clientY,
startTime: timeStamp
})
}
/*
* @触摸变换
* @坐标轴
* X -> 右, X轴自左向右自增
* Y -> 下, Y轴自上向下自增
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|),终点X坐标 - 起点X坐标 > 0
* > 0;(页面向右滑动,偏移距离增大。偏移距离 = offsetOld + |X|)
* < 0;(页面向左滑动,偏移距离减小。偏移距离 = offsetOld - |X|)
*
*/
function handleMove(e){ // 坐标变换,触摸变换触发页面左右滑动
const { clientX, clientY } = e.touches[0]
let { startX, startY, offsetOld } = this.data
let _X = clientX - startX,
_Y = clientY - startY
if(Math.abs(_X) <= Math.abs(_Y)) return
this.setData({ offset: offsetOld + _X })
}
/*
* @触摸结束
*
* @上下滑动(|Y| > |X|),终止计算
* @左右滑动(|Y| < |X|)
*
* @快速滑动: 时间最长小于300ms,最短距离50触发滑动事件 T < 300 && |X| >= 50
* @慢速滑动: T > 300 && |X| >= width/2
* index = 0 终止右移(X > 0),并复原move效果
* index = last 终止左移(X < 0),并复原move效果
*/
function handleEnd(e){ // 坐标变换终止
const { timeStamp, target: { dataset: { index } } } = e // index 小圆点变换状态
const { clientX, clientY } = e.changedTouches[0]
let { list, startX, startY, startTime, width, offset, offsetOld } = this.data
let T = timeStamp - startTime,
_X = clientX - startX,
_Y = clientY - startY,
X = Math.abs(_X),
Y = Math.abs(_Y)
if(X < Y || T < 300 && X < 50 || T >= 300 && X < Math.round(width/2) || index == 0 && _X > 0 || index == list.length - 1 && _X < 0) {
this.setData({
offset: offsetOld
})
}else {
if(_X < 0) width = -width
this.setData({
offset: offsetOld + width,
offsetOld: offsetOld + width,
})
}
}
module.exports = swiper
修改index.js
const swiper = require('~/util/swiper')
Page({
data: {
list: [
{
page: '',
title: '展览展览'
},
{
page: '',
title: 'VIP专区VIP专区'
},
{
page: '',
title: '购票购票购票'
},
{
page: '',
title: '动态动态动态'
}
],
offsetOld: 0, // 保留距离状态
offset: 0, // 向左移动的距离
startX: 0, // X轴起点坐标
startY: 0, // Y轴起点坐标
startTime: 0, // 触摸起点时间
width: 375 //默认屏幕宽度
},
/*
* @获取设备宽度
*/
onLoad() {
const res = wx.getSystemInfoSync()
this.setData({ width: res.windowWidth })
swiper(this)
}
})