โดเมนของแอป
หากต้องการแสดงวิธีเขียนโปรแกรมแบบ มินิแอป ที่ใช้กับเว็บแอป ผมจำเป็นต้องมีไอเดียแอปขนาดเล็กแต่สมบูรณ์พอ การออกกำลังกายแบบ HIIT (High-Intensity Interval Training) เป็นกลยุทธ์การออกกำลังกายแบบคาร์ดิโอที่สลับเซ็ตการออกกำลังกายแบบไม่ใช้ออกซิเจนที่มีความเข้มข้นสูงในช่วงเวลาสั้นๆ กับช่วงพักฟื้นที่เบาลง การฝึกแบบ HIIT หลายๆ แบบใช้ตัวจับเวลา HIIT เช่น เซสชันออนไลน์ 30 นาที จากช่อง YouTube ของ The Body Coach TV
แอปตัวอย่าง HIIT Time
สำหรับบทนี้ ผมได้สร้างแอปพลิเคชันตัวจับเวลา HIIT พื้นฐานที่ชื่อว่า "HIIT Time" ซึ่งช่วยให้ผู้ใช้กำหนดและจัดการตัวจับเวลาต่างๆ ได้ โดยตัวจับเวลาแต่ละตัวจะประกอบด้วยช่วงเวลาที่มีความเข้มข้นสูงและต่ำเสมอ จากนั้นก็เลือกตัวจับเวลาตัวใดตัวหนึ่งสำหรับเซสชันการฝึก แอปนี้เป็นแอปที่ปรับเปลี่ยนตามขนาดหน้าจอได้ โดยมีแถบนำทาง แถบแท็บ และ 3 หน้าดังนี้
- Workout: หน้าที่ใช้งานอยู่ระหว่างการออกกำลังกาย ซึ่งช่วยให้ผู้ใช้เลือกตัวจับเวลาตัวใดตัวหนึ่งได้ และมีวงแหวนความคืบหน้า 3 วง ได้แก่ จำนวนเซ็ต ช่วงออกกำลังกาย และช่วงพัก
- Timers: จัดการตัวจับเวลาที่มีอยู่และช่วยให้ผู้ใช้สร้างตัวจับเวลาใหม่ได้
- Preferences: อนุญาตให้เปิด/ปิดเอฟเฟกต์เสียงและเอาต์พุตเสียงพูด รวมถึงเลือกภาษาและธีม
ภาพหน้าจอด้านล่างแสดงให้เห็นภาพรวมของแอปพลิเคชัน
โครงสร้างแอป
ตามที่ระบุไว้ข้างต้น แอปประกอบด้วยแถบนำทาง แถบแท็บ และ 3 หน้าที่จัดเรียงเป็นตารางกริด
แถบนำทางและแถบแท็บได้รับการสร้างขึ้นเป็น iframe โดยมีคอนเทนเนอร์ <div> อยู่ระหว่าง iframe เหล่านั้น และมี iframe อีก 3 รายการ
สำหรับหน้าต่างๆ ซึ่งจะมี iframe หนึ่งรายการที่มองเห็นได้เสมอและขึ้นอยู่กับการเลือกที่ใช้งานอยู่ในแถบแท็บ
iframe สุดท้ายที่ชี้ไปยัง about:blank ใช้สำหรับหน้าในแอปที่สร้างขึ้นแบบไดนามิก ซึ่งจำเป็นสำหรับการแก้ไขตัวจับเวลาที่มีอยู่หรือสร้างตัวจับเวลาใหม่
ผมเรียกรูปแบบนี้ว่าแอปหน้าเดียวแบบหลายหน้า (MPSPA)
มาร์กอัป lit-html ที่อิงตามคอมโพเนนต์
โครงสร้างของแต่ละหน้าได้รับการสร้างขึ้นเป็น โครงสร้างพื้นฐานของ lit-html
ที่ได้รับการประเมินแบบไดนามิกในขณะรันไทม์
สำหรับข้อมูลพื้นฐานเกี่ยวกับ lit-html นั้นเป็นไลบรารีการสร้างเทมเพลต HTML ที่มีประสิทธิภาพ แสดงออกได้ดี และขยายได้สำหรับ JavaScript
การใช้ไลบรารีนี้โดยตรงในไฟล์ HTML จะทำให้โมเดลการเขียนโปรแกรมในใจมุ่งเน้นไปที่เอาต์พุตโดยตรง
ในฐานะโปรแกรมเมอร์ คุณจะเขียนเทมเพลตของเอาต์พุตสุดท้ายที่จะมีลักษณะอย่างไร จากนั้น lit-html จะเติมช่องว่างแบบไดนามิกตามข้อมูลของคุณและเชื่อมต่อตัวฟังเหตุการณ์
แอปใช้คอมโพเนนต์ที่กำหนดเองของบุคคลที่สาม เช่น Shoelace's <sl-progress-ring> หรือคอมโพเนนต์ที่กำหนดเองที่ผมสร้างขึ้นเองที่เรียกว่า <human-duration>
เนื่องจากองค์ประกอบที่กำหนดเองมี API แบบประกาศ (เช่น แอตทริบิวต์ percentage ของวงกลมแสดงความคืบหน้า) องค์ประกอบเหล่านี้จึงทำงานร่วมกับ lit-html ได้ดี ดังที่คุณเห็นในรายการด้านล่าง
<div>
<button class="start" @click="${eventHandlers.start}" type="button">
${strings.START}
</button>
<button class="pause" @click="${eventHandlers.pause}" type="button">
${strings.PAUSE}
</button>
<button class="reset" @click="${eventHandlers.reset}" type="button">
${strings.RESET}
</button>
</div>
<div class="progress-rings">
<sl-progress-ring
class="sets"
percentage="${Math.floor(data.sets/data.activeTimer.sets*100)}"
>
<div class="progress-ring-caption">
<span>${strings.SETS}</span>
<span>${data.sets}</span>
</div>
</sl-progress-ring>
</div>
โมเดลการเขียนโปรแกรม
แต่ละหน้าจะมีคลาส Page ที่สอดคล้องกัน ซึ่งจะเติมมาร์กอัป lit-html ให้มีชีวิตชีวาด้วยการให้การใช้งานตัวจัดการเหตุการณ์และให้ข้อมูลสำหรับแต่ละหน้า
คลาสนี้ยังรองรับเมธอดวงจรชีวิต เช่น onShow(), onHide(), onLoad() และ onUnload()
หน้าต่างๆ มีสิทธิ์เข้าถึงที่เก็บข้อมูลที่ใช้สำหรับการแชร์สถานะต่อหน้าและสถานะส่วนกลางที่อาจมีการคงอยู่
ระบบจะจัดการสตริงทั้งหมดจากส่วนกลาง จึงมีการสร้างการแปลเป็นภาษาต่างๆ ไว้ในตัว
เบราว์เซอร์จะจัดการการกำหนดเส้นทางให้โดยแทบไม่มีค่าใช้จ่าย เนื่องจากสิ่งที่แอปทำคือการสลับการมองเห็น iframe และเปลี่ยนแอตทริบิวต์ src ของ iframe ตัวยึดตำแหน่งสำหรับหน้าที่สร้างขึ้นแบบไดนามิก
ตัวอย่างด้านล่างแสดงโค้ดสำหรับการปิดหน้าที่สร้างขึ้นแบบไดนามิก
import Page from '../page.js';
const page = new Page({
eventHandlers: {
back: (e) => {
e.preventDefault();
window.top.history.back();
},
},
});
การจัดรูปแบบ
การจัดรูปแบบหน้าจะเกิดขึ้นต่อหน้าในไฟล์ CSS ที่มีขอบเขตของตัวเอง
ซึ่งหมายความว่าโดยปกติแล้วองค์ประกอบสามารถระบุได้โดยตรงตามชื่อองค์ประกอบ เนื่องจากไม่มีการขัดแย้งกับหน้าอื่นๆ
ระบบจะเพิ่มรูปแบบส่วนกลางลงในแต่ละหน้า ดังนั้นจึงไม่จำเป็นต้องประกาศการตั้งค่าส่วนกลางซ้ำๆ เช่น font-family หรือ box-sizing
นอกจากนี้ยังเป็นที่ที่กำหนดตัวเลือกธีมและโหมดมืดด้วย
รายการด้านล่างแสดงกฎสำหรับหน้าการตั้งค่า ซึ่งจะจัดวางองค์ประกอบแบบฟอร์มต่างๆ ในตารางกริด
main {
max-width: 600px;
}
form {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 0.5rem;
margin-block-end: 1rem;
}
label {
text-align: end;
grid-column: 1 / 2;
}
input,
select {
grid-column: 2 / 3;
}
Wake Lock หน้าจอ
หน้าจอไม่ควรปิดระหว่างการออกกำลังกาย ในเบราว์เซอร์ที่รองรับ HIIT Time จะทำให้เป็นจริงได้ผ่าน Wake Lock หน้าจอ ข้อมูลโค้ดด้านล่างแสดงวิธีดำเนินการ
if ('wakeLock' in navigator) {
const requestWakeLock = async () => {
try {
page.shared.wakeLock = await navigator.wakeLock.request('screen');
page.shared.wakeLock.addEventListener('release', () => {
// Nothing.
});
} catch (err) {
console.error(`${err.name}, ${err.message}`);
}
};
// Request a screen wake lock…
await requestWakeLock();
// …and re-request it when the page becomes visible.
document.addEventListener('visibilitychange', async () => {
if (
page.shared.wakeLock !== null &&
document.visibilityState === 'visible'
) {
await requestWakeLock();
}
});
}
การทดสอบแอปพลิเคชัน
แอปพลิเคชัน HIIT Time พร้อมใช้งานใน GitHub คุณสามารถลองใช้เดโมในหน้าต่างใหม่ หรือใน iframe ที่ฝังไว้ด้านล่างนี้ ซึ่งจำลองอุปกรณ์เคลื่อนที่
คำขอบคุณ
บทความนี้ได้รับการตรวจสอบโดย Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent, และ Keith Gu.