Search
search Search
search Search
search Search
No results for search
const templateName = SHOPLAZZA?.meta?.page?.template_name || ''; const SEARCH_URL = '/search'; const TAG = 'spz-custom-smart-search-location'; const SEARCH_CONTAINER_CLASS = 'app-smart-product-search-container'; const THEME_NAME = window.SHOPLAZZA.theme.merchant_theme_name.replace(/ /g, ''); const BREAKPOINT = 960; const DELAY = 300; const DEFAULT_SEARCH_STYLE_CONFIG = { styleType: 'imageText', borderRadius: 4, marginEnabled: false, margin: { mobile: { left: 0, right: 0, linked: true }, pc: { left: 0, right: 0, linked: true }, }, showSearchButton: true, searchButtonType: 'text', iconEnabled: true, iconType: 'system', customIcon: '', textEnabled: false, fontStyle: 'normal', fontBold: false, fontSize: 14, fontItalic: false, searchText: 'Search', colorType: 'theme', iconColor: '#202020', textColor: '#202020', buttonTextColor: '#FFFFFF', buttonIconColor: '#FFFFFF', buttonColor: '#202020', searchBorderColor: '#202020', searchBgColor: '#FFFFFF', inputIconTextColor: '#6D7175', }; const DEFAULT_CLICK_SEARCH_STYLE_CONFIG = { buttonType: 'text', iconType: 'system', customIcon: '', fontStyle: 'normal', fontBold: false, fontSize: 14, fontItalic: false, searchText: 'Search', borderRadius: 4, colorType: 'theme', iconColor: '#FFFFFF', textColor: '#FFFFFF', buttonColor: '#202020', searchBorderColor: '#202020', searchBgColor: '#FFFFFF', inputIconTextColor: '#6D7175', hotSearchBgStartColor: '#FFE5E6', hotSearchBgEndColor: '#FFFCFC', }; // --- 工具函数 --- function parseHeaderStyle(headerStyleStr) { const hasHeaderStyle = headerStyleStr && headerStyleStr !== '' && headerStyleStr !== '{}'; if (!hasHeaderStyle) { return { searchStyleConfig: { ...DEFAULT_SEARCH_STYLE_CONFIG }, clickSearchStyleConfig: { ...DEFAULT_CLICK_SEARCH_STYLE_CONFIG }, }; } try { const parsed = typeof headerStyleStr === 'string' ? JSON.parse(headerStyleStr) : headerStyleStr; return { searchStyleConfig: { ...DEFAULT_SEARCH_STYLE_CONFIG, ...(parsed.searchStyleConfig || {}) }, clickSearchStyleConfig: { ...DEFAULT_CLICK_SEARCH_STYLE_CONFIG, ...(parsed.clickSearchStyleConfig || {}) }, }; } catch (e) { console.error('parseHeaderStyle error:', e); return { searchStyleConfig: { ...DEFAULT_SEARCH_STYLE_CONFIG }, clickSearchStyleConfig: { ...DEFAULT_CLICK_SEARCH_STYLE_CONFIG }, }; } } function matchTheme(target) { return THEME_NAME.toLocaleLowerCase().includes(target.toLocaleLowerCase()); } function resolveThemeValue(themeMap, defaultValue) { let result = defaultValue; for (const key of Object.keys(themeMap)) { if (matchTheme(key)) result = themeMap[key]; } return result; } function joinSelectors(selectorList) { return [...new Set(selectorList)].join(','); } function isDesktop() { // 编辑器环境检测:编辑器可能使用 CSS transform 模拟移动端,此时 matchMedia 不准确 // 优先使用 document.documentElement.clientWidth 检测实际可视区域宽度 const viewportWidth = document.documentElement.clientWidth || window.innerWidth; return viewportWidth >= BREAKPOINT; } // --- 元素查找 Mixin --- const ElementFinderMixin = { getBlockWrap() { return this.element.closest('.app-smart-product-search-wrap') || document.querySelector('.app-smart-product-search-wrap'); }, getBlockContainer() { return this.element.closest('.' + SEARCH_CONTAINER_CLASS) || document.querySelector('.' + SEARCH_CONTAINER_CLASS); }, resolveBlockElement(selector, fallbackId) { const wrap = this.getBlockWrap(); const el = wrap?.querySelector(selector) || document.getElementById(fallbackId); return el ? SPZ.whenApiDefined(el) : Promise.resolve(null); }, getSmartSearchEl() { return this.resolveBlockElement('ljs-search', 'app-smart-search-947'); }, getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-947'); }, }; // --- 主题配置 --- const HEADER_SELECTOR = resolveThemeValue({ eva: 'header .header_grid_layout', geek: '.header-mobile-inner-container', onePage: 'header .header', wind: 'header #header-nav', nova: 'header .header', hero: 'header .header__nav', flash: '#shoplaza-section-header>div>div', lifestyle: '.header__wrapper', reformia: 'header#header', }, 'header'); const SEARCH_ICON_CLASS = resolveThemeValue({ flash: 'app-smart-icon-search-large-flash', hero: 'app-smart-icon-search-large-hero', geek: 'app-smart-icon-search-large-geek', nova: 'app-smart-icon-search-large-nova', }, 'app-smart-icon-search-large-default'); const PLUGIN_RELOCATION_CONFIG = resolveThemeValue({ reformia: { pc: '.header-layout .header__actions', mobile: '.header-layout .header__actions', }, }, null); // --- 布局 Mixin --- const MobileLayoutMixin = { relocatePlugin() { if (!PLUGIN_RELOCATION_CONFIG) return; const targetSelector = isDesktop() ? PLUGIN_RELOCATION_CONFIG.pc : PLUGIN_RELOCATION_CONFIG.mobile; if (!targetSelector) return; if (this._relocateTimer) { clearInterval(this._relocateTimer); } const attemptRelocate = () => { const container = this.element.closest('.' + SEARCH_CONTAINER_CLASS) || document.querySelector('#app-smart-product-search-container-947'); if (!container || !document.body.contains(container)) return false; const target = document.querySelector(targetSelector); if (!target) return false; if (target.contains(container)) return true; target.insertBefore(container, target.firstChild); return true; }; if (attemptRelocate()) return; let attempts = 0; this._relocateTimer = setInterval(() => { attempts++; if (attemptRelocate() || attempts >= 20) { clearInterval(this._relocateTimer); this._relocateTimer = null; } }, 500); }, applySearchIconClass() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.classList.add(SEARCH_ICON_CLASS); }); }, adjustLifestyleIcon() { if (!matchTheme('lifestyle') || this.searchItemType === 'input' || isDesktop()) return; if (window.__smartSearchLifestyleIconMoved__) { this._lifestyleIconMoved = true; return; } const container = this.getBlockContainer(); if (!container) return; const alreadyMoved = !!document.querySelector( '.header__wrapper .container .row.header>div>.app-smart-product-search-container' ); if (alreadyMoved) { this._lifestyleIconMoved = true; window.__smartSearchLifestyleIconMoved__ = true; return; } const headerDivs = document.querySelectorAll('.header__wrapper .container .row.header>div'); if (!headerDivs.length) return; const lastDiv = headerDivs[headerDivs.length - 1]; lastDiv.appendChild(container); this._lifestyleIconMoved = true; window.__smartSearchLifestyleIconMoved__ = true; }, initInputMode() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.style.display = 'none'; }); const searchWrap = this.getBlockWrap(); const pcContainer = this.getBlockContainer(); const mobileContainer = document.querySelector('.smart-search-mobile-container'); if (!this._originalSearchWrapParent && searchWrap && searchWrap.parentElement) { this._originalSearchWrapParent = searchWrap.parentElement; } if (isDesktop()) { if (mobileContainer) mobileContainer.style.display = 'none'; if (searchWrap && this._originalSearchWrapParent) { if (mobileContainer && mobileContainer.contains(searchWrap)) { this._originalSearchWrapParent.appendChild(searchWrap); } } // PC 端:显示所有 PC 容器 document.querySelectorAll('.' + SEARCH_CONTAINER_CLASS).forEach(el => { el.style.display = 'block'; }); return; } if (templateName === 'search') { this._skipMobileInit = true; return; } // 移动端:先确认 mobile container 归属,再决定是否隐藏 PC 容器 // 避免多实例场景:Instance B 不应影响 Instance A 已设置好的 mobile container this.ensureMobileSearchContainer(); const mobileContainerAfterEnsure = document.querySelector('.smart-search-mobile-container'); if (!mobileContainerAfterEnsure) return; const existingWrap = mobileContainerAfterEnsure.querySelector('.app-smart-product-search-wrap'); if (existingWrap && existingWrap !== searchWrap) { // 另一个实例已占用 mobile container,不干预全局 DOM return; } // 确认是本实例管理 mobile container,再隐藏所有 PC 容器 document.querySelectorAll('.' + SEARCH_CONTAINER_CLASS).forEach(el => { el.style.display = 'none'; }); if (searchWrap && !mobileContainerAfterEnsure.contains(searchWrap)) { mobileContainerAfterEnsure.appendChild(searchWrap); } mobileContainerAfterEnsure.style.display = ''; }, ensureMobileSearchContainer() { if (document.querySelector('.smart-search-mobile-container')) return; const header = document.querySelector(HEADER_SELECTOR); if (!header) return; const container = document.createElement('div'); container.classList.add('smart-search-mobile-container'); container.classList.add('smart-search-mobile-container-' + THEME_NAME.toLocaleLowerCase()); header.appendChild(container); }, initIconMode() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.style.display = 'flex'; }); const searchWrap = this.getBlockWrap(); const mobileContainer = document.querySelector('.smart-search-mobile-container'); if (mobileContainer) { const existingWrap = mobileContainer.querySelector('.app-smart-product-search-wrap'); // 只有 mobile container 是空的或归属本实例时才隐藏,避免隐藏其他实例的搜索插件 if (!existingWrap || existingWrap === searchWrap) { mobileContainer.style.display = 'none'; } } // 显示所有 PC 容器 document.querySelectorAll('.' + SEARCH_CONTAINER_CLASS).forEach(el => { el.style.display = ''; }); }, hasMobilePluginParent() { return !['geek', 'flash', 'boost', 'reformia'].includes(THEME_NAME.toLocaleLowerCase()); }, showMobileSmartSearch() { if (this._mobileSearchShown) return; const PLUGIN_PARENT_SELECTORS = { nova: '.header__mobile #header__plugin-container', hero: '.header__icons .tw-flex.tw-justify-end.tw-items-center.tw-space-x-7', onePage: '.header__mobile #header__plugin-container', wind: '#header-icons .flex.justify-end.items-center', eva: '#header__icons .plugin_content', }; const parentEl = document.querySelector( joinSelectors(Object.values(PLUGIN_PARENT_SELECTORS)) ); if (!parentEl) return; const hasHiddenClass = parentEl.classList.contains('md:hidden') || parentEl.classList.contains('md:tw-hidden'); if (hasHiddenClass) { Array.from(parentEl.children).forEach((child) => { if (!this.isSmartSearchElement(child)) { child.style.display = 'none'; } }); parentEl.classList.remove('md:hidden', 'md:tw-hidden'); } else { const smartSearchEl = Array.from(parentEl.children).find( (child) => this.isSmartSearchElement(child) ); if (smartSearchEl) { smartSearchEl.style.display = 'block'; } } this._mobileSearchShown = true; }, isSmartSearchElement(el) { return ( el.classList.contains(SEARCH_CONTAINER_CLASS) || el.querySelectorAll(`.${SEARCH_CONTAINER_CLASS}`).length > 0 ); }, addMobileSmartSearch() { if (this._mobileSearchAdded) return; const HEADER_ICONS_SELECTORS = { geek: '#header-mobile-container .flex.items-center.justify-end.flex-shrink-0', flash: '#header-layout .header__icons', boost: '.header__mobile-bottom .tw-flex.tw-items-center.tw-justify-end.tw-flex-1', reformia: '.header-layout .header__actions', }; const SMART_SEARCH_ANCESTORS = [ '#header-menu-mobile #menu-drawer', '#menu-drawer .plugin__header-content', '.header__drawer', '.header-content .logo-wrap', '.header_hamburger_sidebar-container', ]; const iconsEl = document.querySelector( joinSelectors(Object.values(HEADER_ICONS_SELECTORS)) ); const searchWrapSelector = joinSelectors( SMART_SEARCH_ANCESTORS.map(a => `${a} .${SEARCH_CONTAINER_CLASS}`) ); const searchWrapEl = document.querySelector(searchWrapSelector); if (!iconsEl || !searchWrapEl) return; iconsEl.insertAdjacentElement('afterbegin', searchWrapEl); this._mobileSearchAdded = true; }, initMobileSmartSearch() { if (this._lifestyleIconMoved) return; if (this.hasMobilePluginParent()) { this.showMobileSmartSearch(); } else { this.addMobileSmartSearch(); } }, }; const StyleApplicatorMixin = { _getMarginConfig(config) { if (!config.marginEnabled || !config.margin) { return { left: 0, right: 0 }; } const device = isDesktop() ? 'pc' : 'mobile'; return config.margin[device] || { left: 0, right: 0 }; }, _applySearchInlineStyles(searchWrap, config) { const isCustom = config.colorType === 'custom'; const find = (sel) => searchWrap.querySelector(sel); const borderRadius = `${config.borderRadius}px`; const fontSize = `${config.fontSize}px`; const fontWeight = config.fontBold ? 'bold' : 'normal'; const fontStyle = config.fontItalic ? 'italic' : 'normal'; const inputContainer = find('.smart-search-outside-input-container'); if (inputContainer) { inputContainer.style.setProperty('border-radius', borderRadius, 'important'); if (isCustom) { inputContainer.style.setProperty('border-color', config.searchBorderColor, 'important'); inputContainer.style.setProperty('background-color', config.searchBgColor, 'important'); } else { inputContainer.style.removeProperty('border-color'); inputContainer.style.removeProperty('background-color'); } } const outsideButtons = searchWrap.querySelectorAll('.smart-search-outside-input-button'); outsideButtons.forEach((btn) => { if (isCustom) { btn.style.setProperty('background-color', config.buttonColor, 'important'); } else { btn.style.removeProperty('background-color'); } }); const btnSystemIcons = searchWrap.querySelectorAll('.smart-search-button-system-icon'); btnSystemIcons.forEach((icon) => { if (isCustom) { icon.style.setProperty('color', config.buttonIconColor, 'important'); } else { icon.style.removeProperty('color'); } }); const btnTexts = searchWrap.querySelectorAll('.smart-search-button-text'); btnTexts.forEach((txt) => { txt.style.setProperty('font-size', fontSize, 'important'); txt.style.setProperty('font-weight', fontWeight, 'important'); txt.style.setProperty('font-style', fontStyle, 'important'); if (isCustom) { txt.style.setProperty('color', config.buttonTextColor, 'important'); } else { txt.style.removeProperty('color'); } }); const inputIcons = searchWrap.querySelectorAll('.smart-search-outside-input-icon, .smart-search-outside-input-icon svg'); inputIcons.forEach((el) => { if (isCustom) { el.style.setProperty('color', config.inputIconTextColor, 'important'); el.style.setProperty('fill', config.inputIconTextColor, 'important'); } else { el.style.removeProperty('color'); el.style.removeProperty('fill'); } }); const placeholderTexts = searchWrap.querySelectorAll('.smart-search-outside-input-placeholder-text'); placeholderTexts.forEach((el) => { if (isCustom) { el.style.setProperty('color', config.inputIconTextColor, 'important'); } else { el.style.removeProperty('color'); } }); const systemIcons = searchWrap.querySelectorAll('.smart-search-system-icon, .smart-search-system-icon svg'); systemIcons.forEach((el) => { if (isCustom) { el.style.setProperty('color', config.iconColor, 'important'); el.style.setProperty('fill', config.iconColor, 'important'); } else { el.style.removeProperty('color'); el.style.removeProperty('fill'); } }); const iconText = find('.smart-search-icon-text'); if (iconText) { iconText.style.setProperty('font-size', fontSize, 'important'); iconText.style.setProperty('font-weight', fontWeight, 'important'); iconText.style.setProperty('font-style', fontStyle, 'important'); if (isCustom) { iconText.style.setProperty('color', config.textColor, 'important'); } else { iconText.style.removeProperty('color'); } } }, _applyClickSearchInlineStyles(sidebar, config) { const isCustom = config.colorType === 'custom'; const find = (sel) => sidebar.querySelector(sel) || document.querySelector(sel); const searchForm = find('.smart-search-form'); if (searchForm) { searchForm.style.setProperty('border-radius', `${config.borderRadius}px`, 'important'); searchForm.style.setProperty('border-width', '1px', 'important'); searchForm.style.setProperty('border-style', 'solid', 'important'); searchForm.style.setProperty('overflow', 'hidden'); } const submitBtn = find('.smart-search-submit-btn'); const buttonText = find('.smart-search-sidebar-button-text'); if (buttonText) { buttonText.style.setProperty('font-size', `${config.fontSize}px`, 'important'); buttonText.style.setProperty('font-weight', config.fontBold ? 'bold' : 'normal', 'important'); buttonText.style.setProperty('font-style', config.fontItalic ? 'italic' : 'normal', 'important'); } if (submitBtn) { const hotWordsCarousel = sidebar.querySelector('.hot-words-carousel'); if (hotWordsCarousel) { const btnWidth = submitBtn.offsetWidth || 66; hotWordsCarousel.style.setProperty('right', `${btnWidth + 8}px`, 'important'); } } if (isCustom) { if (searchForm) { searchForm.style.setProperty('border-color', config.searchBorderColor, 'important'); } const inputContent = find('.smart-search-input-content'); if (inputContent) { inputContent.style.setProperty('background', config.searchBgColor, 'important'); inputContent.style.setProperty('border-color', 'transparent', 'important'); } if (submitBtn) { submitBtn.style.setProperty('background-color', config.buttonColor, 'important'); submitBtn.style.setProperty('color', config.textColor, 'important'); } const systemIcon = find('.smart-search-sidebar-button-system-icon'); if (systemIcon) { systemIcon.style.setProperty('color', config.iconColor, 'important'); const svg = systemIcon.querySelector('svg'); if (svg) svg.style.setProperty('fill', config.iconColor, 'important'); } if (buttonText) { buttonText.style.setProperty('color', config.textColor, 'important'); } const insideIcon = find('.smart-search-inside-system-icon'); if (insideIcon) { insideIcon.style.setProperty('color', config.inputIconTextColor, 'important'); const svg = insideIcon.querySelector('svg'); if (svg) svg.style.setProperty('fill', config.inputIconTextColor, 'important'); } const searchInput = find('.smart-search-input'); if (searchInput) { searchInput.style.setProperty('color', config.inputIconTextColor, 'important'); } } this._injectClickSearchScopedStyle(config); }, _injectClickSearchScopedStyle(config) { const isCustom = config.colorType === 'custom'; const styleId = 'smart-search-click-scoped-style'; let style = document.getElementById(styleId); if (!style) { style = document.createElement('style'); style.id = styleId; document.head.appendChild(style); } let css = ''; if (isCustom) { css = ` .hot-search { background: linear-gradient(180deg, ${config.hotSearchBgStartColor} 0%, ${config.hotSearchBgEndColor} 100%) !important; } .smart-search-input::placeholder { color: ${config.inputIconTextColor} !important; opacity: 0.6; } .hot-words-carousel-word { color: ${config.inputIconTextColor} !important; opacity: 0.6; } `; } style.textContent = css; }, applySearchStyleConfig(retryCount = 0) { const config = this.searchStyleConfig; const searchWrap = this.getBlockWrap(); if (!searchWrap) return; // 设置锁标记,防止 resize 期间重复调用 this._isApplyingStyle = true; // 重构后:静态内容在 ljs-render 外部,DOM 元素始终存在 const iconSearchLarge = searchWrap.querySelector('.app-smart-icon-search-large'); const isSearchBox = config.styleType === 'searchBox'; // 检查轮播是否已渲染,如果没有则短暂等待后重试 const placeholder = searchWrap.querySelector('.smart-search-outside-input-placeholder'); const carousel = searchWrap.querySelector('.app-smart-search-outside-carousel'); // 轮播组件可能需要额外时间渲染,等待后重试 if (placeholder && !carousel && retryCount < 10) { this._isApplyingStyle = false; setTimeout(() => this.applySearchStyleConfig(retryCount + 1), 50); return; } // 轮播已渲染,隐藏默认占位文本 if (placeholder && carousel) { placeholder.classList.add('has-carousel'); } this._applySearchInlineStyles(searchWrap, config); const searchBtn = searchWrap.querySelector('.app-smart-search-btn'); const outsideInputContainer = searchWrap.querySelector('.smart-search-outside-input-container'); const buttonType = config.searchButtonType || config.buttonType; if (searchBtn) { const marginConfig = this._getMarginConfig(config); searchBtn.style.marginLeft = `${marginConfig.left}px`; searchBtn.style.marginRight = `${marginConfig.right}px`; // 使用 data 属性控制样式类型显示(searchBox 或 imageText) searchBtn.dataset.styleType = isSearchBox ? 'searchBox' : 'imageText'; } // 搜索按钮显示/隐藏控制 const outsideButtons = searchWrap.querySelectorAll('.smart-search-outside-input-button'); outsideButtons.forEach((btn) => { btn.style.display = config.showSearchButton ? '' : 'none'; this._applyButtonContentDisplay(btn, config, { customIconSelector: '.smart-search-button-custom-icon', systemIconSelector: '.smart-search-button-system-icon', textSelector: '.smart-search-button-text', }); }); // 图文样式配置 - 使用 data 属性控制显示 if (iconSearchLarge) { const customIcon = iconSearchLarge.querySelector('.smart-search-custom-icon'); const iconText = iconSearchLarge.querySelector('.smart-search-icon-text'); const mobile = !isDesktop(); // 设置 data 属性,让 CSS 控制显示 iconSearchLarge.dataset.iconEnabled = config.iconEnabled ? 'true' : 'false'; iconSearchLarge.dataset.iconType = config.iconType || 'system'; if (mobile) { // 移动端:只显示图标,不显示文本 iconSearchLarge.dataset.textEnabled = 'false'; } else { iconSearchLarge.dataset.textEnabled = config.textEnabled ? 'true' : 'false'; } // 设置自定义图标 src(如果有) if (config.iconType === 'custom' && config.customIcon && customIcon) { customIcon.src = config.customIcon; } // 设置文本内容 if (iconText && config.textEnabled) { iconText.textContent = config.searchText || 'Search'; } } if (searchBtn) { searchBtn.classList.add('style-ready'); } // 解除锁标记 this._isApplyingStyle = false; }, _applyButtonContentDisplay(btn, config, selectors) { const { customIconSelector, systemIconSelector, textSelector } = selectors; const customIcon = btn.querySelector(customIconSelector); const systemIcon = btn.querySelector(systemIconSelector); const textSpan = btn.querySelector(textSelector); const buttonType = config.searchButtonType || config.buttonType; // 使用 data 属性驱动 CSS 显示,确保降级和一致性 btn.dataset.buttonType = buttonType || 'text'; if (buttonType === 'icon') { // 设置图标类型:custom 或 system(默认) const iconType = (config.iconType === 'custom' && config.customIcon) ? 'custom' : 'system'; btn.dataset.iconType = iconType; // 如果是自定义图标,设置 src if (iconType === 'custom' && customIcon) { customIcon.src = config.customIcon; } } else { // text 类型:移除 iconType 属性,更新文本内容 delete btn.dataset.iconType; // 侧边栏按钮文本只在首次渲染时写入,避免与多语言插件产生覆写死循环 const isSidebarBtn = !!btn.closest('.smart-search-sidebar-overlay'); if (textSpan && (!isSidebarBtn || !this._sidebarBtnTextApplied)) { textSpan.textContent = config.searchText || 'Search'; if (isSidebarBtn) this._sidebarBtnTextApplied = true; } } }, applyClickSearchStyleConfig(retryCount = 0) { const config = this.clickSearchStyleConfig; const sidebar = this._getSidebarOverlay ? this._getSidebarOverlay() : document.querySelector('.smart-search-sidebar-overlay'); if (!sidebar) return; const findElement = (selector) => sidebar.querySelector(selector) || document.querySelector(selector); const submitBtn = findElement('.smart-search-submit-btn'); if (!submitBtn && retryCount < 10) { setTimeout(() => this.applyClickSearchStyleConfig(retryCount + 1), 100); return; } if (this._sidebarObserver) this._sidebarObserver.disconnect(); this._applyClickSearchInlineStyles(sidebar, config); if (submitBtn) { this._applyButtonContentDisplay(submitBtn, config, { customIconSelector: '.smart-search-sidebar-button-custom-icon', systemIconSelector: '.smart-search-sidebar-button-system-icon', textSelector: '.smart-search-sidebar-button-text', }); } if (this._sidebarObserver) { this._sidebarObserver.observe(sidebar, { childList: true, subtree: true }); } }, }; // --- 侧边栏管理 Mixin(预加载模式)--- const SidebarManagerMixin = { // 侧边栏状态: idle -> preloading -> ready -> open -> idle _sidebarState: 'idle', _sidebarReady: false, _contentPreloaded: false, _contentPreloadPromise: null, _getSidebarOverlay() { const wrap = this.getBlockWrap(); if (wrap) { const overlay = wrap.querySelector('.smart-search-sidebar-overlay'); if (overlay) return overlay; } return document.querySelector('.smart-search-sidebar-overlay'); }, _getSidebarPanel() { const wrap = this.getBlockWrap(); if (wrap) { const panel = wrap.querySelector('.smart-search-sidebar'); if (panel) return panel; } return document.querySelector('.smart-search-sidebar'); }, _findVisibleSearchEntry() { const wrap = this.getBlockWrap(); if (wrap) { const content = wrap.querySelector('[id^="app-smart-product-search-content-"]'); if (content) return content; } return document.querySelector('[id^="app-smart-product-search-content-"]'); }, _alignSidebarToOutsideInput() { if (!isDesktop()) return; const panel = this._getSidebarPanel(); if (!panel) return; const refEl = this._findVisibleSearchEntry(); let topPos = 80; let rightPos = 20; if (refEl) { const rect = refEl.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; topPos = Math.max(0, rect.top); rightPos = Math.max(0, viewportWidth - rect.right); } panel.style.setProperty('top', topPos + 'px', 'important'); panel.style.setProperty('right', rightPos + 'px', 'important'); }, preloadSidebar() { const overlay = this._getSidebarOverlay(); if (!overlay) return; const currentState = overlay.getAttribute('data-state'); if (this._sidebarReady || this._sidebarState === 'preloading' || this._sidebarState === 'open') return; if (currentState === 'open' || currentState === 'preloading') return; this._sidebarState = 'preloading'; overlay.setAttribute('data-state', 'preloading'); const configReady = new Promise((resolve) => { if (this._configLoaded) { resolve(); return; } this.getOutsideItemEl().then((outsideItem) => { if (outsideItem) { const apiData = outsideItem.getData() || {}; const { clickSearchStyleConfig } = parseHeaderStyle(apiData.header_style); this.clickSearchStyleConfig = clickSearchStyleConfig; this._configLoaded = true; } resolve(); }).catch(() => resolve()); }); // 先渲染内容(创建 DOM),再应用样式(依赖 DOM 存在) configReady.then(() => { const currentState = overlay.getAttribute('data-state'); if (currentState === 'open') return; this._contentPreloaded = false; this._contentPreloadPromise = this.initSidebarContent().then(() => { this.applyClickSearchStyleConfig(); this._contentPreloaded = true; }).catch(() => { this._contentPreloaded = false; this._contentPreloadPromise = null; }); this._sidebarReady = true; this._sidebarState = 'ready'; overlay.setAttribute('data-state', 'ready'); }); }, // 打开侧边栏 openSidebar() { const overlay = this._getSidebarOverlay(); if (!overlay) return; this._sidebarOpenedAsDesktop = isDesktop(); this._savedScrollbarWidth = parseFloat(getComputedStyle(document.documentElement).marginRight) || 0; this._sidebarOpenTimestamp = performance.now(); const configReady = new Promise((resolve) => { if (this._configLoaded) { resolve(); return; } this.getOutsideItemEl().then((outsideItem) => { if (outsideItem) { const apiData = outsideItem.getData() || {}; const { clickSearchStyleConfig } = parseHeaderStyle(apiData.header_style); this.clickSearchStyleConfig = clickSearchStyleConfig; this._configLoaded = true; } resolve(); }).catch(() => resolve()); }); configReady.then(() => { this.applyClickSearchStyleConfig(); this._sidebarReady = true; this._showSidebar(overlay); }); document.body.style.overflow = 'hidden'; if (!this._resizeHandler) { this._resizeHandler = () => this._alignSidebarToOutsideInput(); window.addEventListener('resize', this._resizeHandler); } this._setupSidebarObserver(overlay); }, _showSidebar(overlay) { const panel = this._getSidebarPanel(); if (!panel) return; this._sidebarState = 'open'; overlay.setAttribute('data-state', 'open'); const _isDesktop = isDesktop(); const ANIM_DURATION = 280; const _setupPanelLayout = () => { const smartSearchWrap = panel.querySelector('.smart-search-wrap'); if (smartSearchWrap) { smartSearchWrap.style.cssText = _isDesktop ? 'display: block !important; width: 100% !important;' : 'display: flex !important; flex-direction: column !important; width: 100% !important; flex: 1 !important; min-height: 0 !important;'; } const pageContent = panel.querySelector('.page-content'); if (pageContent) { pageContent.style.cssText = _isDesktop ? 'display: flex !important; flex-direction: column !important; width: 100% !important;' : 'display: flex !important; flex-direction: column !important; width: 100% !important; flex: 1 !important; min-height: 0 !important;'; } }; const _applyPanelPosition = () => { if (_isDesktop) { const refEl = this._findVisibleSearchEntry(); let topPos = 80; let rightPos = 20; if (refEl) { const rect = refEl.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; topPos = Math.max(0, rect.top); rightPos = Math.max(0, viewportWidth - rect.right); } panel.style.cssText = ` display: block !important; position: fixed !important; top: ${topPos}px !important; right: ${rightPos}px !important; left: auto !important; bottom: auto !important; width: 520px !important; max-width: 520px !important; background: #fff !important; visibility: visible !important; opacity: 1 !important; z-index: 10000 !important; padding: 16px !important; border-radius: 6px !important; box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15) !important; pointer-events: auto !important; `; } else { panel.style.cssText = ` display: flex !important; flex-direction: column !important; position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; width: 100vw !important; max-width: 100vw !important; background: #fff !important; visibility: visible !important; opacity: 1 !important; z-index: 10000 !important; padding: 16px !important; border-radius: 0 !important; box-shadow: none !important; pointer-events: auto !important; transform: translateX(100%) !important; `; } }; const revealSidebar = () => { _applyPanelPosition(); _setupPanelLayout(); this.applyClickSearchStyleConfig(); overlay.style.cssText = ` position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; width: 100vw !important; z-index: 9999 !important; visibility: visible !important; pointer-events: auto !important; display: block !important; `; this.checkHistoryOverflow(); if (!_isDesktop) { // 移动端 panel 全屏,backdrop 不可见但 @tap 还在,禁止 pointer-events 防止滚动/幽灵点击触发关闭 const backdrop = overlay.querySelector('.smart-search-sidebar-backdrop'); if (backdrop) backdrop.style.setProperty('pointer-events', 'none', 'important'); const contentWrap = panel.querySelector('.smart-search-wrap'); if (contentWrap) { contentWrap.style.setProperty('opacity', '0', 'important'); } requestAnimationFrame(() => { panel.style.setProperty('transition', `transform ${ANIM_DURATION}ms cubic-bezier(0.16, 1, 0.3, 1)`, 'important'); panel.style.setProperty('transform', 'translateX(0)', 'important'); }); const fontsReady = (document.fonts && document.fonts.ready) ? document.fonts.ready : Promise.resolve(); const stableDelay = new Promise(r => setTimeout(r, ANIM_DURATION)); Promise.all([fontsReady, stableDelay]).then(() => { requestAnimationFrame(() => { if (contentWrap) { contentWrap.style.setProperty('opacity', '1', 'important'); } }); }); } if (_isDesktop) { const input = overlay.querySelector('.smart-search-input'); if (input) { setTimeout(() => input.focus(), 50); } } this._syncInsideCarousel(overlay); }; if (this._contentPreloaded) { this.renderSearchHistory(); revealSidebar(); return; } overlay.style.cssText = ` position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; width: 100vw !important; z-index: 9999 !important; visibility: hidden !important; pointer-events: none !important; display: block !important; opacity: 0 !important; `; _applyPanelPosition(); _setupPanelLayout(); const contentReady = this._contentPreloadPromise || this.initSidebarContent(); contentReady.then(() => { requestAnimationFrame(() => revealSidebar()); }).catch(() => { revealSidebar(); }); }, _setupSidebarObserver(overlay) { if (this._sidebarObserver) { this._sidebarObserver.disconnect(); } this._sidebarObserver = new MutationObserver(() => { if (this._applyStyleDebounceTimer) { clearTimeout(this._applyStyleDebounceTimer); } this._applyStyleDebounceTimer = setTimeout(() => { this.checkHistoryOverflow(); }, 50); }); this._sidebarObserver.observe(overlay, { childList: true, subtree: true }); }, _syncOutsideCarousel() { if (this.insideCarouselIndex === this.outsideCarouselIndex) return; this.outsideCarouselIndex = this.insideCarouselIndex; const outsideEl = document.querySelector('ljs-carousel[id^="app-smart-search-outside-carousel-"]'); if (!outsideEl) return; SPZ.whenApiDefined(outsideEl).then((api) => { try { api.goToSlide(String(this.outsideCarouselIndex)); } catch(e) {} }); }, closeSidebar() { const overlay = this._getSidebarOverlay(); if (!overlay) return; const overlayState = overlay.getAttribute('data-state'); if (this._sidebarState === 'closing') return; if (this._sidebarState === 'idle' && overlayState !== 'open') return; this._syncOutsideCarousel(); this._sidebarState = 'closing'; const panel = this._getSidebarPanel(); const _wasDesktop = this._sidebarOpenedAsDesktop !== undefined ? this._sidebarOpenedAsDesktop : isDesktop(); const ANIM_DURATION = 250; const _cleanup = () => { this._sidebarState = 'idle'; this._sidebarReady = false; this._sidebarOpenedAsDesktop = undefined; overlay.setAttribute('data-state', 'idle'); overlay.style.cssText = ''; const _backdrop = overlay.querySelector('.smart-search-sidebar-backdrop'); if (_backdrop) _backdrop.style.removeProperty('pointer-events'); if (panel) { panel.style.cssText = ''; const smartSearchWrap = panel.querySelector('.smart-search-wrap'); if (smartSearchWrap) smartSearchWrap.style.cssText = ''; const pageContent = panel.querySelector('.page-content'); if (pageContent) pageContent.style.cssText = ''; const input = panel.querySelector('.smart-search-input'); if (input) { input.value = ''; input.removeAttribute('has-value'); } panel.removeAttribute('has-value'); panel.removeAttribute('data-empty'); panel.removeAttribute('loading'); const loadingEl = panel.querySelector('.smart-search-loading'); if (loadingEl) { loadingEl.removeAttribute('show'); loadingEl.setAttribute('hide', ''); } document.querySelectorAll('.hot-words-carousel-inner-container').forEach(el => { el.style.display = 'block'; }); } document.body.style.overflow = ''; const scrollbarWidth = this._savedScrollbarWidth || 0; if (scrollbarWidth > 0) { const html = document.documentElement; html.style.setProperty('overflow', 'hidden', 'important'); html.style.setProperty('margin-right', scrollbarWidth + 'px', 'important'); setTimeout(() => { html.style.removeProperty('overflow'); html.style.removeProperty('margin-right'); }, 50); } this._savedScrollbarWidth = 0; if (this._sidebarObserver) { this._sidebarObserver.disconnect(); this._sidebarObserver = null; } if (this._applyStyleDebounceTimer) { clearTimeout(this._applyStyleDebounceTimer); this._applyStyleDebounceTimer = null; } if (this._resizeHandler) { window.removeEventListener('resize', this._resizeHandler); this._resizeHandler = null; } this._historyExpanded = false; }; if (panel && !_wasDesktop) { panel.style.setProperty('transition', `transform ${ANIM_DURATION}ms cubic-bezier(0.5, 0, 0.7, 0.4)`, 'important'); panel.style.setProperty('transform', 'translateX(100%)', 'important'); setTimeout(_cleanup, ANIM_DURATION); } else { _cleanup(); } const sectionPrefix = 'shoplaza-section'; const announcement = document.getElementById(sectionPrefix + '-announcement'); const header = document.getElementById(sectionPrefix + '-header'); if (announcement) announcement.classList.remove('header_mask_open'); if (header) header.classList.remove('header_mask_open'); }, _restartCarouselAutoplay(carouselEl) { carouselEl.removeAttribute('autoplay'); carouselEl.setAttribute('pause', ''); setTimeout(() => { carouselEl.setAttribute('autoplay', ''); carouselEl.removeAttribute('pause'); }, 50); }, _syncInsideCarousel(overlay) { const targetIndex = this.outsideCarouselIndex || 0; const doSync = () => { const carouselEl = overlay.querySelector('ljs-carousel[id^="inside-hot-words-carousel-"]'); if (!carouselEl) return; SPZ.whenApiDefined(carouselEl).then((carouselApi) => { try { carouselApi.goToSlide(String(targetIndex)); } catch(e) {} this._restartCarouselAutoplay(carouselEl); }); }; const renderEl = overlay.querySelector('ljs-render[id^="hot-words-carousel-"]'); if (renderEl) { const existingCarousel = overlay.querySelector('ljs-carousel[id^="inside-hot-words-carousel-"]'); if (existingCarousel && existingCarousel.hasAttribute('dom-mounted')) { doSync(); } else { const observer = new MutationObserver(() => { const el = overlay.querySelector('ljs-carousel[id^="inside-hot-words-carousel-"]'); if (el && el.hasAttribute('dom-mounted')) { observer.disconnect(); doSync(); } }); observer.observe(renderEl, { childList: true, subtree: true, attributes: true }); setTimeout(() => { observer.disconnect(); doSync(); }, 3000); } } else { doSync(); } }, // 兼容旧的 onSidebarOpen/Close 方法 onSidebarOpen() { this.openSidebar(); }, onSidebarClose() { this.closeSidebar(); }, }; // --- 搜索历史折叠/展开 Mixin --- const HISTORY_COLLAPSED_ROWS = 6; const HISTORY_EXPAND_THRESHOLD = 10; const HistoryOverflowMixin = { _findHistoryList(root) { const sources = [root, document]; for (const src of sources) { const list = src.querySelector('.recently-history-list'); if (list) return list; const els = src.querySelectorAll('*'); for (const el of els) { if (el.shadowRoot) { const l = el.shadowRoot.querySelector('.recently-history-list'); if (l) return l; } } } return null; }, _getRowHeight(list) { const item = list.querySelector('.recently-history-item'); if (!item || item.getBoundingClientRect().height === 0) return 0; const rowGap = parseFloat(getComputedStyle(list).rowGap) || 0; return item.getBoundingClientRect().height + rowGap; }, _findToggleBtn(list) { const parent = list.closest('.recently-history-content'); return parent ? parent.querySelector('.history-toggle-btn') : null; }, _applyMaxHeight(list) { const item = list.querySelector('.recently-history-item'); if (!item || item.getBoundingClientRect().height === 0) return; const itemHeight = item.getBoundingClientRect().height; const rowGap = parseFloat(getComputedStyle(list).rowGap) || 0; const paddingTop = parseFloat(getComputedStyle(list).paddingTop) || 0; var maxHeight = Math.ceil(itemHeight * HISTORY_COLLAPSED_ROWS + rowGap * (HISTORY_COLLAPSED_ROWS - 1)) + paddingTop; if (isDesktop()) maxHeight--; list.style.setProperty('max-height', maxHeight + 'px'); }, checkHistoryOverflow() { const overlay = this._getSidebarOverlay(); if (!overlay) return; const list = this._findHistoryList(overlay); if (!list) return; const items = list.querySelectorAll('.recently-history-item'); if (items.length === 0) return; this._applyMaxHeight(list); const needsCollapse = items.length > HISTORY_EXPAND_THRESHOLD; if (needsCollapse && !this._historyExpanded) { list.classList.add('history-collapsed'); } else { list.classList.remove('history-collapsed'); } const toggleBtn = this._findToggleBtn(list); if (toggleBtn) { if (needsCollapse && !this._historyExpanded) { toggleBtn.classList.remove('hidden'); } else { toggleBtn.classList.add('hidden'); } } }, expandHistory() { const overlay = this._getSidebarOverlay(); if (!overlay) return; const list = this._findHistoryList(overlay); if (!list) return; this._historyExpanded = true; list.classList.remove('history-collapsed'); this._applyMaxHeight(list); const toggleBtn = this._findToggleBtn(list); if (toggleBtn) toggleBtn.classList.add('hidden'); }, }; const HotKeywordsMixin = { generateHotKeywordList(data) { const searchKeywords = data?.hotKeywordList || []; const isShowHotKeyword = data?.isShowHotKeyword || false; this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const hotwords = outsideItem.getData()?.search_keywords || []; const enrichedKeywords = this.enrichKeywords(searchKeywords, hotwords); this.renderHotKeywords(enrichedKeywords, isShowHotKeyword); }); }, enrichKeywords(keywords, hotwords) { return keywords.map((item) => { item.url_obj = item.url_obj || {}; const hotwordItem = hotwords.find(h => h.word === item.word); if (hotwordItem) { item.icon = hotwordItem.icon || ''; } if (!item.urlObj || !item.urlObj.url) { item.urlObj = { ...item.url_obj, url: item.url_obj.type === 'search' ? `${SEARCH_URL}?q=${item.word}` : item.url_obj.url, }; } return item; }); }, renderHotKeywords(keywords, isShowHotKeyword) { document.querySelectorAll('.app-hot-keyword-render-child').forEach((el) => { SPZ.whenApiDefined(el).then((hotWordsChild) => { hotWordsChild.render({ list: keywords, isShowHotKeyword }); }); }); }, normalizeOutsideKeywords(findKeywords, searchKeywords, findKeywordEnable) { if (findKeywordEnable === false) return []; if (findKeywords && findKeywords.length > 0) { return findKeywords.map(keyword => ({ word: keyword, icon: '', pic: '', type: 'find_keyword', url_obj: { type: 'search', url: `${SEARCH_URL}?q=${keyword}`, }, })); } return searchKeywords || []; }, normalizeKeywordUrl(item) { if (!item) return null; if (item.url_obj) { item.url_obj.url = item.url_obj.type === 'search' ? `${SEARCH_URL}?q=${item.word}` : item.url_obj.url; } return item; }, onTapHotWord(type) { const index = type === 'inside' ? this.insideCarouselIndex : this.outsideCarouselIndex; this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const apiData = outsideItem.getData(); const findKeywords = apiData?.find_keywords || []; const searchKeywords = apiData?.search_keywords || []; const findKeywordEnable = apiData?.find_keyword_enable !== false; const keywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords, findKeywordEnable); const currentItem = this.normalizeKeywordUrl(keywords[index] || null); if (currentItem) { this.handleHotKeyword({ args: { word: currentItem.word, query_type: currentItem.type, url: currentItem.url_obj?.url, } }); } else { this.executeSearch([''], 1); } }); }, getOutsideCarouselConfig() { return this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return { outsideCarouselIndex: this.outsideCarouselIndex }; const apiData = outsideItem.getData(); const findKeywords = apiData?.find_keywords || []; const searchKeywords = apiData?.search_keywords || []; const findKeywordEnable = apiData?.find_keyword_enable !== false; const carouselKeywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords, findKeywordEnable); return { ...apiData, search_keywords: carouselKeywords, outsideCarouselIndex: this.outsideCarouselIndex, }; }); }, }; const HISTORY_CACHE_KEY = 'smart_search_history'; const HISTORY_MAX_LEN = 30; const HOT_SEARCH_LEN = 6; const SMART_SEARCH_THINK_URL = '/api/search/suggestion'; const SearchControllerMixin = { // 搜索历史缓存 _historyCache: null, _searchData: null, _hotList: [], _curFindKeyword: '', // 初始化搜索历史 initHistoryCache() { if (this._historyCache) return; try { const cached = localStorage.getItem(HISTORY_CACHE_KEY); this._historyCache = cached ? JSON.parse(cached) : []; } catch (e) { this._historyCache = []; } }, // 获取历史列表 getHistoryList() { try { const cached = localStorage.getItem(HISTORY_CACHE_KEY); const historyList = cached ? JSON.parse(cached) : []; return historyList.slice().reverse(); } catch (e) { return []; } }, // 添加历史记录 addHistory(keyword) { if (!keyword || !keyword.trim()) return; this.initHistoryCache(); const index = this._historyCache.indexOf(keyword); if (index > -1) { this._historyCache.splice(index, 1); } this._historyCache.push(keyword); if (this._historyCache.length > HISTORY_MAX_LEN) { this._historyCache.shift(); } try { localStorage.setItem(HISTORY_CACHE_KEY, JSON.stringify(this._historyCache)); } catch (e) {} }, // 清除历史 clearHistory() { this._historyCache = []; try { localStorage.removeItem(HISTORY_CACHE_KEY); } catch (e) {} }, // 渲染表单区域 renderSearchForm() { const panel = this._getSidebarPanel(); if (!panel) return Promise.resolve(); return this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const apiData = outsideItem.getData() || {}; const formData = { isOpenAutoThink: apiData.auto_think_enable || false, isOpenFindKeyword: apiData.find_keyword_enable || false, findKeywordList: apiData.find_keywords || [], }; const formRender = panel.querySelector('[role="form"]'); if (formRender) { return SPZ.whenApiDefined(formRender).then((api) => { api.render(formData); }); } }); }, // 渲染历史区域 renderSearchHistory() { const panel = this._getSidebarPanel(); if (!panel) return Promise.resolve(); return this.getOutsideItemEl().then((outsideItem) => { const apiData = outsideItem?.getData() || {}; const historyList = this.getHistoryList(); const historyData = { isShowHistory: (apiData.user_history_enable !== false) && historyList.length > 0, historyList: historyList, }; const historyRender = panel.querySelector('[role="history"]'); if (historyRender) { return SPZ.whenApiDefined(historyRender).then((api) => { api.render(historyData); }); } }); }, // 渲染联想结果 renderThinkResult(thinkResult) { const panel = this._getSidebarPanel(); if (!panel) return; const thinkRender = panel.querySelector('[role="thinkresult"]'); if (thinkRender) { SPZ.whenApiDefined(thinkRender).then((api) => { api.render({ thinkResult }); }); } }, // 获取联想结果 fetchThinkResult(keyword) { if (!keyword || !keyword.trim()) { this.setThinkResultStatus(false, false); return Promise.resolve([]); } this.setThinkResultStatus(true, false); this.setLoadingStatus(true); return fetch(`${SMART_SEARCH_THINK_URL}?surface=autocomplete&keyword=${encodeURIComponent(keyword)}`) .then(res => res.json()) .then(res => { this.setLoadingStatus(false); const items = res.items || []; this.setThinkResultStatus(true, items.length === 0); const lowerKeyword = keyword.toLowerCase(); const thinkResult = items.map(item => ({ ...item, highlightHtml: item.word.replace( new RegExp(lowerKeyword, 'gi'), `${lowerKeyword}` ), })); this.renderThinkResult(thinkResult); return thinkResult; }) .catch(() => { this.setLoadingStatus(false); this.setThinkResultStatus(true, true); return []; }); }, // 设置联想结果状态 setThinkResultStatus(hasValue, isEmpty) { const panel = this._getSidebarPanel(); if (!panel) return; if (hasValue) { panel.setAttribute('has-value', ''); } else { panel.removeAttribute('has-value'); } if (isEmpty) { panel.setAttribute('data-empty', ''); } else { panel.removeAttribute('data-empty'); } }, // 设置 loading 状态 setLoadingStatus(loading) { const panel = this._getSidebarPanel(); if (!panel) return; if (loading) { panel.setAttribute('loading', ''); } else { panel.removeAttribute('loading'); } const loadingEl = panel.querySelector('.smart-search-loading'); if (loadingEl) { if (loading) { loadingEl.removeAttribute('hide'); loadingEl.setAttribute('show', ''); } else { loadingEl.removeAttribute('show'); loadingEl.setAttribute('hide', ''); } } }, // 处理表单输入 handleFormInput(invocation) { const keyword = invocation?.args?.keyword ?? invocation?.keyword ?? ''; this.getOutsideItemEl().then((outsideItem) => { const apiData = outsideItem?.getData() || {}; if (!apiData.auto_think_enable) return; this.fetchThinkResult(keyword); }); }, // 处理搜索提交 handleSearchSubmit(value) { const searchStr = Array.isArray(value) ? value[0] : value; if (!searchStr || !searchStr.trim()) { window.location.href = SEARCH_URL; return; } this.addHistory(searchStr); this.trackSearch(searchStr, 'user_input'); window.location.href = `${SEARCH_URL}?q=${encodeURIComponent(searchStr)}`; }, // 处理历史点击 handleHistory(invocation) { const value = invocation?.args?.value ?? ''; if (!value) return; this.addHistory(value); this.trackSearch(value, 'user_history'); window.location.href = `${SEARCH_URL}?q=${encodeURIComponent(value)}`; }, // 处理热词点击 handleHotKeyword(invocation) { const word = invocation?.args?.word ?? ''; const queryType = invocation?.args?.query_type ?? 'user_keyword'; const url = invocation?.args?.url ?? ''; if (!word) return; this.addHistory(word); this.trackSearch(word, queryType); if (url && !url.includes(SEARCH_URL)) { window.location.href = url; } else { window.location.href = `${SEARCH_URL}?q=${encodeURIComponent(word)}`; } }, // 处理联想结果点击 handleThinkResult(invocation) { const word = invocation?.args?.word ?? ''; if (!word) return; this.addHistory(word); this.trackSearch(word, 'auto_think'); window.location.href = `${SEARCH_URL}?q=${encodeURIComponent(word)}`; }, // 处理清除历史 handleClearHistory() { this.clearHistory(); this.renderSearchHistory(); }, // 处理刷新热词 handleRefreshHot() { this.getOutsideItemEl().then((outsideItem) => { const apiData = outsideItem?.getData() || {}; const searchKeywords = apiData.search_keywords || []; if (searchKeywords.length <= HOT_SEARCH_LEN) return; // 直接调用渲染方法(会使用 _hotList 的分页逻辑) this.renderHotKeywordDirect(); }); }, // 埋点 trackSearch(query, queryType) { const trackQueryType = { 'user_input': 1, 'user_history': 2, 'user_keyword': 3, 'smart_keyword': 4, 'auto_think': 5, 'find_keyword': 6, }; if (window.sa) { window.sa.track('search_request', { event_info: JSON.stringify({ query, query_type: queryType }), function_name: 'smart_search', }); window.sa.registerAID(`smart_search.${trackQueryType[queryType] || 1}.${query}`); } }, // 初始化侧边栏内容渲染(返回 Promise,所有内容渲染完成后 resolve) initSidebarContent() { return Promise.all([ this.renderSearchForm(), this.renderSearchHistory(), this.renderHotKeywordDirect(), ]); }, // 直接渲染热搜词 renderHotKeywordDirect() { const panel = this._getSidebarPanel(); if (!panel) return Promise.resolve(); return this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const apiData = outsideItem.getData() || {}; const searchKeywords = apiData.search_keywords || []; const hotKeywordList = this.getHotKeywordList(searchKeywords); const hotKeywordData = { isShowHotKeyword: searchKeywords.length > 0, list: hotKeywordList, }; const hotKeywordRender = panel.querySelector('[role="hotkeyword"].app-hot-keyword-render-child'); if (hotKeywordRender) { return SPZ.whenApiDefined(hotKeywordRender).then((api) => { api.render(hotKeywordData); }); } }); }, // 获取热搜词列表(带分页逻辑) getHotKeywordList(searchKeywords) { const enrichedList = searchKeywords.map(item => ({ ...item, urlObj: { ...item.url_obj, url: item.url_obj?.type === 'search' ? `${SEARCH_URL}?q=${item.word}` : item.url_obj?.url, }, })); // 用于刷新功能的分页逻辑 if (!this._hotListIndex) { this._hotListIndex = 0; } const startIndex = this._hotListIndex; const endIndex = startIndex + HOT_SEARCH_LEN; const result = enrichedList.slice(startIndex, endIndex); // 更新索引,循环使用 this._hotListIndex = endIndex >= enrichedList.length ? 0 : endIndex; return result.length > 0 ? result : enrichedList.slice(0, HOT_SEARCH_LEN); }, }; // --- 主组件 --- class SpzCustomSmartSearchLocation extends SPZ.BaseElement { constructor(element) { console.log('SpzCustomSmartSearchLocation55'); super(element); this.outsideCarouselIndex = 0; this.insideCarouselIndex = 0; this.searchItemType = 'icon'; this._originalSearchWrapParent = null; this._skipMobileInit = false; this.searchStyleConfig = { ...DEFAULT_SEARCH_STYLE_CONFIG }; this.clickSearchStyleConfig = { ...DEFAULT_CLICK_SEARCH_STYLE_CONFIG }; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.bindResizeListener(); this.registerActions(); // 设置超时降级:如果 API 在 5 秒内没有返回,显示默认样式 this._styleFallbackTimer = setTimeout(() => { if (!this._configLoaded) { this._applyStyleFallback(); } }, 5000); } mountCallback(){ this.safeInit(); } // API 超时/报错时的降级处理 _applyStyleFallback() { const searchWrap = this.getBlockWrap(); if (!searchWrap) return; const searchBtn = searchWrap.querySelector('.app-smart-search-btn'); if (searchBtn && !searchBtn.classList.contains('style-ready')) { searchBtn.classList.add('style-fallback'); } } // 清除降级定时器 _clearFallbackTimer() { if (this._styleFallbackTimer) { clearTimeout(this._styleFallbackTimer); this._styleFallbackTimer = null; } } unmountCallback(){ this.unbindResizeListener(); this.unregisterActions(); } // --- 初始化 --- safeInit() { this.relocatePlugin(); this.applySearchIconClass(); this.adjustLifestyleIcon(); if (!isDesktop() && !this._skipMobileInit && !this._mobileInitDone && templateName !== 'search') { this.initMobileSmartSearch(); this._mobileInitDone = true; } } init() { this.safeInit(); if (this.searchItemType === 'input') { this.initInputMode(); return; } this.initIconMode(); } // --- Action 注册 --- registerActions() { this.registerAction('onSearchInputChange', (invocation) => { this.onSearchInputChange(invocation.args.keyword); }); this.registerAction('onSearchFormSubmit', (invocation) => { this.onSearchFormSubmit(invocation.args.event); }); this.registerAction('onOutsideCarouselIndexChange', (invocation) => { this.outsideCarouselIndex = invocation.args.index || 0; }); this.registerAction('onInsideCarouselIndexChange', (invocation) => { this.insideCarouselIndex = invocation.args.index || 0; }); this.registerAction('getSearchItemType', () => { this.fetchAndApplySearchItemType(); }); this.registerAction('generateHotKeywordList', (invocation) => { this.generateHotKeywordList(invocation.args?.data?.data); }); this.registerAction('onTapHotWord', (invocation) => { this.onTapHotWord(invocation.args.type); }); this.registerAction('onSidebarOpen', () => { this.onSidebarOpen(); }); this.registerAction('onSidebarClose', () => { this.onSidebarClose(); }); this.registerAction('openSidebar', () => { this.openSidebar(); }); this.registerAction('closeSidebar', () => { this.closeSidebar(); }); this.registerAction('expandHistory', () => { this.expandHistory(); }); // 搜索控制器 actions this.registerAction('handleFormInput', (invocation) => { this.handleFormInput(invocation); }); this.registerAction('handleHistory', (invocation) => { this.handleHistory(invocation); }); this.registerAction('handleHotKeyword', (invocation) => { this.handleHotKeyword(invocation); }); this.registerAction('handleThinkResult', (invocation) => { this.handleThinkResult(invocation); }); this.registerAction('handleClearHistory', () => { this.handleClearHistory(); }); this.registerAction('handleRefreshHot', () => { this.handleRefreshHot(); }); } // --- 搜索输入 & 提交 --- onSearchInputChange(keyword) { const hasValue = keyword && keyword.length > 0; const display = hasValue ? 'none' : 'block'; // 控制热词轮播显示 document.querySelectorAll('.hot-words-carousel-inner-container').forEach(el => { el.style.display = display; }); // 设置 input 元素的 has-value 属性(控制清除按钮和热词轮播的 CSS 样式) const panel = this._getSidebarPanel(); if (panel) { const input = panel.querySelector('.smart-search-input'); if (input) { if (hasValue) { input.setAttribute('has-value', ''); } else { input.removeAttribute('has-value'); } } } } onSearchFormSubmit(event) { const keywordArray = event.q || []; const keyword = keywordArray[0]; if (keyword !== null && keyword.length) { this.executeSearch(keywordArray, 1); } else { this.onTapHotWord('inside'); } } executeSearch(value, retryCount) { const searchStr = Array.isArray(value) ? value[0] : value; this.handleSearchSubmit(searchStr); } // --- 搜索项类型 --- fetchAndApplySearchItemType() { this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) { // API 获取失败,应用降级样式 this._applyStyleFallback(); return; } // 清除降级定时器 this._clearFallbackTimer(); const apiData = outsideItem.getData() || {}; const hasHeaderStyle = apiData.header_style && apiData.header_style !== '' && apiData.header_style !== '{}'; const { searchStyleConfig, clickSearchStyleConfig } = parseHeaderStyle(apiData.header_style); this.searchStyleConfig = searchStyleConfig; this.clickSearchStyleConfig = clickSearchStyleConfig; this._configLoaded = true; if (hasHeaderStyle) { this.searchItemType = searchStyleConfig.styleType === 'searchBox' ? 'input' : 'icon'; } else { const type = apiData.search_item_type; if (type) { this.searchItemType = type; } else { this.searchItemType = 'icon'; } this.searchStyleConfig.styleType = this.searchItemType === 'input' ? 'searchBox' : 'imageText'; } this.applySearchStyleConfig(); this.init(); // 接口数据加载完成后,预加载侧边栏 this.preloadSidebar(); }).catch(() => { // API 报错,应用降级样式 this._applyStyleFallback(); }); } // --- 窗口监听 --- bindResizeListener() { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = SPZCore.Types.debounce( this.win, () => { // 防止在 ljs-render 渲染过程中触发重复操作 if (this._isApplyingStyle) return; const overlay = this._getSidebarOverlay && this._getSidebarOverlay(); const overlayOpen = overlay && overlay.getAttribute('data-state') === 'open'; // 多实例场景:检查页面上所有 sidebar overlay,任何一个处于活跃状态都应阻止重初始化 const anyOverlayActive = !!document.querySelector( '.smart-search-sidebar-overlay[data-state="open"],' + '.smart-search-sidebar-overlay[data-state="ready"],' + '.smart-search-sidebar-overlay[data-state="preloading"]' ); const sidebarActive = anyOverlayActive || overlayOpen || this._sidebarState === 'open' || this._sidebarState === 'ready' || this._sidebarState === 'preloading'; if (sidebarActive) { // 仅在 PC/移动端模式切换时关闭弹窗(编辑器预览切换场景) const modeChanged = this._sidebarOpenedAsDesktop !== undefined && this._sidebarOpenedAsDesktop !== isDesktop(); if (modeChanged) { this.closeSidebar(); } // sidebar 处于任何活跃状态时不重新初始化搜索 UI // 防止 initInputMode() 把父容器 display:none 导致搜索插件消失 return; } this.fetchAndApplySearchItemType(); }, DELAY ); window.addEventListener('resize', window.smartSearchResizeCallback); } unbindResizeListener() { if (window.smartSearchResizeCallback) { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = null; } if (this._relocateTimer) { clearInterval(this._relocateTimer); this._relocateTimer = null; } } unregisterActions() { const actionNames = [ 'onSearchInputChange', 'onSearchFormSubmit', 'onOutsideCarouselIndexChange', 'onInsideCarouselIndexChange', 'getSearchItemType', 'generateHotKeywordList', 'onTapHotWord', 'expandHistory', ]; actionNames.forEach((name) => { this.registerAction(name, () => {}); }); } } Object.assign(SpzCustomSmartSearchLocation.prototype, ElementFinderMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, StyleApplicatorMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, SidebarManagerMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, HistoryOverflowMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, HotKeywordsMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, MobileLayoutMixin); Object.assign(SpzCustomSmartSearchLocation.prototype, SearchControllerMixin); SPZ.defineElement(TAG, SpzCustomSmartSearchLocation); class SpzCustomSmartSearchToast extends SPZ.BaseElement { constructor(element) { super(element); this.toastDom = null; this.toastTimeout = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback(){ this.init(); } init(){ const toast = document.createElement('div'); toast.id = 'spz-custom-smart-search-toast-947'; toast.className = 'spz-custom-smart-search-toast'; document.body.appendChild(toast); this.toastDom = toast; this.registerAction('showToast',(invocation)=>{ this.showToast(invocation.args); }); this.registerAction('hideToast',(invocation)=>{ this.hideToast(invocation.args); }); } showToast({ message, duration = 2000 }){ if( !this.toastDom ) return; this.toastDom.innerHTML = message; this.toastDom.classList.add('smart-search-toast-show'); clearTimeout(this.toastTimeout); this.toastTimeout = setTimeout(() => { this.hideToast(); }, duration); } hideToast(){ if( !this.toastDom ) return; this.toastDom.classList.remove('smart-search-toast-show'); } } SPZ.defineElement('spz-custom-smart-search-toast', SpzCustomSmartSearchToast); class SpzCustomSmartSearchCookie extends SPZ.BaseElement { constructor(element) { super(element); } buildCallback() { this.registerAction('getCookie',(invocation)=>{ this.getCookie(invocation.args); }); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } getCookie(key) { let cookieMap = {} document.cookie.split(';').map(item=>{ let [key, value] = item.trim().split('=') cookieMap[key] = value }) return cookieMap[key] || ''; } } SPZ.defineElement('spz-custom-smart-search-cookie', SpzCustomSmartSearchCookie); const default_function_name = 'smart_search'; const default_plugin_name = 'smart_search'; const default_module_type = 'smart_search'; const default_module = 'apps'; const default_business_type = 'product_plugin'; const default_event_developer = 'ray'; class SpzCustomSmartSearchTrack extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.registerAction('track', (invocation) => { const { trackType, trackData } = invocation.args; this.track({trackType, trackData}); }); } track({trackType, trackData}) { const { function_name, plugin_name, module_type, module, business_type, event_developer, event_type, event_desc, trackEventInfo, ...otherTrackData } = trackData; window.sa.track(trackType, { function_name: function_name || default_function_name, plugin_name: plugin_name || default_plugin_name, module_type: module_type || default_module_type, module: module || default_module, business_type: business_type || default_business_type, event_developer: event_developer || default_event_developer, event_type: event_type, event_desc: event_desc, ...otherTrackData, event_info: JSON.stringify({ ...(trackEventInfo || {}), }), }); } } SPZ.defineElement('spz-custom-smart-search-track', SpzCustomSmartSearchTrack);
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
1/15
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft
1/15

Leopard 5D DIY Diamond Painting Handmade Tissue Holder Wooden Tissue Box Craft

£16.53
£16.53
Save 0%
class SpzCustomDiscountFlashsale extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.getFlashSaleApi = "\/api\/storefront\/promotion\/flashsale\/display_setting\/product_setting"; this.timer = null; this.variantId = "62832d27-8fd8-42b4-ad20-57508532daef"; // 促销活动数据 this.flashsaleData = {} } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.templates_ = SPZServices.templatesForDoc(); this.viewport_ = this.getViewport(); // 挂载bind函数 解决this指向问题 this.render = this.render.bind(this); this.resize = this.resize.bind(this); this.switchVariant = this.switchVariant.bind(this); } mountCallback() { // 获取数据 this.getData(); this.element.onclick = (e) => { const cur = this.win.document.querySelector(".app_discount_flashsale_desc"); const setting = this.flashsaleData.product_setting; const landingUrl = `/promotions/discount-default/${this.flashsaleData.discount_info.id}`; const finalUrl = appDiscountUtils.resolveDiscountHref(setting, landingUrl); if (finalUrl && appDiscountUtils.inProductBody(this.element) && e.target !== cur) { this.win.open(finalUrl, '_blank', 'noopener'); } } // 绑定 this.viewport_.onResize(this.resize); // 监听子款式切换,重新渲染 this.win.document.addEventListener('dj.variantChange', this.switchVariant); } unmountCallback() { // 解绑 this.viewport_.removeResize(this.resize); this.win.document.removeEventListener('dj.variantChange', this.switchVariant); // 清除定时器 if (this.timer) { clearTimeout(this.timer); this.timer = null; } } resize() { if (this.timer) { clearTimeout(this.timer) this.timer = null; } this.timer = setTimeout(() => { this.render(); }, 200) } switchVariant(event) { const variant = event.detail.selected; if (variant.product_id == 'ed857109-dd60-4574-86de-de769e86873e' && variant.id != this.variantId) { this.variantId = variant.id; this.getData(); } } getData() { const reqBody = { product_id: "ed857109-dd60-4574-86de-de769e86873e", product_type: "default", variant_id: this.variantId } this.flashsaleData = {}; this.win.fetch(this.getFlashSaleApi, { method: "POST", body: JSON.stringify(reqBody), headers: { "Content-Type": "application/json" } }).then(async (response) => { if (response.ok) { this.flashsaleData = await response.json(); this.render(); } else { this.clearDom(); } }).catch(err => { this.clearDom(); }); } clearDom() { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); } render() { this.templates_ .findAndRenderTemplate(this.element, { isMobile: appDiscountUtils.judgeMobile(), isRTL: appDiscountUtils.judgeRTL(), inProductDetail: appDiscountUtils.inProductBody(this.element), flashsaleData: this.flashsaleData, image_domain: this.win.SHOPLAZZA.image_domain, }) .then((el) => { this.clearDom(); this.element.appendChild(el); }) } } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
Quantity
Free Shipping Over £50【Uk (After Discount )】
£5.99 Shipping Fee【Uk】
Secure payments
Specification:
Origin: Mainland China
Material: Wood
Product Size: 225.00 x 135.00 x 105.00 mm / 8.86 x 5.31 x 4.13 inches

Note:
Due to different monitor settings and lighting conditions, the actual color of the item may vary slightly from the pictures. Thanks for your understanding!
Please allow a 1-2 cm difference in measurements due to manual measuring.



Package Content:
6Pcs x Wooden Boards
1 x Tool Kit
1 x Drill Kit

Standard shipping fee is £4.99(UK)

Shipment takes 7 to 20 business days(UK)

Shipping and Delivery time

At uk.diamondpaintinggifts.com, we care about the speed of delivery. We understand that the delivery of goods to your hand nimbly is important.

About Shipping
Receiving time = Processing time +Shipping time 
Processing time: 1-2 business days.This typically takes 1 to 2 days; however, it may take longer time due to order surge.
Free Shipping:7-20 business days

NOTES:

1.Order Processing: The amount of time it takes for us to prepare your order for shipping. This typically takes 1 to 2 days; however, it may take longer time due to order surge.
2. Delivery time: The amount of time it takes to receive your order after your order has been shipped. Delivery times can vary depending on your location and shipping methods. Please check details below.
3. We offer free shipping world without checking number. Direct Line delivery and Express delivery if your order reach certain amount, check details below.
4. Direct Line delivery and Express delivery have specific tracking information and can be tracked through “My Order” section in your account or “Order Status” on the top of uk.diamondpaintinggifts.com website.

Track Your Order

It may take up to 5 business days after your order has shipped for your tracking information to become available online (it might take longer depending on how fast the postal services are processing shipments).

We accept the following payment method:

-PayPal

PayPal: the most convenient payment method in the world

We primarily uses PayPal to process secure payments. Through PayPal, we accept MasterCard, VISA, American Express, Discover, and bank transfer (debit card).You can connect your PayPal, credit card, debit card or bank account to PayPal for purchasing some of our products. After submitting an order, you will be redirected to PayPal to complete the transaction.
1.Log in to your PayPal account or use Credit Card Express;
2.Enter your card details and the order will be shipped to your PayPal address. Then click “Submit”;
3.Your payment will be processed and an invoice will be sent to your e-mail address;
NOTE: Your order will be shipped to your PayPal address. Please ensure that it is correct and complete.

About Diamond Painting:


What is Diamond Painting?
Similar to both cross-stitch and paint-by-numbers, diamond painting is a new creative hobby that has taken the world by storm, especially fans of DIY crafts. Crafters all around the world have fallen in love with this activity because it is easy to learn and incredibly rewarding. Even novices and people who struggle with other crafts find diamond painting relaxing and enjoyable. Mastering the basics is a breeze, and people of all ages and skill levels can create breathtaking artworks.

What’s Included in a Diamond Painting Kit?
Our Diamond Painting kits include a canvas and a set of painting tools (Pen, Tray, Wax , Rhinestones)【Without Frame】

How do I get started?
Really, any of our diamond painting kits are a great way to get started, because they come with everything you need!
What we recommend to start with is a smaller sized diamond painting, so you can make sure it's something you enjoy and that you don't bite off more than you can chew. Some diamond paintings take weeks!

How to Use Discount Code?
The discount can be applied on the payment page. Just copy and paste your code and select "Apply" to redeem.

What is the best size for diamond painting?

There are different sizes of diamond painting Kits. The bigger the size of a canvas, the better the effect you will get at the end. Smaller canvas can give a “Lego brick” effect, while bigger canvas give a more realistic piece of art.

Note:The size indicated in our title are canvas dimensions and not picture size.

About Delivery:

How much will delivery cost?(To UK)

Delivery fees costs vary based on the delivery window.
For Standard Shipping(7-25 days), Order Value below £50, shipping fee is £5.99;Order Value over £50, free shipping.
IMPORTANT:Shipping fee is calculated at the discounted price

For Fast Shipping (7-10days),Shipping fee on all orders is £46.99.(If you choose Fast Shipping, in order to deliver faster, please leave a message to note "Fast Shipping")

How can I qualify for free delivery?

Free delivery on purchases over £50 (after discount)*

How do I place a Standard Delivery order?

To place a standard shipping order, simply add the product to your cart, select your shipping address and fill in the information. Follow the checkout process to complete your order.

How do I place a Fast Delivery order?

To place a Fast Shipping order, simply add the product to your cart, select your shipping address and fill in the information. Follow the checkout process to complete your order.(in order to deliver faster, please leave a message to note "Fast Shipping")

Hot Sale Collection List