In diesem Artikel wird die Implementierung einer einfachen DrawerLayout-Layoutkomponente (ähnlich der DrawerLayout-Komponente von Android) vorgestellt.
Dieser Artikel führt ein einfaches DrawerLayout ein ( Implementierung von Layoutkomponenten ähnlich dem DrawerLayout von Android, basierend auf Vue.js. Der eingeführte Inhalt wurde in die Vue-Drawer-Layout-Komponente umgewandelt.
Vorwort
Bei Interesse scannen Sie bitte zuerst diesen QR-Code mit Ihrem Handy, oder klicken Sie auf mich
und klicken Sie dann auf „Schublade öffnen“ oder ziehen Sie den Avatar in der oberen linken Ecke der Seite nach rechts oder links, und Sie können den Effekt des GIF unten sehen. Sehen Sie nicht so aus? :)
Google nennt dieses Layout offiziell DrawerLayout (Schubladennavigationsleiste). Wie erreichen wir das? Beginnen wir mit dem Hauptfilm!
HTML-Struktur
Die Seitenstruktur ist sehr einfach, mit einer Schublade und einem Hauptcontainer, und der Inhalt kann über Slots extern angepasst werden .
<p class="drawer-layout"> <!--抽屉--> <p class="drawer-wrap"> <slot name="drawer"></slot> </p> <!--主容器--> <p class="content-wrap"> <!--遮罩--> <p class="drawer-mask"></p> <slot name="content"></slot> </p> </p>
Die Schublade ist zunächst außerhalb des linken Bildschirms ausgeblendet. Stellen Sie also links: -100 % ein, um sie vollständig außerhalb auszublenden.
Benutzen Sie Touch
Bestimmen Sie zunächst, ob der Browser touchEvent unterstützt
let isTouch = 'ontouchstart' in window; let mouseEvents = isTouch ? { down: 'touchstart', move: 'touchmove', up: 'touchend', over: 'touchstart', out: 'touchend' } : { down: 'mousedown', move: 'mousemove', up: 'mouseup', over: 'mouseover', out: 'mouseout' };
Touchdown-Ereignis binden
document.addEventListener(mouseEvents.down, initDrag, false);
Definieren Sie zunächst eine Variable, das x -Koordinate des gedrückten Fingers wird als startX markiert, die x-Koordinate des Fingers während des Gleitens wird als nowX markiert und der x-Koordinatenversatz der Schublade wird als startPos markiert
let startX, nowX, startPos;
Wenn Touchstart ausgelöst wird, Die Startposition wird aufgezeichnet und gebunden. Bestimmen Sie touchmove. Hinweis: Wenn es sich um ein MouseEvent handelt, wird die aktuelle X-Koordinate über e.clientX abgerufen. Wenn es sich um ein TouchEvent handelt, wird die X-Koordinate über e.changedTouches[0].clientX < abgerufen 🎜>
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);
Unterscheiden Sie zwischen vertikalem und horizontalem Gleiten
Als nächstes werden Sie ein Problem finden: Wenn Ihr Finger den Hauptinhalt vertikal scrollt, schieben Sie Ihren Finger nach rechts Es wird auch die Schublade herausziehen. Zu diesem Zeitpunkt sollten Sie eines tun: zwischen vertikalem Gleiten und horizontalem Gleiten unterscheiden Natürlich gibt es viele Möglichkeiten, die trigonometrische Funktionen verwenden zu bestimmenAngenommen, jeder Pfeil im obigen Bild ist die Richtung, in die der Finger gleitet. Der grüne Pfeil bedeutet, dass die Schublade herausgezogen werden kann, und der rote Pfeil bedeutet dass es nicht herausgezogen werden kann (beachten Sie, dass der rote Pfeil auch den Versatz der x-Koordinate hat). Das heißt, wenn die Schublade nicht herausgezogen werden kann, sollten Standardereignisse wie vertikales Scrollen usw. ausgelöst werden. Wenn der Finger drückt, um Touchstart auszulösen, wird die Anfangsposition P 0 aufgezeichnet. Wenn der Finger gleitet, wird die erste Touchmove ausgelöst, die Position P 1 wird aufgezeichnet und wir zeichnen den Vektor von P 0 bis auf P 1 als S (Verzeihen Sie mir, dass ich ein Seelenmaler bin)
Zu diesem Zeitpunkt ist es leicht zu erkennen, dass ∠θ größer als ein bestimmter Wert ist, beispielsweise 30 Grad kann es sich um einen vertikalen Bildlauf handeln, anstatt die Schublade zu ziehen. Daher kann die Beurteilungsbedingung basierend auf y/x>tan30° erhalten werden:
if (isVerticle === undefined) isVerticle = Math.abs(nowY - startY) / Math.abs(nowX - startX) > (Math.sqrt(3) / 3);
.moving transition transform .3s ease
<p 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> </p>
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 ? width : 0; } if (!this.moving) { this.willChange = false; //留个悬念 } isVerticle = undefined; //取消touchmove和touchend事件绑定 document.removeEventListener(mouseEvents.move, drag, false); document.removeEventListener(mouseEvents.up, removeDrag, false); }.bind(this);
Will-Change-Transformation
const initDrag = function (e) { //... this.willChange = true; }.bind(this);
Hä? Was zum Teufel ist passiv?
网站使用被动事件侦听器以提升滚动性能,在您的触摸和滚轮事件侦听器上设置 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 ? {passive: true} : false);
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在React Native中使用prop-types如何实现属性确认
Das obige ist der detaillierte Inhalt vonSo implementieren Sie eine seitlich verschiebbare Menükomponente in Vue. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!