PageSourceSearch

https://www.szumao.com/assets/js/unit/attr-text-search.js

js szumao.com collected 2026-10-09 00:49:26 UTC 7,277 bytes, 234 lines download raw bytes

1/**
2 * 产品属性文本搜索组件
3 */
4class ScriptAttrTextSearch extends Script {
5	constructor(params) {
6		super(params)
7		this.$unit = document.querySelector(`#${this.attrId}`)
8		if (!this.$unit) return
9		this.$main = this.$unit.querySelector('.unit-attr-text-search__items')
10		this.product_attr_id = ''
11		this.showSearchItemName = '--Please Selected--'
12	}
13
14	async init() {
15		// 如果是装修时才调用
16		if (this.utilts.checkDesign()) this.renderAttr()
17	}
18
19	initLoadData() {
20		this.$droupDowm.innerHTML = ''
21		const list = this.getAttrList()
22		if (list.length > 0){
23			this.product_attr_id = list[0].id
24			for (const item of list) {
25				const $item = document.createElement('div')
26				$item.classList.add('dropdown-item')
27				$item.setAttribute('data-id', item.id)
28				$item.setAttribute('href', '#')
29        $item.setAttribute('title', item.name)
30				$item.innerText = item.name
31				this.$droupDowm.append($item)
32				$item.onclick = () => {
33					this.product_attr_id = item.id
34					const $btnText = this.$button.querySelector('.btn-text')
35					$btnText.innerText = item.name
36					this.$droupDowm.classList.toggle('show')
37				}
38			}
39		} else {
40			const tip = window.app.utilts.$t('no data')
41			this.$droupDowm.innerHTML = `<div class='dropdown-item' style='color:grey;text-align:center;'>${tip}<div>`
42		} 
43		
44	}
45
46	initEvent() {
47		// 下拉属性名改变事件
48		this.$button.addEventListener('click', (event) => {
49			event.stopPropagation()
50			this.$droupDowm.classList.toggle('show')
51		})
52
53		// 搜索图标点击查找事件
54		this.$incofont.addEventListener('click', (event) => {
55			event.stopPropagation()
56			this.searchData()
57		})
58
59		// 回车跳转
60		this.$input.addEventListener('keydown', (event) => {
61			event = event || window.event;
62			event.stopPropagation()
63			if (event.keyCode === 13) this.searchData()
64		})
65
66		// 点击页面空白,折叠已展开栏目
67		document.querySelector('body').addEventListener('click', () => {
68			this.$droupDowm.classList.remove('show')
69		})
70    // 显示下拉菜单时防止被遮挡
71    this.observeClassChange(this.$droupDowm, () => {
72      this.preventOverflow(this.$droupDowm.classList.contains('show'))
73    });
74	}
75  observeClassChange(element, callback) {
76    const observer = new MutationObserver((mutations) => {
77      mutations.forEach((mutation) => {
78        if (
79          mutation.type === 'attributes' &&
80          mutation.attributeName === 'class'
81        ) {
82          // 检查新旧值是否不同
83          const newClass = element.className;
84          const oldClass = mutation.oldValue;
85          if (newClass !== oldClass) {
86            callback(newClass, oldClass);
87          }
88        }
89      });
90    });
91  
92    observer.observe(element, {
93      attributes: true, // 监听属性变化
94      attributeFilter: ['class'], // 仅监听 class 属性
95      attributeOldValue: true // 记录旧值
96    });
97  
98    return observer; // 返回 observer 实例以便后续断开监听
99  }
100  preventOverflow(show) { // 防止被遮挡
101    // 给定的 CSS 选择器数组
102    const selectors = ['[package-item="unit"]', '[package-item="cell"]', '[package-item="grid"]', '[package-item="module"]', '[package-item="block"]'];
103
104    // 假设当前元素是 targetElement
105    const targetElement = this.$unit;
106    // 从当前元素开始向上遍历父元素
107    let currentElement = targetElement;
108    while (currentElement) {
109      // 遍历选择器数组
110      selectors.forEach(selector => {
111        // 检查当前元素是否匹配选择器
112        if (currentElement.matches(selector)) {
113          // 如果匹配,提高层级
114          if (show) {
115            currentElement.style.position = 'relative';
116            currentElement.style.zIndex = '99';
117          } else {
118            currentElement.style.position = '';
119            currentElement.style.zIndex = '';
120          }
121        }
122      });
123
124      // 移动到父元素
125      currentElement = currentElement.parentElement;
126    }
127  }
128
129	/**
130	 * 搜索数据
131	 */
132	searchData() {
133		window.app.info.pagination.page_number = 1
134		const content = this.$input.value
135		this.setAttrParams(content)
136		window.app.info.renderListView()
137		const product_list_el= this.$unit.parentNode.parentNode.parentNode.querySelector('[package-unit-type="product-list"]')
138		const list_el = this.$unit.parentNode.parentNode.parentNode.querySelector('[package-unit-type="list"]')
139		if (!list_el && !product_list_el) return
140		if(list_el) {
141			list_el.parentNode.parentNode.style.overflow = 'auto'
142			window.scrollTo({ top: list_el.getBoundingClientRect().top - 85})
143		}
144		if(product_list_el) window.scrollTo({ behavior: 'smooth', top: product_list_el.getBoundingClientRect().top - 85})
145	}
146
147	/**
148	 * 设置全局attr_params参数
149	 * @param {string} content 查找的内容 
150	 * @returns 
151	 */
152	setAttrParams(content) {
153		// 如果没有内容,删除存在的
154		let attrs = window.app.info.attr_params
155		if (!content) {
156			// 清空文本查找项
157			if (attrs.length > 0) {
158				window.app.info.attr_params = attrs.filter(p => typeof p.content !== 'string')
159			}
160			return
161		}
162		// 如果当前属性查找参数为空,添加一条数组记录
163		const params = { product_attr_id: this.product_attr_id, content }
164		if (attrs.length === 0) window.app.info.attr_params = [params]
165		else {
166			// 是否有文本查找项
167			const attrInfo = attrs.find(p => typeof p.content === 'string')
168			if (attrInfo) {
169				attrInfo.product_attr_id = this.product_attr_id
170				attrInfo.content = content
171			}
172			else window.app.info.attr_params.push(params)
173		}
174	}
175
176	/** 
177	 * 获取产品属性参数
178	 */
179	getAttrList() {
180		const list = window.app.info.productAttrList
181			.filter(p => p.input_type === 1 && p.status && p.is_show)
182			.map((p, i) => ({ id: p.id, name: p.sign || `name${i}`, type: p.input_type }))
183		return list
184	}
185
186	renderAttr() {
187		// 创建元素
188		this.createdSearchElement()
189		// 加载数据
190		this.initLoadData()
191		// 添加事件
192		this.initEvent()
193	}
194
195
196	createdSearchElement() {
197		// 清空旧的数据
198		this.$main.innerHTML = ''
199		// 创建divBox
200		const $searchBox = document.createElement('div')
201		$searchBox.classList.add('input-group')
202
203		const $inputGroup = document.createElement('div')
204		$inputGroup.classList.add('input-group-prepend')
205		// 创建下拉属性项
206		this.$button = null
207		this.$button = document.createElement('button')
208		this.$button.classList.add('btn', 'btn-outline-secondary')
209		const html = `<span class="btn-text text-truncate"> ${this.showSearchItemName} </span>
210			<span class="iconfont icon-action-bottom-lighter ml-1"></span>`
211		this.$button.innerHTML = html
212		$inputGroup.append(this.$button)
213
214		// 创建搜索文本项
215		this.$droupDowm = document.createElement('div')
216		this.$droupDowm.classList.add('dropdown-menu')
217		$inputGroup.append(this.$droupDowm)
218
219		this.$input = null
220		this.$input = document.createElement('input')
221		this.$input.classList.add('form-control')
222		$inputGroup.append(this.$input)
223		// 创建搜索图标
224		this.$incofont = null
225		this.$incofont = document.createElement('span')
226		this.$incofont.classList.add('iconfont', 'icon-action-search-lighter', 'btnSearch')
227
228		$searchBox.append($inputGroup)
229		$searchBox.append(this.$input)
230		$searchBox.append(this.$incofont)
231		this.$main.append($searchBox)
232	}
233
234}

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.