Demo interaktif PS5.js
Berikut adalah demo dari PS5 UI yang dibuat dengan JavaScript dan animasi CSS yang akan kami tulis dalam tutorial ini. Contoh interaktif dapat disentuh di artikel aslinya .
Letakkan proyek asterisk atau forknite ps5.js 35.9 KB di GitHub.
Saya menulis tweet tentang demo PS3 ketika saya sedang membangun versi dasar dari UI konsol PS 3 di JavaScript . Saya belum memiliki kodenya, tetapi saya berencana untuk mempostingnya. Selain itu, tutorial ini dibangun di atas pengetahuan yang diperoleh saat membuat pekerjaan pertama.
Latihan
Agar tidak mempersulit hidup kami, kami tidak akan menggunakan kerangka kerja apa pun.
Tetapi bahkan jika Anda menggunakan kerangka kerja atau pustaka, Anda masih perlu mengembangkan pola Anda sendiri untuk memecahkan masalah. Dalam tutorial UI ini, saya akan memandu Anda melalui konsep di balik pengembangan. Pendekatan ini dapat dengan mudah diadaptasi ke React, Vue, atau Angular.
Saya menggunakan file HTML template ini dengan gaya fleksibel yang sudah dibuat sebelumnya. Ini berisi semua yang Anda butuhkan dan struktur umum aplikasi untuk memulai. Ini bukan React atau Vue, tapi ini adalah konfigurasi minimum yang diperlukan untuk membuat aplikasi. Saya menggunakan blank ini setiap kali saya perlu mulai mengerjakan aplikasi atau situs web vanilla baru.
HTML dan CSS
Pada bagian ini, saya akan menjelaskan beberapa dasar dari mematikan file HTML.
Kerangka Kerja CSS DIY Sederhana
Saya bukan penggemar berat kerangka CSS dan lebih suka memulai dari awal. Namun, setelah ribuan jam pengkodean, Anda mulai melihat pola yang sering berulang. Mengapa tidak membuat beberapa kelas sederhana untuk mencakup kasus yang paling umum? Ini mencegah kita mengetik nama dan nilai properti yang sama ratusan kali.
.rel { position: relative }
.abs { position: absolute }
.top { top: 0 }
.left { left: 0 }
.right { right: 0 }
.bottom { bottom: 0 }
/* flex */
.f { display: flex; }
.v { align-items: center }
.vs { align-items: flex-start }
.ve { align-items: flex-end }
.h { justify-content: center }
.hs { justify-content: flex-start }
.he { justify-content: flex-end }
.r { flex-direction: row }
.rr { flex-direction: row-reverse }
.c { flex-direction: column }
.cr { flex-direction: column-reverse }
.s { justify-content: space-around }
.zero-padding { padding: 0 }
.o { padding: 5px }
.p { padding: 10px }
.pp { padding: 20px }
.ppp { padding: 30px }
.pppp { padding: 50px }
.ppppp { padding: 100px }
.m { margin: 5px }
.mm { margin: 10px }
.mmm { margin: 20px }
.mmmm { margin: 30px }
Kelas CSS ini berbicara sendiri.
Gaya CSS pertama kami
Sekarang setelah kita menyiapkan CSS dasar, mari tambahkan beberapa gaya untuk mengubah tampilan wadah menu yang disembunyikan dan ditampilkan. Ingatlah bahwa karena kita memiliki banyak menu dan dapat beralih di antaranya, kita perlu menentukan menu mana yang "aktif" dan mana yang "tidak aktif".
Yang saya maksud dengan banyak menu adalah bahwa setiap menu memiliki layarnya sendiri, yang ditentukan oleh elemen HTML yang terpisah. Saat beralih ke menu berikutnya, penampung sebelumnya disembunyikan dan yang baru ditampilkan. Transisi CSS juga dapat digunakan untuk membuat transisi UX yang mulus dengan mengubah opasitas, posisi, dan skala.
Semua kontainer dengan kelas
.menu
default akan berada dalam status "off" (yaitu, tersembunyi). Elemen apa pun dengan kelas
.menu
dan
.current
akan berada dalam status "aktif" dan ditampilkan di layar.
Elemen lain, seperti tombol yang dapat dipilih di menu, menggunakan kelas itu sendiri
.current
, tetapi dalam konteks hierarki CSS yang berbeda. Kami akan menjelajahi gaya CSS mereka di bagian selanjutnya dari tutorial.
#ps5 {
width: 1065px;
height: 600px;
background: url('https://semicolon.dev/static/playstation_5_teaser_v2.jpg');
background-size: cover;
}
/* default menu container - can be any UI screen */
#ps5 section.menu {
display: none;
opacity: 0;
// gives us automatic transitions between opacities
// which will create fade in/fade out effect.
// without writing any additional JavaScript
transition: 400ms;
}
#ps5 section.menu.current {
display: flex;
opacity: 1;
}
section.menu
sekali lagi adalah wadah induk standar untuk semua lapisan menu yang kita buat. Ini bisa menjadi layar "browser game" atau layar "pengaturan". Ini tidak terlihat secara default sampai kita menerapkan
classlist
kelas ke properti elemen
.current
.
A
section.menu.current
menunjukkan menu yang saat ini dipilih. Semua menu lainnya harus tidak terlihat dan kelas
.current
tidak boleh diterapkan ke lebih dari satu menu pada saat yang bersamaan!
Html
Kerangka kerja CSS kecil buatan kami sangat menyederhanakan HTML. Inilah kerangka utamanya:
<body>
<section id = "ps5" class = "rel">
<section id = "system" class = "menu f v h"></section>
<section id = "main" class = "menu f v h"></section>
<section id = "browser" class = "menu f v h"></section>
<section id = "settings" class = "menu f v h"></section>
</section>
</body>
Elemen
ps5
adalah wadah utama aplikasi.
Bagian utamanya
flex
adalah
f v h
untuk memusatkan elemen, jadi kita akan sering melihat kombinasi ini.
Juga kita akan bertemu,
f r
bukan
flex-direction:row;
dan
f c
sebagai gantinya
flex-direction:column;
.
Subbagian adalah area terpisah dari menu yang membutuhkan kelas
menu
. Kita bisa beralih di antara mereka.
Dalam kode, mereka akan dihitung oleh objek yang dibekukan (kita akan melihat ini di bawah).
Mengganti latar belakang
Salah satu tugas pertama yang ingin saya tangani adalah fungsi perubahan latar belakang. Jika saya dapat menerapkannya terlebih dahulu, maka saya akan mengintegrasikannya nanti ke semua fungsi masa depan yang perlu mengubah latar belakang. Untuk ini, saya memutuskan untuk membuat dua
div
.
Ketika latar belakang baru menjadi aktif, saya cukup menukar dua
div
, mengganti nilai properti
style.background
dengan URL gambar baru, dan menerapkan kelas ke latar belakang baru
.fade-in
, menghapusnya dari yang sebelumnya.
Saya mulai dengan CSS berikut:
#background-1, #background-2 {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
background: transparent;
background-position: center center;
background-size: cover;
pointer-events: none;
transition: 300ms;
z-index: 0;
opacity: 0;
transform: scale(0.9)
}
/* This class will be applied from Background.change() function */
.fade-in { opacity: 1 !important; transform: scale(1.0) !important; z-index: 1 }
/* set first visible background */
#background-2 { background-image: url(https://semicolon.dev/static/playstation_5_teaser_v2.jpg); }
Kemudian saya membuat fungsi statis pembantu
.change
yang berasal dari kelas
Background
yang menukar dua
div
dan memudarkannya masuk atau keluar (fungsi tersebut mengambil satu argumen, URL dari gambar berikutnya):
class Background {constructor() {}}
Background.change = url => {
console.log(`Changing background to ${url}`)
let currentBackground = $(`.currentBackground`);
let nextBackground = $(`.nextBackground`);
// set new background to url
nextBackground.style.backgroundImage = `url(${url})`
// fade in and out
currentBackground.classList.remove('fade-in')
nextBackground.classList.add('fade-in')
// swap background identity
currentBackground.classList.remove('currentBackground')
currentBackground.classList.add('nextBackground')
nextBackground.classList.remove('nextBackground')
nextBackground.classList.add('currentBackground')
}
Sekarang, setiap kali saya perlu menampilkan latar belakang baru, saya cukup memanggil fungsi ini dengan URL gambar yang akan ditampilkan:
Background.change('https://semicolon.dev/static/background-1.png')
Fade in akan dilakukan secara otomatis karena
transform: 300ms
sudah diterapkan ke setiap latar belakang dan kelas
.fade-in
sedang melakukan sisanya.
Cara membuat menu navigasi utama
Sekarang kerangka dasar sudah siap, kita bisa mulai membangun UI lainnya. Tapi kita juga perlu menulis kelas untuk mengelola UI. Sebut saja kelas ini
PS5Menu
. Saya akan menjelaskan cara menggunakannya di bawah ini.
Layar sistem
CSS sederhana digunakan untuk membuat tombol Start . Setelah menekan tombol oleh pengguna, kita masuk ke menu utama PS5. Mari tempatkan tombol Mulai di menu pertama di layar - di menu Sistem:
<section id = "system" class = "menu f v h">
<div id = "start" class = "f v h">Start</div>
</section>
Demikian pula, konten dari semua menu lainnya akan ditempatkan di elemen wadah induk yang sesuai.
Kami akan membahasnya nanti. Sekarang kita perlu mencari cara untuk mengatur beberapa layar menu.
Pada titik ini, kita perlu belajar tentang konsep mengantre beberapa menu. PS5 memiliki beberapa lapisan UI navigasi yang berbeda. Misalnya, saat Anda memilih Pengaturan, menu baru yang sama sekali berbeda terbuka, dan kontrol keyboard dibawa ke menu baru ini.
Kita membutuhkan objek untuk melacak semua menu ini yang terus-menerus dibuka, ditutup, dan kemudian diganti dengan menu baru atau sebelumnya.
Anda dapat menggunakan metode bawaan
push
Array objek dalam JavaScript untuk menambahkan menu baru ke antrian. Dan ketika kita perlu kembali, kita dapat memanggil metode
pop
array untuk kembali ke menu sebelumnya.
Kami mencantumkan menu berdasarkan atribut
id
elemen:
const MENU = Object.freeze({
system: `system`,
main: `main`,
browser: `browser`,
settings: `settings`,
/* add more if needed*/
});
Saya menggunakan
Object.freeze()
agar tidak ada properti yang berubah setelah disetel. Beberapa jenis objek sebaiknya dibekukan. Ini adalah objek yang pasti tidak boleh berubah selama masa pakai aplikasi.
Di sini, setiap nilai adalah nama properti dalam format string. Dengan cara ini kita dapat menautkan ke item menu dengan
MENU.system
atau
MENU.settings
. Tidak ada apa pun selain estetika sintaksis dalam pendekatan ini, dan ini juga merupakan cara sederhana untuk menghindari penyimpanan semua objek menu "dalam satu keranjang".
Kelas PS5Menu
Pertama, saya membuat kelas
PS5Menu
. Konstruktornya menggunakan properti
this.queue
type
Array
.
// menu queue object for layered PS5 navigation
class PS5Menu {
constructor() {
this.queue = []
}
set push(elementId) {
// hide previous menu on the queue by removing "current" class
this.queue.length > 0 && this.queue[this.queue.length - 1].classList.remove(`current`)
// get menu container
const menu = $(`#${elementId}`)
// make the new menu appear by applying "current" class
!menu.classList.contains(`current`) && menu.classList.add(`current`)
// push this element onto the menu queue
this.queue.push( menu )
console.log(`Pushed #${elementId} onto the menu queue`)
}
pop() {
// remove current menu from queue
const element = this.queue.pop()
console.log(`Removed #${element.getAttribute('id')} from the menu queue`)
}
}
Bagaimana cara menggunakan kelas PS5Menu?
Kelas ini memiliki dua metode, penyetel dan fungsi statis . Mereka akan melakukan hal yang hampir sama seperti metode array dan melakukannya dengan array kita . Misalnya, untuk membuat instance menu kelas dan menambah atau menghapusnya dari menu tumpukan, kita dapat memanggil metode dan langsung dari instance kelas.
push(argument)
pop()
.push()
.pop
this.queue
push
pop
// instantiate the menu object from class
const menu = new PS5Menu()
// add menu to the stack
menu.push = `system`
// remove the last menu that was pushed onto the stack from it
menu.pop()
Fungsi penyetel kelas seperti ini
set push()
tidak bisa dipanggil dengan
()
. Mereka menetapkan nilai menggunakan operator penugasan
=
. Fungsi penyetel kelas
set push()
akan dijalankan dengan parameter ini.
Mari gabungkan semua yang telah kita lakukan:
/* Your DOM just loaded */
window.addEventListener('DOMContentLoaded', event => {
// Instantiate the queable menu
const menu = new PS5Menu()
// Push system menu onto the menu
menu.push = `system`
// Attach click event to Start button
menu.queue[0].addEventListener(`click`, event => {
console.log(`Start button pressed!`)
// begin the ps5 demo!
menu.push = `main`
});
});
Di sini kita telah membuat sebuah instance dari kelas
PS5Menu
dan menyimpan instance objeknya dalam sebuah variabel
menu
.
Kemudian, kami mengantri beberapa menu dengan menu pertama dengan id
#system
.
Selanjutnya, kami melampirkan acara ke tombol Mulai
click
. Ketika kita mengklik tombol ini, kita membuat menu utama (dengan
id
, sama dengan
main
) menu kita saat ini. Dalam hal ini, menu sistem akan disembunyikan (menu saat ini ada dalam antrian menu) dan penampung akan ditampilkan
#menu
.
Perhatikan bahwa karena kelas wadah menu kita
.menu.current
memiliki properti
transform: 400ms;
, lalu dengan penambahan atau penghapusan sederhana kelas
.current
dari sebuah elemen, properti yang baru ditambahkan atau dihapus akan beranimasi dalam 0,4 milidetik.
Sekarang Anda perlu memikirkan tentang cara membuat konten untuk menu utama.
Perhatikan bahwa langkah ini dilakukan dalam acara DOM "Content Loaded" (
DOMContentLoaded
). Ini harus menjadi titik masuk untuk aplikasi UI apa pun. Titik masuk kedua adalah sebuah acara
window.onload
, tetapi dalam demo ini kami tidak membutuhkannya. Itu menunggu media (gambar, dll.) Untuk menyelesaikan pengunduhan, yang bisa terjadi lebih lama dari elemen DOM tersedia.
Layar splash
Awalnya, UI utama adalah rangkaian dari beberapa elemen. Seluruh baris muncul dari tepi kanan layar. Saat pertama kali muncul, itu dianimasikan dengan menyeret ke kiri.
Saya telah menyematkan elemen-elemen ini ke dalam wadah
#main
seperti ini:
<section id = "main" class = "menu f v h">
<section id = "tab" class = "f">
<div class = "on">Games</div>
<div>Media</div>
</section>
<section id = "primary" class = "f">
<div class = "sel t"></div>
<div class = "sel b current"></div>
<div class = "sel a"></div>
<div class = "sel s"></div>
<div class = "sel d"></div>
<div class = "sel e"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
</section>
</section>
Menu PS5 pertama ditempatkan di dalam wadah induk, dengan gaya sebagai berikut:
#primary {
position: absolute;
top: 72px;
left: 1200px;
width: 1000px;
height: 64px;
opacity: 0;
/* animate at the rate of 0.4s */
transition: 400ms;
}
#primary.hidden {
left: 1200px;
}
Secara default, dalam keadaan tersembunyi
#primary
, ini sengaja tidak ditampilkan; itu dipindahkan cukup jauh ke kanan (sebesar 1200px).
Kami harus melalui trial and error dan menggunakan intuisi kami. Sepertinya 1200px cocok. Penampung ini juga diwarisi
opacity:0
dari kelas
.menu
.
Jadi saat
#primary
muncul untuk pertama kali, ia menggeser dan meningkatkan kecerahannya pada saat yang bersamaan.
Di sini sekali lagi nilai
transform:400ms;
(ekuivalen
0.4s
) digunakan, karena sebagian besar mikroanimasi terlihat bagus
0.4s
. Nilai
0.3s
juga bekerja dengan baik, tetapi mungkin terlalu cepat dan
0.5s
terlalu lambat.
Menggunakan transisi CSS untuk mengontrol animasi UI
Alih-alih memanipulasi gaya CSS secara manual setiap kali kita perlu mengubah gaya atau posisi blok UI, kita cukup menetapkan dan menghapus kelas:
// get element:
const element = $(`#primary`)
// check if element already contains a CSS class:
element.style.classList.contains("menu")
// add a new class to element's class list:
element.style.classList.add("menu")
// remove a class from element's class list:
element.style.classList.remove("menu")
Ini adalah strategi penting yang akan menghemat banyak waktu dan menjaga kode Anda tetap bersih dalam proyek vanilla apa pun. Alih-alih mengubah properti,
style.left
kami hanya akan menghapus kelas
.hidden
dari elemen
#primary
. Sejak itu
transform:400ms;
, animasi akan diputar secara otomatis.
Kami akan menggunakan taktik ini untuk mengubah hampir setiap status elemen UI.
Animasi Slide-Out Sekunder
Saat bekerja dengan desain UX, ada berbagai jenis animasi. Beberapa animasi dipicu saat beralih ke menu baru. Mereka biasanya mulai setelah beberapa saat, tak lama setelah beralih ke layar baru.
Ada juga animasi hover yang aktif saat mouse atau pengontrol memilih item baru yang berdekatan di menu navigasi saat ini.
Perhatian terhadap detail itu penting, terutama saat Anda ingin menciptakan produk yang berkualitas.
Menggunakan fungsi setTimeout untuk mengontrol status animasi
Animasi sekunder kecil diputar saat item ditarik keluar . Untuk mensimulasikan efek ganda ini, fungsi JavaScript digunakan
setTimeout
segera setelah pohon DOM dimuat sepenuhnya.
Karena ini adalah layar menu pertama yang muncul segera setelah mengklik tombol Start , kita sekarang perlu memperbarui event
click
tombol Start di event DOMContentLoaded tepat setelahnya
menu.push = `main`
.
Kode berikut akan duduk di bagian bawah fungsi acara yang sudah ada
DOMContentLoaded
(lihat contoh kode sumber yang ditunjukkan di atas):
/* Your DOM just loaded */
window.addEventListener('DOMContentLoaded', event => {
/* Initial setup code goes here...see previous source code example */
// Attach click event to Start button
menu.queue[0].addEventListener(`click`, event => {
console.log(`Start button pressed!`)
// begin the ps5 demo!
menu.push = `main`
// new code: animate the main UI screen for the first time
// animate #primary UI block within #main container
primary.classList.remove(`hidden`)
primary.classList.add(`current`)
// animate items up
let T1 = setTimeout(nothing => {
primary.classList.add('up');
def.classList.add('current');
// destroy this timer
clearInterval(T1)
T1 = null;
}, 500)
});
});
Apa hasilnya
Semua kode yang kami tulis menghasilkan animasi awal ini:
Buat item yang dapat dipilih
Kami telah membuat CSS untuk elemen yang dapat dipilih (kelas
.sel
).
Tapi masih terlihat rustic, tidak semulus antarmuka PS5.
Di bagian selanjutnya, kita akan melihat kemungkinan untuk membuat antarmuka yang lebih bagus. Kami akan meningkatkan UI menjadi tampilan dan nuansa profesional dari sistem navigasi PlayStation 5.
Animasi standar dari elemen "yang dipilih" atau "saat ini"
Tiga jenis animasi untuk item yang saat ini dipilih
Di UI konsol PS5, item yang saat ini dipilih memiliki tiga efek visual. Garis besar yang berputar - "halo", titik cahaya acak yang bergerak di latar belakang, dan terakhir, "gelombang cahaya" - efek yang terlihat seperti gelombang yang bergerak ke arah tombol arah yang ditekan pada pengontrol.
Di bagian ini, kita akan belajar cara membuat efek garis besar tombol PS5 klasik dengan titik cahaya di latar belakang dan gelombang cahaya. Di bawah ini adalah analisis dari setiap jenis animasi dan kelas CSS yang kita butuhkan untuk semua jenis ini:
Halo animasi dengan gradien
Efek ini menambahkan bingkai animasi yang berputar di sekitar item yang dipilih.
Di CSS, ini dapat disimulasikan dengan memutar gradien meruncing.
Berikut garis besar CSS umum untuk elemen yang dapat dipilih:
.sel {
position: relative;
width: 64px;
height: 64px;
margin: 5px;
border: 2px solid #1f1f1f;
border-radius: 8px;
cursor: pointer;
transition: 400ms;
transform-style: preserve-3d;
z-index: 3;
}
.sel.current {
width: 100px;
height: 100px;
}
.sel .under {
content:'';
position: absolute;
width: calc(100% + 8px);
height: calc(100% + 8px);
margin: -4px -4px;
background: #1f1f1f;
transform: translateZ(-2px);
border-radius: 8px;
z-index: 1;
}
.sel .lightwave-container {
position: relative;
width: 100%;
height: 100%;
transition: 400ms;
background: black;
transform: translateZ(-1px);
z-index: 2;
overflow: hidden;
}
.sel .lightwave {
position: absolute;
top: 0;
right: 0;
width: 500%;
height: 500%;
background: radial-gradient(circle at 10% 10%, rgba(72,72,72,1) 0%, rgba(0,0,0,1) 100%);
filter: blur(30px);
transform: translateZ(-1px);
z-index: 2;
overflow: hidden;
}
Saya mencoba menggunakan pseudo-elemen
::after
dan
::before
, tetapi saya tidak dapat mencapai hasil yang saya inginkan dengan cara yang sederhana, dan dukungan mereka oleh browser dipertanyakan; selain itu, JavaScript tidak memiliki cara asli untuk mengakses elemen semu.
Sebagai gantinya, saya memutuskan untuk membuat elemen baru
.under
dan mengurangi posisi Z-nya dengan -1 menggunakan
transform: translateZ(-1px)
; jadi, kami menjauhkannya dari kamera, membiarkan induknya muncul di atasnya.
Anda mungkin juga perlu menambahkan
.sel
properti ke elemen induk yang diidentifikasi oleh elemen
transform-style: preserve-3d;
untuk mengaktifkan urutan-z dalam ruang 3D elemen.
Idealnya, kami ingin memberi
.under
induk pada lapisan ke elemen dan membuat titik terang dengan elemen tombol yang sebenarnya di dalamnya. Tetapi trik ini memiliki
translateZ
prioritas yang lebih tinggi, dan begitulah cara saya mulai membangun UI. Ini dapat dikerjakan ulang, tetapi pada tahap ini tidak perlu.
HTML cukup sederhana. Yang penting di sini adalah kita sekarang memiliki elemen baru
.under
. Ini adalah elemen di mana gradien kerucut berputar akan dirender untuk membuat batas bercahaya halus.
.lightwave-container
akan membantu kami menerapkan efek cahaya bergerak dengan
overflow: hidden
.
.lightwave
- ini adalah elemen di mana efek akan diberikan, ini adalah div yang lebih besar yang melampaui batas tombol dan berisi gradien radial offset.
<div id = "o0" data-id = "0" class = "sel b">
<div class = "under"></div>
<div class = "lightwave-container">
<div class = "lightwave"></div>
</div>
</div>
Mulai awal Maret 2021, animasi CSS tidak mendukung rotasi latar belakang gradien.
Untuk mengatasi masalah ini, saya menggunakan fungsi JavaScript bawaan
window.requestAnimationFrame
. Ini dengan lancar menganimasikan properti latar belakang sesuai dengan kecepatan bingkai monitor, yang biasanya 60FPS.
// Continuously rotate currently selected item's gradient border
let rotate = () => {
let currentlySelectedItem = $(`.sel.current .under`)
let lightwave = $(`.sel.current .lightwave`)
if (currentlySelectedItem) {
let deg = parseInt(selectedGradientDegree);
let colors = `#aaaaaa, black, #aaaaaa, black, #aaaaaa`;
// dynamically construct the css style property
let val = `conic-gradient(from ${deg}deg at 50% 50%, ${colors})`;
// rotate the border
currentlySelectedItem.style.background = val
// rotate lightwave
lightwave.style.transform = `rotate(${selectedGradientDegree}deg)`;
// rotate the angle
selectedGradientDegree += 0.8
}
window.requestAnimationFrame(rotate)
}
window.requestAnimationFrame(rotate)
Fungsi ini bertanggung jawab untuk menganimasikan batas yang berputar dan elemen gelombang cahaya yang lebih besar.
Paradigma Pendengar Acara
Karena kita tidak menggunakan React atau framework lain, kita perlu menangani sendiri event listenernya. Setiap kali kita mengganti menu, kita perlu melepaskan semua peristiwa mouse dari semua item di dalam wadah induk dari menu sebelumnya, dan melampirkan pendengar peristiwa mouse ke semua item interaktif di dalam wadah induk dari menu baru yang dipilih.
Setiap layar itu unik. Cara termudah adalah dengan membuat kode acara untuk setiap layar. Ini bukan peretasan, tetapi hanya kode khusus untuk setiap sistem navigasi unik. Untuk beberapa hal, tidak ada solusi yang mudah.
Dua fungsi berikutnya akan mengaktifkan dan menonaktifkan acara dari layar yang berbeda.
Lihat kode sumber PS5.js lengkapuntuk memahami bagaimana semuanya bekerja secara umum.
function AttachEventsFor(parentElementId) {
switch (parentElementId) {
case "system":
break;
case "main":
break;
case "browser":
break;
case "settings":
break;
}
}
function RemoveEventsFrom(parentElementId) {
switch (parentElementId) {
case "system":
break;
case "main":
break;
case "browser":
break;
case "settings":
break;
}
}
Ini memastikan bahwa kita tidak pernah mendengarkan lebih banyak kejadian mouse daripada yang kita miliki sehingga kode UX berjalan secara optimal untuk setiap layar menu individu.
Menavigasi dengan keyboard
Kontrol keyboard jarang digunakan dalam aplikasi web dan situs web. Jadi saya membuat pustaka keyboard vanilla JS yang mengenali tombol dasar dan memungkinkan Anda untuk menghubungkan acara penekanan tombol.
Kita perlu mencegat kunci berikut:
- Enter atau Spasi - Memilih item yang saat ini dipilih.
- Kiri , Kanan , Atas , Bawah - navigasi melalui menu yang saat ini dipilih.
- Escape - Membatalkan menu antrian saat ini dan kembali ke menu sebelumnya.
Anda dapat mengikat semua kunci dasar ke variabel sebagai berikut:
// Map variables representing keys to ASCII codes
const [ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z ] = Array.from({ length: 26 }, (v, i) => 65 + i);
const Delete = 46;
const Shift = 16;
const Ctrl = 17;
const Alt = 18;
const Left = 37;
const Right = 39;
const Up = 38;
const Down = 40;
const Enter = 13;
const Return = 13;
const Space = 32;
const Escape = 27;
Lalu buat penangan peristiwa keyboard:
function keyboard_events_main_menu(e) {
let key = e.which || e.keyCode;
if (key == Left) {
if (menu.x > 0) menu.x--
}
if (key == Right) {
if (menu.x < 3) menu.x++
}
if (key == Up) {
if (menu.y > 0) menu.y--
}
if (key == Down) {
if (menu.y < 3) menu.y++
}
}
Dan hubungkan ke objek dokumen:
document.body.addEventListener("keydown", keyboard_events_main_menu);
Sound API
Masih mengerjakannya ...
Sementara itu, Anda dapat mengunduh di sini pustaka API suara sederhana di vanilla JS.