Now.js Framework Documentation
AppConfigManager
AppConfigManager
ภาพรวม
AppConfigManager คือระบบจัดการธีมและ configuration ใน Now.js Framework ดูแลเรื่องต่อไปนี้
- สลับธีม — โหมด light/dark พร้อมตรวจค่าที่ระบบปฏิบัติการตั้งไว้
- จัดการ CSS Variables — โหลด CSS custom properties จาก backend มาใช้
- ผูกข้อมูลกับ Template — ส่ง payload ทั้งก้อนจาก API ให้ TemplateManager (แบบเดียวกับ ApiComponent)
- ความปลอดภัย — ล้างค่า CSS ก่อนใช้ เพื่อกัน XSS
- เสริมปุ่มอัตโนมัติ — ปุ่มที่มี
data-component="config"กลายเป็นปุ่มสลับธีมเอง - เปลี่ยนธีมแบบลื่น — กัน FOUC (Flash of Unstyled Content) ด้วยการ fade
ใช้เมื่อ:
- ต้องการจัดการธีมจากที่เดียวทั้งแอป
- ต้องการโหลด CSS variables จาก backend แบบ dynamic
- ต้องการผูก configuration เข้ากับ template โดยไม่ต้องเขียน JS
- ต้องการให้การเปลี่ยนธีมลื่นไม่กะพริบ
สิ่งที่ต้องมี
- Now.js Framework core
- เบราว์เซอร์ที่รองรับ ES6+
- ไม่บังคับ: EventManager (สำหรับส่ง event)
- ไม่บังคับ: TemplateManager (สำหรับผูกข้อมูล)
- ไม่บังคับ: HttpClient (สำหรับเรียก API)
การใช้งานพื้นฐาน
เริ่มต้นใช้งาน
// Initialize with Now framework
await Now.init({
config: {
enabled: true,
defaultTheme: 'light',
storageKey: 'app_theme',
systemPreference: true,
api: {
enabled: true,
configUrl: '/api/index/config/frontend-settings',
cacheResponse: true
}
}
});ลำดับที่เกิดขึ้น:
- AppConfigManager อ่านธีมที่เก็บไว้จาก localStorage
- ถ้ายังไม่มีค่าที่เก็บไว้ ใช้ค่าที่ระบบปฏิบัติการตั้งไว้แทน
- ใส่ธีมให้
document.documentElement - โหลด configuration จาก API (ถ้าเปิดไว้)
- ใส่ CSS variables
- ประมวลผลการผูกข้อมูลกับ template
- ทำเครื่องหมายว่าหน้าพร้อมแล้ว (เอาสถานะ loading ออก)
เริ่มต้นเอง
// If not using Now framework
await AppConfigManager.init({
enabled: true,
defaultTheme: 'dark',
api: {
enabled: true,
configUrl: '/api/config'
}
});รูปแบบ Response ของ API
ฝั่ง backend ควรคืน JSON ตามโครงสร้างนี้
{
"variables": {
"--color-primary": "#29336b",
"--color-secondary": "#6366f1",
"--logo-url": "/images/logo.png",
"--hero-bg": "/images/hero.jpg"
},
"web_title": "My Website",
"web_description": "Website description",
"company": {
"name": "Company Name",
"phone": "+1-234-567-8900",
"email": "info@example.com",
"address": "123 Main St"
},
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
}คำอธิบายฟิลด์:
variables(object, ไม่บังคับ) — CSS custom properties ที่จะนำไปใช้- คีย์อื่นทั้งหมด — ใช้ได้ใน context ของ template สำหรับผูกข้อมูล
หมายเหตุ: โครงสร้าง response ยืดหยุ่นได้ AppConfigManager จะส่งข้อมูลทั้งหมดต่อให้ TemplateManager ทำให้ template เข้าถึงคีย์ใดก็ได้ที่ backend ส่งมา
ความสามารถหลัก
1. จัดการธีม
สลับธีม
// Toggle between light and dark
AppConfigManager.toggle();
// Set specific theme
await AppConfigManager.setTheme('dark');
// Get current theme
const theme = AppConfigManager.getCurrentTheme();
console.log(theme); // 'light' or 'dark'การจดจำธีม
ธีมถูกบันทึกลง localStorage อัตโนมัติ
// Stored with key from config.storageKey (default: 'app_theme')
// Retrieved automatically on next page loadตรวจค่าที่ระบบตั้งไว้
// Enable in config
await Now.init({
config: {
systemPreference: true // Detect prefers-color-scheme
}
});
// AppConfigManager will:
// 1. Check localStorage first
// 2. If no stored theme, use system preference
// 3. Listen for system preference changes2. CSS Variables
ใส่ค่าตัวแปร
// Apply single variable
AppConfigManager.applyVariables({
'--color-primary': '#6366f1'
});
// Apply multiple variables
AppConfigManager.applyVariables({
'--color-primary': '#6366f1',
'--color-secondary': '#8b5cf6',
'--font-size-base': '16px',
'--spacing-unit': '8px'
});
// Apply image URLs (auto-wrapped with url())
AppConfigManager.applyVariables({
'--logo-url': '/images/logo.png',
'--hero-bg': './images/hero.jpg'
});ผลลัพธ์:
:root {
--color-primary: #6366f1;
--color-secondary: #8b5cf6;
--logo-url: url('/images/logo.png');
--hero-bg: url('./images/hero.jpg');
}ล้างค่าตัวแปร
// Remove all applied variables
AppConfigManager.clearVariables();อ่านค่าตัวแปรที่ใส่ไว้
// Get object of currently applied variables
const vars = AppConfigManager.getAppliedVariables();
console.log(vars);
// { '--color-primary': '#6366f1', ... }3. ผูกข้อมูลกับ Template
AppConfigManager ส่ง response ทั้งก้อนจาก API ต่อให้ TemplateManager ทำให้ template เข้าถึงข้อมูลจาก backend ได้
<!-- Header with dynamic data -->
<header>
<h1 data-text="web_title"></h1>
<p data-text="web_description"></p>
</header>
<!-- Footer with company info -->
<footer>
<div data-text="company.name"></div>
<a data-attr="href:'tel:' + company.phone" data-text="company.phone"></a>
<a data-attr="href:'mailto:' + company.email" data-text="company.email"></a>
</footer>
<!-- Conditional rendering based on user -->
<nav>
<li data-if="user === null">
<a href="/login">Login</a>
</li>
<li data-if="user !== null">
<a href="/profile" data-text="user.name"></a>
</li>
</nav>ทำงานอย่างไร:
- AppConfigManager โหลด config จาก API
- สร้าง context เป็น
{ state: config, data: config, computed: {} } - เรียก
TemplateManager.processDataDirectives(container, context) - Template เข้าถึงข้อมูลด้วยจุด เช่น
company.name
4. เสริมปุ่มสลับธีมอัตโนมัติ
HTML
<!-- Automatically enhanced -->
<button data-component="config">🌓 Toggle Theme</button>
<!-- Multiple toggles sync automatically -->
<button data-component="config" class="nav-toggle">Theme</button>
<button data-component="config" class="footer-toggle">🌙</button>ลำดับที่เกิดขึ้น:
- ComponentManager เรียก
AppConfigManager.enhance(element) - ผูก click handler ให้สลับธีม
- เพิ่ม attribute
data-theme-stateเช่นdata-theme-state="light" - ปุ่มสลับธีมทุกตัวอัปเดตพร้อมกันเมื่อธีมเปลี่ยน
CSS สำหรับปุ่มสลับธีม
/* Style based on current theme */
[data-component="config"][data-theme-state="light"]::before {
content: "🌙"; /* Show moon in light mode */
}
[data-component="config"][data-theme-state="dark"]::before {
content: "☀️"; /* Show sun in dark mode */
}
/* With icon fonts */
[data-component="config"]::before {
font-family: 'icomoon' !important;
}
[data-component="config"][data-theme-state="light"]::before {
content: "\e929"; /* icon-moon */
}
[data-component="config"][data-theme-state="dark"]::before {
content: "\e9d4"; /* icon-sun */
}5. เปลี่ยนธีมแบบลื่น (กัน FOUC)
CSS ที่ต้องมี
body {
opacity: 0;
transition: opacity 0.3s ease;
}
body.theme-ready {
opacity: 1;
}
body.theme-transitioning {
opacity: 0;
}
body.theme-loading {
opacity: 0;
}ทำงานอย่างไร:
- หน้าเว็บโหลดมาพร้อม
body { opacity: 0 } - AppConfigManager เริ่มทำงานและโหลดธีม
- เพิ่มคลาส
theme-readyแล้วหน้าค่อย ๆ ปรากฏ - เมื่อสลับธีม
- เพิ่มคลาส
theme-transitioningแล้วจางหาย - ใส่ธีมใหม่
- เพิ่มคลาส
theme-readyแล้วจางกลับมา
- เพิ่มคลาส
ตั้งค่าการเปลี่ยนผ่าน
await Now.init({
config: {
transition: {
enabled: true,
duration: 300, // Transition duration (ms)
hideOnSwitch: true, // Fade out during switch
loadingClass: 'theme-loading',
readyClass: 'theme-ready',
transitionClass: 'theme-transitioning'
}
}
});ตัวอย่างขั้นสูง
ตัวอย่างที่ 1: เชื่อมต่อ API ของตัวเอง
// Custom endpoint with headers
await AppConfigManager.init({
enabled: true,
api: {
enabled: true,
configUrl: '/api/v2/config',
headers: {
'X-API-Key': 'your-api-key',
'Accept': 'application/json'
},
timeout: 10000,
cacheResponse: true
}
});
// Manual load with custom URL
try {
const config = await AppConfigManager.loadFromAPI('/api/custom-config');
console.log('Loaded:', config);
} catch (error) {
console.error('Failed to load config:', error);
}
// Refresh (clears cache)
const freshConfig = await AppConfigManager.refreshFromAPI();ตัวอย่างที่ 2: ควบคุมธีมจากโค้ด
// Listen for theme changes
EventManager.on('theme:changed', ({ theme }) => {
console.log('Theme changed to:', theme);
// Update analytics
gtag('event', 'theme_change', { theme });
// Update external service
updateThemePreference(theme);
});
// Set theme based on user action
async function applyUserTheme(userPreference) {
if (userPreference === 'system') {
// Use system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
await AppConfigManager.setTheme(prefersDark ? 'dark' : 'light');
} else {
await AppConfigManager.setTheme(userPreference);
}
}
// Toggle with custom transition
await AppConfigManager.setTheme('dark', {
transition: true // Force transition even if disabled
});
// Set without transition
await AppConfigManager.setTheme('light', {
transition: false // Skip transition
});ตัวอย่างที่ 3: อัปเดตตัวแปรตามธีม
// Update variables based on theme
EventManager.on('theme:changed', ({ theme }) => {
if (theme === 'dark') {
AppConfigManager.applyVariables({
'--logo-url': '/images/logo-dark.png',
'--hero-bg': '/images/hero-dark.jpg'
});
} else {
AppConfigManager.applyVariables({
'--logo-url': '/images/logo-light.png',
'--hero-bg': '/images/hero-light.jpg'
});
}
});
// Load theme-specific stylesheet
EventManager.on('theme:changed', ({ theme }) => {
const linkId = 'theme-specific-styles';
let link = document.getElementById(linkId);
if (!link) {
link = document.createElement('link');
link.id = linkId;
link.rel = 'stylesheet';
document.head.appendChild(link);
}
link.href = `/css/themes/${theme}.css`;
});ตัวอย่างที่ 4: Configuration แบบหลายผู้เช่า
// Load tenant-specific config
const tenantId = getCurrentTenantId();
await AppConfigManager.init({
enabled: true,
api: {
enabled: true,
configUrl: `/api/tenants/${tenantId}/config`,
cacheResponse: false // Don't cache (tenant-specific)
}
});
// Each tenant gets:
// - Custom CSS variables (colors, logos, fonts)
// - Custom company info
// - Custom theme preferencesAPI Reference
ตัวเลือกการตั้งค่า
{
enabled: boolean, // Enable AppConfigManager (default: false)
defaultTheme: string, // Default theme: 'light' or 'dark' (default: 'light')
storageKey: string, // localStorage key (default: 'app_theme')
systemPreference: boolean, // Use system color scheme (default: false)
api: {
enabled: boolean, // Load config from API (default: false)
configUrl: string|null, // API endpoint URL (default: null)
headers: object, // Custom request headers (default: {})
timeout: number, // Request timeout in ms (default: 5000)
cacheResponse: boolean // Cache API responses (default: true)
},
transition: {
enabled: boolean, // Enable transitions (default: true)
duration: number, // Transition duration in ms (default: 300)
hideOnSwitch: boolean, // Fade out during switch (default: true)
loadingClass: string, // Loading state class (default: 'theme-loading')
readyClass: string, // Ready state class (default: 'theme-ready')
transitionClass: string // Transitioning class (default: 'theme-transitioning')
}
}เมธอด
init(options)
เริ่มต้นใช้งาน AppConfigManager
พารามิเตอร์:
options(object) — ตัวเลือกการตั้งค่า
คืนค่า: Promise
ตัวอย่าง:
await AppConfigManager.init({
enabled: true,
defaultTheme: 'dark'
});toggle()
สลับระหว่างธีม light กับ dark
คืนค่า: void
ตัวอย่าง:
AppConfigManager.toggle();setTheme(theme, options)
ตั้งธีมที่ต้องการ
พารามิเตอร์:
theme(string) — ชื่อธีม: 'light' หรือ 'dark'options(object, ไม่บังคับ) — ตัวเลือกtransition(boolean) — ให้มี animation หรือไม่ (ค่าเริ่มต้น: true)
คืนค่า: Promise
ตัวอย่าง:
await AppConfigManager.setTheme('dark');
await AppConfigManager.setTheme('light', { transition: false });getCurrentTheme()
อ่านธีมที่ใช้อยู่
คืนค่า: string — ชื่อธีมปัจจุบัน
ตัวอย่าง:
const theme = AppConfigManager.getCurrentTheme();
console.log(theme); // 'light' or 'dark'applyVariables(variables)
ใส่ CSS custom properties
พารามิเตอร์:
variables(object) — คู่ชื่อและค่าของ CSS variable
คืนค่า: object — ตัวแปรที่ใส่จริงหลังผ่านการล้างค่า
ตัวอย่าง:
const applied = AppConfigManager.applyVariables({
'--color-primary': '#6366f1',
'--logo-url': '/images/logo.png'
});ความปลอดภัย: รับเฉพาะ CSS custom properties (--*) เท่านั้น รูปแบบที่อันตรายถูกตัดออก ส่วน URL ของรูปถูกตรวจแล้วครอบด้วย url()
clearVariables()
ลบ CSS variables ที่ใส่ไว้ทั้งหมด
คืนค่า: void
ตัวอย่าง:
AppConfigManager.clearVariables();getAppliedVariables()
อ่าน CSS variables ที่ใส่ไว้อยู่
คืนค่า: object — อ็อบเจ็กต์ของตัวแปรที่ใส่ไว้
ตัวอย่าง:
const vars = AppConfigManager.getAppliedVariables();loadFromAPI(url)
โหลด configuration จาก backend API
พารามิเตอร์:
url(string, ไม่บังคับ) — URL ของ API (ถ้าไม่ระบุจะใช้ config.api.configUrl)
คืนค่า: Promise — อ็อบเจ็กต์ configuration จาก API
โยนข้อผิดพลาด: เมื่อเรียกไม่สำเร็จหรือ response ไม่ถูกต้อง
ตัวอย่าง:
try {
const config = await AppConfigManager.loadFromAPI();
console.log('Config loaded:', config);
} catch (error) {
console.error('Load failed:', error);
}refreshFromAPI()
โหลด configuration จาก API ใหม่ (ล้าง cache ก่อน)
คืนค่า: Promise — configuration ชุดใหม่
ตัวอย่าง:
const config = await AppConfigManager.refreshFromAPI();enhance(element)
เสริมความสามารถให้ปุ่มสลับธีม (ComponentManager เป็นผู้เรียก)
พารามิเตอร์:
element(HTMLElement) — อีลิเมนต์ที่จะเสริม
คืนค่า: HTMLElement — อีลิเมนต์ที่เสริมแล้ว
ตัวอย่าง:
const button = document.querySelector('.theme-toggle');
AppConfigManager.enhance(button);destroy()
ทำลาย AppConfigManager และคืนทรัพยากรทั้งหมด
คืนค่า: void
ตัวอย่าง:
// On app unmount
AppConfigManager.destroy();reset()
คืน AppConfigManager สู่สถานะเริ่มต้นโดยไม่ทำลายทิ้ง
คืนค่า: void
ตัวอย่าง:
AppConfigManager.reset();
await AppConfigManager.init(newConfig);เหตุการณ์
theme:initialized
ส่งเมื่อ AppConfigManager เริ่มต้นเสร็จ
Payload:
{
theme: string // Current theme
}ตัวอย่าง:
EventManager.on('theme:initialized', ({ theme }) => {
console.log('Initialized with theme:', theme);
});theme:changed
ส่งเมื่อธีมเปลี่ยน
Payload:
{
theme: string // New theme
}ตัวอย่าง:
EventManager.on('theme:changed', ({ theme }) => {
console.log('Theme changed to:', theme);
// Update UI, analytics, etc.
});theme:ready
ส่งเมื่อธีมพร้อมแสดงผล (กัน FOUC)
Payload: ไม่มี
ตัวอย่าง:
EventManager.on('theme:ready', () => {
console.log('Theme ready - page visible');
});theme:variables-applied
ส่งเมื่อใส่ CSS variables เรียบร้อย
Payload:
{
variables: object // Applied variables
}ตัวอย่าง:
EventManager.on('theme:variables-applied', ({ variables }) => {
console.log('Variables applied:', variables);
});theme:variables-cleared
ส่งเมื่อล้าง CSS variables
Payload: ไม่มี
ตัวอย่าง:
EventManager.on('theme:variables-cleared', () => {
console.log('Variables cleared');
});theme:api-loaded
ส่งเมื่อโหลด configuration จาก API สำเร็จ
Payload:
{
config: object, // Configuration data
fromCache: boolean // Whether loaded from cache
}ตัวอย่าง:
EventManager.on('theme:api-loaded', ({ config, fromCache }) => {
console.log('Config loaded:', config);
console.log('From cache:', fromCache);
});theme:api-error
ส่งเมื่อเรียก API ไม่สำเร็จ
Payload:
{
error: string, // Error message
url: string // API URL
}ตัวอย่าง:
EventManager.on('theme:api-error', ({ error, url }) => {
console.error('API error:', error);
console.error('URL:', url);
});theme:destroyed
ส่งเมื่อ AppConfigManager ถูกทำลาย
Payload: ไม่มี
ตัวอย่าง:
EventManager.on('theme:destroyed', () => {
console.log('AppConfigManager destroyed');
});theme:reset
ส่งเมื่อ AppConfigManager ถูก reset
Payload: ไม่มี
ตัวอย่าง:
EventManager.on('theme:reset', () => {
console.log('AppConfigManager reset');
});ความปลอดภัย
การตรวจสอบ CSS Variable
AppConfigManager ตรวจค่าอย่างเข้มงวดเพื่อกัน XSS
ตรวจชื่อ property
// ✅ Allowed - CSS custom properties only
AppConfigManager.applyVariables({
'--color-primary': '#6366f1',
'--font-size': '16px'
});
// ❌ Rejected - Not a CSS custom property
AppConfigManager.applyVariables({
'color': 'red', // Rejected
'background': 'blue' // Rejected
});ล้างค่าที่อันตราย
รูปแบบที่อันตรายถูกตัดออกอัตโนมัติ
// ❌ Dangerous patterns (automatically removed)
'javascript:alert(1)' // javascript: protocol
'expression(alert(1))' // IE expression()
'<script>alert(1)</script>' // script tags
'url(javascript:alert(1))' // javascript in url()ตรวจสอบ URL
URL ของรูปถูกตรวจและล้างก่อนใช้
// ✅ Allowed URLs
'/images/logo.png' // Local absolute path
'./images/hero.jpg' // Local relative path
'https://example.com/image.png' // Same-origin absolute (if allowed)
// ❌ Rejected URLs
'../../../etc/passwd' // Path traversal
'http://evil.com/xss.jpg' // External domain (default policy)
'/images/file.svg' // SVG not allowed (default)
'/images/file.php' // Non-image extensionตั้งค่าความปลอดภัย
AppConfigManager.security = {
allowedPropertyPattern: /^--[\w-]+$/, // CSS custom properties only
maxValueLength: 500, // Prevent DoS
dangerousPatterns: [
// Patterns to remove from values
],
url: {
enabled: true,
allowedExtensions: ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.avif', '.ico'],
blockPathTraversal: true,
stripQueryString: true,
allowedOrigins: [window.location.origin]
}
};ข้อผิดพลาดที่พบบ่อย
❌ ข้อที่ 1: ไม่ได้เปิดใช้ AppConfigManager
// ❌ Wrong - AppConfigManager not enabled
AppConfigManager.toggle(); // Does nothing
// ✅ Correct - Enable first
await Now.init({
config: { enabled: true }
});
AppConfigManager.toggle();❌ ข้อที่ 2: ลืม await เมธอดที่เป็น async
// ❌ Wrong - Not awaiting
AppConfigManager.setTheme('dark');
console.log(AppConfigManager.getCurrentTheme()); // May still be 'light'
// ✅ Correct - Await theme change
await AppConfigManager.setTheme('dark');
console.log(AppConfigManager.getCurrentTheme()); // 'dark'❌ ข้อที่ 3: ใช้ property ที่ไม่ใช่ CSS custom property
// ❌ Wrong - Regular CSS properties rejected
AppConfigManager.applyVariables({
'color': 'red',
'font-size': '16px'
});
// ✅ Correct - Use CSS custom properties
AppConfigManager.applyVariables({
'--color-primary': 'red',
'--font-size-base': '16px'
});❌ ข้อที่ 4: ไม่ได้ตั้ง CSS สำหรับการเปลี่ยนผ่าน
// ❌ Wrong - No CSS for anti-FOUC
// Page will flash unstyled content
// ✅ Correct - Add required CSSbody {
opacity: 0;
transition: opacity 0.3s ease;
}
body.theme-ready {
opacity: 1;
}❌ ข้อที่ 5: คิดว่าตัวแปรมีผลทันที
// ❌ Wrong - Variables not applied yet
AppConfigManager.applyVariables({ '--color': 'red' });
const computed = getComputedStyle(document.documentElement)
.getPropertyValue('--color'); // May be empty
// ✅ Correct - Variables applied synchronously to DOM
AppConfigManager.applyVariables({ '--color': 'red' });
// But CSS paint may be deferred by browser
requestAnimationFrame(() => {
const computed = getComputedStyle(document.documentElement)
.getPropertyValue('--color'); // 'red'
});แนวปฏิบัติที่ดี
✅ ควรทำ
-
เปิดใช้ AppConfigManager ก่อนเรียกใช้
await Now.init({ config: { enabled: true } }); -
ใช้ CSS custom properties ในการทำธีม
.button { background: var(--color-primary); color: var(--color-text); } -
ตั้ง CSS กัน FOUC
body { opacity: 0; transition: opacity 0.3s ease; } body.theme-ready { opacity: 1; } -
รับมือ error จาก API ให้เรียบร้อย
EventManager.on('theme:api-error', ({ error }) => { console.error('Config load failed:', error); // Fallback to defaults }); -
คืนทรัพยากรเมื่อเลิกใช้แอป
window.addEventListener('unload', () => { AppConfigManager.destroy(); });
❌ ไม่ควรทำ
-
อย่าสลับธีมถี่เกินไป
// ❌ Bad - Causes flickering setInterval(() => AppConfigManager.toggle(), 100); -
อย่าแก้ state ตรง ๆ
// ❌ Bad AppConfigManager.state.current = 'dark'; // ✅ Good await AppConfigManager.setTheme('dark'); -
อย่าใส่ตัวแปรทีละตัวจำนวนมาก
// ❌ Bad - Performance impact for (let i = 0; i < 1000; i++) { AppConfigManager.applyVariables({ [`--var-${i}`]: 'value' }); } // ✅ Good - Batch apply const vars = {}; for (let i = 0; i < 100; i++) { vars[`--var-${i}`] = 'value'; } AppConfigManager.applyVariables(vars); -
อย่าข้ามการตรวจสอบความปลอดภัย
// ❌ Bad - Trying to bypass validation document.documentElement.style.setProperty('color', 'red'); // ✅ Good - Use AppConfigManager API AppConfigManager.applyVariables({ '--color': 'red' });
แก้ปัญหา
ธีมไม่ถูกจดจำ
อาการ: ธีมกลับเป็นค่าเดิมทุกครั้งที่โหลดหน้าใหม่
วิธีแก้:
// Check storageKey is set
await Now.init({
config: {
storageKey: 'app_theme' // Must be set
}
});
// Check localStorage is available
try {
localStorage.setItem('test', '1');
localStorage.removeItem('test');
} catch (e) {
console.error('localStorage blocked:', e);
}API ไม่โหลด
อาการ: configuration ไม่ถูกโหลดจาก API
วิธีแก้:
// Check API is enabled
await Now.init({
config: {
api: {
enabled: true, // Must be true
configUrl: '/api/config' // Must be set
}
}
});
// Check URL security
// Only HTTPS same-origin or HTTP same-origin allowed by default
// External domains are blocked
// Listen for errors
EventManager.on('theme:api-error', ({ error, url }) => {
console.error('API error:', error, url);
});ตัวแปรไม่มีผล
อาการ: CSS variables ไม่ปรากฏใน style
วิธีแก้:
// 1. Check variables are valid CSS custom properties
AppConfigManager.applyVariables({
'--color': 'red' // ✅ Good
// 'color': 'red' // ❌ Bad
});
// 2. Check variables in DevTools
console.log(AppConfigManager.getAppliedVariables());
// 3. Check computed styles
const computed = getComputedStyle(document.documentElement);
console.log(computed.getPropertyValue('--color'));
// 4. Verify CSS is using variables
// body { color: var(--color); }หน้ากะพริบตอนเปลี่ยนธีม
อาการ: หน้าเว็บกะพริบระหว่างเปลี่ยนธีม
วิธีแก้:
/* Ensure CSS is set up correctly */
body {
opacity: 0;
transition: opacity 0.3s ease;
}
body.theme-ready {
opacity: 1;
}
body.theme-transitioning {
opacity: 0;
}// Adjust transition duration if needed
await Now.init({
config: {
transition: {
duration: 500 // Slower transition
}
}
});เอกสารที่เกี่ยวข้อง
- TemplateManager — การผูกข้อมูลและ directive
- ApiComponent — การเชื่อม API ระดับ component
- ComponentManager — การลงทะเบียน component
- EventManager — ระบบ event
- HttpClient - ไคลเอนต์ HTTP ระดับต่ำ