Kehidupan penuh di Svelte

Radislav Gandapas memiliki buku yang luar biasa Lengkap J. Ini berbicara tentang bagaimana menilai arah hidup Anda, dan bagaimana mengembangkan rencana pembangunan.


Saya ingin membuat alat yang akan ada di ponsel cerdas saya dan membantu menyusun radar saya.


gambar


1. Persiapan


Kode sumber tutorial dan demo dapat dilihat di sini .


Proyek ini kecil, jadi kami akan segera menulis di REPL , editor langsing online. Jika Anda menyukai pengembangan lokal, Anda dapat menggunakan template webpack atau rollup svelte.


Saya dapat merekomendasikan alat codesandbox online sebagai alternatif untuk pengembangan lokal.


Jika Anda menggunakan VScode, maka saya sarankan untuk menginstal plugin svelte-vscode


Jadi, kita buka REPL dan kita mulai


2. Bingkai


Sekarang kita memiliki file App.svelte , ini adalah titik masuk ke aplikasi. Komponen langsing ditata dalam tag gaya , seperti dalam html biasa. Dengan melakukannya, Anda mendapatkan isolasi gaya di tingkat komponen. Jika Anda perlu menambahkan gaya global yang akan dapat diakses "di luar" objek, maka Anda perlu menggunakan arahan : global () . Tambahkan gaya dan buat wadah untuk aplikasi kita.


App.svelte
<style> :global(body) { height: 100%; overscroll-behavior: none; /*  pull to refresh*/ user-select: none; /*      */ margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; background: rgb(35, 41, 37); } :global(html) { height: 100%; } .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: center; height: 100%; } </style> <div class="container"> </div> 

Buat komponen Radar.svelte . Ini akan menjadi elemen SVG di mana kita akan menggambar roda kita.


Radar.svelte
 <svg viewBox="-115 -110 230 220"> </svg> 

Kode Javascript di komponen Svelte ditempatkan di tag skrip . Kami mengimpor Radar.svelte kami ke App.svelte dan menariknya.


App.svelte
 <script> import Radar from './Radar.svelte' /*    */ </script> <style> :global(body) { height: 100%; overscroll-behavior: none; user-select: none; margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; background: rgb(35, 41, 37); } :global(html) { height: 100%; } .container { flex-grow: 1; display: flex; flex-direction: column; justify-content: center; height: 100%; } </style> <div class="container"> <Radar/> <!--   Radar --> </div> 

Radar itu sendiri akan terdiri dari sektor-sektor yang sesuai dengan aspek kehidupan. Setiap sektor memiliki indeks sendiri.


gambar


Setiap sektor terdiri dari kotak, yang, pada gilirannya, adalah sektor dengan ukuran lebih kecil.


gambar


Untuk menggambar suatu sektor, kita perlu mengetahui koordinat dari ketiga simpul.


gambar


Vertex A selalu dengan koordinat [0, 0], karena titik asal akan berada di pusat radar kami. Untuk menemukan simpul B dan C, kami menggunakan fungsi dari tutorial yang sangat baik tentang kisi heksagonal. Pada input, fungsi menerima ukuran dan arah sektor, dan mengembalikan string dengan koordinat 'x, y'.
Buat file getHexCorner.js , tempat kami meletakkan fungsi getHexCorner (ukuran, arah)


getHexCorner.js
 export default function getHexCorner(size, direction) { const angleDeg = 60 * direction - 30; const angleRad = (Math.PI / 180) * angleDeg; return `${size * Math.cos(angleRad)},${size * Math.sin(angleRad)}`; } 

Sekarang buat komponen sektor, sektor.svelte , yang menggambar kisi. Kami membutuhkan siklus 10 langkah. Dalam isi komponen, svelte tidak dapat mengimplementasikan loop for, jadi saya hanya membuat array grid, yang akan saya ulas di dalam arahan #each . Jika Anda punya ide bagaimana membuatnya lebih elegan, tulis di komentar.


Sector.svelte
 <script> import getHexCorner from "./getHexCorner.js"; export let direction = 0; const grid = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; </script> <style> polygon { fill: #293038; stroke: #424a54; } </style> {#each grid as gridValue, i} <polygon points={`${getHexCorner(gridValue * 10, direction)}, ${getHexCorner(gridValue * 10, direction + 1)}, 0, 0`} strokeLinejoin="miter-clip" stroke-dasharray="4" stroke-width="0.5" /> {/each} 

Mengimpor dan menggambar sektor dalam komponen Radar.svelte .


Radar.svelte
 <script> import Sector from './Sector.svelte'; </script> <svg viewBox="-115 -110 230 220"> <Sector/> </svg> 

Sekarang aplikasi kami menampilkan 1 sektor.


gambar


3. Penyimpanan data


Untuk menggambar seluruh radar, Anda perlu mengetahui daftar sektor. Karena itu, kami akan membuat toko negara. Kami akan menggunakan gerbang khusus tempat kami menerapkan logika memperbarui negara. Secara umum, ini adalah repositori Svelte biasa, yang dibungkus dalam suatu fungsi. Ini melindungi repositori dari perubahan dengan menyediakan serangkaian tindakan yang tersedia. Saya suka pendekatan ini karena struktur data dan logika bekerja dengan mereka ada di satu tempat.


Buat file store.js


Kami membutuhkan dua penyimpanan:


  • radar untuk menyimpan nilai saat ini
  • activeSector untuk menyimpan sektor aktif jika terjadi touchmove dan mousemove.

store.js
 import { writable } from "svelte/store"; const defaultStore = ["hobby", "friendship", "health", "job", "love", "rich"]; function Radar() { /*      */ const { subscribe, update } = writable(defaultStore.map(item=>({name:item, value:0}))); /*         */ return { subscribe, set: (id, value) => update(store => store.map(item => (item.name === id ? { ...item, value } : item)) ) }; } export const radar = Radar(); export const activeSector = writable(null); 

Sekarang kita mengimpor penyimpanan yang dibuat ke komponen Radar.svelte dan menambahkan logika untuk merender radar penuh.


Radar.svelte
 <script> import { radar } from "./store.js"; import Sector from "./Sector.svelte"; </script> <svg viewBox="-115 -110 230 220"> {#each $radar as sector, direction (sector.name)} <Sector {...sector} {direction} /> {/each} </svg> 

Beberapa kehalusan dari arahan #ach . Kami menggunakan nama variabel $ radar . $ Directive memperjelas kepada kompiler Svelte bahwa ekspresi kita adalah repositori, dan itu membuat langganan untuk perubahan. Variabel arah menyimpan indeks iterasi saat ini, sesuai dengan itu kami akan menetapkan arah sektor kami. Ekspresi (sector.name) menunjuk langsing ke id objek dalam iterasi . Kunci analog dalam Bereaksi.


Sekarang kotak kami terlihat seperti ini


gambar


Tetap mempersiapkan sektor untuk bekerja dengan acara mengklik dan menarik.
Acara touchmove, tidak seperti mousemove, hanya menembak pada elemen di mana ia dimulai. Karena itu, kami tidak dapat menangkap momen ketika pointer pindah ke sektor lain. Untuk mengatasi masalah ini, dalam markup elemen, kami akan menyimpan nama sektor saat ini dan nilainya. Pada saat acara, kami akan menentukan sektor mana yang berada di bawah kursor dan mengubah nilainya.

Perhatikan bahwa Svelte dapat memperluas konstruksi {varName} menjadi varName = {varName} . Ini membuatnya sangat mudah untuk menggulung properti.


Sector.svelte
 <script> import getHexCorner from "./getHexCorner.js"; export let direction = 0; export let name; export let value; const grid = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; </script> <style> polygon { fill: #293038; stroke: #424a54; } .rich { fill: #469573; } .hobby { fill: #7c3f7a; } .friendship { fill: #5c6bc0; } .health { fill: #e5b744; } .job { fill: #e16838; } .love { fill: #e23f45; } </style> {#each grid as gridValue, i} <polygon points={`${getHexCorner(gridValue * 10, direction)}, ${getHexCorner(gridValue * 10, direction + 1)}, 0, 0`} strokeLinejoin="miter-clip" stroke-dasharray="4" stroke-width="0.5" class={value >= gridValue ? name : ''} {name} value={gridValue} /> /> {/each} 

Jika kami menambahkan nilai selain nol di toko kami (store.js), maka ini akan menghasilkan:


4. Acara


Sudah waktunya untuk menghembuskan kehidupan ke dalam radar kami, membuat pawang yang mengambil simpul pada input, dan di dalamnya memproses peristiwa sentuhan dan mouse.


handleRadar.js
 import { radar, activeSector } from "./store.js"; /*  get            */ import { get } from "svelte/store"; export default function handleRadar(node) { const getRadarElementAtPoint = e => { /*   :    */ const event = e.touches ? e.touches[0] : e; const element = document.elementFromPoint(event.pageX, event.pageY); /*       html  */ const score = element.getAttribute("value"); const id = element.getAttribute("name"); return { id, score, type: event.type }; }; const start = e => { /*       */ const { id } = getRadarElementAtPoint(e); /*     */ activeSector.set(id); }; const end = () => { /*    */ activeSector.set(null); }; const move = e => { /*   requestAnimationFrame       */ window.requestAnimationFrame(() => { const { id, score, type } = getRadarElementAtPoint(e); /* ,      , ..    ,     */ if (!id || (id !== get(activeSector) && type !== "click") || !score) return; /*    */ radar.set(id, score); }); }; /*   */ node.addEventListener("mousedown", start); node.addEventListener("touchstart", start); node.addEventListener("mouseup", end); node.addEventListener("touchend", end); node.addEventListener("mousemove", move); node.addEventListener("touchmove", move); node.addEventListener("touch", move); node.addEventListener("click", move); /*     destroy,          DOM */ return { destroy() { node.removeEventListener("mousedown", start); node.removeEventListener("touchstart", start); node.removeEventListener("mouseup", end); node.removeEventListener("touchend", end); node.removeEventListener("mousemove", move); node.removeEventListener("touchmove", move); node.removeEventListener("touch", move); node.removeEventListener("click", move); } }; } 

Sekarang tambahkan saja handler kita ke elemen radar svg melalui petunjuk penggunaan:


Radar.svelte
 <script> import { radar } from "./store.js"; import Sector from "./Sector.svelte"; import handleRadar from "./handleRadar.js"; </script> <svg viewBox="-115 -110 230 220" use:handleRadar> {#each $radar as sector, direction (sector.name)} <Sector {...sector} {direction} /> {/each} </svg> 

Radar sekarang merespons klik dan seret.


6. Sentuhan akhir


Tambahkan keterangan untuk sektor dan deskripsi


Sector.svelte
 <script> import getHexCorner from "./getHexCorner.js"; export let name; export let value; export let direction; const grid = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; const flip = direction === 2 || direction === 1; const radarTranslation = { hobby: "", friendship: "", health: "", job: "", love: "", rich: "" }; </script> <style> polygon { fill: #293038; stroke: #424a54; } text { font-size: 8px; fill: white; } .value { font-weight: bold; font-size: 12px; } .rich { fill: #469573; } .hobby { fill: #7c3f7a; } .friendship { fill: #5c6bc0; } .health { fill: #e5b744; } .job { fill: #e16838; } .love { fill: #e23f45; } </style> {#each grid as gridValue, i} <polygon points={`${getHexCorner(gridValue * 10, direction)}, ${getHexCorner(gridValue * 10, direction + 1)}, 0, 0`} strokeLinejoin="miter-clip" stroke-dasharray="4" stroke-width="0.5" class={value >= gridValue ? name : ''} {name} value={gridValue} /> {/each} <g transform={`translate(${getHexCorner(105, flip ? direction + 1 : direction)}) rotate(${direction * 60 + (flip ? -90 : 90)})`}> <text x="50" y={flip ? 5 : 0} text-anchor="middle"> {radarTranslation[name]} </text> <text x="50" y={flip ? 18 : -10} text-anchor="middle" class="value"> {value} </text> </g> 

Radar seharusnya terlihat seperti ini.


gambar


5. Bonus


Saya sedikit memperluas fungsionalitas radar, menambahkan penyimpanan data di localStorage dan rencana aksi. Anda dapat mencoba aplikasi pemeriksaan seumur hidup , kode sumber tersedia di gitlab .


Source: https://habr.com/ru/post/id458974/


All Articles