/* * Dolly Club 全站商品頁 JS * 只在「已套用新版商品簡介」(頁面上有 .dc-intro)的商品頁動作,其他商品頁完全不碰。 * 功能: * 1. 購買鈕下方加出貨資訊 * 2. 同款其他花色、同花色其他款縮圖各最多 5 個(缺貨不顯示,新花色排前面) * 3. 縮圖在頁面載入完成後才抓,並暫存在瀏覽器,不拖慢開頁速度 * 拿掉這支 JS,全站立刻恢復原狀;它不會改動後台任何資料。 */ (function () { if (!/^\/store\/product\/\d+/.test(location.pathname)) return; if (window.__dcProductPage) return; window.__dcProductPage = true; var CONFIG = { shipText: '隔日出貨 · 滿 NT$799 超商取貨免運', maxThumbs: 5, // 每排最多幾個 maxChecks: 15, // 每排最多檢查幾個商品的庫存 concurrency: 3, // 同時檢查幾個 stockTTL: 6 * 60 * 60 * 1000, // 庫存暫存 6 小時 listTTL: 60 * 60 * 1000 // 列表暫存 1 小時 }; function start() { // 沒有新版簡介 → 什麼都不做 if (!document.querySelector('.dc-intro')) return; var currentId = (location.pathname.match(/\/store\/product\/(\d+)/) || [])[1]; var titleEl = document.querySelector('h1.product-title') || document.querySelector('h1'); var title = titleEl ? titleEl.textContent.trim() : ''; var parts = title.split('-'); var model = parts.length >= 3 ? parts[1].trim() : ''; var pattern = parts.length >= 3 ? parts[parts.length - 1].trim() : ''; addStyle(); var anchor = addShipping() || document.getElementById('buy-now') || document.querySelector('.dc-intro'); var run = function () { buildMore(anchor, currentId, model, pattern); }; if (document.readyState === 'complete') later(run); else window.addEventListener('load', function () { later(run); }); } function later(fn) { if ('requestIdleCallback' in window) requestIdleCallback(fn, { timeout: 2000 }); else setTimeout(fn, 300); } /* ---------- 暫存 ---------- */ function cacheGet(key, ttl) { try { var raw = localStorage.getItem(key); if (!raw) return null; var o = JSON.parse(raw); if (Date.now() - o.t > ttl) return null; return o.v; } catch (e) { return null; } } function cacheSet(key, v) { try { localStorage.setItem(key, JSON.stringify({ t: Date.now(), v: v })); } catch (e) {} } /* ---------- 樣式 ---------- */ function addStyle() { if (document.getElementById('dc-pp-style')) return; var css = [ '.dc-ship,.dc-more,.dc-more *{text-transform:none !important;letter-spacing:0 !important;font-family:"Zen Maru Gothic","PingFang TC","Noto Sans TC",sans-serif !important;}', '.dc-ship{margin:12px 0 0 !important;padding:9px 12px !important;background:#f7f3ec !important;border-radius:8px;font-size:13px !important;line-height:1.5 !important;color:#4f4540 !important;-webkit-text-fill-color:#4f4540 !important;opacity:1 !important;}', '.dc-more{margin:18px 0 0;}', '.dc-row{margin:0 0 16px;}', '.dc-row-head{display:flex;justify-content:space-between;align-items:baseline;margin:0 0 8px;}', '.dc-row-title{font-size:14px !important;font-weight:700 !important;color:#3b302b !important;-webkit-text-fill-color:#3b302b !important;}', '.dc-row-title small{font-size:11px !important;font-weight:400 !important;color:#a0968c !important;-webkit-text-fill-color:#a0968c !important;margin-left:4px;}', '.dc-row-all{font-size:12px !important;color:#5a4a3c !important;-webkit-text-fill-color:#5a4a3c !important;text-decoration:none !important;}', // 手機:5 格平分寬度(約 60px);電腦:每格最大 72px,不會撐太大 '.dc-grid{display:grid;grid-template-columns:repeat(5,minmax(0,72px));gap:6px;}', '.dc-grid a{display:block;aspect-ratio:1;border-radius:8px;overflow:hidden;background:#efe2c8;transition:opacity .55s;}', '.dc-grid a:hover{opacity:.75;}', '.dc-grid img{width:100%;height:100%;object-fit:cover;display:block;}', '.dc-ph{aspect-ratio:1;border-radius:8px;background:#f3ece0;}' ].join(''); var s = document.createElement('style'); s.id = 'dc-pp-style'; s.textContent = css; document.head.appendChild(s); } /* ---------- 出貨資訊 ---------- */ function addShipping() { var buy = document.getElementById('buy-now'); if (!buy || document.querySelector('.dc-ship')) return document.querySelector('.dc-ship'); var p = document.createElement('p'); p.className = 'dc-ship'; p.textContent = CONFIG.shipText; buy.parentNode.insertBefore(p, buy.nextSibling); return p; } /* ---------- 讀列表頁 ---------- */ // 不依賴列表頁的 class 名稱:找出所有連到 /store/product/數字 的連結,就近抓圖片和名稱 function fetchList(keyword) { var key = 'dc-list:' + keyword; var hit = cacheGet(key, CONFIG.listTTL); if (hit) return Promise.resolve(hit); return fetch('/store?search=' + encodeURIComponent(keyword), { credentials: 'same-origin' }) .then(function (r) { return r.text(); }) .then(function (html) { var doc = new DOMParser().parseFromString(html, 'text/html'); var map = {}; doc.querySelectorAll('a[href*="/store/product/"]').forEach(function (a) { var m = (a.getAttribute('href') || '').match(/\/store\/product\/(\d+)/); if (!m) return; var id = m[1]; var it = map[id] || (map[id] = { id: id, title: '', img: '' }); var t = (a.getAttribute('title') || a.textContent || '').trim(); if (t.split('-').length >= 3 && t.length > it.title.length) it.title = t; var box = a; for (var i = 0; i < 4 && box && !it.img; i++) { var img = box.querySelector && box.querySelector('img'); if (img) { it.img = img.getAttribute('data-src') || img.getAttribute('src') || ''; if (!it.title) { var alt = (img.getAttribute('alt') || '').trim(); if (alt.split('-').length >= 3) it.title = alt; } } box = box.parentElement; } }); var list = Object.keys(map).map(function (k) { return map[k]; }) .filter(function (it) { return it.title && it.img; }) .sort(function (a, b) { return Number(b.id) - Number(a.id); }); cacheSet(key, list); return list; }) .catch(function () { return []; }); } /* ---------- 檢查庫存(讀商品頁的結構化資料) ---------- */ function inStock(id) { var key = 'dc-stock:' + id; var hit = cacheGet(key, CONFIG.stockTTL); if (hit !== null) return Promise.resolve(hit); return fetch('/store/product/' + id, { credentials: 'same-origin' }) .then(function (r) { return r.text(); }) .then(function (html) { var ok = !/schema\.org\/(OutOfStock|SoldOut|Discontinued)/i.test(html); cacheSet(key, ok); return ok; }) .catch(function () { return false; }); } function pickInStock(items) { var out = [], idx = 0, active = 0, checked = 0; return new Promise(function (resolve) { function next() { if (out.length >= CONFIG.maxThumbs || (idx >= items.length && active === 0) || (checked >= CONFIG.maxChecks && active === 0)) { resolve(out.slice(0, CONFIG.maxThumbs)); return; } while (active < CONFIG.concurrency && idx < items.length && checked < CONFIG.maxChecks && out.length < CONFIG.maxThumbs) { (function (it) { active++; checked++; inStock(it.id).then(function (ok) { active--; if (ok && out.length < CONFIG.maxThumbs) out.push(it); next(); }); })(items[idx++]); } } next(); }); } /* ---------- 縮圖排 ---------- */ function buildRow(label, sub, allHref) { var row = document.createElement('div'); row.className = 'dc-row'; var head = '
' + label + '' + sub + '' + '全部 ›
'; var ph = ''; for (var i = 0; i < CONFIG.maxThumbs; i++) ph += '
'; row.innerHTML = head + '
' + ph + '
'; return row; } function fillRow(row, keyword, test, currentId) { return fetchList(keyword).then(function (list) { var items = list.filter(function (it) { return it.id !== currentId && test(it); }); return pickInStock(items); }).then(function (picked) { if (!picked.length) { row.parentNode && row.parentNode.removeChild(row); return; } var grid = row.querySelector('.dc-grid'); grid.innerHTML = picked.map(function (it) { var name = it.title.replace(/"/g, '"'); return '' + name + ''; }).join(''); }); } function buildMore(anchor, currentId, model, pattern) { if (!anchor || (!model && !pattern) || document.querySelector('.dc-more')) return; var box = document.createElement('div'); box.className = 'dc-more'; var jobs = []; if (model) { var r1 = buildRow('同款其他花色', 'Same model', '/store?search=' + encodeURIComponent(model)); box.appendChild(r1); jobs.push(function () { return fillRow(r1, model, function (it) { return it.title.indexOf('-' + model + '-') > -1; }, currentId); }); } if (pattern) { var r2 = buildRow('同花色其他款', 'Same pattern', '/store?search=' + encodeURIComponent(pattern)); box.appendChild(r2); jobs.push(function () { return fillRow(r2, pattern, function (it) { return it.title.slice(-(pattern.length + 1)) === '-' + pattern; }, currentId); }); } anchor.parentNode.insertBefore(box, anchor.nextSibling); jobs.forEach(function (fn) { fn(); }); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); else start(); })();

開口笑斜背包小 M12S 玫瑰粉

斜背包・圓弧包型・2WAY

Dolly Club 開口笑斜背包(小) M12S 純色尼龍款,邊條車縫固定出優雅的圓弧包型,2WAY 兩種使用方式。素色尼龍布料輕量好搭配,多種顏色可選,台灣製造,全館滿799免運。

imgimgimgimg

開口笑斜背包小-M12S-純色尼龍-玫瑰粉-RPN

透過邊條的車縫,將包型固定在優雅的圓弧
/內從五金扣環 拉鍊到背繩,都是在詮釋我們的執著
/2WAY的使用方式讓你有更多角度感受這份優雅


 

NTD 480


數量
加入喜愛清單

SHARE

詳細說明

 

 

Dolly Club 開口笑斜背包(小) M12S 純色尼龍款,邊條車縫固定出優雅的圓弧包型,2WAY 兩種使用方式。素色尼龍布料輕量好搭配,多種顏色可選,台灣製造,全館滿799免運。
zh_tw