PageSourceSearch

https://www.meritsunpower.com/assets/js/unit/column-tabs.js

js meritsunpower.com collected 2026-10-07 19:45:29 UTC 9,915 bytes, 261 lines download raw bytes

1class ScriptColumnTabs extends Script {
2  constructor(params) {
3    super(params)
4    this.$dom = document.querySelector(`#${this.attrId}`)
5    this.$swiperButtonPrev = this.$dom.querySelector('.swiper-button-prev')
6    this.$swiperButtonNext = this.$dom.querySelector('.swiper-button-next')
7    this.$tabsHeader = this.$dom.querySelector(`.unit-column-tabs__header`)
8    this.$tabsNavWrap = this.$dom.querySelector(`.unit-column-tabs__nav-wrap`)
9    this.$tabItems = this.$dom.querySelectorAll('.unit-column-tabs__nav-item')
10    
11    this.config = JSON.parse(this.utilts.htmlDecode(params.config))
12    // this.tab_list = JSON.parse(this.$dom.querySelector(`[column-tab-list]`)?.getAttribute('column-tab-list') || '[]')
13    this.tab_list = JSON.parse(this.utilts.htmlDecode(params.tab_list).replace(/\n<\s*br\s*\/*\s*>/ig, '<br/>').replace(/\n<\s*p\s*>/ig, '<p>').replace(/<\s*p\s*>\n/ig, '<p>').replace(/\n<\s*\/p\s*>/ig, '</p>'))
14    
15    this.panelList = []
16    this.tab_list.forEach(item => {
17      let temp = []
18      item.tab_panel.forEach(panelItem => {
19        let $module = document.querySelector(`[package-item="module"][tab-key="#${panelItem.relate_tab_key}"]`)        
20        if ($module) temp.push($module)
21      })
22      
23      this.panelList.push(temp)
24    })
25
26    this.activeIndex = 0
27    if (this.utilts.checkDesign()) { // 装修时,重新渲染保持 activeIndex,避免编辑其他tab的内容总是跳回第一个tab
28      if (!window.columnTabsState) window.columnTabsState = {};
29      if (!window.columnTabsState[this.attrId]) window.columnTabsState[this.attrId] = { activeIndex: 0 }
30      if (window.columnTabsState[this.attrId].activeIndex < this.tab_list.length) {
31        this.activeIndex = window.columnTabsState[this.attrId].activeIndex
32      }
33    }
34    // console.log(`ScriptColumnTabs`, this.utilts.checkDesign(), window.columnTabsState, this.tab_list, this.panelList);
35    
36  }
37
38  async init() {
39    // siwper
40    if (!window.Swiper) await new Load('/assets/plugins/swiper.min.js')
41    this.initTab()
42    this.initContent()
43    // this.initScreen()
44    // window.addEventListener('resize', () => {
45    //   if (this.currentScreen === this.utilts.getScreen()) return
46    //   this.initScreen()
47    // })
48    this.checkBlank()
49  }
50  // initScreen() {
51  //   this.currentScreen = this.utilts.getScreen()
52  //   this.initTab()
53  //   // this.initContentSwiper()
54  //   this.initContentSwiperHack()
55  // }
56  initTab() {
57    this.$tabsSwiper?.destroy(true, true)
58    if (this.utilts.checkDesign()) {
59      this.$tabItems.forEach((it, i) => { // html 中默认第一个是 active,需要同步一下 window.columnTabsState[this.attrId].activeIndex
60        if (i === this.activeIndex) {
61          it.classList.add('active')
62        } else {
63          it.classList.remove('active')
64        }
65      })
66    }
67
68    const swiperConfig = {
69      slidesPerView: 'auto',
70      spaceBetween: 0,
71      initialSlide: this.activeIndex,
72      // slideToClickedSlide: true,
73      // centeredSlides: true,
74      freeMode: true,
75      navigation: {
76        prevEl: '.swiper-button-prev',
77        nextEl: '.swiper-button-next',
78      },
79      on: {
80        // slideChange: (swiper) => {
81        //   this.tabClick(swiper, swiper.activeIndex)
82        // },
83      }
84    }
85
86    // if (['default', 'md'].includes(this.currentScreen)) {
87    //   this.$swiperButtonPrev.classList.remove('d-none')
88    //   this.$swiperButtonNext.classList.remove('d-none')
89    //   this.$tabsHeader.classList.add('swiper-container')
90    //   this.$tabsNavWrap.classList.add('swiper-wrapper')
91    //   this.$dom.querySelectorAll(`.unit-column-tabs__nav-item`).forEach(($item) => {
92    //     $item.classList.add('swiper-slide')
93    //   })
94      // setTimeout(() => {
95        swiperConfig.spaceBetween = this.initBetween()
96        this.$tabsSwiper = new Swiper(`#${this.attrId} .unit-column-tabs__header`, swiperConfig)
97        this.$tabsSwiper.on('resize', this.utilts.debounce((swiper) => {
98          swiper.params.spaceBetween = this.initBetween()
99          swiper.update()
100        }))
101      // });
102    // } else {
103    //   this.$swiperButtonPrev.classList.add('d-none')
104    //   this.$swiperButtonNext.classList.add('d-none')
105    //   this.$tabsHeader.classList.remove('swiper-container')
106    //   this.$tabsNavWrap.classList.remove('swiper-wrapper')
107    //   this.$dom.querySelectorAll(`.unit-column-tabs__nav-item`).forEach(($item) => {
108    //     $item.classList.remove('swiper-slide')
109    //   })
110    // }
111    this.initEvent()
112  }
113  initBetween() { // 去掉间距,读取间距的值传给swiper处理
114    this.$dom.querySelector(`#initBetween_${this.attrId}`)?.remove()
115    const itemClass = 'unit-column-tabs__nav-item'
116    const $itemFirst = this.$dom.querySelector(`.${itemClass}`)
117    if (!$itemFirst) return
118    const style = this.utilts.getNodeStyle($itemFirst)
119    const item_pr = parseFloat(style.paddingRight) || 0
120    const item_pl = parseFloat(style.paddingLeft) || 0
121    // const item_mr = parseFloat(style.marginRight) || 0
122    // const item_ml = parseFloat(style.marginLeft) || 0
123    
124    // console.log(item_pr , item_pl , item_mr , item_ml);
125    
126    const $style = document.createElement('style')
127    $style.setAttribute('id', `initBetween_${this.attrId}`)
128    /* 如果nav-item超过宽度,清空居中 */
129    let itemWidthSum = 0
130    let isClearJustifyContent = false
131    this.$dom.querySelectorAll('.unit-column-tabs__nav-item').forEach(item => {
132      itemWidthSum += item.offsetWidth
133    })
134    itemWidthSum -= item_pr + item_pl;
135    if (itemWidthSum > this.$tabsHeader.offsetWidth) {
136      isClearJustifyContent = true
137    }
138    
139    let html = `#${this.attrId} .unit-column-tabs__header .unit-column-tabs__nav-wrap {margin:0!important;width: calc(100% + ${item_pr + item_pl}px);${isClearJustifyContent? 'justify-content: flex-start;': ''}}
140    #${this.attrId} .unit-column-tabs__header .${itemClass}{margin-left:0!important;padding:0!important}`
141    
142    $style.innerHTML = html
143    this.$dom.appendChild($style)
144    return item_pr + item_pl /*+ item_mr + item_ml*/
145  }
146  initContent() {
147    let showModuleList = []
148    this.panelList.forEach((panelItem, panelIndex) => {
149      if (panelIndex === this.activeIndex) {
150        panelItem.forEach(item => {
151          item.classList.remove('d-none')
152          showModuleList.push(item)
153        })
154      } 
155      // else {
156      //   panelItem.forEach(item => item.classList.add('d-none'))
157      // }
158    })
159    if (this.utilts.checkDesign()) {
160      document.querySelectorAll('[package-item="module"][tab-key]').forEach(item => {
161        if (!showModuleList.includes(item)) {
162          item.classList.add('d-none')
163        }
164      })
165    }
166  }
167  // initContentSwiperHack() {
168  //   const slideTo = () => {
169  //     this.$tabPanels.forEach((tabItem, tabIndex) => {
170  //       if (tabIndex === this.activeIndex) {
171  //         tabItem.style.display = ''
172  //       } else {
173  //         tabItem.style.display = 'none'
174  //       }
175  //     })
176  //   }
177  //   slideTo()
178  //   if (this.$contentSwiper) return
179  //   this.$contentSwiper = {
180  //     slideTo
181  //   }
182  // }
183  initEvent() {
184    this.$tabItems.forEach((item, index) => {
185      item.addEventListener('click', (e) => this.tabClick(e, index))
186    })
187    if (!this.utilts.checkDesign()) {
188      const handleSticky = () => {
189        let offsetTop = 0
190        let headerBlock = document.querySelector(`[package-block-type="header"]`)
191        if (['2'].includes(headerBlock?.getAttribute('position')) || (['3'].includes(headerBlock?.getAttribute('position')) && this.utilts.getScreen() !== 'xl')) {
192          offsetTop = headerBlock.offsetHeight
193        } else if (['3'].includes(headerBlock?.getAttribute('position'))){
194          offsetTop = () => {
195            if (headerBlock.classList.contains('header-hide')) {
196              return 0
197            }
198            return headerBlock.offsetHeight
199          }
200        }
201        this.utilts.stickyByViewport(this.$dom, offsetTop, 999)
202      }
203      handleSticky()
204      window.addEventListener('resize', this.utilts.debounce(handleSticky));
205    }
206  }
207  tabChange(e, index) {
208    if (this.utilts.checkDesign()) {
209      window.columnTabsState[this.attrId].activeIndex = index
210    }
211    this.activeIndex = index
212    this.$tabItems.forEach(it => it.classList.remove('active'))
213    this.$tabItems[index].classList.add('active')
214
215    this.checkBlank()
216  }
217  tabClick(e, index) {
218    this.tabChange(e, index)
219    // if (['default', 'md'].includes(this.currentScreen)) {
220      // this.$tabsSwiper.slideTo(index)
221    // }
222    // this.$contentSwiper.slideTo(index)
223    this.panelList.forEach((panelItem, panelIndex) => {
224      if (panelIndex === index) {
225        panelItem.forEach(item => {
226          item.classList.remove('d-none')
227          item.querySelectorAll('[data-observer]').forEach(($item) => {
228            if ('_observer' in $item && $item._observer instanceof Function) {
229              // 切换时执行图片加载检查
230              $item._observer()
231            } else {
232              $item.removeAttribute('[data-observer]')
233            }
234          })
235        })
236      } else {
237        panelItem.forEach(item => item.classList.add('d-none'))
238      }
239      
240    })
241    // this.panelList[index]?.forEach(item => {
242
243    //   item.querySelectorAll('[data-observer]').forEach(($item) => {
244    //     if ('_observer' in $item && $item._observer instanceof Function) {
245    //       // 切换时执行图片加载检查
246    //       $item._observer()
247    //     } else {
248    //       $item.removeAttribute('[data-observer]')
249    //     }
250    //   })
251    // })
252  }
253  checkBlank() {
254    let $main = document.querySelector('[package-block-type="main"]')    
255    if (!this.tab_list[this.activeIndex].tab_panel.length) {
256      $main?.classList.add('fake-blank-package')
257    } else {
258      $main?.classList.remove('fake-blank-package')
259    }
260  }
261}

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.