PageSourceSearch

https://www.goodwaytechs.com/assets/js/unit/product-list.js

js goodwaytechs.com collected 2026-10-04 04:05:24 UTC 33,450 bytes, 878 lines download raw bytes

1class ScriptProductList extends Script {
2  constructor(params) {
3    super(params)
4    // 产品列表组件dom
5    this.$productUnit = document.getElementById(`${this.attrId}`)
6    if (!this.$productUnit) return
7    // tab选项卡dom
8    this.$tabList = this.$productUnit.querySelectorAll('.nav-item')
9    // 产品选项卡内容dom
10    this.$tabTypeItem = this.$productUnit.querySelectorAll('[tab-type]')
11    this.$imgBoxs = this.$productUnit.querySelectorAll('.unit-product-list__image')
12    this.pageInfo = JSON.parse(this.utilts.htmlDecode(params.pageInfo))
13    this.swiper = JSON.parse(this.utilts.htmlDecode(params.swiper))
14    this.colInfo = JSON.parse(this.utilts.htmlDecode(params.colInfo))
15    this.config = JSON.parse(this.utilts.htmlDecode(params.config))
16    this.config.hover_img = (params.hoverImg === 'true')
17    this.open_hover = params.open_hover // hover动画   fadeInUp,fadeOutUp,
18  }
19
20  render() {
21    if (this.$productUnit._zoom && this.$productUnit._zoom.render) {
22      this.$productUnit._zoom.render()
23    }
24  }
25
26  async init() {
27    const params = {
28      open_hover: this.open_hover,
29      attrId: this.attrId,
30      pageInfo: this.pageInfo,
31      swiper: this.swiper,
32      colInfo: this.colInfo,
33      config: this.config,
34    }
35
36    this.clientData = new ScriptProductListData(params)
37    await this.clientData.initLoadData()
38    this.initAllInfo()
39  }
40
41  /** 初始化选项卡切换事件 */
42  initTabEvent() {
43    if (this.$tabList.length === 0) return
44    this.$tabList.forEach($tab => {
45      $tab.addEventListener('click', () => {
46        // 当前选项卡选中
47        this.$tabList.forEach(p => p.classList.remove('active'))
48        $tab.classList.add('active')
49        // 当前内容选中
50        const tabtype = $tab.dataset.tabtype
51        // 产品选项卡内容dom
52        const $tabTypeItem = this.$productUnit.querySelectorAll('[tab-type]')
53        $tabTypeItem.forEach($tabContent => {
54          const selected = $tabContent.getAttribute('tab-type') === tabtype
55          if (selected) {
56            $tabContent.classList.remove('d-none')
57          } else {
58            $tabContent.classList.add('d-none')
59          }
60        })
61      })
62    })
63  }
64
65  initWinEvent() {
66    const hoverImgEffect = (this.open_hover || '').replace(/[^A-Za-z0-9,_-]/g, '').split(',')
67    const hoverImgIn = hoverImgEffect[0] || ''
68    const hoverImgOut = hoverImgEffect[1] || ''
69    const hoverImgDuration = hoverImgEffect[2] || ''
70    this.$imgBoxs = this.$productUnit.querySelectorAll('.unit-product-list__image')
71    if (!this.$imgBoxs.length) return
72    const name = '.unit-product-list__btns'
73    this.$imgBoxs.forEach($item => {
74      let h_dom = $item.querySelector('.unit-product-list__img[hover-img="true"] .unit-list-hover__image')
75      const hoverProductImg = $item.querySelector('.unit-product-list__img[hover-img="true"]')
76      const video_gif = hoverProductImg ? hoverProductImg.getAttribute('video-gif') : ''
77      let h_img = ''
78      let hoverNextImg = null
79      let e_in = video_gif ? '' : hoverImgIn ? `animate__${hoverImgIn}` : ''
80      let e_out = video_gif ? '' : hoverImgOut ? `animate__${hoverImgOut}` : ''
81      if (h_dom) {
82        h_img = h_dom.querySelector('img')
83        hoverNextImg = h_img && h_img.src
84        // e_in = 'animate__' + h_img.getAttribute('effect-in')
85        // e_out = 'animate__' + h_img.getAttribute('effect-out')
86        const dom = $item.querySelector('.unit-product-list__img[hover-img="true"]')
87        if (dom) {
88          const style_val = window.getComputedStyle(dom)
89          const pt = style_val['paddingTop'] || '0px'
90          const pb = style_val['paddingBottom'] || '0px'
91          const pl = style_val['paddingLeft'] || '0px'
92          const pr = style_val['paddingRight'] || '0px'
93          if (`${pt + pb + pl + pr}` !== '0px0px0px0px') {
94            h_dom.setAttribute('style', `top:${pt};left:${pl};width:calc(100% - ${pl} - ${pr});height:calc(100% - ${pt} - ${pb});`)
95          }
96        }
97      }
98
99      let originImg = $item.children[0].children[0].querySelector('.base-image__item') // hover原图的效果
100      if (hoverImgDuration) {
101        originImg.classList.add(hoverImgDuration)
102      }
103      h_dom && h_dom.classList.add('hover_img_before_load')
104      $item.addEventListener('mouseover', () => {
105        const $winBox = $item.querySelector(name)
106        // 功能不完善,暂不启用
107        // if ($winBox) $winBox.classList.remove('d-none')
108        let h_img = $item.querySelector('.unit-list-hover__image img')
109        const hoverNextImg = h_img && h_img.src
110        if (h_dom && h_dom.classList.contains('hover_img_before_load')) {
111          h_dom.classList.remove('hover_img_before_load')
112        }
113        if (hoverNextImg) {
114          if (e_in) {
115            originImg.classList.remove(e_in)
116            if (h_dom) {
117              h_dom.classList.add(e_in, 'animate__animated')
118            }
119          }
120          if (e_out) {
121            originImg.classList.add(e_out, 'animate__animated')
122            if (h_dom) {
123              h_dom.classList.remove(e_out)
124            }
125          } else {
126            originImg.classList.add('opacity0')
127          }
128        } else {
129          if (e_in) {
130            originImg.classList.add(e_in, 'animate__animated')
131          }
132          if (e_out) {
133            originImg.classList.remove(e_out)
134          }
135        }
136        const video_gif = hoverProductImg ? hoverProductImg.getAttribute('video-gif') : ''
137        if (video_gif) {
138          originImg.classList.add('opacity0')
139          // h_img.setAttribute('src', video_gif)
140          $item.querySelector('.base-video__play')?.classList.add('opacity0')
141        }
142      })
143
144
145      $item.addEventListener('mouseout', () => {
146        const $winBox = $item.querySelector(name)
147        if ($winBox) $winBox.classList.add('d-none')
148        originImg.classList.remove('opacity0')
149        let h_img = $item.querySelector('.unit-list-hover__image img')
150        const hoverNextImg = h_img && h_img.src
151        if (hoverNextImg) {
152          if (e_in) {
153            originImg.classList.add(e_in, 'animate__animated')
154            h_dom.classList.remove(e_in)
155          }
156          if (e_out) {
157            originImg.classList.remove(e_out)
158            h_dom.classList.add(e_out, 'animate__animated')
159          } else {
160            if (h_dom) {
161              h_dom.classList.add('hover_img_before_load')
162            }
163          }
164        } else {
165          if (e_in) {
166            originImg.classList.remove(e_in)
167          }
168          // if (e_out) {
169          //   originImg.classList.add(e_out, 'animate__animated')
170          // }
171        }
172        const video_gif = hoverProductImg ? hoverProductImg.getAttribute('video-gif') : ''
173        if (video_gif) {
174          // h_img.setAttribute('src', '')
175          $item.querySelector('.base-video__play')?.classList.remove('opacity0')
176        }
177      })
178
179    })
180
181  }
182
183  initOtherEvent() {
184    if (!this.$ImgBoxs) return
185    this.$ImgBoxs.forEach($item => {
186      const $btnView = $item.querySelector('.unit-product-list__btn--view')
187      if ($btnView === null) return
188      $btnView.addEventListener('click', (event) => {
189        event.stopPropagation()
190        // new Message().info('查看成功')
191      })
192      const $btnlike = $item.querySelector('.unit-product-list__btn--like')
193      $btnlike.addEventListener('click', (event) => {
194        event.stopPropagation()
195        // new Message().info('点赞成功')
196      })
197      const $btnCart = $item.querySelector('.unit-product-list__btn--cart')
198      $btnCart.addEventListener('click', (event) => {
199        event.stopPropagation()
200        // new Message().info('添加购物车成功')
201      })
202    })
203  }
204  /** 限时产品,显示倒计时 */
205  showCountTime() {
206    // 查找所有限时折扣产品
207    const $limit = this.$productUnit.querySelectorAll('.unit-product-list__limit')
208    if (!$limit) return
209    $limit.forEach(($limitItem, index) => {
210      this.setCountTime($limitItem)
211    })
212  }
213
214  /** 设置倒计时 */
215  setCountTime($limitItem) {
216    // 活动开始时间
217    const startdate = $limitItem.dataset.startdate
218    // 活动结束时间
219    const enddate = $limitItem.dataset.enddate
220    // 当前产品id,方便删除倒计时结束的产品
221    const productId = $limitItem.dataset.productid;
222    const countInfo = this.utilts.getCountTime(startdate, enddate)
223    // 如果未有开始时间或结束时间退出
224    if (!countInfo) return
225    const $discountTimer = $limitItem.querySelector(`.discount-timer`)
226    const time = this.utilts.getTimeParseInt(countInfo.counttime)
227    this.utilts.countTime(time, $discountTimer, countInfo.type, () => {
228      if (countInfo.type === 'now') {
229        this.showClearProductNoData(productId)
230      } else if (countInfo.type === 'upcoming') {
231        this.setCountTime($limitItem)
232      }
233    })
234  }
235
236  /** 初始化所有信息 */
237  async initAllInfo() {
238    // 初始选项卡切换事件
239    this.initTabEvent()
240    const that = this
241    const initContent = () => {
242      // 等待contentRender完成再进行初始化
243      // 初始化mouse经过显示隐藏事件
244      setTimeout(function () {
245        that.initWinEvent()
246      }, 500)
247    }
248    if (this.utilts.checkDesign() || (window.app && window.app.hookEvents && window.app.hookEvents['hookInitContentRender'])) {
249      initContent();
250    } else {
251      window.addEventListener('hookInitContentRender', initContent, {
252        once: false
253      })
254    }
255    // 初始华按钮事件
256    this.initOtherEvent()
257    // 限时产品倒计时
258    this.showCountTime()
259    // 放大图片
260    if (this.config.target === 'zoom') {
261      await new Load('/assets/plugins/zoom.js')
262      this.$productUnit._zoom = new ZoomBuilder({
263        attrId: this.attrId,
264        dom: this.$productUnit,
265        selector: '.unit-list__image--zoom[zoom-img="true"]',
266        titleSelector: ".unit-product-list__title",
267        boxClass: 'product-list-zoom-box'
268      })
269    }
270  }
271
272  /** 如果倒计时结束删除产品,如果全部删除,显示nodata */
273  showClearProductNoData(productId) {
274    const $productIntm = this.$productUnit.querySelector(`[data-id="${productId}"]`)
275    $productIntm.remove($productIntm)
276    const $showNoData = this.$productUnit.querySelector('.show-no-data')
277    if ($showNoData) $showNoData.classList.remove('d-none')
278  }
279
280  /**
281   * 属性参数查找,客户端无刷新渲染数据
282   */
283  async renderList(keyword='') {
284    this.clientData.pageInfo.page_number = window.app.info.pagination.page_number || 1
285    const $pageContent = this.$productUnit.querySelector('[tab-type="page_content"]')
286    if ($pageContent) {
287      const data = await this.clientData.getPageContentList(keyword)
288      const $noData = this.$productUnit.querySelector('.show-no-data')
289      if (data.list.length === 0) {
290        $pageContent.innerHTML = ''
291        if ($noData) $noData.classList.remove('d-none')
292      } else {
293        if ($noData) $noData.classList.add('d-none')
294        this.clientData.getTabList($pageContent, data.list)
295      }
296      const self = this;
297      if (!self.contentRenderLock) {
298        self.contentRenderLock = setTimeout(function () {
299          self.contentRenderLock = null
300        })
301        if (window.app && window.app.initContentRender) {
302          await window.app.initContentRender(self.$productUnit)
303        }
304      }
305      this.initAllInfo()
306    }
307  }
308}
309
310/** 客户端加载数据 */
311class ScriptProductListData {
312  constructor(params) {
313    this.open_hover = params.open_hover
314    this.attrId = params.attrId
315    // 分页信息
316    this.pageInfo = params.pageInfo
317    // 轮播信息
318    this.swiper = params.swiper
319    this.is_swiper = this.swiper.is_swiper
320    // 列数信息
321    this.colInfo = params.colInfo
322    // 配置信息
323    this.config = params.config
324    this.init()
325  }
326
327  init() {
328    this.initSelector()
329  }
330  /**
331   * 初始化选择器,判断是否是需要客户端加载数据
332   */
333  initSelector() {
334    // 正在进行的限时折扣页
335    this.$discountNowPage = document.querySelector('[page-type="product_discount_now"]')
336    // 即将进行的限时折扣页
337    this.$discountUpcomingPage = document.querySelector('[page-type="product_discount_upcoming"]')
338    // 无数据时显示Nodata
339    this.$discountNoData = document.querySelector(".discount_page_no_data")
340    // 如果有表示限时折扣页
341    if (this.$discountNowPage) {
342      this.$now = this.$discountNowPage.querySelector('[tab-type="page_content"]')
343    } else if (this.$discountUpcomingPage) {
344      // 如果有表示正在进行的限时折扣页
345      this.$upcoming = this.$discountUpcomingPage.querySelector('[tab-type="page_content"]')
346    } else {
347      // 是否是客户加载的组件tab项
348      this.$productUnit = document.getElementById(`${this.attrId}`)
349      if (this.$productUnit) {
350        // 正在进行的限时折扣tab项
351        this.$now = this.$productUnit.querySelector('[tab-type="now"]')
352        // 即将进行的限时折扣tab项
353        this.$upcoming = this.$productUnit.querySelector('[tab-type="upcoming"]')
354        // 历史记录的tab项
355        this.$history = this.$productUnit.querySelector('[tab-type="history"]')
356      }
357    }
358  }
359
360  async initLoadData() {
361    const num = this.pageInfo.page_number
362    const size = this.pageInfo.page_size || 12
363    if (this.$now) {
364      console.log('this.$now');
365      const data = await window.app.getProductListPageBySearch('now', num, size)
366      if (data) this.getTabList(this.$now, data.list)
367      this.initVideoData(this.$now)
368    }
369    if (this.$upcoming) {
370      console.log('this.$upcoming');
371      const data = await window.app.getProductListPageBySearch('upcoming', num, size)
372      if (data) this.getTabList(this.$upcoming, data.list)
373      this.initVideoData(this.$upcoming)
374    }
375    if (this.$history) {
376      console.log('this.$history');
377      const data = await window.app.getProductListPageBySearch('history', num, size)
378      if (data) this.getTabList(this.$history, data.list)
379      this.initVideoData(this.$history)
380    }
381  }
382
383	initVideoData(currentDom) {
384		const doms = currentDom?.querySelectorAll('.unit-product-list__img[video-gif]')
385		if (doms.length) {
386			doms.forEach(item => {
387				this.renderHoverImg(item)
388			})
389		}
390	}
391	renderHoverImg(node) {
392		const video_gif = node.getAttribute('video-gif')
393		console.log('video_gif', video_gif, node);
394		node.setAttribute('hover-img', true)
395		node.setAttribute('video-gif', video_gif)
396		let hoverImgEl = ''
397		if (node.querySelector('.unit-list-hover__image > img')) {
398			hoverImgEl = node.querySelector('.unit-list-hover__image > img')
399			hoverImgEl.setAttribute('lazy-src', video_gif)
400			const wrapper = node.children[0].cloneNode(true)
401			wrapper.querySelector('.base-image__item').innerHTML = hoverImgEl.outerHTML
402			node.querySelector('.unit-list-hover__image').innerHTML = wrapper.outerHTML
403			const hoverImg = node.querySelector('.unit-list-hover__image img')
404			new LazyImg(hoverImg)
405			// node.querySelector('.unit-list-hover__image img').setAttribute('lazy-type', '')
406		} else {
407			hoverImgEl = document.createElement('div')
408			// unit-list-hover__image animate__animated hover_img_before_load
409			hoverImgEl.classList.add('unit-list-hover__image', 'hover_img_before_load')
410			const wrapper = node.children[0].cloneNode(true)
411			wrapper.querySelector('.base-image__item').innerHTML = `<img class="base-image__img img-fluid" lazy-src="${video_gif}"  alt="">`
412			hoverImgEl.innerHTML = wrapper.outerHTML
413			const hoverImg = hoverImgEl.querySelector('.unit-list-hover__image img')
414			new LazyImg(hoverImg)
415			node.appendChild(hoverImgEl)
416			// node.querySelector('.unit-list-hover__image img').setAttribute('lazy-type', '')
417		}
418	}
419
420  async getPageContentList(keyword='') {
421    const num = this.pageInfo.page_number
422    const size = this.pageInfo.page_size || 12
423    const data = await window.app.getProductListPageBySearch('page_content', num, size,keyword)
424    return data
425  }
426
427  getTabList($tabNode, list) {
428    if (list.length > 0) $tabNode.innerHTML = ''
429    else if (this.$discountNoData) this.$discountNoData.classList.remove('d-none')
430    const params = {
431      open_hover: this.open_hover,
432      attrId: this.attrId, pageInfo: this.pageInfo,
433      swiper: this.swiper, colInfo: this.colInfo,
434      config: this.config
435    }
436    this.elementNode = new ScriptProductLisElement(params)
437    for (let index = 0; index < list.length; index++) {
438      const item = list[index];
439      const $itemNode = this.elementNode.getItem(item)
440      if (item.video_gif) {
441        $itemNode.querySelector('.unit-product-list__img')?.setAttribute('hover-img', true)
442        $itemNode.querySelector('.unit-product-list__img')?.setAttribute('video-gif', item.video_gif)
443      }
444      this.elementNode.$items.append($itemNode)
445    }
446    $tabNode.append(this.elementNode.$container)
447    if (this.swiper.is_swiper) {
448      $tabNode.setAttribute('data-carousel', 0)
449    }
450    window.app.initPlug(this.attrId).catch(e => console.error(e))
451  }
452}
453
454/**
455 * 客户端数据html
456 */
457class ScriptProductLisElement {
458  constructor({ attrId, pageInfo, swiper, colInfo, config, open_hover }) {
459    this.open_hover = open_hover
460    this.attrId = attrId
461    this.pageInfo = pageInfo
462    this.swiper = swiper
463    this.is_swiper = this.swiper.is_swiper
464    this.colInfo = colInfo
465    this.config = config
466    this.init()
467  }
468
469  init() {
470    this.getMainHtml()
471  }
472
473  getMainHtml() {
474    this.$container = document.createElement('div')
475    this.$container.classList.add('swiper-container')
476    this.$items = this.getItems()
477    this.$container.append(this.$items)
478    this._setSwiperNode()
479  }
480
481  getItems() {
482    const $items = document.createElement('div')
483    $items.classList.add('unit-product-list__items')
484    $items.classList.add('swiper-wrapper')
485    if (!this.is_swiper) $items.classList.add('row')
486    if (this.is_swiper && !this.swiper.pagination) $items.classList.add('no-swiper-pagination')
487    return $items
488  }
489
490  /** 获取产品列表项 **/
491  getItem(item) {
492    const $item = document.createElement('div')
493    $item.setAttribute('data-id', item.content_id)
494    $item.classList.add('animate', 'unit-product-list__item', 'swiper-slide')
495    if (!this.is_swiper) {
496      $item.classList.add(`col-${this.colInfo.cols_col}`)
497      $item.classList.add(`col-md-${this.colInfo.cols_md}`)
498      $item.classList.add(`col-xl-${this.colInfo.cols_xl}`)
499    }
500    const $content = this.getItemContent(item)
501    $item.append($content)
502    return $item
503  }
504  /** 获取产品列表项内容 **/
505  getItemContent(item) {
506    const $listInner = document.createElement('div')
507    $listInner.classList.add('unit-product-list__inner', 'd-flex', 'flex-column')
508    $listInner.append(this.getLinkImage(item))
509    $listInner.append(this.getLinkText(item))
510    return $listInner
511  }
512
513  /**
514   * 图片,按钮节点
515   * **/
516  getLinkImage(item) {
517    const hoverImgEffect = (this.open_hover || '').replace(/[^A-Za-z0-9,_-]/g, '').split(',')
518    const hoverImgIn = hoverImgEffect[0] || 'fadeIn'
519    const hoverImgOut = hoverImgEffect[1] || 'fadeOut'
520    const hoverImgDuration = hoverImgEffect[2] || ''
521    const self = this
522    const subNode = {
523      /** 产品主图 */
524      get baseImage() {
525        let scale = ''
526        let effect = 0
527        if (self.config.image) {
528          scale = self.config.image.scale || ''
529          if (scale) scale = Number(scale) * 100 + '%'
530          effect = self.config.image.effect
531        }
532        return `
533          <div class="base-image ${scale ? 'base-image--scale' : ''} ${effect ? 'base-image--effect-' + effect : ''}" ${scale ? 'style="--img-pt: ' + scale + '"' : ''}>
534              <div class="base-image__item base-image__item--default">
535                <img class="base-image__img img-fluid" effect-in="${hoverImgIn}" effect-out="${hoverImgOut}" lazy-src="${item.img}" alt="${item.alt || item.title}" lazy-type="img">
536              </div>
537          </div>
538          `
539      },
540      /** 最新,最热 */
541      get labels() {
542        return {
543          get newHtml() {
544            return `
545              <div class="unit-product-list__label unit-product-list__label--news">
546                <i class="unit-product-list__label-icon">NEW</i>
547                <span class="unit-product-list__label-text">NEW</span>
548              </div>
549              `
550          },
551          get recommendHtml() {
552            return `
553              <div class="unit-product-list__label unit-product-list__label--tui">
554                <i class="unit-product-list__label-icon iconfont icon-base-like-2"></i>
555                <span class="unit-product-list__label-text">Rec</span>
556              </div>
557              `
558          },
559          get hotHtml() {
560            return `
561              <div class="unit-product-list__label unit-product-list__label--hot">
562                <i class="unit-product-list__label-icon iconfont icon-base-hot-2"></i>
563                <span class="unit-product-list__label-text">HOT</span>
564              </div>
565              `
566          }
567        }
568      },
569      /** 折扣信息 */
570      get sale() {
571        return `
572          <span class="unit-product-list__sale-inner">
573            ${item.max_discount}% ${window.app.utilts.$t('Off')}
574          </span>
575          `
576      },
577      /** 收藏,查看... */
578      get btns() {
579        return {
580          get quickView() {
581            return `
582              <div data-href="${globalThis.Server.getRinseHref(item.href, window.app.info.site)}"
583              class="unit-product-list__btn unit-product-list__btn--view">
584                <i class="unit-product-list__btn-icon iconfont icon-action-search-lighter"></i>
585                <span class="unit-product-list__btn-text">
586                  ${window.app.utilts.$t('Quick View')}
587                </span>
588              </div>
589              `
590          },
591          get like() {
592            return `
593              <div class="unit-product-list__btn unit-product-list__btn--like">
594                <i class="unit-product-list__btn-icon iconfont icon-base-collect"></i>
595                <span class="unit-product-list__btn-text">
596                  ${window.app.utilts.$t('Like')}
597                </span>
598              </div>
599              `
600          },
601          get addToCart() {
602            return `
603              <div class="unit-product-list__btn unit-product-list__btn--cart">
604                <i class="unit-product-list__btn-icon iconfont icon-base-cart-lighter"></i>
605                <span class="unit-product-list__btn-text">
606                  ${window.app.utilts.$t('Add to Cart')}
607                </span>
608              </div>
609              `
610          }
611        }
612      }
613    }
614    const $imgBoxs = document.createElement('a')
615    $imgBoxs.classList.add('unit-product-list__image', 'unit-product-list__a')
616    const href = globalThis.Server.getRinseHref(item.href || 'javascript:;', window.app.info.site)
617    $imgBoxs.setAttribute('href', href)
618    $imgBoxs.setAttribute('target', item.target || '_self')
619
620    // 产品图片
621    const $baseImg = document.createElement('div')
622    $baseImg.classList.add('unit-product-list__img')
623    $baseImg.setAttribute('content-render', 'product_hover,video_icon')
624    $baseImg.setAttribute('content-type', item.content_type)
625    $baseImg.setAttribute('content-id', item.content_id);
626    (item.hover_img || self.config.hover_img) && $baseImg.setAttribute('open-hover', this.open_hover)
627    if (item.cover_url) {
628      const videoNode = document.createElement('div')
629      videoNode.classList.add('base-video__play')
630      videoNode.innerHTML = `<i class="iconfont icon-action-play"></i>`
631      $baseImg.appendChild(videoNode)
632    }
633
634    $baseImg.innerHTML = subNode.baseImage
635    $imgBoxs.append($baseImg)
636    // 最新,最热,推荐
637    if (this.config.show_tag && this.config.has_tag) {
638      const $labeDiv = document.createElement('div')
639      $labeDiv.classList.add('unit-product-list__labels')
640      const labeInfo = subNode.labels
641      if (item.is_new) $labeDiv.innerHTML = labeInfo.newHtml
642      if (item.is_redommend) $labeDiv.innerHTML = labeInfo.recommendHtml
643      if (item.is_hot) $labeDiv.innerHTML = labeInfo.hotHtml
644      $imgBoxs.append($labeDiv)
645    }
646    // 打折信息
647    if (this.config.show_off && this.config.has_off
648      && item.max_discount && item.max_discount !== 100) {
649      const $sale = document.createElement('div')
650      $sale.classList.add('unit-product-list__sale')
651      $sale.innerHTML = subNode.sale
652      $imgBoxs.append($sale)
653    }
654    // 收藏,查看
655    if (this.config.show_btns && this.config.has_btns) {
656      const $btnsDiv = document.createElement('div')
657      $btnsDiv.classList.add('unit-product-list__btns')
658      $btnsDiv.classList.add('d-none')
659      $btnsDiv.innerHTML = subNode.btns.quickView
660      $btnsDiv.innerHTML = subNode.btns.like
661      $btnsDiv.innerHTML = subNode.btns.addToCart
662      $imgBoxs.append($btnsDiv)
663    }
664    return $imgBoxs
665  }
666  /**
667   * 标题描述,价格,倒计时
668   */
669  getLinkText(item) {
670    const self = this
671    const getShowContent = (className, item, textStyle) => {
672      const $titleBox = document.createElement('div')
673      $titleBox.classList.add(`unit-product-list__${className}`)
674      $titleBox.setAttribute('text-style', textStyle || '')
675
676      let $textBox
677      if (className === 'title') {
678        $textBox = document.createElement('a')
679        const href = globalThis.Server.getRinseHref(item.href || 'javascript:;', window.app.info.site)
680        $textBox.setAttribute('href', href)
681        $textBox.setAttribute('target', item.target || '_self')
682      } else {
683        $textBox = document.createElement('div')
684      }
685      $textBox.classList.add('text_ellipsis')
686      $textBox.setAttribute('_html', item[className + '_sign'] || '')
687      $textBox.setAttribute('toolbar', 'false')
688      $textBox.innerHTML = item[className]
689      $titleBox.append($textBox)
690
691      return $titleBox
692    }
693    const subNode = {
694      /** ä»·æ ¼ */
695      get priceInfo() {
696        return {
697          get minDiscount() {
698            return `
699              <span class="unit-product-list__price unit-product-list__price--discount">
700                $${item.price_min}
701              </span>
702            `
703          },
704          get maxDiscount() {
705            return `
706              <span class="unit-product-list__price unit-product-list__price--original">
707                $${item.price_max}
708              </span>
709            `
710          },
711          get noQuotes() {
712            return `<div style="opacity: .6;">${window.app.utilts.$t('No Quotation')}</div>`
713          },
714          get inquiryOnline() {
715            return `<div style="opacity: .6;">${window.app.utilts.$t('Inquiry')}</div>`
716          },
717        }
718      },
719      /** 倒计时 */
720      get limitTime() {
721        return `
722          <div class="discount-timer">
723            <div class="discount-timer__title text-truncate"></div>
724            <div class="discount-timer__date-wrap discount-timer__date-wrap--day">
725              <div class="discount-timer__date discount-timer__date--dd"><em>00</em><i>d</i></div>
726            </div>
727            <div class="discount-timer__date-wrap discount-timer__date-wrap--time">
728              <div class="discount-timer__date discount-timer__date--hh"><em>00</em><i>:</i></div>
729              <div class="discount-timer__date discount-timer__date--mm"><em>00</em><i>:</i></div>
730              <div class="discount-timer__date discount-timer__date--ss"><em>00</em></div>
731            </div>
732          </div>
733        `
734      },
735      /** 满减 */
736      get reduce() {
737        return `
738            <i class="iconfont icon-2c-coupon"></i>
739            <span class="text-truncate">
740              ${item.reduction}
741            </span>
742          `
743      },
744      /** 添加到购物车 */
745      get cart() {
746        return `
747          <a class="unit-product-list__cart-text" href="${globalThis.Server.getRinseHref(item.href, window.app.info.site)}" target="${item.target || '_self'}">
748            ${window.app.utilts.$t('Add to Cart')} ➔
749          </a>
750        `
751      },
752      get comment() {
753        return ` <div class="unit-product-list__comment">
754          <div class="unit-product-list__comment-score__content">
755            <div class="unit-product-list__comment-score__icons">
756              <span class="iconfont star-item icon-base-collection"></span>
757              <span class="iconfont star-item icon-base-collection"></span>
758              <span class="iconfont star-item icon-base-collection"></span>
759              <span class="iconfont star-item icon-base-collection"></span>
760              <span class="iconfont star-item icon-base-collection"></span>
761            </div>
762            <div class="unit-product-list__comment-score__scores pl-1">${item.comment.score}</div>
763          </div>
764          <div class="unit-product-list__comment--reviews">
765            ${window.app.utilts.$t('Reviews')}:
766            <span class="unit-product-list__comment--reviews-num">${item.comment.count}</span>
767          </div>
768        </div>`
769      }
770    }
771    const $textBox = document.createElement('div')
772    $textBox.classList.add('unit-product-list__text')
773
774    // 标题
775    if (this.config.show_title && item.title && this.config.has_title) {
776      const style_title = self.config.style_type_title
777      const $title = getShowContent('title', item, style_title)
778      $textBox.append($title)
779    }
780    // 子标题
781    if (this.config.show_subtitle && item.subtitle && this.config.has_subtitle) {
782      const style_subtitle = self.config.style_type_subtitle
783      const $subtitle = getShowContent('subtitle', item, style_subtitle)
784      $textBox.append($subtitle)
785    }
786    // 描述
787    if (this.config.show_description && item.description && this.config.has_description) {
788      const style_description = self.config.style_type_description
789      const $description = getShowContent('description', item, style_description)
790      $textBox.append($description)
791    }
792    // 满减
793    if (this.config.show_reduce && this.config.has_reduce) {
794      const $reduceBox = document.createElement('div')
795      $reduceBox.classList.add('unit-product-list__reduce')
796      if (!item.reduction) { $reduceBox.classList.add('d-none'); }
797      $reduceBox.innerHTML = subNode.reduce
798      $textBox.append($reduceBox)
799
800    }
801    // 评分和评论数
802    if (this.config.show_comment && item.comment && this.config.has_comment) {
803      const $commentBox = document.createElement('div')
804      $commentBox.classList.add('unit-product-list__comment')
805      $commentBox.innerHTML = subNode.comment
806      $textBox.append($commentBox)
807      const $icons = $commentBox.querySelectorAll('.icon-base-collection')
808      if (item.comment.score > 5 || item.comment.score === 0) item.comment.score = 5
809      for (let index = 0; index < item.comment.score; index++) {
810        $icons[index].classList.add('on')
811      }
812    }
813    // ä»·æ ¼
814    if (this.config.show_price && this.config.has_price) {
815      const $pricesBox = document.createElement('div')
816      $pricesBox.classList.add('unit-product-list__prices')
817      if (item.price_min > 0) {
818        $pricesBox.innerHTML = subNode.priceInfo.minDiscount
819        if (item.price_max > 0) $pricesBox.innerHTML += subNode.priceInfo.maxDiscount
820      } else {
821        if (window.app.info.site.site_type === 21) {
822          $pricesBox.innerHTML = ''
823        } else {
824          $pricesBox.innerHTML = subNode.priceInfo.inquiryOnline
825        }
826      }
827
828      $textBox.append($pricesBox)
829    }
830    // 倒计时
831    if (this.config.show_date && this.config.has_date && item.discount_end_time) {
832      const $limitBox = document.createElement('div')
833      $limitBox.classList.add('unit-product-list__limit')
834      $limitBox.setAttribute('data-enddate', item.discount_end_time)
835      $limitBox.setAttribute('data-startdate', item.discount_start_time)
836      $limitBox.setAttribute('data-productid', item.content_id)
837      $limitBox.innerHTML = subNode.limitTime
838      $textBox.append($limitBox)
839    }
840    // 添加到购物车
841    if (this.config.show_cart && this.config.has_cart) {
842      const $cart = document.createElement('div')
843      $cart.classList.add('unit-product-list__cart')
844      $cart.setAttribute('button-style', self.config.style_type_button)
845      $cart.innerHTML = subNode.cart
846      $textBox.append($cart)
847    }
848    return $textBox
849  }
850
851  /** **/
852  _setSwiperNode() {
853    if (this.swiper) {
854      if (this.swiper.pagination) {
855        const $div1 = document.createElement('div')
856        $div1.classList.add('unit-product-list__pagination')
857        $div1.classList.add('swiper-pagination')
858        this.$container.append($div1)
859      }
860      if (this.swiper.navigation) {
861        const $div2 = document.createElement('div')
862        $div2.classList.add('unit-product-list__button-prev')
863        $div2.classList.add('swiper-button-prev')
864        this.$container.append($div2)
865        const $div3 = document.createElement('div')
866        $div3.classList.add('unit-product-list__button-next')
867        $div3.classList.add('swiper-button-next')
868        this.$container.append($div3)
869      }
870      if (this.swiper.scrollbar) {
871        const $div4 = document.createElement('div')
872        $div4.classList.add('unit-product-list__scrollbar')
873        $div4.classList.add('swiper-scrollbar')
874        this.$container.append($div4)
875      }
876    }
877  }
878}

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.