• 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-24'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-24'); } // --- 插件位置纠正 --- 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-24'); 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-24' ); 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-24'; 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-910'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-910'); } // --- 插件位置纠正 --- 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-910'); 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-910' ); 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-910'; 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-107'); } getOutsideItemEl() { return this.resolveBlockElement('.app-smart-search-outside-item', 'app-smart-search-outside-item-107'); } // --- 插件位置纠正 --- 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-107'); 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-107' ); 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-107'; 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

Sisters always stick together through thick and thin.

13 Products
13 Products
    For Friend-When Fate Brought Us Together We Became Sisters at Heart Crystal Necklace For Friend-When Fate Brought Us Together We Became Sisters at Heart Crystal Necklace

    For Friend-When Fate Brought Us Together We Became Sisters at Heart Crystal Necklace

    from $35.90 $55.90
    Save 36%
    For Sister - S925 Big Sis and Lil Sis Forever Linked Together Sterling Silver Circle Necklace For Sister - S925 Big Sis and Lil Sis Forever Linked Together Sterling Silver Circle Necklace

    For Sister - S925 Big Sis and Lil Sis Forever Linked Together Sterling Silver Circle Necklace

    from $44.90
    For Sister - My Life is Better With You Book Necklace For Sister - My Life is Better With You Book Necklace

    For Sister - My Life is Better With You Book Necklace

    from $39.90 $59.90
    Save 33%
    For Sisters - Best Sis Ever Book Necklace For Sisters - Best Sis Ever Book Necklace

    For Sisters - Best Sis Ever Book Necklace

    from $39.90 $59.90
    Save 33%
    For Sister - My Incredible Sister Book Necklace For Sister - My Incredible Sister Book Necklace

    For Sister - My Incredible Sister Book Necklace

    $39.90 $69.90
    Save 43%
    For Unbiological Daughter - Crystal Sister Necklace For Unbiological Daughter - Crystal Sister Necklace

    For Unbiological Daughter - Crystal Sister Necklace

    from $34.90 $54.90
    Save 36%
    For Friend - I Love You Diamond Knot Bracelet For Friend - I Love You Diamond Knot Bracelet

    For Friend - I Love You Diamond Knot Bracelet

    from $29.90 $55.80
    Save 46%
    For Friend - Not Sisters By Blood But Sisters By Heart Infinity Bracelet For Friend - Not Sisters By Blood But Sisters By Heart Infinity Bracelet

    For Friend - Not Sisters By Blood But Sisters By Heart Infinity Bracelet

    from $29.80
    For Sister - S925 A Sister is God's Way of Making Sure We Never Walk Alone Sister Crystal Necklace For Sister - S925 A Sister is God's Way of Making Sure We Never Walk Alone Sister Crystal Necklace

    For Sister - S925 A Sister is God's Way of Making Sure We Never Walk Alone Sister Crystal Necklace

    from $34.90 $54.90
    Save 36%
    For Sister - S925 If You Need Me I'll Always be There Crystal Tree of Life Necklace For Sister - S925 If You Need Me I'll Always be There Crystal Tree of Life Necklace

    For Sister - S925 If You Need Me I'll Always be There Crystal Tree of Life Necklace

    from $44.90
    For Sister - S925 The Friendship Between Sisters is Unbroken Heart to Heart Bracelet For Sister - S925 The Friendship Between Sisters is Unbroken Heart to Heart Bracelet

    For Sister - S925 The Friendship Between Sisters is Unbroken Heart to Heart Bracelet

    from $44.90
    For Sister - S925 A Sister is GOD's Way of Making Sure We Never Walk Alone Crystal Tree of Life Necklace For Sister - S925 A Sister is GOD's Way of Making Sure We Never Walk Alone Crystal Tree of Life Necklace

    For Sister - S925 A Sister is GOD's Way of Making Sure We Never Walk Alone Crystal Tree of Life Necklace

    from $39.90 $44.90
    Save 11%
    For Sister - We Always Have Each Other's Back Sun Moon Ring For Sister - We Always Have Each Other's Back Sun Moon Ring

    For Sister - We Always Have Each Other's Back Sun Moon Ring

    from $36.90
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