小程序手势冲突做不了?不存在的!

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

实现效果如下:

页面区域及支持手势

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

原理实现

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

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

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

Talk is cheap, show me the code

代码部分

wxml

html 复制代码
<!--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

typescript 复制代码
// 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

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;
}
相关推荐
丁总学Java6 小时前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
mosen8687 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq22951165028 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
小飞哥liac18 小时前
微信小程序的组件
微信小程序
stormjun19 小时前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
shenweihong1 天前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
1 天前
微信小程序运营日记(第四天)
微信小程序·小程序
qq22951165021 天前
小程序Android系统 校园二手物品交换平台APP
微信小程序·uni-app
一只不会编程的猫2 天前
微信小程序配置
微信小程序·小程序