เพิ่มการเชื่อมโยงลิงค์ในหน้าเว็บด้วย Stimulus

ลิงค์ Anchor เป็นอีกวิธีการหนึ่งที่จะทำให้เราสามารเข้าถึงเนื้อหาภายในหน้าเว็บได้ง่ายขึ้น ผ่านการปักสมอหรือหมุดไม่ว่าจะด้วยชื่อหรือไอดีไว้บน Heading ต่างๆ สำหรับบล๊อกนี้สร้างขึ้นด้วย Jekyll ซึ่งเนื้อหาจะถูกสร้างขึ้นจาก Markdown เป็น HTML แต่ Markdown เองก็ไม่ได้ Syntax ที่รองรับให้มีลิงค์ Anchor ด้วย ดังนั้นเราจะมาเพิ่มเติม Anchor ให้เว็บของเราด้วย Stimulus กัน

// javascripts/controllers/anchor_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static headings = [ "h1", "h2", "h3", "h4", "h5", "h6" ]
  static values = { idEnabled: Boolean }
  static classes = [ "anchorLink" ]

  connect () {
    const headings = document.querySelectorAll(this.constructor.headings.join(","))
    const anchorLinkClass = this.hasAnchorLinkClass ? this.anchorLinkClass : "anchor-link"
    headings.forEach(heading => {
      const id = this.slugify(heading.innerHTML)
      if (this.idEnabledValue) { heading.id = id }
      heading.innerHTML = `<a href="#${id}" class="${anchorLinkClass}">${heading.innerText}<\/a>`
    })

    document.addEventListener("turbo:click", (event) => {
      if (event.detail.url.includes("#")) {
        return event.preventDefault()
      }
    })
  }

  slugify (text) {
    return text.replace(/^\s+|\s+$/g, '')
        .replace(/\s+/g, '-')
        .replace(/-+/g, '-')
        .toLowerCase()
  }
}

โค้ดข้างต้นเราจะทำการค้นหา Heading ที่เราต้องการจะใส่ลิงค์ Anchor เข้าไปโดยไล่ตั้งแต่ <h1/> ไปถึง <h6/> จากนั้นเราก็ยัด <a/> ที่มี href เชื่อมโยงกับ Heading นั้นๆ ไว้ภายใน

ในกรณีที่มีการใช้งานร่วมกัน Turbo เราจะต้องเพิ่มการรับฟังเหตุการณ์จาก turbo:click ไว้ด้วย โดยถ้า URL ที่คลิกมีเครื่องหมาย # เราจะต้องหยุดไม่ให้โค้ดทำงานต่อ เพราะจะทำให้ลิงค์ที่กดไม่เชื่อมโยงไปยัง Anchor ที่เรากำหนดไว้

เอาจริงตอนแรกได้ทดลองใช้ anchor-js แล้วรู้สึกว่าใช้งานง่ายมาก แต่ตอนปรับแก้ CSS แล้วมันยากนิดหน่อยก็เลยเลือกที่จะเขียนโค้ดที่จัดการทุกอย่างเอง สำหรับตัวอย่างการใช้งานโค้ดก็ดูได้ในเว็บของเราได้ เพราะได้ทำการ deploy เอาไว้แล้ว

References