In het eerste deel van deze Draggable-reis bespraken we hoe we scripts moesten opnemen, de ThrowPropsPlugin hebben onderzocht, inclusief de vereisten om ons project te starten in de hoop er elf te halen! Maak je nu klaar om een menusysteem te maken dat niet op canvas staat en reageert op het toetsenbord en aanraken.
De volledige demo die we gaan bouwen en bespreken voor de rest van deze tutorial is ook beschikbaar op CodePen.
Ik moedig je aan om dit voor jezelf te testen op zoveel mogelijk apparaten, met name toetsenbordnavigatie. Elke interactie - aanraking, toetsenbord of muis - is in rekening gebracht, maar zoals u zult zien in ons huidige landschap, kunt u geen touchscreen detecteren en soms proberen dit zelfs in vals-positieve resultaten..
Met behulp van de opmaak van deel I beginnen we met het toevoegen van een container div
voor structurele doeleinden, samen met correlerende klassen voor CSS- en JavaScript-hooks.
... ...
Klassen die beginnen met het voorvoegsel "js" geven aan dat deze klassen alleen in JavaScript worden weergegeven; het verwijderen zou de functionaliteit belemmeren. Ze worden nooit gebruikt in CSS, waardoor de focus van zorgen wordt geïsoleerd. De omringende container zal helpen om het scrolgedrag onder controle te houden, wat wordt besproken in de komende sectie CSS.
Met de basis op zijn plek is het tijd om een laag ARIA aan de bovenkant toe te voegen om semantische betekenis te verlenen aan schermlezers en toetsenbordgebruikers.
Omdat het menu standaard verborgen is, is de aria-verborgen
attribuut is gelabeld waar
en zal dienovereenkomstig worden bijgewerkt afhankelijk van de status van het menu; vals
voor open, waar
voor gesloten. Hier is een uitleg van het attribuut aria-verborgen
volgens de W3C-specificatie:
Geeft aan dat het element en al zijn afstammelingen niet zichtbaar of waarneembaar zijn voor een gebruiker zoals geïmplementeerd door de auteur. [...] Auteurs MOETEN aria-hidden = "true" instellen op inhoud die niet wordt weergegeven, ongeacht het mechanisme dat wordt gebruikt om het te verbergen. Hierdoor kunnen hulptechnologieën of gebruikersagenten verborgen elementen in het document op de juiste manier overslaan. ~ W3C WAI-ARIA Spec
Auteurs moeten voorzichtig zijn met welke inhoud ze verbergen, waardoor dit kenmerk een aparte discussie wordt buiten de reikwijdte van dit artikel. Voor nieuwsgierigen definieert de specificatie het attribuut in verdere lengte en is het enigszins grokkable; iets dat ik meestal niet vaak over specificatie jargon zeg.
Onze CSS is waar de magie echt begint. Laten we de belangrijke delen uit de demo nemen die betekenis hebben en opsplitsen.
body // scroll fix hoogte: 100%; overloop verborgen; // einde scrol fix .app // scrol fix overflow-y: scroll; hoogte: 100vh; // einde scrol fix .dragaebel-nav height: 100vh; overflow-y: auto; positie: vast; boven: 0; rechts: 0;
Door de lichaamslengte in te stellen op 100% kan de container het volledige venster rekken, maar het speelt ook een belangrijkere rol; waardoor we de overloop kunnen verbergen.
Met de overloop-scrollfixatie kunt u bepalen hoe de primaire container en navigatie zich gedragen wanneer een van beide overloopende inhoud bevat. Als de container bijvoorbeeld wordt gescrolld of het menu, scrolt de andere niet wanneer de gebruiker het einde van het element dat in het begin wordt gescrold bereikt. Het is een raar gedrag, dat meestal niet wordt besproken, maar zorgt voor een betere gebruikerservaring.
Viewport-units zijn echt krachtig en spelen een vitale rol in de manier waarop de primaire container overvolle content bevat. Viewport-apparaten bieden tegenwoordig fantastische ondersteuning voor browsers en ik raad u ten zeerste aan ze te gaan gebruiken. Ik heb vh-eenheden op de nav gebruikt, maar ik had in plaats daarvan een percentage kunnen gebruiken. Tijdens de ontwikkeling werd ontdekt dat div.app
moet gebruiken vh
eenheden, aangezien het percentage niet toestaat dat de overlopende inhoud het typische scrolgedrag behoudt; de inhoud resulteert in een clip. Overloop is ingesteld op rol
in voorbereiding voor het geval de menu-items de hoogte van het menu overschrijden of de hoogte van de viewport te smal wordt.
// Sta toe dat nav opent wanneer JS mislukt .no-js .dragaebel-nav: target margin-right: 0; .dragaebel-nav margin-right: -180px; breedte: 180 px;
De .no-js .nav: doel
biedt toegang tot ons menu, ongeacht of JavaScript faalt of is uitgeschakeld, vandaar de reden dat we de ID-waarde hebben toegevoegd aan de href
kenmerk van de menarnrigger.
De primaire navigatie wordt naar rechts verplaatst via een negatieve marge die ook gelijk is aan de breedte van de nav. Kortheidshalve schrijf ik Vanilla CSS, maar ik weet zeker dat je iets leuker zou kunnen schrijven in een pre-processor naar keuze.
JavaScript is de laatste stop van deze versleepbare menureis, maar voordat we één regel JS schrijven, moeten we een modulepatroon opstellen.
var dragaebelMenu = (function () function doSomething () ... return init: function () ...) (); dragaebelMenu.init (); // begin het!
Voor de configuratie-instellingen definiëren we enkele variabelen voor toekomstig gebruik.
var dragaebelMenu = (function () var container = document.querySelectorAll ('. js-dragsurface') [0], nav = document.querySelectorAll ('. js-dragnav') [0], nav_trigger = document.querySelectorAll (' .js-dragtoggle ') [0], logo = document.querySelectorAll ('. js-draglogo ') [0], gs_targets = [container, nav, logo, nav_trigger], closed_nav = nav.offsetWidth + getScrollBarWidth (); ) ();
De meeste van deze variabelen zijn eenvoudigweg grijpen DOM
elementen, met uitzondering van de laatste twee die onze GreenSock-doelen definiëren plus de breedte van het navigatiemenu. De nutsfunctie getScrollBarWidth ()
(buiten onze discussie van vandaag) haalt de breedte van de schuifbalk op, zodat we de navigatiebalk net buiten de breedte van de balk zelf kunnen positioneren om deze te bekijken wanneer het menu wordt geopend. De doelen zijn wat we verplaatsen wanneer het menu wordt geopend, zodat aangrenzende content kan worden gepusht.
Om het kort te houden bespreek ik alleen methoden die van groot belang zijn voor de functionaliteit van het menugedrag. Al het andere dat u in de demo zult zien die hier niet wordt besproken, is de 'sugar on top'-spul die het menu nog krachtiger maakt.
functiemenu (duur) container._gsTransform.x === -closed_nav? TweenMax.to (gs_targets, duration, x: 0, ease: Linear.easeIn): TweenMax.to (gs_targets, duration, x: -closed_nav, ease: Linear.easeOut);
De menu
functie detecteert of de x-coördinaat van de container gelijk is aan de gesloten nav-status. Als dit het geval is, worden de doelen teruggezet naar hun startpositie, anders worden ze in hun open positie geplaatst.
function isOpen () return container._gsTransform.x < 0;
Dit is een functie om de status van het menu te controleren. Dit komt terug 0
als het menu gesloten is of een negatieve waarde als het open is.
function updateNav (event) TweenMax.set ([nav, logo, nav_trigger], x: container._gsTransform.x);
Dit is een andere utility-functie die de x-coördinaat van het doel instelt binnen de array-parameter van de .set ()
methode om de container x positie telkens de ondrag
of onThrowUpdate
evenement gebeurt. Dit is onderdeel van de Sleepbaar
object instantie.
function enableSelect () container.onselectstart = null; // Branden wanneer het object wordt geselecteerd. TweenMax.set (container, userSelect: 'text'); function disableSelect () TweenMax.set (container, userSelect: 'none'); function isSelecting () // window.getSelection: Retourneert een Selection-object dat // het tekstbereik representeert dat door de gebruiker is geselecteerd, of de huidige positie // van de caret. return !! window.getSelection (). toString (). length;
Deze functies helpen bepalen of iemand echt tekst selecteert om selectiemogelijkheden in / uit te schakelen wanneer iemand over het scherm sleept. Dit is niet het meest ideale gedrag voor muisgebeurtenissen, maar nogmaals, zoals we al vermeldden, kunt u geen aanraakscherm detecteren.
Draggable.create ([doelen], opties)
Zoals we in de vorige tutorial over Draggable hebben besproken, wordt hiermee het exemplaar van het Draggable-object gemaakt en wordt het gericht op DOM
objecten van onze keuze die kunnen worden doorgegeven als een array.
Draggable.create ([container], type: 'x', dragClickables: false, throwProps: true, dragResistance: 0.025, edgeResistance: 0.99999999, maxDuration: 0.25, throwResistance: 2000, cursor: 'resize', allowEventDefault: true, bounds : ..., onDrag: updateNav, onDragEnd: function (event) ..., liveSnap: function (value) ..., onPress: function (event) ..., onClick: function (event) ..., onThrowUpdate : function () ...);
Dit is onze gehele Draggable-instantie en de gebruikte eigenschappen. De eigenlijke democode bevat opmerkingen die ik heb achtergelaten om te begrijpen en een betere indruk te krijgen van waar iedereen verantwoordelijk voor is. Ik moedig je aan om de democode te bekijken en daag je zelfs uit om het waarom en hoe te deconstrueren.
Dit is het einde van onze GreenSock-reis en ik hoop dat je onderweg een hoop hebt geleerd. Een speciale dank aan Jack en Carl bij GreenSock, samen met de hele GreenSock-community, voor hun ongelooflijke hulp tijdens deze serie. Last but not least, een grote dank aan u, de lezer voor het bereiken van het einde van deze serie; Proficiat! Ik hoop dat deze serie heeft bijgedragen tot een beter inzicht in de krachtige voordelen en capaciteiten van een geweldige JavaScript-animatiebibliotheek. Bouw geweldige dingen en blijf creatief!