微信小程序翻书效果
wxml
<view
wx:for="{{imgList}}"
hidden="{{pagenum > imgList.length - index - 1}}"
wx:key="index"
class="list-pape"
style="{{index == imgList.length - pagenum - 1 ? clipPath1 : ''}}"
bindtouchstart="touchstart"
bindtouchmove="touchmove"
bindtouchend="touchend">
<image src="{{item}}" mode="aspectFit" data-src="{{item}}" bindtap="previewImage"></image>
</view>
<!-- 背面部分 -->
<view wx:if="{{transformCss}}" class="page-back" style="{{transformCss}};{{clipPath2}};{{transformOrigin}}">
<image src="{{pageBackImage}}" mode="aspectFit"></image>
</view>
js
data:{
imgList:[ ],
pageBackImage: '',
transformCss: '',
transformOrigin: '',
clipPath2: '',
clipPath1: '',
pagenum: 0,
startPoint: 0, //记录滑动的初始位置
slipFlag: false, //定义 滑动事件 节流阀, 防止一次滑动触发多次滑动事件
imgboxh: 0,
imgboxw: 0,
}
touchstart:function(e) {
this.setData({
startPoint: e.touches[0],
slipFlag: true
})
},
touchmove:function(e) {
let clientX = e.touches[0].clientX;
let clientY = e.touches[0].clientY;
if (((this.data.startPoint.clientX - clientX) > 80) && this.data.slipFlag) {
console.log("左滑事件");
this.setData({
slipFlag: false
})
this.next()
} else if (((this.data.startPoint.clientX - clientX) < -80) && this.data.slipFlag) {
console.log("右滑事件");
this.setData({
slipFlag: false
})
this.prev()
}
},
touchend:function() {
this.setData({
pageBackImage: this.data.imgList[this.data.imgList.length - this.data.pagenum - 1],
transformCss: '',
transformOrigin: '',
clipPath2: 'clip-path: polygon(100% 100%, 100% 100%, 100% 100%)',
clipPath1: '',
})
},
//计算翻书效果
flippingPage:function(clientX,clientY){
// 本人比较懒,这里写死了书的宽度和高度
let width = this.data.imgboxw;
let height = this.data.imgboxh;
let x = width - clientX;
let y = height - clientY;
let a = ((x/2 * x/2) + (y/2 * y/2)) / (x/2);
let b = ((x/2 * x/2) + (y/2 * y/2)) / (y/2);
a = a > width ? width : a;
let angle = (Math.atan(a / b) * (180 / Math.PI));
angle = 180 - angle * 2;
this.setData({
pageBackImage: this.data.imgList[this.data.imgList.length - this.data.pagenum - 1],
transformCss: 'transform: rotateX(180deg) rotateZ('+ angle +'deg)',
transformOrigin: 'transform-origin: right '+ (height - b) +'px',
clipPath2: 'clip-path: polygon(100% 100%, ' + (width-a) +'px 100%, 100% ' + (height - b) + 'px)',
clipPath1: 'clip-path: polygon(0% 0%, 0% 100%, ' + (width-a) +'px 100%, 100% ' + (height - b) + 'px, 100% 0%)',
})
},
animate1(callback) {
let clientX = this.data.imgboxw;
let clientY = this.data.imgboxh;
let timer = setInterval(() => {
clientX -= 30;
clientY -= 1;
if (clientX < -this.data.imgboxw) {
clientX = -this.data.imgboxw;
clientY = this.data.imgboxh-1;
this.flippingPage(clientX, clientY)
clearInterval(timer);
this.setData({
transformCss: '',
transformOrigin: '',
clipPath2: 'clip-path: polygon(100% 100%, 100% 100%, 100% 100%)',
clipPath1: '',
})
callback && callback();
}
this.flippingPage(clientX, clientY)
}, 20);
},
animate2(callback) {
let clientX = -this.data.imgboxw;
let clientY = this.data.imgboxh;
let timer = setInterval(() => {
clientX += 30;
clientY -= 1;
if (clientX > this.data.imgboxw) {
clientX = this.data.imgboxw;
clientY = this.data.imgboxh-1;
this.flippingPage(clientX, clientY)
clearInterval(timer);
this.setData({
transformCss: '',
transformOrigin: '',
clipPath2: 'clip-path: polygon(100% 100%, 100% 100%, 100% 100%)',
clipPath1: '',
})
callback && callback();
}
this.flippingPage(clientX, clientY)
}, 20);
},
toHomePage() {
this.setData({
pagenum: 0
})
},
toLastPage() {
this.setData({
pagenum: this.data.imgList.length - 1
})
},
next() {
let pagenum = this.data.pagenum
if (pagenum > this.data.imgList.length - 2) return;
this.animate1(() => {
this.data._timer = setTimeout(()=>{
clearTimeout(this.data._timer)
pagenum++;
this.setData({
pagenum,
clipPath1: ''
})
},0)
})
},
prev() {
let pagenum = this.data.pagenum
if (pagenum <= 0) return;
pagenum--;
this.setData({
pagenum,
})
this.animate2(() => {})
},
css
.imgbox {
width: 100%;
position: relative;
transform-style: preserve-3d;
overflow: hidden;
height: calc(100% - 170px);
padding: 40rpx 0;
background-color: #000000;
}
.list-pape,
.page-back {
overflow: hidden;
width: 100%;
height: calc(100% - 80rpx);
position: absolute;
left: 0;
top: 40rpx;
/* box-shadow: 3px 0px 8px 0px #0000004d; */
}
.list-pape image,
.page-back image {
width: 100%;
height: 100%;
}
.page-back {
transform-origin: right bottom;
pointer-events: none;
filter: contrast(0.4);
}