搜索
首页微信小程序小程序开发微信小程序开发之抽屉菜单实例详解

抽屉菜单是app上常见的菜单设计方式,典型的抽屉菜单如下图所示

微信小程序开发之抽屉菜单实例详解

抽屉菜单

下面展示如何基于微信小程序实现抽屉菜单,最终效果如下图所示:

微信小程序开发之抽屉菜单实例详解

抽屉菜单

页面包含一个主页和抽屉菜单页,为了实现滑动效果,页面采用absolute布局,代码如下
index.wxml

<view id=&#39;id-main-page&#39; class=&#39;main-page&#39; animation=&#39;{{animationData}}&#39; style=&#39;left:{{mainPageLeft}}rpx;&#39;
 bindtouchstart=&#39;onMainPageTouchstart&#39; catchtouchmove=&#39;onMainPageTouchmove&#39; bindtouchend=&#39;onMainPageTouchend&#39; bindtap=&#39;onMainPageTap&#39;>
  <view class="userinfo">
    <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
    <text class="userinfo-nickname">{{userInfo.nickName}}</text>
  </view>
</view>
<view class=&#39;drawer-menu&#39; animation=&#39;{{animationData}}&#39; style=&#39;left:{{drawerMenuLeft}}rpx;&#39;>
  <view class="userinfo">
    <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
    <text class="userinfo-nickname">{{userInfo.nickName2}}</text>
  </view>
</view>

index.wxss

.main-page {
  width:100%;
  height:2000rpx;
  position: absolute;
  top: 0;
  left: 0;
  padding: 200rpx 0;
}

.drawer-menu {
  width: 800rpx;
  height:2000rpx;
  position: absolute;
  top: 0;
  left: -800rpx;
  padding: 200rpx 0;
  background: rgba(22, 22, 22, 1);
  z-index: 800;
}

程序绑定了主页的touch事件和tap事件,并且使用catchtouchmove阻止了move事件的传递,因为在真机环境下页面会自动响应滑动事件,注意不要catch startend事件,这会导致无法触发tap事件。

首先定义一些数据来记录滑动过程和状态

  drawerMenuMoveData: {
    check: false,   //是否触发滑动操作
    state:0,    //0:初始状态 1:菜单弹出中状态 2:菜单弹入状态中 3:菜单弹出状态
    firstTouchX:0,  //首次触摸X坐标值
    touchCheckX:60,  //触发滑动的触摸X
    moveX:0,   // 滑动操作横向的移动距离
    maxMoveX: (app.globalData.deviceInfo.windowWidth - 60), //抽屉菜单最大移动距离
    lastTranlateX: 0  //上次动画效果的平移距离,用于校准left值
  },

之后就是滑动事件的响应处理
touchstart事件,首先判断当前状态,然后根据触摸位置判断是否激活滑动状态

  onMainPageTouchstart: function(e) {
    var data = this.drawerMenuMoveData;
    var clientX = e.touches[0].clientX;
    //初识状态
    if (data.state === 0) {
      if (clientX <= data.touchCheckX && clientX > 20) {
        data.check = true;
        data.state = 1;
        data.firstTouchX = clientX;
      }
    }
    //菜单弹出状态
    else if (data.state === 3) {
      if (clientX >= data.maxMoveX) {
        data.check = true;
        data.state = 2;
        data.firstTouchX = clientX;
      }
    } 
  },

touchmove 事件,首先判断是否处于滑动状态,之后根据当前模式来计算主页和菜单页的left值来产生滑动效果

  onMainPageTouchmove: function(e) {
    var data = this.drawerMenuMoveData;
    var pixelRatio = app.globalData.deviceInfo.pixelRatio;
    if (data.check) {
      var mainPageLeft = 0, drawerMenuLeft = 0;
      var moveX = e.touches[0].clientX - data.firstTouchX;
      if (data.state === 1)
      {
        //处理边界状态
        if (moveX < 0) {
          moveX = 0;
        }
        if (moveX > data.maxMoveX) {
          moveX = data.maxMoveX;
        }
        if (moveX >= 0 && moveX <= data.maxMoveX) {
          data.moveX = moveX;
          moveX = moveX - data.lastTranlateX;
          //px转为rpx
          moveX = moveX * pixelRatio;
          mainPageLeft = moveX;
          drawerMenuLeft = -800 + moveX;
        }
      }
      else if (data.state === 2) {
        //处理边界状态
        if (moveX > 0) {
          moveX = 0;
        }
        if (moveX < -data.maxMoveX) {
          moveX = -data.maxMoveX; 
        }
        if (moveX <= 0 && moveX >= -data.maxMoveX) {
          data.moveX = moveX;
          moveX = moveX - data.lastTranlateX;
          //px转为rpx
          moveX = moveX * pixelRatio;
          var maxMoveX = data.maxMoveX * pixelRatio;
          mainPageLeft = maxMoveX + moveX;
          drawerMenuLeft = maxMoveX -800 + moveX;
        }
      }

      this.setData({mainPageLeft: mainPageLeft, 
                    drawerMenuLeft: drawerMenuLeft});
    }
  },

touchend事件 根据滑动的距离来判断菜单是否弹出,并创建滑动动画

 onMainPageTouchend: function(e) {
    var data = this.drawerMenuMoveData;
    if (!data.check) {
      return;
    }
    data.check = false;
    data.firstTouchX = 0;
    var moveX = data.moveX;
    data.moveX = 0;
    var animation = wx.createAnimation({duration: 100});
    var translateX = 0;
    var mainPageLeft = 0;
    var windowWidth = app.globalData.deviceInfo.windowWidth;
    if (data.state === 1)
    {
      if (moveX === 0 || moveX === data.maxMoveX) {
        data.state = (moveX === 0) ? 0 : 3;
        return;
      }
      mainPageLeft = moveX;
      //滑动距离是否超过窗口宽度一半
      if (mainPageLeft > (windowWidth / 2)) {
        translateX = data.maxMoveX - moveX;
        data.state = 3;
      }
      else {
        translateX = -moveX;
        data.state = 0;
      }
    } 
    else if (data.state === 2) {
      if (moveX === 0 || moveX === -data.maxMoveX) {
        data.state = (moveX === 0) ? 3 : 0;
        return;
      }
      //滑动距离是否超过窗口宽度一半
      mainPageLeft = data.maxMoveX + moveX
      if (mainPageLeft > (windowWidth / 2)) {
        translateX = -moveX;
        data.state = 3;
      }
      else {
        translateX = -mainPageLeft;
        data.state = 0;
      }
    }
    translateX += data.lastTranlateX;
    data.lastTranlateX = translateX;
    animation.translateX(translateX).step();
    this.setData({
      animationData:animation.export()
    });
  },

tap事件, 如果当前是弹出状态,则将菜单弹回

  onMainPageTap: function(e) {
    var data = this.drawerMenuMoveData;
    if (data.state !== 3) {
      return;
    }
    data.state = 0;
    var translateX = -data.maxMoveX;
    translateX += data.lastTranlateX;
    data.lastTranlateX = translateX;
    var animation = wx.createAnimation({duration: 100});
    animation.translateX(translateX).step();
    this.setData({
      animationData:animation.export()
    });
  }

总体逻辑并不复杂,主要是做好状态判断和坐标运算,但有些问题需要注意

1: 微信小程序提供了rpx单位用于适配设备,但是各种滑动事件和动画的单位通常是px,因此需要进行转换,转换方法为 rpx = px * pixelRatio,其中pixelRatio可以通过 wx.getSystemInfoSync()获取

2: 当对组件使用通过wx.createAnimation 创建的动画时,小程序框架会给组件添加transform属性,其中translateX值会和left属性相互作用,因此计算left值时需要处理translateX的值。

3: 由于在真机环境下,页面左滑(初始触摸点在左侧边界时)默认行为是返回上一页或退出小程序(取决与是否是第一级页面), 抽屉菜单会和该行为发生冲突。

另外目前还不支持swiper操作,后续有机会再补上吧。

以上是微信小程序开发之抽屉菜单实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具