เบากว่าและเร็วกว่า - คู่มือสำหรับ Svelte Framework
เผยแพร่แล้ว: 2022-03-11เว็บแอปพลิเคชันกำลังเป็นที่นิยมมากขึ้นทุกวัน พวกเขาเป็นโลกที่กำลังเติบโตซึ่งผู้คนเลือกใช้ความเรียบง่าย ความเร็ว และความพร้อมใช้งานข้ามแพลตฟอร์ม แอปพลิเคชันหน้าเดียว (SPA) มีส่วนสำคัญในกระบวนการนี้ กรอบงานเช่น Angular, Vue.js และ React ช่วยให้นักพัฒนาสามารถมอบประสบการณ์ผู้ใช้ที่ดีที่สุดในช่วงเวลาสั้น ๆ โดยปล่อยให้โค้ดรองรับและขยายได้ เครื่องมือเหล่านี้ยังคงได้รับความนิยมสูงสุดในภาคสนามมาอย่างยาวนาน โดยมีข้อได้เปรียบเหนือแพ็คเกจที่สร้างขึ้นใหม่มากมาย รู้สึกเหมือนเป็นผู้ขายน้อยรายในโลกของ SPA อย่างไรก็ตาม กลุ่มนักพัฒนาที่มองการณ์ไกลซึ่งกำหนดเป้าหมายไปที่ตลาดนี้สามารถเข้าร่วมกับคู่แข่งที่จริงจัง นั่นคือ Svelte
Svelte เป็นแนวทางใหม่ในการสร้างส่วนต่อประสานผู้ใช้ มาดำดิ่งลงไปและสำรวจสิ่งที่ทำให้มีความสดใหม่โดยการสร้างแบบฟอร์มการเข้าสู่ระบบทั่วไป
สถาปัตยกรรม
Svelte ได้รับการออกแบบทางสถาปัตยกรรมให้เร็วกว่าห้องสมุดอื่น มันทำได้โดยการเปลี่ยนขั้นตอนการโหลดเฟรมเวิร์กสำหรับการสร้าง DOM เสมือน แทนที่จะใช้เครื่องมือในระหว่างกระบวนการทำงาน มันถูกคอมไพล์เป็น vanilla JS ที่ขั้นตอนการสร้าง ดังนั้นแอปพลิเคชันจึงไม่จำเป็นต้องมีการพึ่งพาเพื่อเริ่มต้น
Svelte | ไลบรารี SPA อื่นๆ (React, Vue.js, Angular เป็นต้น) |
---|---|
1. เปิดเว็บไซต์ | 1. เปิดเว็บไซต์ |
ตารางด้านบนอธิบายว่าทำไม Svelte จึงเป็นผู้ชนะอย่างแท้จริงในประสิทธิภาพการเริ่มต้น ที่ไม่ได้มาจากการเพิ่มประสิทธิภาพใด ๆ แต่โดยการใช้คอมไพเลอร์ JavaScript ของเบราว์เซอร์ที่มีอยู่แทนคอมไพเลอร์ด้านข้าง
การติดตั้ง
การติดตั้ง Svelte ทำได้ง่ายมาก ทำให้การใช้งานเป็นไปอย่างราบรื่น ขั้นตอนแรกคือการดาวน์โหลดเทมเพลตของโครงการ:
npx degit sveltejs/template svelte-login-form
การทำตามคำสั่งด้านบนให้สมบูรณ์หมายความว่าเรามีเทมเพลตโครงการ Svelte ขณะนี้ว่างเปล่าและยังไม่ได้ติดตั้งแพ็คเกจ NPM ที่จำเป็น มาแก้ไขกันเถอะ
cd svelte-login-form npm install
ตอนนี้แอปพลิเคชันพร้อมที่จะเริ่มทำงานโดยใช้คำสั่งต่อไปนี้:
npm run dev
โครงสร้าง
ส่วนประกอบ Svelte ใดๆ อาจประกอบด้วยส่วนต่อไปนี้:
- สคริปต์
- สไตล์
- แม่แบบ
มาดูตัวอย่างในไฟล์ src/App.svelte
<script> export let name; </script> <style> h1 { color: purple; } </style> <h1>{name}</h1>
รหัสด้านบนประกอบด้วยสามส่วนเท่านั้น:
แท็ก
script
ซึ่งเป็นบล็อก JavaScript ทางเลือกที่มีการประกาศตัวแปรและฟังก์ชันที่ควรใช้ภายในคอมโพเนนต์แท็ก
style
ซึ่งเป็นบล็อกทางเลือกอื่น มันเหมือนกับแท็กสไตล์ HTML ทั่วไป ยกเว้นข้อแตกต่างที่สำคัญอย่างหนึ่ง กฎที่อธิบายไว้ในบล็อกนี้กำหนดขอบเขตไว้เฉพาะส่วนประกอบนี้ การใช้สไตล์กับองค์ประกอบp
จะไม่มีผลกับย่อหน้าทั้งหมดบนหน้า มันวิเศษมากเพราะคุณไม่จำเป็นต้องคิดชื่อคลาส และคุณจะไม่ลบล้างกฎอื่นโดยไม่ได้ตั้งใจบล็อกสุดท้ายและบล็อกเดียวที่จำเป็นคือบล็อกเทมเพลต - ในกรณีนี้คือแท็ก
h1
เป็นการนำเสนอ/มุมมองขององค์ประกอบของคุณ มีการผูกมัดอย่างแน่นหนากับสไตล์และบล็อกสคริปต์เนื่องจากเป็นตัวกำหนดว่ามุมมองจะถูกจัดรูปแบบอย่างไรและจะทำงานอย่างไร
Svelte เป็นห้องสมุดที่พยายามนำโมดูลาร์มาสู่เกมส่วนหน้า มันทำให้โมดูลาร์นั้นไม่เฉพาะในการแยกส่วนประกอบต่างๆ เท่านั้น แต่ยังรวมถึงการแยกตรรกะ มุมมอง และเทมเพลตด้วย
กลับไปที่แบบฟอร์มการเข้าสู่ระบบที่เรากำลังสร้าง ให้สร้างไฟล์ใหม่ LoginForm.svelte
ภายในโฟลเดอร์ src
ที่มีเนื้อหาต่อไปนี้:
<style> form { background: #fff; padding: 50px; width: 250px; height: 400px; display: flex; flex-direction: column; justify-content: center; align-items: center; box-shadow: 0px 20px 14px 8px rgba(0, 0, 0, 0.58); } label { margin: 10px 0; align-self: flex-start; font-weight: 500; } input { border: none; border-bottom: 1px solid #ccc; margin-bottom: 20px; transition: all 300ms ease-in-out; width: 100%; } input:focus { outline: 0; border-bottom: 1px solid #666; } button { margin-top: 20px; background: black; color: white; padding: 10px 0; width: 200px; border-radius: 25px; text-transform: uppercase; font-weight: bold; cursor: pointer; transition: all 300ms ease-in-out; } button:hover { transform: translateY(-2.5px); box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.58); } h1 { margin: 10px 20px 30px 20px; font-size: 40px; } </style> <form> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" /> <label>Password</label> <input name="password" type="password" placeholder="password" /> <button type="submit">Log in </button> </form>
มันเป็นองค์ประกอบที่โง่เขลาที่เราจะทำให้ฉลาดขึ้นในภายหลัง หากต้องการดูองค์ประกอบนี้บนไซต์ของเรา เราควรแสดงผลภายในองค์ประกอบรูท - แอป ไปแก้ไข src/App.svelte
กัน จะได้หน้าตาแบบนี้:
<script> import LoginForm from "./LoginForm.svelte"; </script> <style> section { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #cd76e2, #e358ab); } </style> <section> <LoginForm /> </section>
หากทุกอย่างถูกต้องและแอปพลิเคชันยังทำงานอยู่ แบบฟอร์มของเราจะปรากฏที่ localhost:5000
มาเพิ่มระดับทักษะ Svelte ของเราด้วยการทำให้แบบฟอร์มฉลาดขึ้น
กำลังเก็บสถานะ
องค์ประกอบใดๆ ใน Svelte สามารถมีสถานะได้ สถานะเป็นตัวแปรพิเศษหรือกลุ่มของตัวแปรพิเศษที่สามารถใช้ได้ภายในเทมเพลต ทำไมฉันถึงพูดว่า "พิเศษ"? เมื่อใดก็ตามที่มีการเปลี่ยนแปลงตัวแปรดังกล่าว เทมเพลตจะได้รับการแจ้งเตือนและแสดงเนื้อหาด้วยสถานะใหม่ล่าสุด ซึ่งช่วยให้แอปพลิเคชันตอบสนองต่อการโต้ตอบของผู้ใช้ได้อย่างรวดเร็ว
เราจะประกาศตัวแปรสถานะ email
และ password
ที่จะจัดเก็บค่าของแบบฟอร์มสำหรับฟิลด์ที่เหมาะสม หมายความว่าตัวแปร email
และ password
ของเราจะซิงค์กับค่าของแบบฟอร์มเสมอ ดังนั้นเราจะพร้อมส่งค่าเหล่านี้เมื่อใดก็ได้โดยไม่ต้องกลัวว่าจะมีความแตกต่างระหว่างค่าที่ส่งกับค่าจริงในแบบฟอร์ม
<script> let email = ""; let password = ""; let isLoading = false; const handleSubmit = () => { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); }; </script> <style> /* Style is unchanged */ </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> {#if isLoading}Logging in...{:else}Log in {/if} </form>
ตัวแปรสถานะดูเหมือนตัวแปร JavaScript ทั่วไป แต่เพื่อให้ซิงโครไนซ์กับค่าของแบบฟอร์ม (เชื่อมโยงกับฟิลด์ของแบบฟอร์ม) จำเป็นต้องใช้คำสั่ง bind:value
นอกจากนี้ยังมีบางสิ่งที่ไม่คุ้นเคย:
on:submit|preventDefault
เป็นชวเลขสำหรับป้องกันพฤติกรรมเริ่มต้นของเหตุการณ์ วิธีนี้สะดวกกว่าการเขียนe.preventDefault()
ทุกครั้ง{#if isLoading}Logging in...{:else}Log in {/if}
เป็นส่วนประกอบหนึ่งของรูปแบบเทมเพลตของ Svelte เนื่องจากไม่มี JS ในบล็อกเทมเพลต จึงมีไวยากรณ์พิเศษสำหรับการใช้ ifs, loops เป็นต้น
สุดท้าย ลองใช้ตัวเลือกที่มีอยู่โดยใช้สถานะเพื่อเพิ่มการตรวจสอบลงในแบบฟอร์มของเรา สามารถทำได้โดยการสร้าง errors
ตัวแปรสถานะอื่น ซึ่งจะเต็มไปด้วยข้อผิดพลาดเมื่อส่งแบบฟอร์มด้วยค่าที่ไม่ถูกต้อง
<script> let email = ""; let password = ""; let isLoading = false; let errors = {}; const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); } }; </script> <style> // Previous styles unchanged .errors { list-style-type: none; padding: 10px; margin: 0; border: 2px solid #be6283; color: #be6283; background: rgba(190, 98, 131, 0.3); } </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} </form>

แบบฟอร์มใกล้จะสมบูรณ์แล้ว สิ่งเดียวที่ยังคงอยู่คือข้อความแสดงความสำเร็จเมื่อรับรองความถูกต้องสำเร็จ

มาสร้างตัวแปรสถานะเพื่อติดตามการส่งที่สำเร็จซึ่งเป็น false
โดยค่าเริ่มต้น หลังจากส่งแบบฟอร์มสำเร็จแล้ว ค่าของตัวแปรนี้ควรตั้งค่า true
let isSuccess = false;
ควรเปลี่ยนฟังก์ชันที่จัดการการส่งแบบฟอร์มเพื่อให้เป็นไปตามตรรกะของการสลับ isSuccess
หลังจากดำเนินการสำเร็จ
const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; isSuccess = true; // Authorize the user }, 1000); } };
การปรับเปลี่ยนนี้ทำให้แบบฟอร์มเข้าสู่สถานะสำเร็จทันทีที่การส่งเสร็จสมบูรณ์
แต่ถ้าคุณตรวจสอบเซิร์ฟเวอร์การพัฒนา คุณจะไม่พบการเปลี่ยนแปลงใดๆ ในลักษณะการทำงานของแบบฟอร์ม เราเปลี่ยนรหัสแต่ยังไม่ได้แตะแม่แบบ เราจำเป็นต้องเพิ่มคำแนะนำในเทมเพลตเพื่อแสดงข้อความแสดงความสำเร็จเมื่อผู้ใช้ลงชื่อเข้าใช้สำเร็จ ไวยากรณ์เทมเพลตของ Svelte ช่วยให้เรานำไปใช้ได้อย่างง่ายดาย:
<form on:submit|preventDefault={handleSubmit}> {#if isSuccess} <div class="success"> <br /> You've been successfully logged in. </div> {:else} <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} {/if} </form>
บทคัดย่อด้วยคุณสมบัติ
เราได้แยกแยะทุกอย่างเกี่ยวกับสถานะของส่วนประกอบภายในแล้ว ถึงเวลาที่ต้องพิจารณาการพึ่งพาภายนอกที่เรียกว่าคุณสมบัติหรือ "อุปกรณ์ประกอบฉาก" อุปกรณ์ประกอบฉากคืออินพุตหรืออาร์กิวเมนต์ที่ส่งผ่านไปยังส่วนประกอบเพื่ออธิบายสิ่งที่ควรปรากฏหรือองค์ประกอบที่ควรแสดงแก่ส่วนประกอบ
การประกาศคุณสมบัติคล้ายกับสถานะ ยกเว้นสำหรับการ export
คำหลัก
<script> export let answer; </script> <p>The answer is {answer}</p>
<script> import Nested from './Nested.svelte'; </script> <Nested answer={42}/>
มันคือทั้งหมดที่เกี่ยวกับคุณสมบัติ ประกาศและผ่าน - ทั้งหมดที่คุณต้องรู้เพื่อใช้อุปกรณ์ประกอบฉาก
แต่คุณสมบัติเหล่านี้นำไปใช้กับองค์ประกอบแบบฟอร์มการเข้าสู่ระบบได้อย่างไร อุปกรณ์ประกอบฉากสามารถทำให้แบบฟอร์มการเข้าสู่ระบบของเราเป็นแบบทั่วไปมากขึ้นโดยแยกฟังก์ชันการส่งลงในพร็อพเพอร์ตี้ จะช่วยให้คุณใช้ส่วนประกอบนี้กับการดำเนินการส่งที่คุณต้องการได้ (ขอเซิร์ฟเวอร์ทดสอบ ขอไปยังเซิร์ฟเวอร์จริง ฯลฯ) พร็อพนี้จะถูกเรียกว่า send และจะเป็นฟังก์ชันที่ submit
คืนสัญญาที่ได้รับการแก้ไขแล้ว หากการดำเนินการส่งสำเร็จ และสัญญาที่ถูกปฏิเสธหากมีข้อผิดพลาด ขอประกาศพร็อพตามตัวอย่างที่ให้ไว้ข้างต้น:
export let submit;
ตัวจัดการการส่งภายในแบบฟอร์มการเข้าสู่ระบบควรได้รับการแก้ไขเพื่อใช้คุณสมบัติ submit
ใหม่
const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; submit({ email, password }) .then(() => { isSuccess = true; isLoading = false; }) .catch(err => { errors.server = err; isLoading = false; }); } };
ดูเหมือนว่าองค์ประกอบจะพร้อม อย่างไรก็ตาม หากคุณกลับไปที่แบบฟอร์มและพยายามส่ง คุณจะสังเกตเห็นว่าสถานะของปุ่มไม่ได้เปลี่ยนจากการโหลด นอกจากนี้ยังมีข้อยกเว้นในคอนโซล Uncaught TypeError: submit is not a function
แน่นอน เราประกาศพร็อพแล้ว แต่ลืมส่งไป มาประกาศฟังก์ชันในองค์ประกอบของแอปและส่งต่อไปยังแบบฟอร์มการเข้าสู่ระบบ
const submit = ({ email, password }) => new Promise((resolve, reject) => setTimeout(resolve, 1000));
<section> <LoginForm submit={submit} /> </section>
ตอนนี้แบบฟอร์มทำงานตามที่ตั้งใจไว้ สามารถแสดงข้อผิดพลาดและแจ้งให้ผู้ใช้ทราบว่าการเข้าสู่ระบบสำเร็จหรือไม่

การแบ่งปันบริบท
ดูเหมือนว่าทุกสิ่งที่จำเป็นในการสร้างแอปพลิเคชันจะแสดงอยู่ในรายการ ด้วยคุณสมบัติและสภาพภายใน เราก็พร้อมลุย นั่นเป็นความจริงเพียงบางส่วนเท่านั้น ประเด็นทั่วไปสองข้อนี้ทำให้สามารถออกแบบ SPA ที่มีความซับซ้อนสูงได้ อย่างไรก็ตาม หากคุณพยายามแบ่งปันข้อมูลระหว่างองค์ประกอบต่างๆ คุณจะพบว่ามันยากมาก
ตัวอย่างที่ง่ายที่สุดคือการมีตัวแปร user
ที่เข้าถึงได้ทั่วโลก ส่วนประกอบจำนวนมากควรเปลี่ยนพฤติกรรมที่เกี่ยวข้องกับผู้ใช้ ขึ้นอยู่กับบทบาทของผู้ใช้ อายุ สถานะ ฯลฯ อย่างไรก็ตาม มันไม่ DRY ที่จะทำซ้ำตัวเองโดยส่งผู้ใช้ไปยังแต่ละองค์ประกอบในแอปโดยใช้อุปกรณ์ประกอบฉาก
Svelte มีวิธีแก้ปัญหาสำหรับสิ่งนี้: บริบท API
API บริบทมีกลไกสำหรับส่วนประกอบในการ 'พูดคุย' ซึ่งกันและกันโดยไม่ต้องส่งต่อข้อมูลและทำหน้าที่เป็นอุปกรณ์ประกอบฉากหรือส่งกิจกรรมจำนวนมาก เป็นคุณลักษณะขั้นสูง แต่มีประโยชน์
มาเพิ่มบริบทผู้ใช้ให้กับแบบฟอร์มการเข้าสู่ระบบที่เรากำลังออกแบบกัน สร้างไฟล์ userContext.js
ภายในโฟลเดอร์ src
ด้วยเนื้อหาต่อไปนี้:
export const key = "userContext"; export const initialValue = null;
key
เป็นตัวระบุเฉพาะสำหรับบริบท เนื่องจากแอปพลิเคชันอาจมีบริบทที่แตกต่างกันจำนวนไม่จำกัดซึ่งต้องสามารถเข้าถึงได้ initialValue
เป็นเพียงค่าเริ่มต้นสำหรับบริบทก่อนที่จะตั้งค่า
ขั้นตอนต่อไปคือการเพิ่มบริบทให้กับแอปพลิเคชันของเรา ไปที่ไฟล์ App.svelte
และเพิ่มคำสั่งนำเข้า 2 รายการ:
import { onMount, setContext } from "svelte"; import { key as userContextKey, initialValue as userContextInitialValue } from "./userContext";
เมื่อดูโค้ดด้านบน คุณอาจสงสัยว่าเรากำลังนำเข้าอะไรจากแพ็คเกจ svelte
onMount
เป็นฟังก์ชันตัวช่วยที่ต้องการฟังก์ชันเรียกกลับเป็นอาร์กิวเมนต์ การเรียกกลับนี้จะดำเนินการเมื่อมีการต่อเชื่อมส่วนประกอบปัจจุบัน (เมื่อเริ่มต้นการโหลดส่วนประกอบ) setContext
เป็นฟังก์ชัน setter สำหรับบริบท ต้องใช้คีย์ในบริบทและค่าใหม่เป็นอาร์กิวเมนต์
ลองใช้ฟังก์ชัน onMount
เพื่อตั้งค่าเริ่มต้นสำหรับบริบท:
onMount(() => { setContext(userContextKey, userContextInitialValue); });
และแก้ไขฟังก์ชัน submit
เพื่อกำหนดบริบทของผู้ใช้:
const submit = ({ email, password }) => new Promise((resolve, reject) => { setTimeout(() => { setContext(userContextKey, { name: "Foo", lastName: "Bar", email: "[email protected]" }); resolve(); }, 1000); });
แค่นั้นแหละ. การส่งที่สำเร็จจะเปลี่ยนบริบทของผู้ใช้เป็นวัตถุผู้ใช้ปลอม ซึ่งสามารถเข้าถึงได้โดยตัวรับบริบท getContext
:
<script> import { getContext } from 'svelte'; import { key as userContextKey } from "./userContext"; const user = getContext(key); </script>
สรุป
Svelte เป็นเครื่องมือที่ทรงพลังที่มีประสิทธิภาพสูงและมี API ที่ยืดหยุ่น นอกจากข้อมูลพื้นฐานที่กล่าวถึงในโพสต์นี้ Svelte ยังมีคุณสมบัติดังต่อไปนี้:
- การประกาศและแถลงการณ์เชิงโต้ตอบ
- รอบล็อกเทมเพลต
- การผูกมิติ
- ร้านค้าระดับโลกอย่าง Redux
- แอนิเมชั่นและตัวช่วยการเปลี่ยนแปลง
- ผู้ช่วยดีบัก
โดยสรุป Svelte เป็นห้องสมุดที่ยอดเยี่ยมที่ตอบสนองทุกความต้องการในการสร้าง SPA และอื่นๆ มันสามารถแข่งขันกับผู้เล่นรายใหญ่ที่สุดในตลาดและแม้กระทั่งชนะ สิ่งที่สามารถใช้ได้ในขณะนี้คือการสนับสนุนในชุมชนนักพัฒนาส่วนหน้า
หมายเหตุ: รหัสทั้งหมดในบทความนี้มีอยู่ในที่เก็บ GitHub teimurjan/svelte-login-form
การสาธิตสำหรับแบบฟอร์มการเข้าสู่ระบบมีอยู่ที่นี่