1// 夿 customElements 注åè¡¨éæ¯å¦å·²ç»æ "product-info" ç»ä»¶ 2if (!customElements.get("product-info")) { 3 // èªå®ä¹ HTML å ç´ ï¼ååä¿¡æ¯ç»ä»¶ 4 class ProductInfo extends HTMLElement { 5 abortController = undefined; // æ§å¶ fetch ç䏿 6 pendingRequestUrl = null; // å½åå¾ å起请æ±ç URL 7 preProcessHtmlCallbacks = []; // HTML æ¿æ¢åé¢å¤çåè° 8 postProcessHtmlCallbacks = []; // HTML æ¿æ¢åå¤çåè° 9 10 constructor() { 11 super(); 12 this.onWindowLoad = this.onWindowLoad.bind(this); // ç»å® window load äºä»¶ 13 this.productNoHandleRedirectHome = this.dataset.productNoHandleRedirectHome 14 this.realLevel1TagList = []//åå§åæ¶çéçå®åå¨ç1级æ ç¾å±æ§ 15 this.realOption = {}//éä¸ååå çéçå®åå¨ç 2 3级åå屿§ 16 /* 17 * 妿å¼ä¸º1ï¼ï¼å½åå°ååï¼åå详æ 页ï¼å¦æååä¸åå¨ï¼å跳转å°é¦é¡µ 18 妿å¼ä¸ä¸º1ï¼åæ¾ç¤ºnor found 19 * */ 20 if (!this.productId && window.baseData.page_type === "product") {//没æåå id 21 if (Number(this.productNoHandleRedirectHome) === 1) {//productNoHandleRedirectHome === 1 跳转è³é¦é¡µ 22 window.location.href = window.common_base_url 23 } else if (Number(this.productNoHandleRedirectHome) === 2) {//æ¾ç¤º 404页 24 let notFoundTitle = this.dataset.notFoundTitle 25 let notFoundTips = this.dataset.notFoundTips 26 let notFoundButton = this.dataset.notFoundButton 27 let mainContent = document.querySelector("#main-content") 28 // æ¿æ¢æ 404å 容 29 mainContent.innerHTML = ` 30 <div class="section_id_main"> 31 <div class="f-page404"> 32 <span class="f-page404__icon"> 33 <svg class="f-svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 464c-119.1 0-216-96.9-216-216S128.9 40 248 40s216 96.9 216 216-96.9 216-216 216zm0-152c-44.4 0-86.2 19.6-114.8 53.8-5.7 6.8-4.8 16.9 2 22.5 6.8 5.7 16.9 4.8 22.5-2 22.4-26.8 55.3-42.2 90.2-42.2s67.8 15.4 90.2 42.2c5.3 6.4 15.4 8 22.5 2 6.8-5.7 7.7-15.8 2-22.5C334.2 339.6 292.4 320 248 320zm-80-80c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32z"></path></svg> 34 </span> 35 <h1 class="h1" >${notFoundTitle}</h1> 36 <p class="h1">${notFoundTips}</p> 37 <a href="${window.common_base_url}" class="f-button f-button--primary">${notFoundButton}</a> 38 </div> 39 </div>` 40 } 41 } 42 } 43 44 // ---------- 屿§ Getterï¼æ¹ä¾¿ä»£ç éå°å¤è·åç¸å ³å±æ§ ----------- 45 get productId() { 46 return this.getAttribute('data-product-id'); 47 } 48 49 get useScene() { 50 //使ç¨åºæ¯ è¿ä¸ªé常éè¦ï¼ æå®åå¼èµå¼ 51 // ç¨äºå¾å° => <script type="application/json" data-use-scene="{{ scene }}"data - selected - variant = "{{ product.id }}" > {{selected_variant | json}}</script> 52 if (this.getAttribute('data-use-scene')) { 53 return this.getAttribute('data-use-scene'); 54 } 55 return 'block' 56 } 57 58 get sectionId() { 59 return this.dataset.originalSection || this.dataset.sectionId; 60 } 61 62 get disableSelectedVariantDefault() { 63 // é»è®¤è§æ ¼æ¯å¦ç¦ç¨éä¸ 64 return this.dataset.disableSelectedVariantDefault === "1" || false; 65 } 66 67 get enableVariantGroupImages() { 68 // æ¯å¦å¼å¯è§æ ¼ç»å¾ç 69 return this.dataset.enableVariantGroupImages === "1" || false; 70 } 71 72 get enableHistoryState() { 73 // æ¯å¦æ¯æåä½åæ¢åæ¥å°æµè§å¨åå² 74 return this.dataset.enableHistoryState === "1" || false; 75 } 76 77 get viewMode() { 78 // æ¾ç¤ºæ¨¡å¼ï¼ä¸»åååº/å¼¹çªé¢è§çï¼
79 return this.dataset.viewMode || 'main-product' 80 } 81 82 // è·å pickup-availability ç»ä»¶ 83 get pickupAvailability() { 84 return this.querySelector(`pickup-availability`); 85 } 86 87 // è·å product-form ç»ä»¶ 88 get productForm() { 89 return this.querySelector('product-form'); 90 } 91 92 // è·åå¤åªä½å¾éå®¹å¨ 93 get productMedia() { 94 return this.querySelector(`[id^="MediaGallery-${this.productId}"]`); 95 } 96 97 // è·ååä½éæ©å¨ 98 get variantPicker() { 99 return this.querySelector('variant-picker'); 100 } 101 102 // è·å主å è´æ°éè¾å ¥æ¡ 103 get quantityInput() { 104 return this.querySelector(`f-quantity-input input`); 105 } 106 107 // è·ååºé¨æ¬æµ®å è´æ°éè¾å ¥æ¡ 108 get quantityInputStickyAtc() { 109 return this.querySelector(`.f-sticky-addtocart f-quantity-input input`); 110 } 111 112 // æ¬æµ®å è´æ ç»ä»¶ 113 get stickyAtc() { 114 return this.querySelector('sticky-atc'); 115 } 116 117 // ---------- Web Component çå½å¨æ ---------- 118 connectedCallback() { 119 $log('Web Component çå½å¨æ', this.productId); 120 // 主åååºåå§åçå¬ 121 if (this.viewMode === "main-product") { 122 window.addEventListener("load", this.onWindowLoad); 123 } 124 this.init(); 125 } 126 127 disconnectedCallback() { 128 // ç»ä»¶éæ¯æ¶æ¸ çäºä»¶çå¬ 129 window.removeEventListener("load", this.onWindowLoad); 130 this.cartUpdateUnsubscriber?.(); // å¯è½åå¨çè´ç©è½¦åæ´è®¢é åæ¶ 131 } 132 133 // ---------- åå§åæ¹æ³ ---------- 134 init() { 135 this.currentAllVariant = this.getSelectedAllVariant(this); // å½ååä½å¯¹è±¡ 136 this.currentVariant = this.getSelectedVariant(this); // å½ååä½å¯¹è±¡ 137 $log('å½åéä¸ç', this.currentVariant); 138 $log('çå®çä¸çº§è§æ ¼', this.realLevel1TagList) 139 this.quantityInputs = []; 140 141 if (this.quantityInput) { 142 this.quantityInputs.push(this.quantityInput); 143 } 144 if (this.quantityInputStickyAtc) { 145 this.quantityInputs.push(this.quantityInputStickyAtc); 146 } 147 148 if (this.disableSelectedVariantDefault) { 149 this.handleDisableSelectedVariantDefault(); 150 } 151 152 // è§æ ¼/é项忴äºä»¶è®¢é ï¼æ¯å¦åæ¢é¢è²å°ºç ï¼ 153 FecEvents.on(FecTheme.pubSubEvents.optionValueSelectionChange, (payload) => { 154 $log('订é äºä»¶-å½åéä¸çåä½:', payload.data); 155 // æ¨èï¼ç¬ç«åºå¤ç彿° 156 const fn = this.handleOptionValueChange.bind(this); 157 fn(payload); 158 // é常ä¼å»æ´æ°ä»·æ ¼/å¾ç/åºåç 159 }); 160 161 $log('åå详æ 页åå§å', window.location) 162 // 主å¾ç¶æå¤çä¸åªä»åå§åï¼è§é¢/è½®æå¾çï¼ 163 // this.showFeaturedMedia = this.dataset.showFeaturedMedia === "1" || false; 164 165 this.initialMedias = this.productMedia ? this.productMedia.querySelectorAll('.f-product-media--item') : null; 166 this.initialThumbs = this.productMedia ? this.productMedia.querySelectorAll(".f-product-media--slider__thumbnails [data-media-type]") : null; 167 168 // 妿å¯ç¨åä½ç»å¾çï¼åè§£æè¯¥æ°æ® 169 if (this.enableVariantGroupImages) { 170 this.variantGroupImagesData = this.getVariantGroupImagesData(); 171 // this.showFeaturedMedia = false; 172 } 173 174 175 // åå§åæ°éç¸å ³åè½ï¼éå¢éåãéè´ï¼ 176 this.initQuantityHandlers(); 177 $log('åå¤è¿è¡-æ ¹æ®å½ååä½ç¶æï¼æ´æ°ä¸»å¾', this.enableVariantGroupImages, this.currentVariant) 178 // æ ¹æ®å½ååä½ç¶æï¼æ´æ°ä¸»å¾ 179 if (this.currentVariant) { 180 this.updateMedia(this.currentVariant); 181 } 182 this.updateSpecificationAttributeDisablesFunction()//æ ¹æ®éä¸çè§æ ¼å±æ§ç¡®å®æ¯å¦ç¦æ¢è´ä¹°ï¼å¹¶ä¸ºè§æ ¼è®¾ç½®ç¦ç¨æ ·å¼ 183 // æ´æ°é¡¶é¨ url 184 const productUrl = this.dataset.productUrl || this.pendingRequestUrl || this.dataset.url; 185 this.updateURL(this.currentVariant?.id); 186 187 // æ åºåä¸è½è´ä¹°é项 并䏿²¡æåºå ç¦æ¢è´ä¹° 188 if (this.dataset.needsInventory === '1' && this.currentVariant.qty <= 0) { 189 this.setUnavailable(); 190 } 191 } 192 193 // è§£æåä½ç»å¾çé ç½®æ°æ®ï¼JSONï¼ 194 getVariantGroupImagesData() { 195 return ( 196 JSON.parse( 197 this.querySelector('#variantGroup[type="application/json"]') 198 .textContent 199 ) || {} 200 ); 201 } 202 203 // æ ¹æ®éä¸çè§æ ¼å±æ§ç¡®å®æ¯å¦ç¦æ¢è´ä¹°ï¼å¹¶ä¸ºè§æ ¼è®¾ç½®ç¦ç¨æ ·å¼ 204 updateSpecificationAttributeDisablesFunction() { 205 $log('updateSpecificationAttributeDisablesFunction-æ ¹æ®éä¸çè§æ ¼å±æ§ç¡®å®æ¯å¦ç¦æ¢è´ä¹°ï¼å¹¶ä¸ºè§æ ¼è®¾ç½®ç¦ç¨æ ·å¼-1', 206 this.currentVariant, 207 this.dataset.needsInventory); 208 if (!(this.currentAllVariant && this.currentAllVariant.length > 0)) { 209 return; 210 } 211 $log('å½åéä¸', this.currentVariant); 212 213 // ----- æ°å¢ï¼å¨æå¤ææ¯å¦ä¸ºåä¸å±æ§ç»´åº¦ï¼åªæ option1 æå¤ç§å¼ï¼----- 214 const distinctOpt1 = new Set(); 215 const distinctOpt2 = new Set(); 216 const distinctOpt3 = new Set(); 217 this.currentAllVariant.forEach(v => { 218 if (v.option1) distinctOpt1.add(v.option1); 219 if (v.option2) distinctOpt2.add(v.option2); 220 if (v.option3) distinctOpt3.add(v.option3); 221 }); 222 const isSingleDimension = distinctOpt1.size > 0 && distinctOpt2.size <= 1 && distinctOpt3.size <= 1; 223 // ------------------------------------------------------------ 224 225 // --- 夿åºå 没åºåçè¦ç¦ç¨ --- 226 let finalHasStock = false; 227 if (this.dataset.needsInventory === '1' && this.currentVariant.qty > 0) { 228 finalHasStock = true; 229 } 230 231 // åä¸å±æ§ç»´åº¦ååå¤çï¼æ°å¢ï¼ 232 if (isSingleDimension) { 233 $log('å屿§ç»´åº¦ååï¼å¦åªæå°ºå¯¸ï¼ï¼å¯ç¨ç¬ç«ç¦ç¨ä¸èªå¨åæ¢'); 234 if (this.dataset.needsInventory === '1') { 235 const option1Inputs = this.querySelectorAll('variant-picker .f-product-option [data-position="1"]'); 236 // æ¶éæåºåç option1 å¼ 237 const availableOption1 = new Set(); 238 this.currentAllVariant.forEach(v => { 239 if (v.qty > 0) availableOption1.add(v.option1); 240 }); 241 let firstAvailableValue = null;
242 option1Inputs.forEach(input => { 243 const value = input.value; 244 const hasStock = availableOption1.has(value); 245 const parentNode = input.closest('.f-product-option--node'); 246 if (hasStock) { 247 input.disabled = false; 248 parentNode && parentNode.classList.remove('f-product-option--node__unavailable'); 249 if (!firstAvailableValue) firstAvailableValue = value; 250 } else { 251 input.disabled = true; 252 parentNode && parentNode.classList.add('f-product-option--node__unavailable'); 253 } 254 }); 255 // 妿å½åå使 åºåï¼èªå¨åæ¢å°ç¬¬ä¸ä¸ªæåºåçé项 256 if (this.currentVariant && this.currentVariant.qty <= 0 && firstAvailableValue) { 257 const availableInput = Array.from(option1Inputs).find(inp => inp.value === firstAvailableValue); 258 if (availableInput && !availableInput.checked) { 259 if (availableInput.type === 'radio' || availableInput.type === 'checkbox') { 260 availableInput.checked = true; 261 const changeEvent = new Event('change', { bubbles: true }); 262 availableInput.dispatchEvent(changeEvent); 263 } else if (availableInput.tagName === 'SELECT') { 264 const selectEl = availableInput; 265 const option = Array.from(selectEl.options).find(opt => opt.value === firstAvailableValue); 266 if (option) { 267 option.selected = true; 268 const changeEvent = new Event('change', { bubbles: true }); 269 selectEl.dispatchEvent(changeEvent); 270 } 271 } 272 } 273 } 274 } 275 finalHasStock = !(this.dataset.needsInventory === '1' && this.currentVariant?.qty <= 0); 276 } 277 else { 278 // ========== å¤è§æ ¼ååï¼ä»¥ä¸ä»£ç ä¸å代ç å®å ¨ä¸è´ï¼ä¸å䏿¹ ========== 279 $log('æ¯å¤è§æ ¼åå') 280 finalHasStock = true 281 // åç¬å¤æè§æ ¼1 282 // è·è¸ªåºåå¹¶ä¸åºå为0 å¹¶ä¸ ä¸å 许è´ä¹° 283 if (this.dataset.needsInventory === '1') { 284 const option1PossInputs = this.querySelectorAll('variant-picker .f-product-option [data-position="1"]'); 285 option1PossInputs.forEach(input => { 286 const value = input.value; 287 $log('å¤è§æ ¼value', value) 288 289 let hasStock = false 290 // ä¿åä¸ä¸ï¼åªè¦æä¸ä¸ªç»åæåºåï¼å°±ç®æ´ä½æåºå 291 if (this.realLevel1TagList.includes(this.currentVariant.option1)) { 292 hasStock = true 293 } 294 // 设置å½å input æ¯å¦å¯é 没åºåçå°±è¦ç¦æ¢ç¹å» 295 const parentNode = input.closest('.f-product-option--node'); 296 if (hasStock) { 297 input.disabled = false; 298 parentNode && parentNode.classList.remove('f-product-option--node__unavailable'); 299 } else { 300 input.disabled = true; 301 parentNode && parentNode.classList.add('f-product-option--node__unavailable'); 302 } 303 }); 304 } 305 306 // å¤æè§æ ¼2 307 let option1 = this.currentVariant.option1 ? this.currentVariant.option1 : '' 308 let option2 = this.currentVariant.option2 ? this.currentVariant.option2 : '' 309 let option3 = this.currentVariant.option3 ? this.currentVariant.option3 : '' 310 let level1List = [] 311 let level2List = [] 312 let level2OptionList = []//äºçº§å±æ§ æ ¹æ®ä¸çº§éæ©ç屿§ ç¡®å®åº 2级æç屿§ 313 let level3OptionList = []//ä¸çº§å±æ§ æ ¹æ®ä¸çº§éæ©ç屿§ ç¡®å®åº 3级æç屿§ 314 315 this.currentAllVariant.forEach(item => { 316 // option3 å¯éæ ç¾ éè¦ç¡®å®option1 å option2 æ¯é好çåºå®ç 317 if (item.option1 == option1) { 318 level1List.push(item) 319 } 320 }) 321 this.currentAllVariant.forEach(item => { 322 // option3 å¯éæ ç¾ éè¦ç¡®å®option1 å option2 æ¯é好çåºå®ç 323 if (item.option1 == option1 && item.option2 == o
323ption2) { 324 level2List.push(item) 325 } 326 }) 327 level1List.forEach(item => {//çæoption2 å¯éæ ç¾ 328 if (item.option2 && item.option2.length && level2OptionList.indexOf(item.option2) === -1) { 329 level2OptionList.push(item.option2) 330 } 331 }) 332 level2List.forEach(item => { 333 if (item.option3 && item.option3.length && level3OptionList.indexOf(item.option3) === -1) { 334 level3OptionList.push(item.option3) 335 } 336 }) 337 // this.realOption = { 338 // 1: level2OptionList, 339 // 2: level3OptionList 340 // } 341 let realOption = { 342 2: level2OptionList, 343 3: level3OptionList 344 } 345 $log('å¾å°ç-level2OptionList', level2OptionList) 346 $log('å¾å°ç-level3OptionList', level3OptionList) 347 348 for (let pos = 2; pos <= 3; pos++) { 349 const possInputs = this.querySelectorAll('variant-picker .f-product-option [data-position="' + pos + '"]'); 350 possInputs.forEach(input => { 351 const value = input.value; 352 let canChoose = false; 353 354 // æ£æ¥è¯¥å¼æ¯å¦å å«å¨ realOption[pos] ä¸ 355 if (realOption[pos].includes(value)) { 356 canChoose = true; 357 } 358 359 // è·åç¶èç¹ä»¥ä¾¿æ§å¶ç¶æ 360 const parentNode = input.closest('.f-product-option--node'); 361 362 // 设置å½å input æ¯å¦å¯éï¼æ²¡åºåçå°±è¦ç¦æ¢ç¹å» 363 if (canChoose) { 364 input.disabled = false; 365 parentNode && parentNode.classList.remove('f-product-option--node__unavailable'); 366 } else { 367 input.disabled = true; 368 parentNode && parentNode.classList.add('f-product-option--node__unavailable'); 369 } 370 371 // 妿 value å option[pos] å¹é ï¼è®¾ç½®ä¸ºéä¸ç¶æ 372 if (value === this.currentVariant['option' + pos]) { 373 if (input.type === 'radio' || input.type === 'checkbox') { 374 input.checked = true; // 设置为éä¸ 375 } else if (input.type === 'select-one') { 376 input.selected = true; // 妿æ¯ä¸ææ¡ï¼è®¾ç½®ä¸ºéä¸ 377 } 378 } else { 379 if (input.type === 'radio' || input.type === 'checkbox') { 380 input.checked = false; // åæ¶éä¸ 381 } else if (input.type === 'select-one') { 382 input.selected = false; // 妿æ¯ä¸ææ¡ï¼åæ¶éä¸ 383 } 384 } 385 }); 386 } 387 } 388 $log('finalHasStockæç»', finalHasStock) 389 390 // 循ç¯ç»æåï¼åç»ä¸è®¾ç½®æé® 391 const paymentButton = document.querySelector('.fec-payment-button__button'); 392 // const addButtonUpdated = '' 393 const addButtonUpdated = document.getElementById(`ProductSubmitButton-${this.productId}`); 394 $log('å å ¥è´ç©è½¦æé®æ ·å', addButtonUpdated) 395 let customeowInfoSkus = this.getCustomeowInfo()//å®å¶åµæ°æ® 396 const productForm = document.getElementById(`product-form-${this.productId}`); 397 let currentSkuIsCustom = 2 398 if (customeowInfoSkus && customeowInfoSkus.skus && customeowInfoSkus.skus.includes(this.currentVariant.sku)) {//å½åå使¯å¦æ¯å®å¶åå 399 currentSkuIsCustom = 1 400 } else { 401 currentSkuIsCustom = 2 402 } 403 if (productForm) { 404 productForm.dataset.currentSkuIsCustom = currentSkuIsCustom 405 } 406 407 // æ¬æµ®æ è´ç© 408 let stickyAtc = document.querySelector('sticky-atc'); 409 if (stickyAtc) { 410 const btn = stickyAtc.querySelector('button[type="submit"]'); 411 const btnText = stickyAtc.querySelector('button[type="submit"] .f-add-to-cart--text'); 412 const option = stickyAtc.querySelector('.f-product-option--dropdown-select'); 413 //æ åºåæ è½è´ä¹°çè¯å设置ç¦ç¨ç¶æ 414 if (currentSkuIsCustom == 1) { 415 416 if (finalHasStock) {//æåºå 417 btn.disabled = false; 418 option.disabled = false; 419 } else {//没åºå 420 btn.disabled = true; 421 option.disabled = true; 422 } 423 } 424 if (currentSkuIsCustom == 1) {//æ¯å®å¶åå 425 426 btnText.innerHTML = addButtonUpdated.getAttribute('data-customeow-text'); 427 } else { 428 btnText.innerHTML = btn.getAttribute('data-atc-text') 429 } 430 431 432 } 433 if (paymentButton) {//ç«å³è´ä¹° 434 if (this.dataset.needsInventory === '1') {//æ åºåæ è½è´ä¹°çè¯å设置ç¦ç¨ç¶æ 435 paymentButton.disabled = !finalHasStock; 436 if (finalHasStock) {//æåºå 437 let PayPalBox = document.querySelector('product-paypal-payment-express')//PayPal 438 // 容å¨çéæ ç«å³è´ä¹°æé® PayPalç»è´¦ 439 if (PayPalBox) { 440 PayPalBox.removeAttribute('disabled'); 441 442 } 443 } else {//没åºå 444 let PayPalBox = document.querySelector('product-paypal-payment-express')//PayPal 445 // 容å¨çéæ ç«å³è´ä¹°æé® PayPalç»è´¦ 446 if (PayPalBox) { 447 // 设置 disabled 屿§ï¼éç¨äºæé®æå¸¦æäº¤äºç容å¨ï¼ 448 PayPalBox.setAttribute('disabled', 'disabled'); 449 } 450 451 } 452 } 453 } 454 if (addButtonUpdated) {//å å ¥è´ç©è½¦ 455 $log('addButtonUpdated-æ¾ç¤ºå å ¥è´ç©è½¦', addButtonUpdated); 456 let addButtonUpdatedText = addButtonUpdated.querySelector('.f-add-to-cart--text') 457 // if (finalHasStock) { 458 // if (this.dataset.needsInventory === '1') {//æ åºåæ è½è´ä¹°çè¯å设置ç¦ç¨ç¶æ 459 // addButtonUpdated.disabled = false; 460 // } 461 // 462 // if (currentSkuIsCustom == 1) {//æ¯å®å¶åå 463 // addButtonUpdatedText.innerHTML = addButtonUpdated.getAttribute('data-customeow-text'); 464 // } else { 465 // addButtonUpdatedText.innerHTML = addButtonUpdated.getAttribute('data-atc-text'); 466 // } 467 // } else { 468 // addButtonUpdated.disabled = true; 469 // addButtonUpdatedText.innerHTML = addButtonUpdated.getAttribute('data-oos-text'); 470 // 471 // } 472 }
473 this.setColorImageTooltipText()//å¼å§è®¾ç½®æ¯å¦æ¾ç¤ºè²å¡ç说æä¿¡æ¯ 474 this.checkedBuyMinCount()//æ£æ¥æå°è´ä¹°æ°é 475 } 476 477 // ---------- ç¨æ·æ¯æ¬¡åæ¢è§æ ¼ï¼optionï¼æ¶è¢« FecEvents ï¼æ¶é´è®¢é ï¼è°ç¨ ---------- 478 handleOptionValueChange({data: {event, target, selectedOptionValues}}) {//å¤è§æ ¼æ°æ®æ¹åäº 479 $log('handleOptionValueChange', event, target, selectedOptionValues) 480 481 if (!this.contains(event.target)) return; // åªå¤çæ¬ååç»ä»¶å é¨çäºä»¶ 482 483 // å½åååçæ°URLï¼åæ¯å¦éè¦åæ¢äº§åï¼æ¯å¦éæ©äºæ°skuï¼ 484 const productUrl = target.dataset.productUrl || this.pendingRequestUrl || this.dataset.url; 485 const shouldSwapProduct = this.dataset.url !== productUrl; 486 // TODO éè¦ä¸éè¦å ¨é¡µé¢å·æ° ï¼è¿éå¯ä»¥å¨åååç»çæ¶å夿æ¯å¦éè¦å ¨é¡µé¢å·æ° 487 const shouldFetchFullPage = (this.dataset.updateUrl === 'true' || this.dataset.updateUrl === '1') && shouldSwapProduct; 488 //ç°å¨èµ°ç齿¯ handleUpdateProductInfo è¿ä¸ªå½æ° 489 shouldSwapProduct ? this.handleSwapProduct(productUrl, shouldFetchFullPage, this.viewMode) 490 : this.handleUpdateProductInfo(productUrl, selectedOptionValues, this.viewMode) 491 // 渲æåååºåé¡µé¢ 492 // this.renderProductInfo({ 493 // requestUrl: this.buildRequestUrlWithParams(productUrl, selectedOptionValues, shouldFetchFullPage), 494 // targetId: target.id, 495 // callback: shouldSwapProduct 496 // ? this.handleSwapProduct(productUrl, shouldFetchFullPage, this.viewMode) 497 // : this.handleUpdateProductInfo(productUrl, this.viewMode), 498 // }); 499 } 500 501 // ------- æ ¸å¿ï¼æ¸²æé¡µé¢ï¼å±é¨æå ¨é¡µï¼ ------ 502 renderProductInfo({requestUrl, targetId, callback}) { 503 this.abortController?.abort(); // åæ¶ä¸ä¸æ¬¡è¯·æ± 504 this.abortController = new AbortController(); // æ°ç AbortController 505 506 // æ¤å¤çç¥ fetch 请æ±å®ç°ï¼è§ä¸å¡ä»£ç ... 507 } 508 509 // å·¥å ·ï¼æ¼æ¥é项请æ±åæ° URL 510 buildRequestUrlWithParams(url, optionValues, shouldFetchFullPage = false) { 511 const params = []; 512 !shouldFetchFullPage && params.push(`section_id=${this.productId}`); 513 if (optionValues.length) { 514 params.push(`option_values=${optionValues.join(',')}`); 515 } 516 return `${url}?${params.join('&')}`; 517 } 518 519 getCustomeowInfo() {//å®å¶åµ 520 let selectedVariant = document.querySelector('[data-customeow-info]')?.innerHTML; 521 if (selectedVariant) { 522 return !!selectedVariant ? JSON.parse(selectedVariant) : null; 523 } 524 } 525 526 // å¤çä» æ´æ°å±é¨ååä¿¡æ¯çåè°ï¼ä»·æ ¼ãåºåãå¾çåºåçï¼ 527 handleUpdateProductInfo(productUrl, selectedOptionValues, viewMode) { 528 $log('æ´æ°ç对象', productUrl, selectedOptionValues, viewMode) 529 //æ¬å°æ´æ° 530 let html = this 531 // å¿«éé¢è§ï¼å¼¹çªï¼å¤ç 532 const quickView = html.querySelector('#MainProduct-quick-view__content'); 533 if (quickView && viewMode === 'quick-view') { 534 html = new DOMParser().parseFromString(quickView.innerHTML, "text/html"); 535 } 536 this.setNewSelectedVariant(selectedOptionValues)//æ ¹æ®éæ©çè§æ ¼å¼ï¼éåå¾å°å ·ä½çåä½åå 537 // è·åæ°çåä½å¯¹è±¡ 538 this.currentVariant = this.getSelectedVariant(this);//æ ¹æ®éä¸çè§æ ¼å¼ï¼å¹é å°å ·ä½çåä½ååï¼å¹¶è®¾ç½®å° variant-picker [data-selected-variant] é 539 540 $log('æ°çvariant', this.currentVariant) 541 //æ´æ°è§æ ¼æ¯å¦ç¦ç¨ 542 this.updateSpecificationAttributeDisablesFunction() 543 $log('å¼å§æ´æ°-updateURL', productUrl, this.currentVariant) 544 // æ´æ°URLæ°æ®ç 545 this.updateURL(this.currentVariant?.id);
546 // this.updateVariantInputs(variant?.id); 547 548 // æ åºåä¸è½è´ä¹°é项 并䏿²¡æåºå ç¦æ¢è´ä¹° 549 if (this.dataset.needsInventory === '1' && this.currentVariant.qty <= 0) { 550 this.setUnavailable(); 551 return; 552 } 553 554 // æ ¹æ®è§æ ¼å¾ççç¥ï¼æ´æ°æ¶é´è½´/主å¾/è½®æ 555 this.updateMedia(this.currentVariant); 556 // æ¹éæ´æ°å¤ä¸ªç¹å®åºåå 容ï¼ä»·æ ¼ãåºåãSKUãä½ç§¯ä»·çï¼ 557 const updateSourceFromDestination = (id, shouldHide = (source) => false) => { 558 const domInfo = document.getElementById(`${id}-${this.productId}`); 559 $log('updateSourceFromDestination', domInfo, this.productId); 560 if (id === 'Price' && domInfo) {//ä»·æ ¼æ´æ° 561 $log('domInfo', domInfo) 562 let salePrice = domInfo.querySelector('.f-price-item--sale span'); 563 let comparePrice = domInfo.querySelector('.f-strikethrough-price span'); 564 let productPriceInfo = domInfo.querySelector('.product-price-info'); 565 $log('salePrice', salePrice, this.currentVariant) 566 $log('comparePrice', comparePrice,) 567 $log('productPriceInfo', productPriceInfo,) 568 if (salePrice) {//å®ä»·æ¿æ¢ 569 salePrice.innerHTML = this.currentVariant.price 570 } 571 if (Number(this.currentVariant.compare_at_price) > Number(this.currentVariant.price)) { 572 $log('大äºäºå',) 573 } 574 if (comparePrice && this.currentVariant.compare_at_price > 0 && (Number(this.currentVariant.compare_at_price) > Number(this.currentVariant.price))) {//åçº¿ä»·æ¿æ¢ 575 productPriceInfo.classList.remove('f-price--on-sale') 576 $log('ææ²¡æå线价') 577 if (this.currentVariant.compare_at_price > 0) { 578 comparePrice.textContent = this.currentVariant.compare_at_price; 579 // comparePrice.closest('.f-price-item--regular').style.display = 'block'; 580 productPriceInfo.classList.add('f-price--on-sale') 581 $log('ææ²¡æå线价1') 582 } else { 583 $log('ææ²¡æå线价2') 584 585 // 没æå线价就éèå® 586 productPriceInfo.classList.remove('f-price--on-sale') 587 588 // comparePrice.closest('.f-price-item--regular').style.display = 'none'; 589 } 590 } else { 591 $log('ææ²¡æå线价3') 592 productPriceInfo.classList.remove('f-price--on-sale') 593 } 594 595 let regularPrice = domInfo.querySelector('.f-price-item--regular span'); 596 if (regularPrice) { 597 regularPrice.innerHTML = this.currentVariant.price 598 } 599 } 600 }; 601 updateSourceFromDestination('Price');//æ´æ°ä»·æ ¼ 602 603 // updateSourceFromDestination("Inventory");//åºå 604 // updateSourceFromDestination("Sku"); 605 // updateSourceFromDestination("Availability");//å¯ç¨æ§ 606 // updateSourceFromDestination("Volume");//ä½ç§¯ 607 // updateSourceFromDestination('PricePerItem'); 608 const inventoryComponent = document.getElementById('inventory-status');//æ´æ°åºå 609 if (inventoryComponent) { 610 inventoryComponent.update(this.currentVariant); 611 } 612 613 614 this.updateQuantityRules(this.productId, this.productId, html); 615 this.querySelector(`#QuantityRules-${this.dataset.section}`)?.classList.remove('m:hidden'); 616 this.querySelector(`#VolumeNote-${this.dataset.section}`)?.classList.remove('m:hidden'); 617 618 // å è´æé®ç¶æ 619 const addButtonUpdated = document.getElementById(`ProductSubmitButton-${this.productId}`); 620 // this.toggleAddButton( 621 // addButtonUpdated ? addButtonUpdated.hasAttribute('disabled') : true, 622 // window.MinimogStrings.soldOut 623 // ); 624 625 // æ´¾ååä½åæ´èªå®ä¹äºä»¶ 626 document.dispatchEvent( 627 new CustomEvent('variant:changed', { 628 detail: { 629 variant: this.currentVariant, 630 }, 631 }) 632 ); 633 634 } 635 636 // å¤ç â忢å页ä¸åååâ çåè° 637 handleSwapProduct(productUrl, updateFullPage, viewMode) { 638 $log('handleSwapProduct-----', productUrl, updateFullPage, viewMode); 639 // è¿åçæ¯ä¸ä¸ªå®é å¤ç HTML ç彿° 640 return (html) => { 641 // 妿æ¯å¼¹çªå¿«éé¢è§ 642 const quickView = html.querySelector('#MainProduct-quick-view__
642content'); 643 if (quickView && viewMode === 'quick-view') { 644 html = new DOMParser().parseFromString(quickView.innerHTML, "text/html"); 645 } 646 647 // æ¥æ¾åæ¢åç product-info æ ¹èç¹ 648 const selector = updateFullPage ? "product-info[id^='MainProduct']" : 'product-info'; 649 const productInfo = html.querySelector(selector); 650 651 // æ¿å°æ°ååçå½ååä½å¯¹è±¡ 652 const variant = this.getSelectedVariant(productInfo); 653 654 productInfo.dataset.disableSelectedVariantDefault = false; 655 656 this.updateURL(variant?.id); 657 658 // æ¿æ¢é¡µé¢å±é¨æå ¨é¡µå 容 659 if (updateFullPage) { 660 // æ¿æ¢ <title> 661 document.querySelector('head title').innerHTML = html.querySelector('head title').innerHTML; 662 // æ¿æ¢ä¸»å 容åºåï¼æè¿æ¸¡å¨ç» 663 HTMLUpdateUtility.viewTransition( 664 document.querySelector('main'), 665 html.querySelector('main'), 666 this.preProcessHtmlCallbacks, 667 this.postProcessHtmlCallbacks 668 ); 669 } else { 670 // å±é¨ï¼ç»ä»¶å ï¼å å®¹æ¿æ¢ 671 HTMLUpdateUtility.viewTransition( 672 this, 673 productInfo, 674 this.preProcessHtmlCallbacks, 675 this.postProcessHtmlCallbacks 676 ); 677 } 678 679 // è®°å½åæ¢åçåä½ 680 this.currentVariant = variant; 681 }; 682 } 683 684 685 // è§£æå½åéä¸çåä½å¯¹è±¡ï¼éè¿ variant-picker ç data-selected-variantï¼ 686 getSelectedVariant(productInfoNode) { 687 try { 688 const selectedVariant = productInfoNode?.querySelector(`variant-picker script[data-use-scene="${this.useScene}"][data-selected-variant="${this.productId}"]`)?.innerHTML; 689 return selectedVariant && selectedVariant !== 'null' && selectedVariant !== '(null)null' ? JSON.parse(selectedVariant) : null; 690 } catch { 691 return null; 692 } 693 } 694 695 getSelectedAllVariant(productInfoNode) {//å ¨é¨å使°æ® 696 697 $log('needsInventory', this.dataset.needsInventory === '1'); 698 let allWapVariant = productInfoNode.querySelector(`variant-picker script[data-use-scene="${this.useScene}"][data-all-variants="${this.productId}"]`)?.innerHTML; 699 if (allWapVariant) { 700 701 if (this.dataset.needsInventory === '1') { 702 // è·è¸ªåºåå¹¶ä¸å 许è´ä¹°åºå为0çåå 703 let arr = [] 704 let newAllWapVariant = [] 705 try { 706 arr = JSON.parse(allWapVariant) || null 707 } catch (e) { 708 arr = [] 709 } 710 newAllWapVariant = arr.filter(item => { 711 // æ¾å°å±æ§éææçä¸çº§å±æ§ åå ¥æ°ç» å¨å¾ªç¯ä¸çº§å±æ§æ¶ä¼å¤ææ¯å¦ç¦ç¨ 712 if (item.qty > 0) { 713 if (this.realLevel1TagList.indexOf(item.option1) === -1) { 714 this.realLevel1TagList.push(item.option1) 715 } 716 } 717 return item.qty > 0 718 }) 719 if (newAllWapVariant.length < arr.length) {//说æé¿åº¦åçäº 720 return newAllWapVariant 721 } else { 722 return arr 723 } 724 725 } else { 726 try { 727 return allWapVariant && allWapVariant !== '(null)null' && allWapVariant !== 'null' ? JSON.parse(allWapVariant) : null; 728 } catch { 729 return null; 730 } 731 } 732 733 } 734 } 735 736 // 设置éä¸çåä½å¯¹è±¡ï¼éè¿ variant-picker ç data-selected-variantï¼ 737 setNewSelectedVariant(selectedOptionValues) {//è§æ ¼å¼åååï¼è®¾ç½®æ°çåä½å¼ï¼æ¾å° 'variant-picker [data-selected-variant]'é 738 const chosenVariant = this.findSelectedVariant(selectedOptionValues, this.currentAllVariant); 739 let selectedVariantNode = this.querySelector(`variant-picker script[data-use-scene="${this.useScene}"][data-selected-variant="${this.productId}"]`); 740 if (chosenVariant && selectedVariantNode) { 741 selectedVariantNode.innerHTML = JSON.stringify(chosenVariant); 742 } 743 } 744 745 /** 746 * @param {Array} selectedValues ç¨æ·å·²ç»éä¸çé项 [{ name, value, position }] 747 * @param {Array} variants ååææå使°ç» 748 * @return {Object|null} æ¾å°åè¿ååä½å¯¹è±¡ï¼å¦åè¿å null 749 */ 750 findSelectedVariant(selectedValues, variants) { 751 $log('findSelectedVariant-2', variants) 752 // éåææåä½ 753 for (const variant of variants) { 754 // æ£æ¥ææé项æ¯å¦é½å¹é 755 const allMatch = selectedValues.every(selected => { 756 // 注æ optionX ç弿å¯è½æ¯ç©ºå符串ï¼ä¹æå¯è½æªå®ä¹ 757 return variant[selected.position] === selected.value; 758 }); 759 if (allMatch) { 760 return variant; // æ¾å°åç´æ¥è¿å 761 } 762 } 763 return null; // æªæ¾å° 764 } 765 766 // 忢 URL å°åæ åæ°ï¼æé variant idï¼ 767 updateURL(id) { 768 $log('enableHistoryState', this.enableHistoryState) 769 if (!this.enableHistoryState || !id) return; 770 window.setUrlVariant('variant', id) 771 } 772 773 // æ´æ°è¡¨åçåä½ id éèè¾å ¥æ¡ 774 // updateVariantInputs(variantId) { 775 // document 776 // .querySelectorAll(`#product-form-${this.dataset.sectionId}, #product-form-installment-${this.dataset.sectionId}`) 777 // .forEach((productForm) => { 778 // const input = productForm.querySelector('input[name="id"]'); 779 // input.value = variantId ?? ''; 780 // input.dispatchEvent(new Event('change', {bubbles: true})); 781 // }); 782 // } 783 784
785 // æç§è§æ ¼ä¸å¯ç¨ï¼æ¯å¦é¡µé¢éè½½ææ è´§ï¼ 786 setUnavailable() { 787 // console.log('没åºå') 788 // const productForm = document.getElementById( 789 // `product-form-${this.sectionId}` 790 // ); 791 // const addButton = productForm.querySelector('[name="add"]'); 792 // if (addButton) { 793 // this.toggleAddButton(true, 'Out of stock'); 794 // } 795 // // éèç¸å ³åºå 796 // const selectors = [ 797 // "Price", "Inventory", "Sku", "Availability" 798 // ].map((id) => `#${id}-${this.sectionId}`).join(", "); 799 // document 800 // .querySelectorAll(selectors) 801 // .forEach((selector) => selector.classList.add('m:hidden')); 802 } 803 804 // å¯ç¨/ç¦ç¨å è´æé®ï¼ä»¥åæå忢 805 toggleAddButton(disable = true, text, modifyClass = true) { 806 const productForm = document.getElementById(`product-form-${this.productId}`); 807 if (!productForm) return; 808 const addButton = productForm.querySelector('[name="add"]'); 809 const addButtonText = productForm.querySelector('[name="add"] > span.f-add-to-cart--text'); 810 if (!addButton) return; 811 812 if (disable) { 813 addButton.setAttribute('disabled', 'disabled'); 814 if (text) addButtonText.textContent = text; 815 } else { 816 addButton.removeAttribute('disabled'); 817 addButtonText.innerHTML = 'Add To Cart'; 818 } 819 } 820 821 // 忢åä½åï¼æ´æ°åå主å¾è½®æåº 822 updateMedia(variant) { 823 $log('æ´æ°è½®æå¾', variant, this.productMedia); 824 if (!this.productMedia) return; 825 // enableVariantGroupImages => æ¯å¦å¼å¯è§æ ¼ç»å¾ç 826 if (this.enableVariantGroupImages && this.variantGroupImagesData.enable) { 827 $log('æ¯ååè§æ ¼å¾æ¨¡å¼') 828 this.handleVariantGroupImage(variant); 829 // 汽车åå¾éå ¼å®¹ swiper æ»åã缩ç¥å¾åæ¥å¨ç»ç 830 if (this.productMedia.slider) { 831 this.productMedia.slider.updateSlides(); 832 this.productMedia.navSlider.updateSlides(); 833 this.productMedia.slider.slideTo(0); 834 this.productMedia.navSlider.slideTo(0); 835 this.productMedia.handleSlideChange(); 836 } 837 if (this.productMedia.enableImageZoom) { 838 this.productMedia.handlePhotoswipe(); 839 } 840 } else { 841 // æ®éå¾çå¤çï¼å»¶è¿æºå¶ä¿è¯ setActiveMedia åå¨ 842 $log('æ®éå¾çå¤ç', this.productMedia.slider.slides) 843 if (this.productMedia.slider && this.productMedia.slider.slides && this.productMedia.slider.slides.length) { 844 for (let i = 0; i < this.productMedia.slider.slides.length; i++) { 845 let slider = this.productMedia.slider.slides[i]; 846 if (slider.dataset.groupMediaSrc === variant.image) { 847 this.productMedia.slider.slideTo(i); 848 this.productMedia.navSlider.slideTo(i); 849 break 850 } 851 } 852 853 } 854 855 } 856 } 857 858 // âç¦ç¨èªå¨éä¸åä½âé»è¾åå§åï¼å ¨é¨é项é½ä¸éï¼ 859 handleDisableSelectedVariantDefault() { 860 let urlParams = new URLSearchParams(window.location.search); 861 if (urlParams.has("variant")) return; 862 863 this.pickerFields = this.querySelectorAll("[data-picker-field]"); 864 865 this.pickerFields && this.pickerFields.forEach((field) => { 866 let pickerType = field.dataset.pickerField; 867 switch (pickerType) { 868 case "select": 869 let selectBox = field.querySelector("select"); 870 let option = document.createElement("option"); 871 option.text = this.dataset.variantOptionNoneText; 872 option.setAttribute("disabled", ""); 873 option.setAttribute("selected", ""); 874 selectBox.add(option, 0); 875 break; 876 default: 877 let checkedInputs = field.querySelectorAll("input:checked"); 878 checkedInputs &&
879 checkedInputs.forEach(function (input) { 880 input.removeAttribute("checked"); 881 }); 882 break; 883 } 884 field.dataset.selectedValue = ""; 885 if (field.querySelector(".option-label--selected")) field.querySelector(".option-label--selected").textContent = ""; 886 }); 887 888 this.setUnavailable(); 889 this.currentVariant = null; 890 } 891 892 // åä½ç»å¾çå¤çï¼æå®åä½çå¾çã顺åºã缩ç¥å¾ï¼ 893 handleVariantGroupImage(variant) { 894 $log('åä½ç»å¾çå¤ç-ååè§æ ¼å¾') 895 const selectedVariantData = this.variantGroupImagesData.mapping.find( 896 (item) => Number(item.id) === variant.id 897 ); 898 $log('åä½ç»å¾çå¤ç-ååè§æ ¼å¾', selectedVariantData) 899 900 // å é¨å·¥å ·ï¼è¿åæåºå¥½çåªä½èç¹æ°ç» 901 const selectedMedias = (initialItems) => { 902 const selectedVariantMedias = Array.from(initialItems) 903 .map((media) => { 904 const index = selectedVariantData.media.indexOf(media.dataset.mediaId); 905 const mediaType = media.dataset.mediaType; 906 if (index !== -1 || mediaType !== 'image') { 907 return media; 908 } 909 return null; 910 }) 911 .filter(Boolean); 912 913 // 主å¾åè¡¨ä¸ºç©ºåæ¾ç¤ºå ¨é¨ 914 if (selectedVariantMedias.length <= 0) { 915 return Array.from(initialItems).map((media, index) => { 916 media.dataset.index = index; 917 media.removeAttribute('style'); 918 media.querySelector('.f-product-media').setAttribute("style", `--animation-order: ${index + 1};`); 919 return media; 920 }); 921 } 922 923 // åä½å¾çæåº: mapping 顺åºä¼å 924 const orderedMedias = Object.values(selectedVariantData.media) 925 .map(id => selectedVariantMedias.find(media => media.dataset.mediaId === id)) 926 .filter(Boolean); 927 const remainingMedias = selectedVariantMedias.filter(media => !Object.values(selectedVariantData.media).includes(media.dataset.mediaId)); 928 929 // åå¹¶ï¼ä¿è¯å¨ç»é¡ºåºæ ·å¼ 930 return Array.from([...orderedMedias, ...remainingMedias]).map((media, index) => { 931 media.dataset.index = index; 932 media.removeAttribute('style'); 933 media.querySelector('.f-product-media').setAttribute("style", `--animation-order: ${index + 1};`); 934 return media; 935 }); 936 } 937 938 // åªä½å缩ç¥å¾ DOM å®¹å¨ 939 const mediaWrapper = this.productMedia.querySelector(".f-media-gallery__list"); 940 const thumbWrapper = this.productMedia.querySelector(".f-product-media--slider__thumbnails .swiper-wrapper"); 941 const layout = this.productMedia.dataset.layout; 942 943 // å æ¸ 空ï¼åéæ°æå ¥åä½å¯¹åºçåªä½ DOM 944 mediaWrapper.innerHTML = ""; 945 thumbWrapper.innerHTML = ""; 946 947 selectedMedias(this.initialMedias).forEach((media, index) => { 948 // å¸å±2éå¤§æ ¼å¾-è·¨2å 949 if (layout === "layout-2") { 950 media.classList.remove("f-col-span-2"); 951 if (index % 3 === 0) { 952 media.classList.add("f-col-span-2"); 953 } 954 } 955 mediaWrapper.append(media); 956 }); 957 selectedMedias(this.initialThumbs).forEach((media) => { 958 media.classList.toggle("swiper-slide-thumb-active", media.dataset.index === "0"); 959 thumbWrapper.append(media); 960 }); 961 } 962 963 // -------- æ°éè¾å ¥åºåè½å¤ç --------- 964 initQuantityHandlers() { 965 if (this.quantityInputs.length <= 0) return; 966 this.setQuantityBoundries(); 967 if (!this.hasAttribute("data-original-section-id")) { 968 // è´ç©è½¦å忶忥è§åï¼é常ç¨äºéå¶æ¯äººéè´ä¹ç±» 969 // this.cartUpdateUnsubscriber = MinimogEvents.subscribe( 970 // MinimogTheme.pubSubEvents.cartUpdate, 971 972 // ); 973 } 974 } 975 976 // 设置æ°éè¾å ¥æ¡çéè´è§å 977 setQuantityBoundries() {
978 this.quantityInputs.forEach((input) => { 979 const quantityInputWrapper = input.closest('f-quantity-input'); 980 quantityInputWrapper.setQuantityBoundries(this.productId, this.productId); 981 }); 982 } 983 984 985 // å ·ä½æ´æ°é¡µé¢æ°éè§å DOM 986 updateQuantityRules(sectionId, productId, parsedHTML) { 987 if (this.quantityInputs.length <= 0) return; 988 this.quantityInputs.forEach((input) => { 989 const quantityInputWrapper = input.closest('f-quantity-input'); 990 quantityInputWrapper.updateQuantityRules(sectionId, productId, parsedHTML); 991 }); 992 this.setQuantityBoundries(); 993 } 994 995 // --------- è®°å½æè¿æµè§ï¼cookie ä¸ï¼ ----------- 996 addRecentViewedProduct() { 997 // const cookies = Cookies.get('f-recent-viewed-products') 998 // let products = cookies ? JSON.parse(cookies) : [] 999 // if (products.indexOf(MinimogSettings.productHandle) === -1) { 1000 // products.unshift(MinimogSettings.productHandle) 1001 // products = products.slice(0, 20) 1002 // Cookies.set('f-recent-viewed-products', JSON.stringify(products)); 1003 // } 1004 } 1005 1006 // ---------- 页é¢å è½½ååè° (åå页头é¨ç¶æç) ---------- 1007 onWindowLoad() { 1008 this.acc = []; 1009 // å¤çå¯¹æ¯æé®/å¿æ¿åæé® 1010 // MinimogTheme.CompareProduct && MinimogTheme.CompareProduct.setCompareButtonsState(); 1011 // MinimogTheme.Wishlist && MinimogTheme.Wishlist.setWishlistButtonsState(); 1012 this.addRecentViewedProduct(); 1013 1014 // é对 collapsibleï¼åå详æ 坿å 项ï¼å è¯ä»·åºåï¼äºä»¶å¤ç 1015 addEventDelegate({ 1016 context: this, 1017 selector: (window.__minimog_review_selector || '') + '.f-product-collapsible .jdgm-widget-actions-wrapper, .f-product-collapsible .spr-summary-actions-newreview', 1018 handler: (e) => { 1019 const index = e.target.closest('.f-product-collapsible').dataset.index 1020 setTimeout(() => { 1021 this.acc[Number(index)].setContentHeight() 1022 }, 300) 1023 }, 1024 capture: true 1025 }) 1026 } 1027 1028 // å¼å§è®¾ç½®æ¯å¦æ¾ç¤ºè²å¡ç说æä¿¡æ¯ 1029 setColorImageTooltipText() { 1030 // $log('å¼å§è®¾ç½®æ¯å¦æ¾ç¤ºè²å¡ç说æä¿¡æ¯', this.currentVariant) 1031 let colorCard = this.querySelector(['[data-picker-type="color"]']) || null 1032 1033 // å®ä¹ä¸ä¸ªåéæ¥è®°å½æ¯å¦æ¾å°äºå¹é 项 1034 let foundMatchingTooltip = false; 1035 1036 if (colorCard) { 1037 // $log('æåå屿§è²å¡', colorCard) 1038 // è·åææ .f-color-image-tooltip å ç´ 1039 let tooltips = colorCard.querySelectorAll('.f-color-image-tooltip'); 1040 // ä½¿ç¨ for 循ç¯è¿è¡éå 1041 for (let i = 0; i < tooltips.length; i++) { 1042 let tooltip = tooltips[i]; 1043 let optionPosition = tooltip.getAttribute('data-option-position'); 1044 let optionName = tooltip.getAttribute('data-option-name'); 1045 let value = tooltip.getAttribute('data-value'); 1046 let optionKey = 'option' + optionPosition; 1047 // $log('data-option-position:', optionPosition); 1048 // $log('data-option-name:', optionName); 1049 // console.log('data-option-value:', value); 1050 // 妿å½åé项å¼åå½ååä½å¹é ï¼æ¾å°å¯¹åºæ ç¾å¹¶éåºå¾ªç¯ 1051 if (this.currentVariant[optionKey] === value) { 1052 // $log('æ¾å°è¿ä¸ªæ ç¾äº', tooltip); 1053 1054 // åªæ¿æ¢ f-color-image-tooltip-content çå 容 1055 let contentContainer = colorCard.querySelector('.f-color-image-tooltip-content'); 1056 if (contentContainer) { 1057 // æ¸ ç©ºä¹åçå å®¹ï¼æå ¥æ°çtooltipæ ç¾ 1058 contentContainer.innerHTML = ''; // æ¸ ç©ºåå 容 1059 contentContainer.appendChild(tooltip.cloneNode(true)); // éæ°æå ¥å¹é çtooltip 1060 } 1061 1062 // 设置为已æ¾å°å¹é çæ ç¾ 1063 foundMatchingTooltip = true; 1064 break;
1064 // 䏿¦æ¾å°å¹é çæ ç¾ï¼éåºå¾ªç¯ 1065 } 1066 1067 } 1068 // å¦ææ²¡ææ¾å°å¹é çæ ç¾ï¼å é¤ colorCard æåç tooltipï¼å¦ææï¼ 1069 if (!foundMatchingTooltip) { 1070 let contentContainer = colorCard.querySelector('.f-color-image-tooltip-content'); 1071 if (contentContainer) { 1072 contentContainer.innerHTML = ''; 1073 } 1074 } 1075 } 1076 1077 } 1078 1079 //æ£æ¥æå°è´ä¹°æ°é 1080 checkedBuyMinCount() { 1081 $log('currentVariant', this.currentVariant) 1082 if (this.currentVariant && this.currentVariant.buy_min_count && this.currentVariant.buy_min_count > 1) {//妿å家端åå°è®¾ç½®äº é£ä¹ç¨å家端åå°çï¼å¦åè¿åé»è®¤1 1083 let buy_min_count = Number(this.currentVariant.buy_min_count) 1084 $log('buy_min_count', this.sectionId) 1085 let quantityInput = this.querySelector('#Quantity-' + this.sectionId) 1086 if (quantityInput) { 1087 quantityInput.min = buy_min_count; // 设置 min 屿§ 1088 quantityInput.value = buy_min_count; // 设置 value 1089 const el = document.querySelector(`f-quantity-input[data-section-id="${this.sectionId}"]`); 1090 if (el) { 1091 el.onInputChange() 1092 } 1093 } 1094 } else { 1095 let quantityInput = this.querySelector('#Quantity-' + this.sectionId) 1096 if (quantityInput) { 1097 quantityInput.min = 1; // 设置 min 屿§ 1098 quantityInput.value = 1; // 设置 value 1099 const el = document.querySelector(`f-quantity-input[data-section-id="${this.sectionId}"]`); 1100 if (el) { 1101 el.onInputChange() 1102 } 1103 } 1104 } 1105 } 1106 1107 1108 } 1109 1110 // 注åç»ä»¶ 1111 customElements.define("product-info", ProductInfo); 1112} 1113 1114class ProductListAttr extends HTMLElement { 1115 connectedCallback() { 1116 $log('ProductListAttr', this.dataset) 1117 if (this.dataset.defaultHiden === '1') {//é»è®¤éèï¼éè¦å¤ææ¯å¦ç»å½ 1118 if ($getLoginInfo()) { 1119 // 妿已ç»ç»å½ï¼å»æéè 1120 this.classList.remove('m:hidden'); 1121 } 1122 } 1123 } 1124} 1125 1126customElements.define("f-product-list-attr", ProductListAttr); 1127 1128 1129class ProductWholesalePrice extends HTMLElement {//ååä»·æ ¼æ¹å 1130 connectedCallback() { 1131 this.productId = this.dataset.productId; 1132 // this.updateWholesalePrice() 1133 // è§æ ¼/é项忴äºä»¶è®¢é ï¼æ¯å¦åæ¢é¢è²å°ºç ï¼ 1134 this.firstWholesaleText = this.dataset.firstWholesaleText;//æ¹åä»·æ ¼å¦ææ¯ç¬¬ä¸ä¸ªæ¾ç¤ºçæåï¼xx个起æ¹ï¼ 1135 this.wholesaleText = this.dataset.wholesaleText;//第ä¸ä¸ªä»¥å¤çæåï¼æ¯å¦>=xxä»¶ 1136 FecEvents.on(FecTheme.pubSubEvents.optionValueSelectionChange, (payload) => { 1137 this.updateWholesalePrice()//æ´æ°ååæ¹åä»·æ ¼ 1138 }); 1139 } 1140 1141 updateWholesalePrice() {//æ´æ°ååæ¹åä»·æ ¼ 1142 let selectedVariant = this.getSelectedVariant() 1143 $log('ååä»·æ ¼æ¹å-订é äºä»¶-å½åéä¸çåä½:', selectedVariant); 1144 if (selectedVariant && selectedVariant.wholesale_price && selectedVariant.wholesale_price.length > 0) { 1145 $log('ææ¹åä»·æ ¼') 1146 this.classList.remove('m:hidden'); 1147 // const price = this.formatMoney(this.state.shippingCost.curr_shipping_cost || 5.99); 1148 $log('this.firstWholesaleText', this.firstWholesaleText) 1149 $log('this.wholesaleText', this.wholesaleText) 1150 this.renderWholesalePrice(selectedVariant) 1151 } else { 1152 $log('æ²¡ææ¹åä»·æ ¼') 1153 this.classList.add('m:hidden'); 1154 1155 } 1156 1157 } 1158 1159 /** 1160 * æ¸²ææ¹åä»· 1161 * @param {Object} selectedVariant - å½åå使°æ® 1162 */ 1163 renderWholesalePrice(selectedVariant) { 1164 const box = this.querySelector('.wholesale-price-list'); 1165 if (!box) return; 1166 1167 const list = Array.isArray(selectedVariant?.wholesale_price) 1168 ? selectedVariant.wholesale_price 1169 : []; 1170 1171 if (!list.length) { 1172 box.innerHTML = ''; 1173 this.classList.add('m:hidden'); 1174 return; 1175 } 1176 1177 this.classList.remove('m:hidden'); 1178 1179 let html = ''; 1180 1181 list.forEach((item, idx) => { 1182 // æ ¼å¼åä»·æ ¼ 1183 const priceHTML = this.formatMoney(item.price); 1184 1185 // æ°éææ¡ 1186 let numberHTML = ''; 1187 if (idx === 0) { 1188 // ç¬¬ä¸æ¡ï¼æ¿æ¢ firstWholesaleText éç 10086 1189 numberHTML = `
1190 <span class="w-number pc" data-role="number"> 1191 ${this.firstWholesaleText.replace('10086', item.qty)} 1192 </span> 1193 <span class="w-number wap" data-role="number"> 1194 ${this.wholesaleText.replace('10086', item.qty)} 1195 </span>`; 1196 } else { 1197 // å ¶ä»æ¡ï¼æ¿æ¢ wholesaleText éç 10086 1198 numberHTML = ` 1199 <span class="w-number" data-role="number"> 1200 ${this.wholesaleText.replace('10086', item.qty)} 1201 </span>`; 1202 } 1203 1204 html += ` 1205 <div class="wholesale-price-item"> 1206 <p class="w-price" data-role="price">${priceHTML}</p> 1207 ${numberHTML} 1208 </div>`; 1209 }); 1210 1211 // æ¿æ¢æ´ä¸ª wholesale-price-list å é¨ 1212 box.innerHTML = html; 1213 } 1214 1215 // è§£æå½åéä¸çåä½å¯¹è±¡ï¼éè¿ variant-picker ç data-selected-variantï¼ 1216 getSelectedVariant() {//é»è®¤éä¸çæ°æ® 1217 $log('getSelectedVariant-é»è®¤éä¸çæ°æ®', this.productId) 1218 let selectedVariant = document.querySelector(`variant-picker [data-selected-variant="${this.productId}"]`)?.innerHTML; 1219 if (selectedVariant) { 1220 return !!selectedVariant ? JSON.parse(selectedVariant) : null; 1221 } 1222 } 1223 1224 // æ ¼å¼åè´§å¸ 1225 formatMoney(amount) { 1226 // åªåæ¨¡æ¿ 1227 let scriptElement = document.querySelector('script[data-product-wholesale-price-template]'); 1228 if (!scriptElement) return ''; 1229 1230 // ç¼ååå§æ¨¡æ¿ï¼åªå䏿¬¡ 1231 if (!scriptElement._cachedTemplate) { 1232 scriptElement._cachedTemplate = scriptElement.innerHTML.trim(); 1233 } 1234 const template = scriptElement._cachedTemplate; 1235 1236 // æåå§ä»·æ ¼ 1237 const priceSpanElement = template.match(/<span>([^<]+)<\/span>/); 1238 if (!priceSpanElement) return template; 1239 1240 let originalPriceText = priceSpanElement[1]; 1241 1242 // å¤ææ ¼å¼ 1243 const hasDecimal = originalPriceText.includes('.'); 1244 const hasComma = originalPriceText.includes(','); 1245 let formattedPrice; 1246 1247 if (hasDecimal && /\.\d{2}$/.test(originalPriceText)) { 1248 // å°æ°ç¹ï¼ä¸¤ä½å°æ° 1249 let [intPart, decimalPart] = parseFloat(amount).toFixed(2).split('.'); 1250 intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ","); 1251 formattedPrice = intPart + '.' + decimalPart; 1252 } else if (hasDecimal && !/\.\d{2}$/.test(originalPriceText)) { 1253 // . ä½ä¸ºååä½ 1254 formattedPrice = Math.round(amount) 1255 .toString() 1256 .replace(/\B(?=(\d{3})+(?!\d))/g, "."); 1257 } else if (hasComma) { 1258 // , ä½ä¸ºååä½ 1259 formattedPrice = Math.round(amount) 1260 .toString() 1261 .replace(/\B(?=(\d{3})+(?!\d))/g, ","); 1262 } else { 1263 // çº¯æ´æ° 1264 formattedPrice = Math.round(amount).toString(); 1265 } 1266 1267 // è¿åæ°çç»æ 1268 return template.replace(/<span>[^<]+<\/span>/, `<span>${formattedPrice}</span>`); 1269 } 1270 1271 1272} 1273 1274customElements.define("product-wholesale-price", ProductWholesalePrice); 1275 1276 1277if (!customElements.get("f-product-reviews")) { 1278 class FProductReviews extends HTMLElement { 1279 constructor() { 1280 super(); 1281 } 1282 1283 connectedCallback() { 1284 1285 let tabs = document.querySelector('f-product-details-tabs'); 1286 if (tabs) { 1287 let headers = document.querySelectorAll('.f-tabs__header-inner .f-tab-header') 1288 let viewBtn = this.querySelector('.f-view-btn') 1289 let reviewsShow = false 1290 let reviewsIndex = -1 1291 if (headers.length) { 1292 for (let i = 0; i < headers.length; i++) { 1293 let header = headers[i]; 1294 if (header.dataset.blockType === 'reviews') { 1295 reviewsIndex = i//ç¡®è®¤ä¸æ 1296 reviewsShow = true; 1297 break; 1298 } 1299 } 1300 1301 } 1302 if (reviewsShow) { 1303 viewBtn.classList.remove('m:hidden'); 1304 viewBtn.addEventListener('click', () => { 1305 tabs.setActiveTab(reviewsIndex) 1306 requestAnimationFrame(() => { 1307 const headerHeight = parseInt( 1308 getComputedStyle(document.documentElement).getPropertyValue('--f-header-height') 1309 ) || 0; 1310 1311 const rect = tabs.getBoundingClientRect(); 1312 const elementTop = window.scrollY + rect.top - headerHeight; 1313 1314 window.scrollTo({ 1315 top: elementTop, 1316 behavior: 'smooth' 1317 }); 1318 $log('ç¹å»äºæ¥ç', reviewsIndex) 1319 }) 1320 }) 1321 } 1322 } 1323 1324 } 1325 } 1326
1327 customElements.define("f-product-reviews", FProductReviews); 1328} 1329
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.