微信小程序手势冲突?不存在的!

原生的应用经常会有页面嵌套列表,滚动列表能够改变列表大小,然后还能支持列表内下拉刷新等功能。看了很多的小程序好像都没有这个功能,难道这个算是原生独享的吗,难道是由于手势冲突无法实现吗,冷静的思考了一下,又看了看小程序的手势文档(文档地址),感觉我又行了。

实现效果如下:

a.gif

页面区域及支持手势

  • 红色的是列表未展开时内容展示,无手势支持
  • 绿色部分是控制部分,支持上拉下拉手势,对应展开列表及收起列表
  • 蓝色列表部分,支持上拉下拉手势,对应展开列表,上拉下拉刷新等功能
  • 浅蓝色部分是展开列表后的小界面内容展示,无手势支持

原理实现

主要是根据事件系统的事件来自行处理页面应当如何响应,原理其实同原生的差不多。
主要涉及 touchstart、touchmove、touchend、touchcancel 四个

另外的scrollview的手势要借助于 scroll-y、refresher-enable 属性来实现。

之后便是稀疏平常的数学加减法计算题环节。根据不同的内容点击计算页面应当如何绘制显示。具体的还是看代码吧,解释起来又要吧啦吧啦了。

Talk is cheap, show me the code

代码部分

wxml

<!--index.wxml-->
<view>
  <view class="header" style="opacity: {{headerOpacity}};height:{{headerHeight}}px;"></view>
  <view 
    class="toolbar"
    data-type="toolbar"
    style="bottom: {{scrollHeight}}px;height:{{toolbarHeight}}px;"
    catch:touchstart="handleToolbarTouchStart"
    catch:touchmove="handleToolbarTouchMove"
    catch:touchend="handleToolbarTouchEnd"
    catch:touchcancel="handleToolbarTouchEnd"></view>
  <scroll-view 
    class="scrollarea" 
    type="list"
    scroll-y="{{scrollAble}}"
    refresher-enabled="{{scrollAble}}"
    style="height: {{scrollHeight}}px;"
    bind:touchstart="handleToolbarTouchStart"
    bind:touchmove="handleToolbarTouchMove"
    bind:touchend="handleToolbarTouchEnd"
    bind:touchcancel="handleToolbarTouchEnd"
    bindrefresherrefresh="handleRefesh"
    refresher-triggered="{{refreshing}}"
    >
    <view class="item" wx:for="{{[1,2,3,4,5,6,7,8,9,0,1,1,1,1,1,1,1]}}">
      
    </view>
  </scroll-view>

  <view 
    class="mini-header"
    style="height:{{miniHeaderHeight}}px;"
    wx:if="{{showMiniHeader}}">
    
  </view>
</view>

ts

// index.ts
// 获取应用实例
const app = getApp<IAppOption>()

Component({
  data: {
    headerOpacity: 1,
    scrollHeight: 500,
    windowHeight: 1000,
    isLayouting: false,
    showMiniHeader: false,
    scrollAble: false,
    refreshing: false,
    toolbarHeight: 100,
    headerHeight: 400,
    miniHeaderHeight: 200,
    animationInterval: 20,
    scrollviewStartY: 0,
  },
  methods: {
    onLoad() {
      let info = wx.getSystemInfoSync()
      this.data.windowHeight = info.windowHeight
      this.setData({
        scrollHeight: info.windowHeight - this.data.headerHeight - this.data.toolbarHeight
      })
    },
    handleToolbarTouchStart(event) {
      this.data.isLayouting = true
      let type = event.currentTarget.dataset.type
      if (type == 'toolbar') {

      } else {
        this.data.scrollviewStartY = event.touches[0].clientY 
      }
    },
    handleToolbarTouchEnd(event) {
      this.data.isLayouting = false
      
      let top = this.data.windowHeight - this.data.scrollHeight - this.data.miniHeaderHeight - this.data.toolbarHeight
      if (top > (this.data.headerHeight - this.data.miniHeaderHeight) / 2) {
        this.tween(this.data.windowHeight - this.data.scrollHeight, this.data.headerHeight + this.data.toolbarHeight, 200)
      } else {
        this.tween(this.data.windowHeight - this.data.scrollHeight, this.data.miniHeaderHeight + this.data.toolbarHeight, 200)
      }
    },
    handleToolbarTouchMove(event) {
      if (this.data.isLayouting) {
        let type = event.currentTarget.dataset.type
        if (type=='toolbar') {
          this.updateLayout(event.touches[0].clientY + this.data.toolbarHeight / 2)
        } else {
          if (this.data.scrollAble) {
            return
          } else {
            this.updateScrollViewLayout(event.touches[0].clientY)
          }
        }
      }
    },
    handleRefesh() {
      let that = this
      setTimeout(() => {
        that.setData({
          refreshing: false
        })
      }, 3000);
    },
    updateLayout(top: number) {
      if (top < this.data.miniHeaderHeight + this.data.toolbarHeight) {
        top = this.data.miniHeaderHeight + this.data.toolbarHeight
      } else if (top > this.data.headerHeight + this.data.toolbarHeight) {
        top = this.data.headerHeight + this.data.toolbarHeight
      }
      let opacity = (top - (this.data.miniHeaderHeight + this.data.toolbarHeight)) / (this.data.miniHeaderHeight + this.data.toolbarHeight)
      let isReachTop = opacity == 0 ? true : false
      this.setData({
        scrollHeight: this.data.windowHeight - top,
        headerOpacity: opacity,
        showMiniHeader: isReachTop,
        scrollAble: isReachTop
      })
    },
    updateScrollViewLayout(offsetY: number) {
      let delta = offsetY - this.data.scrollviewStartY
      if (delta > 0) {
        return
      }
      delta = -delta
      if (delta > this.data.headerHeight - this.data.miniHeaderHeight) {
        delta = this.data.headerHeight - this.data.miniHeaderHeight
      }
      
      let opacity = 1 - (delta) / (this.data.headerHeight - this.data.miniHeaderHeight)
      let isReachTop = opacity == 0 ? true : false
      this.setData({
        scrollHeight: this.data.windowHeight - this.data.headerHeight - this.data.toolbarHeight + delta,
        headerOpacity: opacity,
        showMiniHeader: isReachTop,
        scrollAble: isReachTop
      })
    },
    tween(from: number, to: number, duration: number) {
      let interval = this.data.animationInterval
      let count = duration / interval
      let delta = (to-from) / count
      this.tweenUpdate(count, delta, from)
    },
    tweenUpdate(count: number, delta: number, from: number) {
      let interval = this.data.animationInterval
      let that = this
      setTimeout(() => {
        that.updateLayout(from + delta)
        if (count >= 0) {
          that.tweenUpdate(count-1, delta, from + delta)
        }
      }, interval);
    }
  },
})

less

/**index.less**/
.header {
  height: 400px;
  background-color: red;
}
.scrollarea {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: blue;
}
.toolbar {
  height: 100px;
  position: fixed;
  left: 0;
  right: 0;
  background-color: green;
}
.mini-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 200px;
  background-color: cyan;
}
.item {
  width: 670rpx;
  height: 200rpx;
  background-color: yellow;
  margin: 40rpx;
}
  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xyccstudio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值