本文介绍一个简单的DrawerLayout(类似Android的DrawerLayout)布局组件的实现,基于Vue.js。介绍的内容已经制作成 vue-drawer-layout 组件。
前言
大家有兴趣先用手机扫一扫这个二维码,或者点我
然后点击页面中左上角的头像打开drawer或者向右向左拖拽,就可以看到下面gif的效果,打开自己的手机QQ,是不是很像:)
谷歌官方把这种布局叫做DrawerLayout(抽屉式导航栏)。那么我们要如何实现呢,好了正片开始!
HTML结构
页面结构很简单,一个抽屉,一个主容器,内容可以利用slot支持外部自行定制。
<div class="drawer-layout"> <!--抽屉--> <div class="drawer-wrap"> <slot name="drawer"></slot> </div> <!--主容器--> <div class="content-wrap"> <!--遮罩--> <div class="drawer-mask"></div> <slot name="content"></slot> </div> </div>
抽屉一开始是隐藏在左侧屏幕外的,故设置 left:-100% 使其整个都藏在外部
使用Touch
首先,判断浏览器是否支持 touchEvent
let isTouch = 'ontouchstart' in window; let mouseEvents = isTouch "color: #ff0000">绑定 touchdown 事件document.addEventListener(mouseEvents.down, initDrag, false);先定义一些变量,手指按下的x坐标记为 startX ,滑动中手指的位置x坐标记为 nowX ,drawer的x坐标偏移量记为 startPos
let startX, nowX, startPos;触发 touchstart 时,记录起始位置并绑定 touchmove ,注意:如果是 mouseEvent ,通过 e.clientX 来获取当前的x坐标,如果是 touchEvent ,要通过 e.changedTouches[0].clientX 来获取x坐标
const initDrag = function (e) { startX = e.clientX || e.changedTouches[0].clientX; //记录手指按下的位置 startPos = this.pos; //记录drawer的上次位置 document.addEventListener(mouseEvents.move, drag, false); document.addEventListener(mouseEvents.up, removeDrag, false); }.bind(this); const drag = function (e) { nowX = e.clientX || e.changedTouches[0].clientX; //滑动中手指的位置x坐标 let pos = startPos + nowX - startX; pos = Math.min(width, pos); //不能超过滑动最大值 pos = Math.max(0, pos); //不能小于0 this.pos = pos; //设置滚动距离为拖动的距离 }.bind(this);那么,手指滑动的距离就是 nowX - startX ,当前drawer的位置为 startPos + nowX - startX ,这样抽屉已经跟随手指向右移动了,并且不会超过我们设置的拖动最大值。
区分垂直滑动和水平滑动
接下来你会发现一个问题,当手指垂直滚动主内容时,向右滑动手指也会拖出抽屉,这时应该做一件事:区分垂直滑动和水平滑动
当然,办法有很多,这里先介绍一种利用三角函数来判定的方法
假设,上图中的每个箭头是手指滑动的方向,绿色箭头代表可以拖出抽屉,红色箭头代表不可以拖出(注意,红色箭头也是有x坐标的偏移量的)。即当不可以拖出抽屉时,应触发默认事件,比如垂直方向的滚动等等。
当手指按下触发 touchstart 时,记录初始位置P 0 ;当滑动手指时,触发的第一次 touchmove 时,记录位置P 1 ,我们将P 0 到P 1 的矢量记为S(原谅我这个灵魂画手)
这时候很容易看出,∠θ大于某个值时,比如30度,就可能是垂直方向的滚动操作而不是拖动抽屉。所以,可以根据 y/x>tan30°
得到判断条件:
if (isVerticle === undefined) isVerticle = Math.abs(nowY - startY) / Math.abs(nowX - startX) > (Math.sqrt(3) / 3);当 isVerticle 为 true 时,不执行drawer的拖动
让Drawer动起来
我们使用css3的 transition 属性使drawer具有过渡动画效果,这里写一个 moving 类
.moving transition transform .3s ease别忘了加上class绑定,拖动时是不需要过渡动画的(要跟随手指),而松开手指时才需要过渡动画。
<div class="drawer-wrap" :class="{'moving':moving,'will-change':willChange}" :style="{width:`${width}px`,left:`-${width)}px`,transform:`translate3d(${pos}px,0,0)`}"> <slot name="drawer"></slot> </div>所以绑定 touchend 事件的方法时要做这些步骤
const removeDrag = function (e) { if (isVerticle !== undefined) { if (!isVerticle) {//当判定为抽屉拖动才进入 let pos = this.pos; this.visible = pos > width * 3 / 5 //当前位置如果大于总宽度的3/5就判定为全部展开抽屉,否则将抽屉弹回隐藏 if (this.pos > 0 && this.pos < width) this.moving = true;//如果位置已经处于最小值或最大值处,不需要有动画效果了 } this.pos = this.visible "htmlcode">const initDrag = function (e) { //... this.willChange = true; }.bind(this);当然最后别忘了在 transitionend 事件后把 transition 和 will-change 去掉,让浏览器歇一会儿~
还有什么可以优化的?
上面说的已经基本上把主要功能实现了,但是这其中还有没有哪里可以优化的?
咦? passive
是什么鬼?
网站使用被动事件侦听器以提升滚动性能,在您的触摸和滚轮事件侦听器上设置 passive 选项可提升滚动性能具体看这里
原来这是现代浏览器的一个新特性,我们需要以新的方式来绑定我们的touch事件,当然首先先检测一下是否支持 passive
const supportsPassive = (() => { let supportsPassive = false; try { const opts = Object.defineProperty({}, 'passive', { get: function () { supportsPassive = true; } }); window.addEventListener("test", null, opts); } catch (e) { } return supportsPassive; })();于是我们的绑定事件代码变成这样
document.addEventListener(mouseEvents.move, drag, supportsPassive "color: #ff0000">写在最后本文介绍了实现抽屉式导航栏的主要过程,详细代码已封装成 vue-drawer-layout 组件,支持更丰富的定制和使用方式,具体文档可以访问我的github 或者npm官网检索。
华山资源网 Design By www.eoogi.com
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
更新日志
- 柏菲·珞叔作品集《金色大厅2》限量开盘母带ORMCD[低速原抓WAV+CUE]
- Gareth.T《sad songs(Explicit)》[320K/MP3][29.03MB]
- Gareth.T《sad songs(Explicit)》[FLAC/分轨][152.85MB]
- 证声音乐图书馆《海风摇曳·盛夏爵士曲》[320K/MP3][63.06MB]
- 龚玥《金装龚玥HQCD》头版限量[WAV分轨]
- 李小春《吻别》萨克斯演奏经典[原抓WAV+CUE]
- 齐秦《辉煌30年24K珍藏版》2CD[WAV+CUE]
- 证声音乐图书馆《海风摇曳·盛夏爵士曲》[FLAC/分轨][321.47MB]
- 群星 《世界经典汽车音乐》 [WAV分轨][1G]
- 冷漠.2011 《冷漠的爱DSD》[WAV+CUE][1.2G]
- 陈明《流金岁月精逊【中唱】【WAV+CUE】
- 群星《Jazz-Ladies1-2爵士女伶1-2》HQCD/2CD[原抓WAV+CUE]
- 群星《美女私房歌》(黑胶)[WAV分轨]
- 郑源.2009《试音天碟》24BIT-96KHZ[WAV+CUE][1.2G]
- 飞利浦试音碟 《环球群星监听录》SACD香港版[WAV+CUE][1.1G]