微信小程序開發教程-抽屜菜單

分類:技術 時間:2017-01-13

抽屜菜單是app上常見的菜單設計方式,典型的抽屜菜單如下圖所示

抽屜菜單

下面展示如何基于微信小程序實現抽屜菜單,最終效果如下圖所示:

抽屜菜單

頁面包含一個主頁和抽屜菜單頁,為了實現滑動效果,頁面采用absolute布局,代碼如下

index.wxml

lt;view id='id-main-page' class='main-page' animation='{{animationData}}' style='left:{{mainPageLeft}}rpx;'
 bindtouchstart='onMainPageTouchstart' catchtouchmove='onMainPageTouchmove' bindtouchend='onMainPageTouchend' bindtap='onMainPageTap'gt;
  lt;view class=quot;userinfoquot;gt;
    lt;image class=quot;userinfo-avatarquot; src=http://www.tuicool.com/articles/quot;{{userInfo.avatarUrl}}quot; background-size=quot;coverquot;gt;lt;/imagegt;
    lt;text class=quot;userinfo-nicknamequot;gt;{{userInfo.nickName}}lt;/textgt;
  lt;/viewgt;
lt;/viewgt;
lt;view class='drawer-menu' animation='{{animationData}}' style='left:{{drawerMenuLeft}}rpx;'gt;
  lt;view class=quot;userinfoquot;gt;
    lt;image class=quot;userinfo-avatarquot; src=http://www.tuicool.com/articles/quot;{{userInfo.avatarUrl}}quot; background-size=quot;coverquot;gt;lt;/imagegt;
    lt;text class=quot;userinfo-nicknamequot;gt;{{userInfo.nickName2}}lt;/textgt;
  lt;/viewgt;
lt;/viewgt;

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 = http://www.tuicool.com/articles/this.drawerMenuMoveData;
    var clientX = e.touches[0].clientX;
    //初識狀態
    if (data.state === 0) {
      if (clientX lt;= data.touchCheckX amp;amp; clientX gt; 20) {
        data.check = true;
        data.state = 1;
        data.firstTouchX = clientX;
      }
    }
    //菜單彈出狀態
    else if (data.state === 3) {
      if (clientX gt;= data.maxMoveX) {
        data.check = true;
        data.state = 2;
        data.firstTouchX = clientX;
      }
    } 
  },

touchmove 事件,首先判斷是否處于滑動狀態,之后根據當前模式來計算主頁和菜單頁的left值來產生滑動效果

onMainPageTouchmove: function(e) {
    var data = http://www.tuicool.com/articles/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 lt; 0) {
          moveX = 0;
        }
        if (moveX gt; data.maxMoveX) {
          moveX = data.maxMoveX;
        }
        if (moveX gt;= 0 amp;amp; moveX lt;= 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 gt; 0) {
          moveX = 0;
        }
        if (moveX lt; -data.maxMoveX) {
          moveX = -data.maxMoveX; 
        }
        if (moveX lt;= 0 amp;amp; moveX gt;= -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 gt; (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 gt; (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 操作,后續有機會再補上吧。

源碼地址: https://github.com/zjxfly/wx-drawermenu


Tags: 微信小程序開發

文章來源:http://www.jianshu.com/p/5f525c62100e


ads
ads

相關文章
ads

相關文章

ad