[
  {
    "path": "README.md",
    "content": "# wx-drawer\n小程序模仿QQ6.0侧滑菜单 wx-drawer 😃\n\n## 其他组件\n- [wx-alphabetical-listview带字母滑动的列表](https://github.com/zhongjie-chen/wx-alphabetical-listview)\n- [wx-scrollable-tab-view可滚动的tabview](https://github.com/zhongjie-chen/wx-scrollable-tab-view)\n\n## 截屏\n\n### 电脑上的截屏\n![](https://github.com/zhongjie-chen/blog/blob/gh-pages/img/wx-drawer.gif?raw=true)\n\n## 功能\n\n- [x] 模仿QQ6.0侧滑菜单功能，小程序实现\n- [x] 在android ios 平台测试过，确保真实环境一致\n- [ ] 小程序目前不支持组件化；后期会抽离一些公共的东西，让使用起来更加方便\n\n## 如何使用\n\n1. 复制page下的文件夹到自己项目中\n2. 配置app.json\n3. 编译\n\n### 其它\n\n- 👉 欢迎issue\n- 👉 欢迎pr\n"
  },
  {
    "path": "app.js",
    "content": "//app.js\nApp({\n  onLaunch: function () {\n    //调用API从本地缓存中获取数据\n    var logs = wx.getStorageSync('logs') || []\n    logs.unshift(Date.now())\n    wx.setStorageSync('logs', logs)\n  },\n  getUserInfo:function(cb){\n    var that = this\n    if(this.globalData.userInfo){\n      typeof cb == \"function\" && cb(this.globalData.userInfo)\n    }else{\n      //调用登录接口\n      wx.login({\n        success: function () {\n          wx.getUserInfo({\n            success: function (res) {\n              that.globalData.userInfo = res.userInfo\n              typeof cb == \"function\" && cb(that.globalData.userInfo)\n            }\n          })\n        }\n      })\n    }\n  },\n  globalData:{\n    userInfo:null\n  }\n})"
  },
  {
    "path": "app.json",
    "content": "{\n  \"pages\":[\n    \"pages/wxDrawer/index\"\n  ],\n  \"window\":{\n    \"backgroundTextStyle\":\"light\",\n    \"navigationBarBackgroundColor\": \"#000\",\n    \"navigationBarTitleText\": \"wx-drawer\",\n    \"navigationBarTextStyle\":\"white\"\n  }\n}\n"
  },
  {
    "path": "app.wxss",
    "content": ""
  },
  {
    "path": "pages/wxDrawer/index.js",
    "content": "//wx-drawer\nconst MENU_WIDTH_SCALE = 0.82;\nconst FAST_SPEED_SECOND = 300;\nconst FAST_SPEED_DISTANCE = 5;\nconst FAST_SPEED_EFF_Y = 50;\nvar app = getApp()\nPage({\n  data: {\n    ui: {\n      windowWidth: 0,\n      menuWidth: 0,\n      offsetLeft: 0,\n      tStart: true\n    }\n  },\n  onLoad() {\n    try {\n      let res = wx.getSystemInfoSync()\n      this.windowWidth = res.windowWidth;\n      this.data.ui.menuWidth = this.windowWidth * MENU_WIDTH_SCALE;\n      this.data.ui.offsetLeft = 0;\n      this.data.ui.windowWidth = res.windowWidth;\n      this.setData({ui: this.data.ui})\n    } catch (e) {\n    }\n  },\n  handlerStart(e) {\n    let {clientX, clientY} = e.touches[0];\n    this.tapStartX = clientX;\n    this.tapStartY = clientY;\n    this.tapStartTime = e.timeStamp;\n    this.startX = clientX;\n    this.data.ui.tStart = true;\n    this.setData({ui: this.data.ui})\n  },\n  handlerMove(e) {\n    let {clientX} = e.touches[0];\n    let {ui} = this.data;\n    let offsetX = this.startX - clientX;\n    this.startX = clientX;\n    ui.offsetLeft -= offsetX;\n    if(ui.offsetLeft <= 0) {\n      ui.offsetLeft = 0;\n    } else if(ui.offsetLeft >= ui.menuWidth) {\n      ui.offsetLeft = ui.menuWidth;\n    }\n    this.setData({ui: ui})\n  },\n  handlerCancel(e) {\n    // console.log(e);\n  },\n  handlerEnd(e) {\n    this.data.ui.tStart = false;\n    this.setData({ui: this.data.ui})\n    let {ui} = this.data;\n    let {clientX, clientY} = e.changedTouches[0];\n    let endTime = e.timeStamp;\n    //快速滑动\n    if(endTime - this.tapStartTime <= FAST_SPEED_SECOND) {\n      //向左\n      if(this.tapStartX - clientX > FAST_SPEED_DISTANCE) {\n        ui.offsetLeft = 0;\n      } else if(this.tapStartX - clientX < -FAST_SPEED_DISTANCE && Math.abs(this.tapStartY - clientY) < FAST_SPEED_EFF_Y) {\n        ui.offsetLeft = ui.menuWidth;\n      } else {\n        if(ui.offsetLeft >= ui.menuWidth/2){\n          ui.offsetLeft = ui.menuWidth;\n        } else {\n          ui.offsetLeft = 0;\n        }\n      }\n    } else {\n      if(ui.offsetLeft >= ui.menuWidth/2){\n        ui.offsetLeft = ui.menuWidth;\n      } else {\n        ui.offsetLeft = 0;\n      }\n    }\n    this.setData({ui: ui})\n  },\n  handlerPageTap(e) {\n    let {ui} = this.data;\n    if(ui.offsetLeft != 0) {\n      ui.offsetLeft = 0;\n      this.setData({ui: ui})\n    }\n  },\n  handlerAvatarTap(e) {\n    let {ui} = this.data;\n    if(ui.offsetLeft == 0) {\n      ui.offsetLeft = ui.menuWidth;\n      this.setData({ui: ui})\n    }\n  }\n})\n"
  },
  {
    "path": "pages/wxDrawer/index.json",
    "content": "{}"
  },
  {
    "path": "pages/wxDrawer/index.wxml",
    "content": "<view class=\"mpage {{!ui.tStart? 'withAnimate': ''}}\" style=\"left:{{ui.offsetLeft}}px;width: {{ui.windowWidth}}px\" bindtouchstart=\"handlerStart\" catchtouchmove=\"handlerMove\" bindtouchcancel=\"handlerCancel\" bindtouchend=\"handlerEnd\" bindtap=\"handlerPageTap\">\n  <scroll-view bindscroll=\"handlerScroll\" scroll-y style=\"height: 100%;\">\n    <view class=\"search\">\n      <view catchtap=\"handlerAvatarTap\" class=\"avatar\">\n        <image src=\"../../imgs/ic_face.png\"></image>\n      </view>\n    </view>\n    <view wx:for=\"1234555\" wx:key=\"unique\" class=\"item\">\n      <image src=\"../../imgs/ic_face.png\"></image>\n    </view>\n  </scroll-view>\n</view>\n<view bindtouchstart=\"handlerStart\" catchtouchmove=\"handlerMove\" bindtouchcancel=\"handlerCancel\" bindtouchend=\"handlerEnd\" class=\"user\" style=\"width: {{ui.menuWidth}}px\">\n   <view style=\"width: {{ui.menuWidth}}px;left:{{-ui.menuWidth/3 + ui.offsetLeft/3}}px\" class=\"user-box {{!ui.tStart? 'withAnimate': ''}}\">\n     <view class=\"user-face-wrapper\">\n       <image class=\"user-face\" src=\"../../imgs/ic_face.png\"></image>\n     </view>\n     <view wx:for=\"1234\" wx:key=\"unique\" class=\"one-menu\">\n        <text>新年大吉</text>\n     </view>\n   </view>\n</view>"
  },
  {
    "path": "pages/wxDrawer/index.wxss",
    "content": ".mpage {\n  z-index: 10;\n  position: fixed;\n  bottom: 0;\n  top: 0;\n  background-color: #e7eaef;\n}\n.withAnimate {\n  transition: all 300ms ease;\n  -webkit-transform: translate3d(0, 0, 0);\n  -moz-transform: translate3d(0, 0, 0);\n  -ms-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  -ms-backface-visibility: hidden;\n  backface-visibility: hidden;\n  -webkit-perspective: 1000;\n  -moz-perspective: 1000;\n  -ms-perspective: 1000;\n  perspective: 1000;\n}\n.search {\n  background: white;\n  display: flex;\n  align-items: center;\n  margin-bottom: 20rpx;\n}\n.search .avatar {\n  padding: 30rpx;\n}\n.search .avatar image {\n  width: 50rpx;\n\theight: 50rpx;\n}\n\n.item {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: white;\n  padding: 60rpx;\n  border-bottom: 20rpx solid #dbdbdb;\n}\n.item image {\n  height: 150rpx;\n  width: 150rpx;\n}\n.user {\n  position: fixed;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  background-color: #e7eaef;\n  border-right: 1px solid #dbdbdb;\n  box-sizing: border-box;\n}\n.user .user-box {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  background: cadetblue;\n}\n.user .user-box .user-face-wrapper {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  background: snow;\n  padding: 20rpx;\n  margin-bottom: 100rpx;\n}\n.user .user-box .user-face {\n  width: 150rpx;\n\theight: 150rpx;\n}\n.user .user-box .one-menu {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 20rpx;\n  margin-bottom: 20rpx;\n  background: lightgray;\n  color: white;\n  font-size: 38rpx;\n}\n"
  }
]