การสร้างคอมโพเนนต์โทสต์

ภาพรวมพื้นฐานของวิธีสร้างคอมโพเนนต์โทสต์แบบปรับเปลี่ยนได้และเข้าถึงง่าย

ในโพสต์นี้ผมอยากจะแชร์วิธีคิดวิธีสร้างคอมโพเนนต์ข้อความโทสต์ ทดลองใช้ สาธิต

สาธิต

หากต้องการดูวิดีโอ โปรดใช้โพสต์นี้ในเวอร์ชัน YouTube

ภาพรวม

ข้อความโทสต์เป็นข้อความสั้นๆ แบบไม่โต้ตอบ แฝง และไม่พร้อมกันสำหรับผู้ใช้ โดยทั่วไปจะใช้เป็นรูปแบบความคิดเห็นเกี่ยวกับอินเทอร์เฟซสำหรับแจ้งให้ผู้ใช้ทราบ เกี่ยวกับผลลัพธ์ของการดำเนินการ

การโต้ตอบ

ข้อความโทสต์นั้นไม่เหมือนกับการแจ้งเตือน การแจ้งเตือนและ ข้อความแจ้งเนื่องจาก วิดีโอจะไม่เป็นแบบอินเทอร์แอกทีฟ ไม่จำเป็นต้องปิดหรือคงอยู่ตลอดไป การแจ้งเตือนมีไว้เพื่อข้อมูลสำคัญมากกว่า โดยเป็นการรับส่งข้อความพร้อมกันที่ ต้องมีการโต้ตอบหรือข้อความระดับระบบ (ตรงข้ามกับระดับหน้าเว็บ) ข้อความโทสต์เป็นแบบเชิงรับมากกว่ากลยุทธ์การแจ้งให้ทราบแบบอื่นๆ

Markup

<output> องค์ประกอบนี้เป็นตัวเลือกที่ดีสำหรับโทสต์ เพราะระบบจะประกาศให้สกรีน ผู้อ่าน HTML ที่ถูกต้องทำให้เราสามารถเพิ่มประสิทธิภาพด้วย JavaScript และ CSS และมี JavaScript จำนวนมาก

ขนมปังปิ้ง

<output class="gui-toast">Item added to cart</output>

ผลลัพธ์อาจมากกว่านี้ ไม่แบ่งแยก โดยเพิ่ม role="status" ซึ่งจะให้ สำรองถ้าเบราว์เซอร์ไม่ได้ให้องค์ประกอบ <output> โดยนัย บทบาท ตามข้อกำหนด

<output role="status" class="gui-toast">Item added to cart</output>

ภาชนะใส่ข้อความโทสต์

แสดงข้อความโทสต์ได้มากกว่า 1 รายการต่อครั้ง เพื่อจัดการเป็นกลุ่ม ข้อความโทสต์ ระบบจะใช้ภาชนะบรรจุ คอนเทนเนอร์นี้ยังจัดการตำแหน่งของ ข้อความโทสต์บนหน้าจอ

<section class="gui-toast-group">
  <output role="status">Wizard Rose added to cart</output>
  <output role="status">Self Watering Pot added to cart</output>
</section>

เลย์เอาต์

ผมเลือกปักหมุดข้อความโทสต์ inset-block-end ของวิวพอร์ต และหากมีการเพิ่มข้อความโทสต์ ข้อความจะซ้อนมาจากขอบหน้าจอนั้น

คอนเทนเนอร์ GUI

คอนเทนเนอร์โทสต์ทำงานเลย์เอาต์ทุกอย่างสำหรับการนำเสนอข้อความโทสต์ ตอนนี้ fixed ไปยังวิวพอร์ตและใช้พร็อพเพอร์ตี้เชิงตรรกะ inset เพื่อระบุ เพื่อตรึงไว้ และอีกเล็กน้อย padding จากขอบ block-end เดียวกัน

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

ภาพหน้าจอแสดงขนาดกล่องเครื่องมือสำหรับนักพัฒนาเว็บและระยะห่างจากขอบที่วางซ้อนบนองค์ประกอบ .gui-toast-container

นอกจากการวางตำแหน่งตัวเองภายในวิวพอร์ตแล้ว คอนเทนเนอร์โทสต์ยังเป็น ภาชนะตารางกริดที่สามารถจัดเรียงและแจกจ่ายข้อความโทสต์ รายการอยู่ตรงกลางเป็น กลุ่มที่มี justify-content และอยู่ตรงกลางแยกกันด้วย justify-items โรย gap ลงไปทีละน้อยเพื่อไม่ให้ขนมปังปิ้ง

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

ภาพหน้าจอที่มีเส้นตาราง CSS วางซ้อนบนกลุ่มข้อความโทสต์ คราวนี้
การไฮไลต์ช่องว่างและช่องว่างระหว่างองค์ประกอบย่อยที่โทสต์

ข้อความโทสต์ GUI

ขนมปังปิ้งแต่ละชิ้นมีpadding รวมไปถึงมุมที่นุ่มนวลกว่า border-radius, และฟังก์ชัน min() เพื่อ ช่วยเรื่องการปรับขนาดในอุปกรณ์เคลื่อนที่และเดสก์ท็อป ขนาดที่ปรับเปลี่ยนตามอุปกรณ์ใน CSS ต่อไปนี้ ป้องกันไม่ให้ข้อความโทสต์ขยายกว้างกว่า 90% ของวิวพอร์ต 25ch

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

ภาพหน้าจอขององค์ประกอบ .gui-toast รายการเดียวพร้อมระยะห่างจากขอบและเส้นขอบ
แสดงรัศมีแล้ว

รูปแบบ

เมื่อมีการตั้งค่าเลย์เอาต์และการวางตำแหน่ง ให้เพิ่ม CSS ที่ช่วยปรับให้เข้ากับผู้ใช้ การตั้งค่าและการโต้ตอบ

ภาชนะใส่ข้อความโทสต์

ข้อความโทสต์จะไม่เป็นแบบโต้ตอบ การแตะหรือปัดบนข้อความจะไม่ส่งผลใดๆ แต่ จะใช้เหตุการณ์ตัวชี้อยู่ ป้องกันไม่ให้ข้อความโทสต์ขโมย คลิกที่มี CSS ต่อไปนี้

.gui-toast-group {
  pointer-events: none;
}

ข้อความโทสต์ GUI

ปรับธีมโทสต์ให้เหมาะกับสีอ่อนหรือสีเข้มพร้อมคุณสมบัติที่กำหนดเอง รวมถึง HSL และ คำค้นหาสื่อค่ากำหนด

.gui-toast {
  --_bg-lightness: 90%;

  color: black;
  background: hsl(0 0% var(--_bg-lightness) / 90%);
}

@media (prefers-color-scheme: dark) {
  .gui-toast {
    color: white;
    --_bg-lightness: 20%;
  }
}

แอนิเมชัน

ข้อความโทสต์ใหม่ควรแสดงตัวเองด้วยภาพเคลื่อนไหวขณะที่ข้อความโทสต์เข้าสู่หน้าจอ รองรับการเคลื่อนไหวที่ลดลงโดยกำหนดค่า translate เป็น 0 ภายใน แต่อัปเดตค่าการเคลื่อนไหวที่มีความยาวในสื่อค่ากำหนดการเคลื่อนไหว การค้นหา ทุกคนจะได้รับภาพเคลื่อนไหวบ้าง แต่มีเพียงผู้ใช้บางรายเท่านั้นที่ได้ยินเสียงโทสต์ ระยะทางหนึ่ง

นี่คือคีย์เฟรมที่ใช้สำหรับภาพเคลื่อนไหวที่แสดงข้อความโทสต์ CSS จะควบคุม การเข้าชม การรอ และการออกจากข้อความโทสต์ ทั้งหมดนี้รวมอยู่ในภาพเคลื่อนไหวเดียว

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

จากนั้นองค์ประกอบข้อความโทสต์จะตั้งค่าตัวแปรและจัดการคีย์เฟรมเป็นกลุ่ม

.gui-toast {
  --_duration: 3s;
  --_travel-distance: 0;

  will-change: transform;
  animation: 
    fade-in .3s ease,
    slide-in .3s ease,
    fade-out .3s ease var(--_duration);
}

@media (prefers-reduced-motion: no-preference) {
  .gui-toast {
    --_travel-distance: 5vh;
  }
}

JavaScript

เมื่อรูปแบบและโปรแกรมอ่านหน้าจอพร้อมใช้งาน HTML แล้ว ระบบจึงจำเป็นต้องใช้ JavaScript เพื่อ จัดการการสร้าง การเพิ่ม และการทำลายโทสต์ตามผู้ใช้ กิจกรรม ประสบการณ์ของนักพัฒนาซอฟต์แวร์คอมโพเนนต์ข้อความโทสต์ควรมีประสบการณ์น้อยที่สุดและ เริ่มต้นใช้งานได้ง่ายๆ ดังนี้

import Toast from './toast.js'

Toast('My first toast')

การสร้างกลุ่มข้อความโทสต์และขนมปังปิ้ง

เมื่อโมดูลข้อความโทสต์โหลดจาก JavaScript ก็จะต้องสร้างคอนเทนเนอร์โทสต์ แล้วเพิ่มลงในหน้าเว็บ ฉันเลือกเพิ่มองค์ประกอบก่อน body ซึ่งจะทำให้ อาจเกิดปัญหาการซ้อน z-index รายการเนื่องจากคอนเทนเนอร์อยู่เหนือคอนเทนเนอร์สำหรับ ทุกองค์ประกอบของร่างกาย

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

ภาพหน้าจอของกลุ่มข้อความโทสต์ระหว่างแท็กส่วนหัวกับแท็กเนื้อหา

จะมีการเรียกฟังก์ชัน init() แบบภายในไปยังโมดูลนี้ โดยซ่อนองค์ประกอบไว้ ในฐานะ Toaster:

const Toaster = init()

การสร้างเอลิเมนต์ HTML โทสต์นั้นทำได้ด้วยฟังก์ชัน createToast() ฟังก์ชันต้องใช้ข้อความสำหรับโทสต์ สร้างองค์ประกอบ <output> โฆษณา พร้อมด้วยคลาสและแอตทริบิวต์บางอย่าง ตั้งค่าข้อความ และแสดงผลโหนด

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

การจัดการข้อความโทสต์อย่างน้อย 1 รายการ

ตอนนี้ JavaScript จะเพิ่มคอนเทนเนอร์ลงในเอกสาร เพื่อให้มีข้อความโทสต์และ พร้อมที่จะเพิ่มข้อความโทสต์ที่สร้างขึ้นแล้ว ฟังก์ชัน addToast() จัดการ 1 หรือขนมปังปิ้งหลายชิ้น ก่อนอื่น การตรวจสอบจำนวนข้อความโทสต์และดูว่าการเคลื่อนไหวเหมาะสมหรือไม่ แล้วใช้ข้อมูลนี้เพื่อนำไปต่อท้ายข้อความโทสต์ หรือแต่งให้ดูดี ภาพเคลื่อนไหวเพื่อให้ข้อความโทสต์อื่นๆ ปรากฏขึ้นเพื่อ "เพิ่มพื้นที่ว่าง" สำหรับขนมปังปิ้งใหม่

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

เมื่อเพิ่มข้อความโทสต์รายการแรก Toaster.appendChild(toast) จะเพิ่มข้อความโทสต์ลงใน หน้าเรียกภาพเคลื่อนไหว CSS: เคลื่อนไหวเข้า รอ 3s เคลื่อนไหว จะมีการเรียก flipToast() เมื่อมีข้อความโทสต์อยู่แล้ว ซึ่งใช้เทคนิค ที่ชื่อ FLIP โดย Paul Lewis แนวคิดก็คือ การคำนวณผลต่าง ในตำแหน่งต่างๆ ของคอนเทนเนอร์ ก่อนและหลังเพิ่มโทสต์ใหม่ เปรียบได้กับการทำเครื่องหมายตำแหน่งของ Toaster ในปัจจุบัน ตำแหน่งของมัน จากนั้น ภาพเคลื่อนไหวจากจุดหนึ่งไปยังอีกจุดหนึ่ง

const flipToast = toast => {
  // FIRST
  const first = Toaster.offsetHeight

  // add new child to change container size
  Toaster.appendChild(toast)

  // LAST
  const last = Toaster.offsetHeight

  // INVERT
  const invert = last - first

  // PLAY
  const animation = Toaster.animate([
    { transform: `translateY(${invert}px)` },
    { transform: 'translateY(0)' }
  ], {
    duration: 150,
    easing: 'ease-out',
  })
}

ตารางกริด CSS จะยกเลย์เอาต์ เมื่อมีการเพิ่มข้อความโทสต์ใหม่ ตารางกริดจะวางข้อความ ไว้ตอนต้นและเว้นระยะเวลากับคนอื่นๆ ในขณะเดียวกัน เว็บ ภาพเคลื่อนไหวคือ ที่ใช้เพื่อทำให้คอนเทนเนอร์เคลื่อนไหวจากตำแหน่งเดิม

กำลังรวม JavaScript ทั้งหมดเข้าด้วยกัน

เมื่อมีการเรียก Toast('my first toast') ระบบจะสร้างข้อความโทสต์และเพิ่มไปยังหน้าเว็บ (หรือแม้แต่ให้คอนเทนเนอร์เคลื่อนไหวเพื่อรองรับข้อความโทสต์ใหม่) สัญญา และแสดงโทสต์ที่สร้างขึ้น ดูสำหรับ ภาพเคลื่อนไหว CSS ที่เสร็จสมบูรณ์ (ภาพเคลื่อนไหว 3 คีย์เฟรม) สำหรับการแก้ปัญหาตามที่สัญญาไว้

const Toast = text => {
  let toast = createToast(text)
  addToast(toast)

  return new Promise(async (resolve, reject) => {
    await Promise.allSettled(
      toast.getAnimations().map(animation => 
        animation.finished
      )
    )
    Toaster.removeChild(toast)
    resolve() 
  })
}

ฉันคิดว่าส่วนที่สับสนของโค้ดนี้อยู่ในฟังก์ชัน Promise.allSettled() และ toast.getAnimations() เนื่องจากฉันใช้ภาพเคลื่อนไหวของคีย์เฟรมหลายรายการ สำหรับขนมปังปิ้ง การที่จะรู้ว่าทั้งหมดจบแล้ว ทุกคนจะต้อง จาก JavaScript และ finished คำสัญญาที่สัญญาไว้ว่าจะบรรลุผลสำเร็จ allSettled วิธีนี้ได้ผลสำหรับเราหรือไม่ ทำให้ระบบเสร็จสมบูรณ์เมื่อทำตามคำสัญญาทั้งหมด ได้รับการดำเนินการแล้ว การใช้ await Promise.allSettled() หมายถึงบรรทัดถัดไปของ โค้ดสามารถนำองค์ประกอบออกได้อย่างมั่นใจและถือว่าข้อความโทสต์เสร็จสมบูรณ์แล้ว ใหม่ และสุดท้าย การโทรหา resolve() จะให้ผลลัพธ์ตามที่สัญญาไว้สูงสุด นักพัฒนาซอฟต์แวร์สามารถล้างหรือดำเนินการอื่นๆ เมื่อข้อความโทสต์แสดงขึ้นมา

export default Toast

สุดท้าย ฟังก์ชัน Toast จะถูกส่งออกจากโมดูล สำหรับสคริปต์อื่นๆ เพื่อ นำเข้าและใช้งาน

การใช้คอมโพเนนต์ข้อความโทสต์

การใช้ข้อความโทสต์หรือประสบการณ์ของนักพัฒนาซอฟต์แวร์ข้อความโทสต์นั้นทำได้โดยการนำเข้าลิงก์ Toast และเรียกใช้ด้วยสตริงข้อความ

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

ถ้านักพัฒนาซอฟต์แวร์ต้องการทำความสะอาด หรืออะไรก็ตาม หลังจากที่ข้อความโทสต์ คุณสามารถใช้อะซิงโครนัส และ รออยู่

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

บทสรุป

ตอนนี้คุณก็รู้แล้วว่าฉันทำท่านั้นได้อย่างไร คุณจะทำยังไงบ้างคะ‽ 🙂

มาเพิ่มความหลากหลายให้กับแนวทางของเราและเรียนรู้วิธีทั้งหมดในการสร้างเนื้อหาบนเว็บกัน สร้างลิงก์สาธิต ทวีตฉัน แล้วฉันจะเพิ่มให้เอง ที่ส่วนรีมิกซ์ของชุมชนด้านล่างนี้ได้เลย

รีมิกซ์ในชุมชน