• FREE SHIPPING ORDER OVER $45

  • CHRISTMAS GIFT EDITION - SAVE UP TO 70% OFF

  • FREE SHIPPING ORDER OVER $45

  • FREE SHIPPING ORDER OVER $45

  • CHRISTMAS GIFT EDITION - SAVE UP TO 70% OFF

  • FREE SHIPPING ORDER OVER $45

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; // --- 工具函数 --- 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() { return window.matchMedia(`(min-width: ${BREAKPOINT}px)`).matches; } // --- 主题配置 --- 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: '#shoplaza-section-header .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'); // 插件位置纠正配置:当商家将插件插入到不可见的区域时,自动迁移到正确的 DOM 位置 // pc / mobile 分别指定 PC 端和移动端的目标父容器选择器,未配置则不做迁移 const PLUGIN_RELOCATION_CONFIG = resolveThemeValue({ reformia: { pc: '.header-layout .header__actions', mobile: '.header-layout .header__actions', }, }, null); // --- 组件 --- class SpzCustomSmartSearchLocation extends SPZ.BaseElement { constructor(element) { super(element); this.outsideCarouselIndex = 0; this.insideCarouselIndex = 0; this.searchItemType = 'icon'; this._originalSearchWrapParent = null; this._skipMobileInit = false; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.bindResizeListener(); this.registerActions(); } mountCallback(){ this.init(); } unmountCallback(){ this.unbindResizeListener(); this.unregisterActions(); } // --- 元素查找(支持 DocumentFragment 上下文)--- 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-71'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-71'); } // --- 插件位置纠正 --- 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-71'); 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); } // --- 初始化 --- init() { this.relocatePlugin(); this.applySearchIconClass(); this.adjustLifestyleIcon(); if (this.searchItemType === 'input') { this.initInputMode(); return; } // icon 模式 this.initIconMode(); if (isDesktop()) return; if (this._skipMobileInit) return; // icon 模式下的移动端额外处理(处理主题特定的 header 布局) if (!window.__isLoadAppSmartSearch__) { this.initMobileSmartSearch(); if (window.self === window.top) { window.__isLoadAppSmartSearch__ = true; } } } 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; const container = this.getBlockContainer(); if (!container) return; const alreadyMoved = !!document.querySelector( '.header__wrapper .container .row.header>div>#app-smart-product-search-container-71' ); if (alreadyMoved) return; const headerDivs = document.querySelectorAll('.header__wrapper .container .row.header>div'); const lastDiv = headerDivs[headerDivs.length - 1]; lastDiv.appendChild(container); } 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()) { // PC 端:确保 searchWrap 在原始位置并显示 if (mobileContainer) mobileContainer.style.display = 'none'; if (searchWrap && this._originalSearchWrapParent) { // 如果 searchWrap 被移到了移动端容器,移回原始位置 if (mobileContainer && mobileContainer.contains(searchWrap)) { this._originalSearchWrapParent.appendChild(searchWrap); } } if (pcContainer) pcContainer.style.display = 'block'; return; } if (templateName === 'search') { this._skipMobileInit = true; return; } // 移动端:隐藏当前实例的 PC 容器 if (pcContainer) pcContainer.style.display = 'none'; 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) { // 已有其他实例,当前实例不需要移动,保持隐藏即可 return; } // 将当前实例的 searchWrap 移到移动端容器 if (searchWrap && !mobileContainerAfterEnsure.contains(searchWrap)) { mobileContainerAfterEnsure.appendChild(searchWrap); } mobileContainerAfterEnsure.style.display = ''; } ensureMobileSearchContainer() { if (document.querySelector('.smart-search-mobile-container')) return; const container = document.createElement('div'); container.classList.add('smart-search-mobile-container'); container.classList.add('smart-search-mobile-container-' + THEME_NAME.toLocaleLowerCase()); document.querySelector(HEADER_SELECTOR).appendChild(container); } initIconMode() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.style.display = 'flex'; }); } initMobileSmartSearch() { if (this.hasMobilePluginParent()) { this.showMobileSmartSearch(); } else { this.addMobileSmartSearch(); } } // --- 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); }); } // --- 搜索输入 & 提交 --- onSearchInputChange(keyword) { const display = (!keyword || !keyword.length) ? 'block' : 'none'; document.querySelectorAll('.hot-words-carousel-inner-container').forEach(el => { el.style.display = display; }); } 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) { this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; try { ljsSearch.handleSearchSubmit_({ value }); } catch (e) { if (retryCount < 3) { this.executeSearch(value, retryCount + 1); return; } const searchStr = value[0] || ''; const searchResult = ljsSearch.setThinkSearchData_(searchStr); ljsSearch.afterSearching({ query: searchResult.query, url: `${SEARCH_URL}?q=${searchStr}`, queryType: searchResult.queryType, }); } }); } // --- 搜索项类型 --- fetchAndApplySearchItemType() { this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const type = outsideItem.getData()?.search_item_type; this.searchItemType = type || this.searchItemType; this.init(); }); } // --- 热词 --- 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 }); }); }); } // --- 底纹词工具方法 --- // 将 find_keywords(字符串数组)转换为统一的关键词对象格式 // 优先使用 find_keywords,兜底使用 search_keywords normalizeOutsideKeywords(findKeywords, searchKeywords) { 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 || []; } // 规范化关键词项的 URL 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 || []; // 外部和内部 carousel 都使用相同逻辑:优先 find_keywords,兜底 search_keywords const keywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); const currentItem = this.normalizeKeywordUrl(keywords[index] || null); this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; if (currentItem) { ljsSearch.handleHotKeyword_({ 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 carouselKeywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); return { ...apiData, search_keywords: carouselKeywords, outsideCarouselIndex: this.outsideCarouselIndex, }; }); } // --- 窗口监听 --- bindResizeListener() { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = SPZCore.Types.debounce( this.win, () => { 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', ]; actionNames.forEach((name) => { this.registerAction(name, () => {}); }); } // --- 移动端布局:插件父容器模式 --- hasMobilePluginParent() { // reformia 使用 relocatePlugin 统一处理,不走 showMobileSmartSearch return !['geek', 'flash', 'boost', 'reformia'].includes(THEME_NAME.toLocaleLowerCase()); } showMobileSmartSearch() { 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'; } } } isSmartSearchElement(el) { return ( el.classList.contains(SEARCH_CONTAINER_CLASS) || el.querySelectorAll(`.${SEARCH_CONTAINER_CLASS}`).length > 0 ); } // --- 移动端布局:图标插入模式 --- addMobileSmartSearch() { 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); } } 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-71'; 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);
  • Best Seller
  • New In
  • Shop By Holiday
      Christmas Day New Year Valentine's Day Mother's Day Father's Day Graduation Day Halloween Thanks-Giving Day
  • Shop For
      Granddaughter Daughter Grandson Son Mother Wife/Girlfriend Self Memorial Sister Friends Grandmother Anyone
  • Shop By Category
      Necklaces Rings Bracelets Earrings Anklets Jewelry Gift Packing
  • More links

37Necklaces 37Necklaces 37Necklaces

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; // --- 工具函数 --- 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() { return window.matchMedia(`(min-width: ${BREAKPOINT}px)`).matches; } // --- 主题配置 --- 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: '#shoplaza-section-header .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'); // 插件位置纠正配置:当商家将插件插入到不可见的区域时,自动迁移到正确的 DOM 位置 // pc / mobile 分别指定 PC 端和移动端的目标父容器选择器,未配置则不做迁移 const PLUGIN_RELOCATION_CONFIG = resolveThemeValue({ reformia: { pc: '.header-layout .header__actions', mobile: '.header-layout .header__actions', }, }, null); // --- 组件 --- class SpzCustomSmartSearchLocation extends SPZ.BaseElement { constructor(element) { super(element); this.outsideCarouselIndex = 0; this.insideCarouselIndex = 0; this.searchItemType = 'icon'; this._originalSearchWrapParent = null; this._skipMobileInit = false; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.bindResizeListener(); this.registerActions(); } mountCallback(){ this.init(); } unmountCallback(){ this.unbindResizeListener(); this.unregisterActions(); } // --- 元素查找(支持 DocumentFragment 上下文)--- 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-102'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-102'); } // --- 插件位置纠正 --- 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-102'); 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); } // --- 初始化 --- init() { this.relocatePlugin(); this.applySearchIconClass(); this.adjustLifestyleIcon(); if (this.searchItemType === 'input') { this.initInputMode(); return; } // icon 模式 this.initIconMode(); if (isDesktop()) return; if (this._skipMobileInit) return; // icon 模式下的移动端额外处理(处理主题特定的 header 布局) if (!window.__isLoadAppSmartSearch__) { this.initMobileSmartSearch(); if (window.self === window.top) { window.__isLoadAppSmartSearch__ = true; } } } 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; const container = this.getBlockContainer(); if (!container) return; const alreadyMoved = !!document.querySelector( '.header__wrapper .container .row.header>div>#app-smart-product-search-container-102' ); if (alreadyMoved) return; const headerDivs = document.querySelectorAll('.header__wrapper .container .row.header>div'); const lastDiv = headerDivs[headerDivs.length - 1]; lastDiv.appendChild(container); } 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()) { // PC 端:确保 searchWrap 在原始位置并显示 if (mobileContainer) mobileContainer.style.display = 'none'; if (searchWrap && this._originalSearchWrapParent) { // 如果 searchWrap 被移到了移动端容器,移回原始位置 if (mobileContainer && mobileContainer.contains(searchWrap)) { this._originalSearchWrapParent.appendChild(searchWrap); } } if (pcContainer) pcContainer.style.display = 'block'; return; } if (templateName === 'search') { this._skipMobileInit = true; return; } // 移动端:隐藏当前实例的 PC 容器 if (pcContainer) pcContainer.style.display = 'none'; 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) { // 已有其他实例,当前实例不需要移动,保持隐藏即可 return; } // 将当前实例的 searchWrap 移到移动端容器 if (searchWrap && !mobileContainerAfterEnsure.contains(searchWrap)) { mobileContainerAfterEnsure.appendChild(searchWrap); } mobileContainerAfterEnsure.style.display = ''; } ensureMobileSearchContainer() { if (document.querySelector('.smart-search-mobile-container')) return; const container = document.createElement('div'); container.classList.add('smart-search-mobile-container'); container.classList.add('smart-search-mobile-container-' + THEME_NAME.toLocaleLowerCase()); document.querySelector(HEADER_SELECTOR).appendChild(container); } initIconMode() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.style.display = 'flex'; }); } initMobileSmartSearch() { if (this.hasMobilePluginParent()) { this.showMobileSmartSearch(); } else { this.addMobileSmartSearch(); } } // --- 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); }); } // --- 搜索输入 & 提交 --- onSearchInputChange(keyword) { const display = (!keyword || !keyword.length) ? 'block' : 'none'; document.querySelectorAll('.hot-words-carousel-inner-container').forEach(el => { el.style.display = display; }); } 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) { this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; try { ljsSearch.handleSearchSubmit_({ value }); } catch (e) { if (retryCount < 3) { this.executeSearch(value, retryCount + 1); return; } const searchStr = value[0] || ''; const searchResult = ljsSearch.setThinkSearchData_(searchStr); ljsSearch.afterSearching({ query: searchResult.query, url: `${SEARCH_URL}?q=${searchStr}`, queryType: searchResult.queryType, }); } }); } // --- 搜索项类型 --- fetchAndApplySearchItemType() { this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const type = outsideItem.getData()?.search_item_type; this.searchItemType = type || this.searchItemType; this.init(); }); } // --- 热词 --- 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 }); }); }); } // --- 底纹词工具方法 --- // 将 find_keywords(字符串数组)转换为统一的关键词对象格式 // 优先使用 find_keywords,兜底使用 search_keywords normalizeOutsideKeywords(findKeywords, searchKeywords) { 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 || []; } // 规范化关键词项的 URL 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 || []; // 外部和内部 carousel 都使用相同逻辑:优先 find_keywords,兜底 search_keywords const keywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); const currentItem = this.normalizeKeywordUrl(keywords[index] || null); this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; if (currentItem) { ljsSearch.handleHotKeyword_({ 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 carouselKeywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); return { ...apiData, search_keywords: carouselKeywords, outsideCarouselIndex: this.outsideCarouselIndex, }; }); } // --- 窗口监听 --- bindResizeListener() { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = SPZCore.Types.debounce( this.win, () => { 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', ]; actionNames.forEach((name) => { this.registerAction(name, () => {}); }); } // --- 移动端布局:插件父容器模式 --- hasMobilePluginParent() { // reformia 使用 relocatePlugin 统一处理,不走 showMobileSmartSearch return !['geek', 'flash', 'boost', 'reformia'].includes(THEME_NAME.toLocaleLowerCase()); } showMobileSmartSearch() { 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'; } } } isSmartSearchElement(el) { return ( el.classList.contains(SEARCH_CONTAINER_CLASS) || el.querySelectorAll(`.${SEARCH_CONTAINER_CLASS}`).length > 0 ); } // --- 移动端布局:图标插入模式 --- addMobileSmartSearch() { 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); } } 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-102'; 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);
  • Log in
  • Create an account
0
  • Best Seller
  • New In
  • Shop By Holiday
    • Shop By Holiday
    • Christmas Day
    • New Year
    • Valentine's Day
    • Mother's Day
    • Father's Day
    • Graduation Day
    • Halloween
    • Thanks-Giving Day
  • Shop For
    • Shop For
    • Granddaughter
    • Daughter
    • Grandson
    • Son
    • Mother
    • Wife/Girlfriend
    • Self
    • Memorial
    • Sister
    • Friends
    • Grandmother
    • Anyone
  • Shop By Category
    • Shop By Category
    • Necklaces
    • Rings
    • Bracelets
    • Earrings
    • Anklets
    • Jewelry Gift Packing
  • Log in
  • Create an account
  • 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; // --- 工具函数 --- 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() { return window.matchMedia(`(min-width: ${BREAKPOINT}px)`).matches; } // --- 主题配置 --- 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: '#shoplaza-section-header .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'); // 插件位置纠正配置:当商家将插件插入到不可见的区域时,自动迁移到正确的 DOM 位置 // pc / mobile 分别指定 PC 端和移动端的目标父容器选择器,未配置则不做迁移 const PLUGIN_RELOCATION_CONFIG = resolveThemeValue({ reformia: { pc: '.header-layout .header__actions', mobile: '.header-layout .header__actions', }, }, null); // --- 组件 --- class SpzCustomSmartSearchLocation extends SPZ.BaseElement { constructor(element) { super(element); this.outsideCarouselIndex = 0; this.insideCarouselIndex = 0; this.searchItemType = 'icon'; this._originalSearchWrapParent = null; this._skipMobileInit = false; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.bindResizeListener(); this.registerActions(); } mountCallback(){ this.init(); } unmountCallback(){ this.unbindResizeListener(); this.unregisterActions(); } // --- 元素查找(支持 DocumentFragment 上下文)--- 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-975'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-975'); } // --- 插件位置纠正 --- 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-975'); 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); } // --- 初始化 --- init() { this.relocatePlugin(); this.applySearchIconClass(); this.adjustLifestyleIcon(); if (this.searchItemType === 'input') { this.initInputMode(); return; } // icon 模式 this.initIconMode(); if (isDesktop()) return; if (this._skipMobileInit) return; // icon 模式下的移动端额外处理(处理主题特定的 header 布局) if (!window.__isLoadAppSmartSearch__) { this.initMobileSmartSearch(); if (window.self === window.top) { window.__isLoadAppSmartSearch__ = true; } } } 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; const container = this.getBlockContainer(); if (!container) return; const alreadyMoved = !!document.querySelector( '.header__wrapper .container .row.header>div>#app-smart-product-search-container-975' ); if (alreadyMoved) return; const headerDivs = document.querySelectorAll('.header__wrapper .container .row.header>div'); const lastDiv = headerDivs[headerDivs.length - 1]; lastDiv.appendChild(container); } 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()) { // PC 端:确保 searchWrap 在原始位置并显示 if (mobileContainer) mobileContainer.style.display = 'none'; if (searchWrap && this._originalSearchWrapParent) { // 如果 searchWrap 被移到了移动端容器,移回原始位置 if (mobileContainer && mobileContainer.contains(searchWrap)) { this._originalSearchWrapParent.appendChild(searchWrap); } } if (pcContainer) pcContainer.style.display = 'block'; return; } if (templateName === 'search') { this._skipMobileInit = true; return; } // 移动端:隐藏当前实例的 PC 容器 if (pcContainer) pcContainer.style.display = 'none'; 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) { // 已有其他实例,当前实例不需要移动,保持隐藏即可 return; } // 将当前实例的 searchWrap 移到移动端容器 if (searchWrap && !mobileContainerAfterEnsure.contains(searchWrap)) { mobileContainerAfterEnsure.appendChild(searchWrap); } mobileContainerAfterEnsure.style.display = ''; } ensureMobileSearchContainer() { if (document.querySelector('.smart-search-mobile-container')) return; const container = document.createElement('div'); container.classList.add('smart-search-mobile-container'); container.classList.add('smart-search-mobile-container-' + THEME_NAME.toLocaleLowerCase()); document.querySelector(HEADER_SELECTOR).appendChild(container); } initIconMode() { document.querySelectorAll('.app-smart-icon-search-large').forEach(el => { el.style.display = 'flex'; }); } initMobileSmartSearch() { if (this.hasMobilePluginParent()) { this.showMobileSmartSearch(); } else { this.addMobileSmartSearch(); } } // --- 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); }); } // --- 搜索输入 & 提交 --- onSearchInputChange(keyword) { const display = (!keyword || !keyword.length) ? 'block' : 'none'; document.querySelectorAll('.hot-words-carousel-inner-container').forEach(el => { el.style.display = display; }); } 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) { this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; try { ljsSearch.handleSearchSubmit_({ value }); } catch (e) { if (retryCount < 3) { this.executeSearch(value, retryCount + 1); return; } const searchStr = value[0] || ''; const searchResult = ljsSearch.setThinkSearchData_(searchStr); ljsSearch.afterSearching({ query: searchResult.query, url: `${SEARCH_URL}?q=${searchStr}`, queryType: searchResult.queryType, }); } }); } // --- 搜索项类型 --- fetchAndApplySearchItemType() { this.getOutsideItemEl().then((outsideItem) => { if (!outsideItem) return; const type = outsideItem.getData()?.search_item_type; this.searchItemType = type || this.searchItemType; this.init(); }); } // --- 热词 --- 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 }); }); }); } // --- 底纹词工具方法 --- // 将 find_keywords(字符串数组)转换为统一的关键词对象格式 // 优先使用 find_keywords,兜底使用 search_keywords normalizeOutsideKeywords(findKeywords, searchKeywords) { 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 || []; } // 规范化关键词项的 URL 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 || []; // 外部和内部 carousel 都使用相同逻辑:优先 find_keywords,兜底 search_keywords const keywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); const currentItem = this.normalizeKeywordUrl(keywords[index] || null); this.getSmartSearchEl().then((ljsSearch) => { if (!ljsSearch) return; if (currentItem) { ljsSearch.handleHotKeyword_({ 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 carouselKeywords = this.normalizeOutsideKeywords(findKeywords, searchKeywords); return { ...apiData, search_keywords: carouselKeywords, outsideCarouselIndex: this.outsideCarouselIndex, }; }); } // --- 窗口监听 --- bindResizeListener() { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = SPZCore.Types.debounce( this.win, () => { 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', ]; actionNames.forEach((name) => { this.registerAction(name, () => {}); }); } // --- 移动端布局:插件父容器模式 --- hasMobilePluginParent() { // reformia 使用 relocatePlugin 统一处理,不走 showMobileSmartSearch return !['geek', 'flash', 'boost', 'reformia'].includes(THEME_NAME.toLocaleLowerCase()); } showMobileSmartSearch() { 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'; } } } isSmartSearchElement(el) { return ( el.classList.contains(SEARCH_CONTAINER_CLASS) || el.querySelectorAll(`.${SEARCH_CONTAINER_CLASS}`).length > 0 ); } // --- 移动端布局:图标插入模式 --- addMobileSmartSearch() { 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); } } 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-975'; 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);

Top searched

S925 Phoenix Dancing Necklace S925 Phoenix Dancing Necklace

S925 Phoenix Dancing Necklace

from $25.90 $48.90
Save 47%
S925 The Fire inside Me  Burns Brighter  than the Fire around Me Flying Phoenix necklace S925 The Fire inside Me  Burns Brighter  than the Fire around Me Flying Phoenix necklace

S925 The Fire inside Me Burns Brighter than the Fire around Me Flying Phoenix necklace

from $34.90 $49.90
Save 30%
For Self - S925 I Survived Because The Fire Inside Me Burns Brighter Than The Fire Around Me Colorful Crystal Phoenix Necklace - Orange For Self - S925 I Survived Because The Fire Inside Me Burns Brighter Than The Fire Around Me Colorful Crystal Phoenix Necklace - Orange

For Self - S925 I Survived Because The Fire Inside Me Burns Brighter Than The Fire Around Me Colorful Crystal Phoenix Necklace - Orange

from $34.90 $54.90
Save 36%
For Self - S925 The Fire inside me Burns Brighter  than the Fire around Me Gold Phoenix Necklace For Self - S925 The Fire inside me Burns Brighter  than the Fire around Me Gold Phoenix Necklace

For Self - S925 The Fire inside me Burns Brighter than the Fire around Me Gold Phoenix Necklace

from $46.90 $66.90
Save 30%
S925 Crystal Phoenix Earrings S925 Crystal Phoenix Earrings

S925 Crystal Phoenix Earrings

$32.90
For Self - S925 I Had Fire in My Soul Wing Phoenix Crystal Necklace For Self - S925 I Had Fire in My Soul Wing Phoenix Crystal Necklace

For Self - S925 I Had Fire in My Soul Wing Phoenix Crystal Necklace

from $39.90
47 Products
47 Products
    We are Forever LInked Together Christmas Ornament

    We are Forever LInked Together Christmas Ornament

    $8.90
    FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME BRAIDED BRACELET FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME BRAIDED BRACELET

    FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME BRAIDED BRACELET

    from $14.90 $49.90
    Save 70%
    S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Rose Gold S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Rose Gold

    S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Rose Gold

    from $14.90
    Magnetic Book Box Magnetic Book Box

    Magnetic Book Box

    $15.00
    Cross Infinite Simple Ring Cross Infinite Simple Ring

    Cross Infinite Simple Ring

    $9.90
    Christmas Gift Box

    Christmas Gift Box

    $10.00
    S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Gold S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Gold

    S925 Even Though Life May be Hard Right Now It'll be Beautiful When You Get to The Top Ring in Gold

    from $14.90
    Nightmare Jack and Sally Earrings Nightmare Jack and Sally Earrings

    Nightmare Jack and Sally Earrings

    $15.90
    Linked Earrings Linked Earrings

    Linked Earrings

    $9.90
    Fruit Stack Earrings Fruit Stack Earrings

    Fruit Stack Earrings

    $9.90
    FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME INFINITY HEART BEAT BRACELET FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME INFINITY HEART BEAT BRACELET

    FOR FRIEND - OUR FRIENDSHIP MEANS THE WORLD TO ME INFINITY HEART BEAT BRACELET

    from $14.90 $49.90
    Save 70%
    Balance Simple Stackable Ring Balance Simple Stackable Ring

    Balance Simple Stackable Ring

    $9.90
    Simple Stack Earrings Simple Stack Earrings

    Simple Stack Earrings

    $9.90
    Stars Stack Earrings Stars Stack Earrings

    Stars Stack Earrings

    from $9.90
    Pearl Square Simple Stackable Ring Pearl Square Simple Stackable Ring

    Pearl Square Simple Stackable Ring

    $12.90
    For Friend -  Our Friendship Means The World To Me Braided Bracelet For Friend -  Our Friendship Means The World To Me Braided Bracelet

    For Friend - Our Friendship Means The World To Me Braided Bracelet

    from $14.90 $49.90
    Save 70%
Sorry, there are no products in this collection.
Load more
Be the first one to know about new arrivals, tips and more.
Thanks for subscribing
ABOUT 37NECKLACES
  • Track your order
  • About us
  • Contact us
  • S925 jewel care
  • FAQs
Policy
  • Shipping Policy
  • Returns & Exchanges
  • Payment Policy
  • Privacy Policy
  • Terms of Service
Get in touch
support@37necklaces.com

Follow us
WE ACCEPT
American Express PayPal Visa Google Pay Diners Club Mastercard Discover
© 2026 37Necklaces 
Buy Engraved Jewelry

Sign up and save

Entice customers to sign up for your mailing list with discounts or exclusive offers. Include an image for extra impact.
Thanks for subscribing
No Thanks