UNPKG

zz-shopify-components

Version:

Reusable Shopify components for theme projects

280 lines (252 loc) 8 kB
// 处理产品变体逻辑 class ProductSelector extends HTMLElement { currentVariantId; options; root; loading = false; constructor() { super(); } connectedCallback() { this.currentVariantId = JSON.parse(this.dataset.currentVariantId); if (!this.currentVariantId) { throw new Error('选择器未传入变体'); } this.options = this.dataset.options; this.init(); console.log( 'this.options, this.currentVariantId', this.options, this.currentVariantId ); } // 初始化 change 事件 init() { this.bandOptionsSelector(); this.bandVersionSelector(); this.bindVersionEvents(); this.updatePrice(); } bandOptionsSelector() { const options = Array.from( this.getElementsByClassName('product-normal-option') ); options.forEach((el) => { el.addEventListener('change', () => { const { productUrl, variantId, sectionId } = el.dataset; this.updateVersionSelector({ productUrl, variantId, sectionId }); this.updateURL(productUrl, variantId); // 通知care更新 const careProducts = document.querySelector('care-product-list'); const careDialog = document.querySelector( 'product-detail-dialog-hovercare-choose' ); if (careDialog) { careDialog.updateSelectProduct(); } if (careProducts) { careProducts.updateSelectProduct(); } }); }); } bandVersionSelector() { const versionOptions = Array.from( this.getElementsByClassName('product-version-option') ); versionOptions.forEach((el) => { el.addEventListener('change', () => { console.log('version change'); const { productUrl, variantId, sectionId, price, before } = el.dataset; // this.currentVariantId = sectionId; this.updateURL(productUrl, variantId); }); }); } // Version Selector 更新函数 updateVersionSelector({ productUrl, variantId, sectionId }) { if (!variantId) { console.warn('无效的变体 ID:', variantId); return; } this.fetchAndUpdateDOM(productUrl, variantId, sectionId) .then(() => this.updateURL(productUrl, variantId)) .catch((error) => console.error('更新选择器时出错:', error)); } // Section rendering api 获取变体信息 async fetchAndUpdateDOM(productUrl, variantId, sectionId) { try { this.toggleLoading(); const currentElement = document.getElementById( 'product-version-selector' ); const response = await fetch( `${productUrl}?variant=${variantId}&section_id=${sectionId}` ); if (!response.ok) { throw new Error(`网络错误:${response.status}`); } // 更新DOM const responseText = await response.text(); const html = new DOMParser().parseFromString(responseText, 'text/html'); const newElement = html.getElementById('product-version-selector'); if (newElement && currentElement) { currentElement.parentNode.replaceChild(newElement, currentElement); this.bandVersionSelector(); this.bindVersionEvents(); } else { console.warn('无法找到替换的 DOM 元素'); } } catch (error) { console.error('fetchAndUpdateDOM 错误:', error); } finally { this.toggleLoading(); } } // 更新路由参数和产品信息 updateURL(productUrl, variantId) { window.history.replaceState({}, '', `${productUrl}?variant=${variantId}`); this.currentVariantId = variantId; this.updatePrice(); } // 清理事件监听器或其他资源 disconnectedCallback() { // const options = this.querySelectorAll('.product-version-option'); // options.forEach((el) => { // el.removeEventListener('click', this.handleOptionClick); // }); // console.log('ProductSelector 已被移除'); } // 更新价格 updatePrice() { const bar = document.querySelector('buy-now-bottom-bar'); if (bar) { bar.updatePrice(); } } // loading 状态 toggleLoading() { this.loading = !this.loading; // const params = { // duration: 0.3, // opacity: this.loading ? 0.2 : 1, // pointerEvents: this.loading ? 'none' : 'auto', // }; // gsap.to('#product-version-selector-container', params); // gsap.set('product-buy-now-selector', { // pointerEvents: this.loading ? 'none' : 'auto', // }); } bindVersionEvents() { const versionOptions = Array.from( this.querySelectorAll(".version-selector-item > button.show-detail") ); versionOptions.forEach((el) => { el.addEventListener("click", (event) => { // 处理详情按钮点击 const detailButton = event.target.closest(".show-detail"); if (detailButton) { event.stopPropagation(); event.preventDefault(); const dialog = detailButton .closest(".version-selector-item") ?.querySelector("dialog"); if (dialog) dialog.showModal(); return; } }); }); } } class ProductBuyNowCounter extends HTMLElement { constructor() { super(); this.input = null; this.min = parseInt(this.getAttribute('min')) || 1; this.max = parseInt(this.getAttribute('max')) || 99; } connectedCallback() { this.input = this.querySelector('input'); if (this.input) { this.init(); } } disconnectedCallback() { const minusButton = this.querySelector('.minus'); const addButton = this.querySelector('.add'); if (minusButton) { minusButton.removeEventListener('click', this.decrementValue); } if (addButton) { addButton.removeEventListener('click', this.incrementValue); } if (this.input) { this.input.removeEventListener('input', this.handleInput); this.input.removeEventListener('blur', this.handleBlur); } } init() { const minusButton = this.querySelector('.minus'); const addButton = this.querySelector('.add'); if (minusButton) { minusButton.addEventListener('click', () => this.decrementValue()); } if (addButton) { addButton.addEventListener('click', () => this.incrementValue()); } this.input.addEventListener('input', (e) => this.handleInput(e)); this.input.addEventListener('blur', () => this.handleBlur()); } handleInput() { let value = parseInt(this.input.value); if (isNaN(value)) { this.input.value = ''; } else { value = Math.min(Math.max(value, this.min), this.max); this.input.value = value; } // this.toggleButtonState(); } handleBlur() { let value = parseInt(this.input.value); if (isNaN(value) || value < this.min) { this.input.value = this.min; } else if (value > this.max) { this.input.value = this.max; } this.updatePrice(); // this.toggleButtonState(); } decrementValue() { let value = parseInt(this.input.value) || this.min; value = Math.max(value - 1, this.min); this.input.value = value; this.updatePrice(); // this.toggleButtonState(); } incrementValue() { let value = parseInt(this.input.value) || this.min; value = Math.min(value + 1, this.max); this.input.value = value; this.updatePrice(); // this.toggleButtonState(); } toggleButtonState() { const minusButton = this.querySelector('.minus'); const addButton = this.querySelector('.add'); if (minusButton) { minusButton.disabled = parseInt(this.input.value) <= this.min; } if (addButton) { addButton.disabled = parseInt(this.input.value) >= this.max; } } updatePrice() { const bar = document.querySelector('buy-now-bottom-bar'); if (bar) { bar.updatePrice(); } } } customElements.define('product-buy-now-counter', ProductBuyNowCounter); customElements.define('product-buy-now-selector', ProductSelector);