微信小程序翻书效果

微信小程序翻书效果

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);
}
相关推荐
OEC小胖胖1 小时前
组件化思维(下):表单与交互组件,倾听用户的心声
前端·微信小程序·小程序·微信开放平台
2501_915921435 小时前
TCP 抓包分析实战,从抓取到定位(命令、常见症状、排查流程与真机抓包补充)
网络·网络协议·tcp/ip·ios·小程序·uni-app·iphone
2501_916013745 小时前
App 上架服务全流程解析,iOS 应用代上架、ipa 文件上传工具、TestFlight 测试与苹果审核实战经验
android·ios·小程序·https·uni-app·iphone·webview
2501_915909067 小时前
App Store 上架完整流程解析,iOS 应用发布步骤、ipa 文件上传工具、TestFlight 测试与苹果审核经验
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_916008897 小时前
iOS 26 全景揭秘,新界面、功能创新、兼容挑战与各种工具在新版系统中的定位
android·macos·ios·小程序·uni-app·cocoa·iphone
云起SAAS15 小时前
老年ai模拟恋爱抖音快手微信小程序看广告流量主开源
人工智能·微信小程序·小程序·ai编程·看广告变现轻·老年ai模拟恋爱·ai模拟恋爱
2501_9160137417 小时前
iOS 混淆与 App Store 审核兼容性 避免被拒的策略与实战流程(iOS 混淆、ipa 加固、上架合规)
android·ios·小程序·https·uni-app·iphone·webview
宠友信息17 小时前
类似小红书垂直社区APP小程序源码
java·开发语言·微信小程序·小程序·uni-app·开源·web app
Stanford_110617 小时前
关于单片机的原理与应用!
c++·单片机·嵌入式硬件·微信小程序·微信公众平台·微信开放平台
OEC小胖胖19 小时前
交互的脉络:小程序事件系统详解
前端·微信小程序·小程序·微信开放平台