Now.js Framework Documentation

Now.js Framework Documentation

ImageGallery

TH 05 Apr 2026 10:11

ImageGallery

ภาพรวม

ImageGallery คือ component แสดงภาพแบบ inline ใน Now.js Framework แสดงภาพหลัก (hero) พร้อม thumbnail strip ด้านล่าง และเปิด fullscreen lightbox ผ่าน MediaViewer เมื่อผู้ใช้กดที่ภาพ

ใช้เมื่อ:

  • แสดงภาพสินค้า หรือชิ้นส่วนภายใน card หรือ modal
  • แสดงชุดภาพในฟอร์ม หรือ loop ของ TemplateManager (data-for)
  • ทุกที่ที่ต้องการให้ดูภาพหลายรูปได้โดยไม่ต้องออกจากหน้า

ทำไมต้องใช้:

  • ✅ Declarative เต็มรูปแบบ — เขียนแค่ HTML ไม่ต้องเขียน JS เพิ่ม
  • ✅ Auto-init ผ่าน ComponentManager (ทำงานใน template, modal, content ที่โหลดจาก API)
  • ✅ เลือก effect ได้ (fade, slide, none)
  • ✅ เลือกตำแหน่ง thumbnail ได้ (bottom, left, right, top)
  • ✅ Fullscreen zoom ผ่าน MediaViewer (swipe, pinch, keyboard)
  • ✅ รองรับ REST API (data-api)
  • ✅ Touch swipe เพื่อเปลี่ยนรูป
  • ✅ Keyboard navigation (← / →)
  • ✅ Responsive ด้วย container queries
  • ✅ Accessible (ARIA labels, focus management)

การใช้งานพื้นฐาน

HTML Declarative

<div data-component="image-gallery">
  <img src="/images/photo1.jpg" alt="ด้านหน้า" data-caption="ด้านหน้า">
  <img src="/images/photo2.jpg" alt="ด้านข้าง" data-caption="ด้านข้าง">
</div>

รูปเต็ม vs รูปย่อ (thumbnail)

ใช้ data-src สำหรับรูปขนาดเต็ม ส่วน src ใช้แสดงเป็น thumbnail
ถ้าไม่ระบุ data-src จะใช้ src ทั้งสองอย่าง

<div data-component="image-gallery">
  <img src="/thumbs/photo1_sm.jpg" data-src="/images/photo1.jpg" alt="ภาพ 1" data-caption="ภาพ 1">
  <img src="/thumbs/photo2_sm.jpg" data-src="/images/photo2.jpg" alt="ภาพ 2">
</div>

Transition effect

<!-- Fade (ค่าเริ่มต้น) -->
<div data-component="image-gallery" data-effect="fade">...</div>

<!-- Slide -->
<div data-component="image-gallery" data-effect="slide">...</div>

<!-- ไม่มี animation -->
<div data-component="image-gallery" data-effect="none">...</div>

Aspect ratio

<!-- สี่เหลี่ยมจัตุรัส (1:1) -->
<div data-component="image-gallery" data-aspect="square">...</div>

<!-- กว้าง (16:9) -->
<div data-component="image-gallery" data-aspect="wide">...</div>

<!-- สูง (3:4) -->
<div data-component="image-gallery" data-aspect="tall">...</div>

<!-- อัตโนมัติตามภาพจริง — ค่าเริ่มต้น -->
<div data-component="image-gallery" data-aspect="auto">...</div>

ตำแหน่ง thumbnail

<!-- ด้านล่าง (ค่าเริ่มต้น) -->
<div data-component="image-gallery" data-thumbnails-position="bottom">...</div>

<!-- ด้านซ้าย -->
<div data-component="image-gallery" data-thumbnails-position="left">...</div>

<!-- ด้านขวา -->
<div data-component="image-gallery" data-thumbnails-position="right">...</div>

<!-- ด้านบน -->
<div data-component="image-gallery" data-thumbnails-position="top">...</div>

ซ่อน thumbnail

Thumbnail จะแสดงอัตโนมัติเมื่อมีภาพ 2 รูปขึ้นไป
ใช้ data-show-thumbnails="false" เพื่อซ่อนเสมอ

<div data-component="image-gallery" data-show-thumbnails="false">
  <img src="/images/hero.jpg" alt="ภาพหลัก">
</div>

ปิด fullscreen zoom

<div data-component="image-gallery" data-enable-zoom="false">...</div>

โหลดภาพจาก REST API

โหลดรายการภาพจาก API endpoint component จะแสดง loading indicator ระหว่างดึงข้อมูล

<div data-component="image-gallery" data-api="api/parts/images?id=5"></div>
<!-- POST endpoint -->
<div data-component="image-gallery"
     data-api="api/products/gallery"
     data-api-method="POST">
</div>

รูปแบบ response ที่รองรับ

API สามารถตอบกลับได้หลายรูปแบบ:

["url1.jpg", "url2.jpg"]
[
  { "url": "photo1.jpg", "alt": "ด้านหน้า", "caption": "ด้านหน้า" },
  { "url": "photo2.jpg", "thumb": "photo2_sm.jpg", "alt": "ด้านข้าง" }
]
{ "data": [ ... ] }
{ "items": [ ... ] }

Field ที่รองรับ: url / src / path, thumb / thumbnail, alt, caption / title

ใช้กับ TemplateManager

ทำงานภายใน loop data-for ได้ ComponentManager จะ auto-init แต่ละ gallery หลังจาก TemplateManager render เสร็จ

ภาพเดียวต่อ card

<div data-for="item in results">
  <div class="product-card">
    <div data-component="image-gallery" data-aspect="square" data-show-thumbnails="false">
      <img data-attr="src:item.image;alt:item.name" data-if="item.image" loading="lazy">
    </div>
    <div data-text="item.name"></div>
  </div>
</div>

หลายภาพต่อ item

เมื่อ API ส่ง item.images[] ใช้ data-for บน <img> โดยตรง:

<div data-component="image-gallery" data-effect="fade">
  <img data-for="img in item.images"
       data-attr="src:img.url;alt:img.alt"
       data-attr-extra="data-caption:img.caption"
       loading="lazy">
</div>

เมื่อเซิร์ฟเวอร์ส่ง HTML ที่มี data-component="image-gallery" กลับมาผ่าน action.html,
Modal.setContent() จะ inject HTML เข้า DOM และ CoreObserver จะ trigger
ComponentManager อัตโนมัติ — ไม่ต้องเขียน JS เพิ่ม

PHP (Kotchasan controller)

// สร้าง HTML จาก images array ที่ได้จาก model
$imgTags = '';
foreach ($part->images as $i => $img) {
    $url = htmlspecialchars($img['url']);
    $imgTags .= '<img src="'.$url.'" data-src="'.$url.'" alt="'.htmlspecialchars($part->name).'">';
}

$html = '<div data-component="image-gallery" data-effect="fade" '
      . 'data-aspect="auto" data-thumbnails-position="bottom" '
      . 'data-show-thumbnails="true" data-enable-zoom="true">'
      . $imgTags
      . '</div>';

// ส่งกลับเป็น modal action
$this->sendSuccess(['html' => $html, ...]);

Programmatic API

ใช้ ImageGallery.create() เมื่อต้องสร้าง gallery จาก JavaScript ล้วนๆ

const gallery = ImageGallery.create(element, {
  images: [
    { url: '/images/photo1.jpg', thumb: '/thumbs/photo1.jpg', alt: 'ภาพ 1', caption: 'ภาพ 1' },
    { url: '/images/photo2.jpg', alt: 'ภาพ 2' }
  ],
  effect: 'slide',
  aspect: 'wide',
  thumbnailsPosition: 'bottom',
  enableZoom: true
});

// ไปยังภาพที่ต้องการ
gallery.goTo(1);

// เปลี่ยนชุดภาพทั้งหมด
gallery.update(newImages);

// ลบ gallery และ cleanup event
gallery.destroy();

Data Attributes อ้างอิง

Attribute ค่าที่รองรับ ค่าเริ่มต้น คำอธิบาย
data-effect fade | slide | none fade Effect ตอนเปลี่ยนภาพ
data-aspect square | wide | tall | auto auto Aspect ratio ของ hero
data-show-thumbnails true | false true แสดง thumbnail strip (ซ่อนอัตโนมัติเมื่อมีภาพ ≤ 1 รูป)
data-thumbnails-position bottom | left | right | top bottom ตำแหน่ง thumbnail strip
data-enable-zoom true | false true เปิด fullscreen zoom ผ่าน MediaViewer
data-empty-icon CSS icon class icon-picture Icon แสดงเมื่อไม่มีภาพ
data-api URL REST API endpoint สำหรับโหลดภาพ
data-api-method GET | POST GET HTTP method สำหรับเรียก API

<img> Attributes อ้างอิง

Attribute คำอธิบาย
src URL รูป thumbnail (แสดงใน thumbnail strip)
data-src URL รูปขนาดเต็ม (ใช้ใน fullscreen viewer) ถ้าไม่ระบุจะใช้ src แทน
alt Alt text สำหรับ accessibility
data-caption คำอธิบายที่แสดงใต้ภาพหลัก ถ้าไม่ระบุจะใช้ alt แทน

Programmatic API อ้างอิง

ImageGallery.create(element, options)

สร้าง gallery บน element ด้วย JavaScript

Parameter Type คำอธิบาย
element HTMLElement Element ที่ต้องการใช้เป็น container
options.images Array Array ของ image objects
options.effect string fade | slide | none
options.aspect string square | wide | tall | auto
options.showThumbnails boolean แสดง thumbnail strip
options.thumbnailsPosition string bottom | left | right | top
options.enableZoom boolean เปิด fullscreen viewer
options.emptyIcon string CSS class สำหรับ icon ตอนไม่มีภาพ

คืนค่า object ที่มี:

Method คำอธิบาย
goTo(index) ไปยังภาพที่ index ที่ระบุ
update(newItems) เปลี่ยนชุดภาพทั้งหมดและ rebuild
destroy() ลบ event listeners และ cleanup

Keyboard & Touch Controls

การควบคุม การทำงาน
/ ภาพก่อนหน้า / ถัดไป (เมื่อ gallery หรือ child มี focus)
คลิก / แตะภาพ เปิด fullscreen MediaViewer
ปุ่ม zoom (hover) เปิด fullscreen MediaViewer
Swipe ซ้าย / ขวา ภาพถัดไป / ก่อนหน้า

CSS Classes อ้างอิง

Class คำอธิบาย
.ig Root element
.ig--fade / .ig--slide / .ig--none Effect modifier ที่ active อยู่
.ig--square / .ig--wide / .ig--tall / .ig--auto Aspect ratio modifier
.ig--bottom / .ig--left / .ig--right / .ig--top ตำแหน่ง thumbnail ที่ active อยู่
.ig-hero Container ของภาพหลัก
.ig-main-img <img> ที่กำลังแสดงอยู่
.ig-zoom-btn ปุ่ม fullscreen zoom (แสดงเมื่อ hover)
.ig-caption ข้อความคำอธิบายใต้ภาพหลัก
.ig-thumbs Container ของ thumbnail strip
.ig-thumb ปุ่ม thumbnail แต่ละรูป
.ig-thumb.is-active Thumbnail ของภาพที่กำลังดูอยู่
.ig-empty Modifier เมื่อไม่มีภาพ
.ig-loading Modifier ระหว่างโหลดจาก API

การทำงานร่วมกับ MediaViewer

เมื่อ data-enable-zoom="true" (ค่าเริ่มต้น) การคลิกที่ hero หรือปุ่ม zoom จะเรียก
MediaViewer.show() โดยส่งภาพทั้งหมดเริ่มจาก index ที่กำลังดูอยู่
MediaViewer จะให้ฟีเจอร์ zoom, pan, keyboard, touch และ autoplay สำหรับมุมมอง fullscreen

MediaViewer ถูกโหลดอัตโนมัติเป็นส่วนหนึ่งของ core bundle

ดูเพิ่มเติม