@whitesev/pops 3.2.1 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +249 -249
  2. package/dist/index.amd.js +702 -667
  3. package/dist/index.amd.js.map +1 -1
  4. package/dist/index.amd.min.js +1 -1
  5. package/dist/index.amd.min.js.map +1 -1
  6. package/dist/index.cjs.js +702 -667
  7. package/dist/index.cjs.js.map +1 -1
  8. package/dist/index.cjs.min.js +1 -1
  9. package/dist/index.cjs.min.js.map +1 -1
  10. package/dist/index.esm.js +702 -667
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/index.esm.min.js +1 -1
  13. package/dist/index.esm.min.js.map +1 -1
  14. package/dist/index.iife.js +702 -667
  15. package/dist/index.iife.js.map +1 -1
  16. package/dist/index.iife.min.js +1 -1
  17. package/dist/index.iife.min.js.map +1 -1
  18. package/dist/index.system.js +702 -667
  19. package/dist/index.system.js.map +1 -1
  20. package/dist/index.system.min.js +1 -1
  21. package/dist/index.system.min.js.map +1 -1
  22. package/dist/index.umd.js +702 -667
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/index.umd.min.js +1 -1
  25. package/dist/index.umd.min.js.map +1 -1
  26. package/dist/types/src/components/folder/types/index.d.ts +43 -13
  27. package/dist/types/src/types/PopsDOMUtilsEventType.d.ts +313 -313
  28. package/dist/types/src/types/animation.d.ts +19 -19
  29. package/dist/types/src/types/button.d.ts +94 -94
  30. package/dist/types/src/types/components.d.ts +211 -211
  31. package/dist/types/src/types/event.d.ts +43 -43
  32. package/dist/types/src/types/global.d.ts +31 -31
  33. package/dist/types/src/types/icon.d.ts +32 -32
  34. package/dist/types/src/types/inst.d.ts +28 -28
  35. package/dist/types/src/types/main.d.ts +66 -66
  36. package/dist/types/src/types/mask.d.ts +52 -52
  37. package/dist/types/src/types/position.d.ts +60 -60
  38. package/package.json +27 -25
  39. package/src/Pops.ts +206 -206
  40. package/src/PopsAnimation.ts +32 -32
  41. package/src/PopsCSS.ts +54 -54
  42. package/src/PopsCore.ts +37 -37
  43. package/src/PopsIcon.ts +95 -95
  44. package/src/PopsInst.ts +21 -21
  45. package/src/components/alert/defaultConfig.ts +62 -62
  46. package/src/components/alert/index.ts +163 -163
  47. package/src/components/alert/types/index.ts +23 -23
  48. package/src/components/confirm/defaultConfig.ts +90 -90
  49. package/src/components/confirm/index.ts +165 -165
  50. package/src/components/confirm/types/index.ts +13 -17
  51. package/src/components/drawer/defaultConfig.ts +89 -89
  52. package/src/components/drawer/index.css +37 -37
  53. package/src/components/drawer/index.ts +245 -245
  54. package/src/components/drawer/types/index.ts +62 -61
  55. package/src/components/folder/defaultConfig.ts +151 -151
  56. package/src/components/folder/folderIcon.ts +28 -28
  57. package/src/components/folder/index.css +303 -303
  58. package/src/components/folder/index.ts +953 -932
  59. package/src/components/folder/types/index.ts +143 -110
  60. package/src/components/iframe/defaultConfig.ts +60 -60
  61. package/src/components/iframe/index.css +76 -76
  62. package/src/components/iframe/index.ts +331 -331
  63. package/src/components/iframe/types/index.ts +96 -96
  64. package/src/components/loading/defaultConfig.ts +29 -29
  65. package/src/components/loading/index.css +66 -66
  66. package/src/components/loading/index.ts +101 -101
  67. package/src/components/loading/types/index.ts +36 -34
  68. package/src/components/panel/css/components-select.css +84 -84
  69. package/src/components/panel/defaultConfig.ts +868 -868
  70. package/src/components/panel/handlerComponents.ts +3993 -3993
  71. package/src/components/panel/index.css +1403 -1403
  72. package/src/components/panel/index.ts +221 -221
  73. package/src/components/panel/types/components-button.ts +56 -56
  74. package/src/components/panel/types/components-common.ts +73 -73
  75. package/src/components/panel/types/components-container.ts +25 -25
  76. package/src/components/panel/types/components-deepMenu.ts +64 -64
  77. package/src/components/panel/types/components-input.ts +90 -90
  78. package/src/components/panel/types/components-own.ts +16 -16
  79. package/src/components/panel/types/components-select.ts +169 -169
  80. package/src/components/panel/types/components-selectMultiple.ts +105 -104
  81. package/src/components/panel/types/components-slider.ts +55 -55
  82. package/src/components/panel/types/components-switch.ts +33 -33
  83. package/src/components/panel/types/components-textarea.ts +45 -45
  84. package/src/components/panel/types/index.ts +244 -244
  85. package/src/components/prompt/defaultConfig.ts +94 -94
  86. package/src/components/prompt/index.css +34 -34
  87. package/src/components/prompt/index.ts +187 -215
  88. package/src/components/prompt/types/index.ts +57 -56
  89. package/src/components/rightClickMenu/defaultConfig.ts +103 -103
  90. package/src/components/rightClickMenu/index.css +115 -115
  91. package/src/components/rightClickMenu/index.ts +662 -662
  92. package/src/components/rightClickMenu/types/index.ts +145 -143
  93. package/src/components/searchSuggestion/defaultConfig.ts +63 -63
  94. package/src/components/searchSuggestion/index.ts +813 -813
  95. package/src/components/searchSuggestion/types/index.ts +244 -242
  96. package/src/components/tooltip/defaultConfig.ts +33 -33
  97. package/src/components/tooltip/index.css +199 -199
  98. package/src/components/tooltip/index.ts +617 -617
  99. package/src/components/tooltip/types/index.ts +123 -121
  100. package/src/config/CommonCSSClassName.ts +17 -17
  101. package/src/config/GlobalConfig.ts +63 -63
  102. package/src/css/animation.css +987 -987
  103. package/src/css/button.css +551 -551
  104. package/src/css/common.css +54 -54
  105. package/src/css/index.css +253 -253
  106. package/src/css/ninePalaceGridPosition.css +50 -50
  107. package/src/css/scrollbar.css +22 -22
  108. package/src/handler/PopsElementHandler.ts +303 -303
  109. package/src/handler/PopsHandler.ts +611 -611
  110. package/src/types/PopsDOMUtilsEventType.d.ts +313 -313
  111. package/src/types/animation.d.ts +19 -19
  112. package/src/types/button.d.ts +94 -94
  113. package/src/types/components.d.ts +211 -211
  114. package/src/types/event.d.ts +43 -43
  115. package/src/types/global.d.ts +31 -31
  116. package/src/types/icon.d.ts +32 -32
  117. package/src/types/inst.d.ts +28 -28
  118. package/src/types/main.d.ts +66 -66
  119. package/src/types/mask.d.ts +52 -52
  120. package/src/types/position.d.ts +60 -60
  121. package/src/utils/PopsDOMUtils.ts +2483 -2483
  122. package/src/utils/PopsDOMUtilsEventsConfig.ts +4 -4
  123. package/src/utils/PopsInstanceUtils.ts +714 -714
  124. package/src/utils/PopsMathUtils.ts +71 -71
  125. package/src/utils/PopsSafeUtils.ts +22 -22
  126. package/src/utils/PopsUtils.ts +421 -421
@@ -1,813 +1,813 @@
1
- import { PopsHandler } from "../../handler/PopsHandler";
2
- import { popsDOMUtils } from "../../utils/PopsDOMUtils";
3
- import { popsUtils } from "../../utils/PopsUtils";
4
- import { PopsSearchSuggestionDefaultConfig } from "./defaultConfig";
5
- import { GlobalConfig } from "../../config/GlobalConfig";
6
- import { PopsSafeUtils } from "../../utils/PopsSafeUtils";
7
- import type { PopsSearchSuggestionData, PopsSearchSuggestionConfig } from "./types/index";
8
- import { PopsCSS } from "../../PopsCSS";
9
- import type { PopsType } from "../../types/main";
10
- import { PopsCommonCSSClassName } from "../../config/CommonCSSClassName";
11
-
12
- export const PopsSearchSuggestion = {
13
- init<T>(__config__: PopsSearchSuggestionConfig<T>) {
14
- const guid = popsUtils.getRandomGUID();
15
- // 设置当前类型
16
- const popsType: PopsType = "searchSuggestion";
17
-
18
- let config = PopsSearchSuggestionDefaultConfig();
19
- config = popsUtils.assign(config, GlobalConfig.getGlobalConfig());
20
- config = popsUtils.assign(config, __config__);
21
- // 如果$inputTarget为空,则根据$target
22
- if (config.$inputTarget == null) {
23
- config.$inputTarget = config.$target as HTMLInputElement;
24
- }
25
-
26
- const { $shadowContainer, $shadowRoot } = PopsHandler.handlerShadow(config);
27
- PopsHandler.handleInit($shadowRoot, [
28
- {
29
- name: "index",
30
- css: PopsCSS.index,
31
- },
32
- {
33
- name: "anim",
34
- css: PopsCSS.anim,
35
- },
36
- {
37
- name: "common",
38
- css: PopsCSS.common,
39
- },
40
- ]);
41
-
42
- if (config.style != null) {
43
- const $css = popsDOMUtils.createElement("style", {
44
- type: "text/css",
45
- innerHTML: config.style,
46
- });
47
- $shadowRoot.appendChild($css);
48
- }
49
- /**
50
- * 监听器的默认配置
51
- */
52
- const defaultListenerOption: AddEventListenerOptions = {
53
- capture: true,
54
- passive: true,
55
- };
56
- const SearchSuggestion = {
57
- /**
58
- * 当前的环境,可以是document,可以是shadowroot,默认是document
59
- */
60
- selfDocument: config.$selfDocument,
61
- $el: {
62
- /** 根元素 */
63
- root: null as any as HTMLElement,
64
- /**
65
- * 包裹ul的容器元素
66
- */
67
- $dropdownWrapper: null as any as HTMLElement,
68
- /** ul元素 */
69
- $dropdownContainer: null as any as HTMLUListElement,
70
- /**
71
- * 箭头元素
72
- */
73
- $arrow: null as any as HTMLDivElement,
74
- /** 动态更新CSS */
75
- $dynamicCSS: null as any as HTMLStyleElement,
76
- },
77
- $evt: {
78
- offInputChangeEvtHandler: [] as ((...args: any[]) => any)[],
79
- },
80
- $data: {
81
- /** 是否结果为空 */
82
- isEmpty: true,
83
- /**
84
- * 存储在元素上的操作的键名
85
- */
86
- storeNodeHandlerKey: "data-SearchSuggestion",
87
- },
88
- /**
89
- * 初始化
90
- * @param $parent 父元素
91
- * @example
92
- * .init();
93
- * .setAllEvent();
94
- */
95
- init($parent = document.body || document.documentElement) {
96
- SearchSuggestion.initEl();
97
- SearchSuggestion.update(SearchSuggestion.getData());
98
- SearchSuggestion.updateStyleSheet();
99
-
100
- SearchSuggestion.hide();
101
- $shadowRoot.appendChild(SearchSuggestion.$el.root);
102
- $parent.appendChild($shadowContainer);
103
- },
104
- /**
105
- * 初始化元素变量
106
- */
107
- initEl() {
108
- SearchSuggestion.$el.root = SearchSuggestion.createSearchSelectElement();
109
- Reflect.set(SearchSuggestion.$el.root, this.$data.storeNodeHandlerKey, SearchSuggestion);
110
- SearchSuggestion.$el.$dynamicCSS =
111
- SearchSuggestion.$el.root.querySelector<HTMLStyleElement>("style[data-dynamic]")!;
112
- SearchSuggestion.$el.$dropdownWrapper = SearchSuggestion.$el.root.querySelector<HTMLElement>(
113
- `.pops-${popsType}-search-suggestion-dropdown-wrapper`
114
- )!;
115
- SearchSuggestion.$el.$dropdownContainer = SearchSuggestion.$el.root.querySelector<HTMLUListElement>(
116
- `ul.pops-${popsType}-search-suggestion-dropdown-container`
117
- )!;
118
- SearchSuggestion.$el.$arrow = SearchSuggestion.$el.root.querySelector<HTMLDivElement>(
119
- `.pops-${popsType}-search-suggestion-arrow`
120
- )!;
121
- },
122
- /**
123
- * 获取数据
124
- */
125
- getData(): PopsSearchSuggestionData<T>[] {
126
- return typeof config.data === "function" ? config.data() : config.data;
127
- },
128
- /**
129
- * 更新数据
130
- * @param data 数据
131
- */
132
- setData(data: PopsSearchSuggestionData<T>[]) {
133
- (<PopsSearchSuggestionConfig<T>["data"]>config.data) = data;
134
- },
135
- /**
136
- * 获取显示出搜索建议框的html
137
- */
138
- createSearchSelectElement() {
139
- const $el = popsDOMUtils.createElement(
140
- "div",
141
- {
142
- className: `pops pops-${popsType}-search-suggestion`,
143
- innerHTML: /*html*/ `
144
- <style type="text/css">
145
- .pops-${popsType}-animation{
146
- -moz-animation: searchSelectFalIn 0.5s 1 linear;
147
- -webkit-animation: searchSelectFalIn 0.5s 1 linear;
148
- -o-animation: searchSelectFalIn 0.5s 1 linear;
149
- -ms-animation: searchSelectFalIn 0.5s 1 linear;
150
- }
151
- </style>
152
- <style type="text/css">
153
- .pops-${popsType}-search-suggestion-arrow{
154
- --suggestion-arrow-box-shadow-left-color: rgba(0, 0, 0, 0.24);
155
- --suggestion-arrow-box-shadow-right-color: rgba(0, 0, 0, 0.12);
156
- --suggestion-arrow--after-color: rgb(78, 78, 78);
157
- --suggestion-arrow--after-bg-color: rgb(255, 255, 255, var(--pops-bg-opacity));
158
- --suggestion-arrow--after-width: 10px;
159
- --suggestion-arrow--after-height: 10px;
160
- }
161
- .pops-${popsType}-search-suggestion-arrow{
162
- position: absolute;
163
- top: 100%;
164
- left: 50%;
165
- overflow: hidden;
166
- width: 100%;
167
- height: 12.5px;
168
- transform: translateX(-50%);
169
- }
170
- .pops-${popsType}-search-suggestion-arrow::after{
171
- position: absolute;
172
- top: 0;
173
- left: 50%;
174
- width: var(--suggestion-arrow--after-width);
175
- height: var(--suggestion-arrow--after-height);
176
- background: var(--suggestion-arrow--after-bg-color);
177
- color: var(--suggestion-arrow--after-color);
178
- box-shadow:
179
- 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
180
- 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
181
- content: "";
182
- transform: translateX(-50%) translateY(-50%) rotate(45deg);
183
- }
184
- .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow{
185
- position: absolute;
186
- top: 100%;
187
- left: 50%;
188
- overflow: hidden;
189
- width: 100%;
190
- height: 12.5px;
191
- transform: translateX(-50%);
192
- }
193
- .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow::after{
194
- position: absolute;
195
- top: 0;
196
- left: 50%;
197
- width: var(--suggestion-arrow--after-width);
198
- height: var(--suggestion-arrow--after-height);
199
- background: var(--suggestion-arrow--after-bg-color);
200
- box-shadow:
201
- 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
202
- 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
203
- content: "";
204
- transform: translateX(-50%) translateY(-50%) rotate(45deg);
205
- }
206
- .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow{
207
- top: -12.5px;
208
- left: 50%;
209
- transform: translateX(-50%);
210
- }
211
- .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow::after{
212
- position: absolute;
213
- top: 100%;
214
- left: 50%;
215
- content: "";
216
- }
217
- </style>
218
- <style type="text/css" data-dynamic="true">
219
- ${SearchSuggestion.getDynamicCSS()}
220
- </style>
221
- <style>
222
- .el-zoom-in-top-animation{
223
- --el-transition-md-fade: transform 0.3s cubic-bezier(0.23, 1, 0.32, 1),
224
- opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1);
225
- transition: var(--el-transition-md-fade);
226
- transform-origin: center top;
227
- }
228
- .el-zoom-in-top-animation[data-popper-placement^="top"] {
229
- transform-origin: center bottom;
230
- }
231
- .el-zoom-in-top-animation-hide{
232
- opacity: 0;
233
- transform: scaleY(0);
234
- }
235
- .el-zoom-in-top-animation-show{
236
- opacity: 1;
237
- transform: scaleY(1);
238
- }
239
- </style>
240
- <style type="text/css" data-user-css>
241
- ${config.style || ""}
242
- </style>
243
- <div class="pops-${popsType}-search-suggestion-dropdown-wrapper">
244
- <ul class="pops-${popsType}-search-suggestion-dropdown-container ${PopsCommonCSSClassName.userSelectNone}">${
245
- config.toSearhNotResultHTML
246
- }</ul>
247
- </div>
248
- <!-- 箭头 -->
249
- ${config.useArrow ? /*html*/ `<div class="pops-${popsType}-search-suggestion-arrow"></div>` : ""}
250
- `,
251
- },
252
- {
253
- "data-guid": guid,
254
- "type-value": popsType,
255
- }
256
- );
257
- if (config.className !== "" && config.className != null) {
258
- popsDOMUtils.addClassName($el, config.className);
259
- }
260
- if (config.isAnimation) {
261
- popsDOMUtils.addClassName($el, `pops-${popsType}-animation`);
262
- }
263
- if (config.useFoldAnimation) {
264
- popsDOMUtils.addClassName($el, "el-zoom-in-top-animation");
265
- }
266
- return $el;
267
- },
268
- /**
269
- * 动态获取CSS
270
- */
271
- getDynamicCSS() {
272
- return /*css*/ `
273
- .pops-${popsType}-search-suggestion{
274
- --search-suggestion-bg-color: #ffffff;
275
- --search-suggestion-box-shadow-color: rgb(0 0 0 / 20%);
276
- --search-suggestion-item-color: #515a6e;
277
- --search-suggestion-item-none-color: #8e8e8e;
278
- --search-suggestion-item-is-hover-bg-color: #f5f7fa;
279
- --search-suggestion-item-is-select-bg-color: #409eff;
280
- }
281
- .pops-${popsType}-search-suggestion{
282
- border: initial;
283
- overflow: initial;
284
- position: ${config.isAbsolute ? "absolute" : "fixed"};
285
- z-index: ${PopsHandler.handleZIndex(config.zIndex)};
286
- }
287
- .pops-${popsType}-search-suggestion-dropdown-wrapper{
288
- max-height: ${config.maxHeight};
289
- border-radius: 4px;
290
- box-shadow: 0 1px 6px var(--search-suggestion-box-shadow-color);
291
- background-color: var(--search-suggestion-bg-color);
292
- padding: 5px 0;
293
- overflow-x: hidden;
294
- overflow-y: auto;
295
- }
296
- .pops-${popsType}-search-suggestion-dropdown-wrapper ul.pops-${popsType}-search-suggestion-dropdown-container{
297
- box-sizing: border-box;
298
- }
299
- // 建议框在上面时
300
- .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-dropdown-container{
301
- display: flex;
302
- flex-direction: column-reverse;
303
- }
304
- .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-dropdown-container li{
305
- flex-shrink: 0;
306
- }
307
- ul.pops-${popsType}-search-suggestion-dropdown-container li{
308
- padding: 7px;
309
- margin: 0;
310
- clear: both;
311
- color: var(--search-suggestion-item-color);
312
- font-size: 14px;
313
- list-style: none;
314
- cursor: pointer;
315
- transition: background .2s ease-in-out;
316
- overflow: hidden;
317
- text-overflow: ellipsis;
318
- width: 100%;
319
- }
320
- ul.pops-${popsType}-search-suggestion-dropdown-container li[data-none]{
321
- text-align: center;
322
- font-size: 12px;
323
- color: var(--search-suggestion-item-none-color);
324
- }
325
- ul.pops-${popsType}-search-suggestion-dropdown-container li:not([data-none]):hover{
326
- background-color: var(--search-suggestion-item-is-hover-bg-color);
327
- }
328
- @media (prefers-color-scheme: dark){
329
- .pops-${popsType}-search-suggestion{
330
- --search-suggestion-bg-color: #1d1e1f;
331
- --search-suggestion-item-color: #cfd3d4;
332
- --search-suggestion-item-is-hover-bg-color: rgba(175, 175, 175, .1);
333
- }
334
- }
335
- `;
336
- },
337
- /**
338
- * 获取data-value值
339
- * @param data 数据项
340
- */
341
- getItemDataValue(data: PopsSearchSuggestionData<T>) {
342
- return data;
343
- },
344
- /**
345
- * 获取显示出搜索建议框的每一项的html
346
- * @param dataItem 当前项的值
347
- * @param dateItemIndex 当前项的下标
348
- */
349
- createSearchItemLiElement(dataItem: PopsSearchSuggestionData<T>, dateItemIndex: number) {
350
- const dataValue = SearchSuggestion.getItemDataValue(dataItem);
351
- const $li = popsDOMUtils.createElement("li", {
352
- className: `pops-${popsType}-search-suggestion-dropdown-item`,
353
- "data-index": dateItemIndex,
354
- "data-value": dataValue,
355
- });
356
- Reflect.set($li, "data-index", dateItemIndex);
357
- Reflect.set($li, "data-value", dataValue);
358
- // 项内容
359
- const $itemInner = dataItem.itemView(dataItem, $li, config);
360
- if (typeof $itemInner === "string") {
361
- PopsSafeUtils.setSafeHTML($li, $itemInner);
362
- } else {
363
- popsDOMUtils.append($li, $itemInner);
364
- }
365
- // 删除按钮
366
- const enableDeleteButton = dataItem.enableDeleteButton;
367
- if (typeof enableDeleteButton === "boolean" && enableDeleteButton) {
368
- const $deleteIcon = SearchSuggestion.createItemDeleteIcon();
369
- popsDOMUtils.append($li, $deleteIcon);
370
- }
371
- popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexCenter);
372
- popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexYCenter);
373
- return $li;
374
- },
375
- /**
376
- * 设置搜索建议框每一项的点击事件
377
- * @param $searchItem 当前项的元素
378
- */
379
- setSearchItemClickEvent($searchItem: HTMLLIElement) {
380
- popsDOMUtils.on(
381
- $searchItem,
382
- "click",
383
- async (event) => {
384
- popsDOMUtils.preventEvent(event);
385
- const $click = event.target as HTMLLIElement;
386
- const data = SearchSuggestion.getData();
387
- const dataItem = Reflect.get($searchItem, "data-value") as PopsSearchSuggestionData<T>;
388
- const isDelete = Boolean($click.closest(`.pops-${popsType}-delete-icon`));
389
- if (isDelete) {
390
- // 删除
391
- if (typeof dataItem.deleteButtonClickCallback === "function") {
392
- const result = await dataItem.deleteButtonClickCallback(event, $searchItem, dataItem, config);
393
- if (typeof result === "boolean" && result) {
394
- data.splice(data.indexOf(dataItem), 1);
395
- $searchItem.remove();
396
- }
397
- }
398
- if (!SearchSuggestion.$el.$dropdownContainer.children.length) {
399
- // 全删完了
400
- SearchSuggestion.clear();
401
- }
402
- SearchSuggestion.updateStyleSheet();
403
- } else {
404
- // 点击选择项
405
- if (typeof dataItem.clickCallback === "function") {
406
- const result = await dataItem.clickCallback(event, $searchItem, dataItem, config);
407
- if (typeof result === "boolean" && result) {
408
- if (
409
- config.$inputTarget instanceof HTMLInputElement ||
410
- config.$inputTarget instanceof HTMLTextAreaElement
411
- ) {
412
- config.$inputTarget.value = String(dataItem.value);
413
- }
414
- }
415
- }
416
- }
417
- },
418
- {
419
- capture: true,
420
- }
421
- );
422
- },
423
- /**
424
- * 设置搜索建议框每一项的选中事件
425
- * @param $li 每一项元素
426
- */
427
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
428
- setSearchItemSelectEvent($li: HTMLLIElement) {
429
- // TODO
430
- },
431
- /**
432
- * 监听输入框内容改变
433
- */
434
- setInputChangeEvent(option: AddEventListenerOptions = defaultListenerOption) {
435
- // 必须是input或者textarea才有input事件
436
- if (!(config.$inputTarget instanceof HTMLInputElement || config.$inputTarget instanceof HTMLTextAreaElement)) {
437
- return;
438
- }
439
- // 是input输入框
440
- // 禁用输入框自动提示
441
- config.$inputTarget.setAttribute("autocomplete", "off");
442
- // 内容改变事件
443
- const listenerHandler = popsDOMUtils.onInput(
444
- config.$inputTarget,
445
- async () => {
446
- const data = SearchSuggestion.getData();
447
- const queryDataResult = await config.inputTargetChangeRefreshShowDataCallback(
448
- config.$inputTarget.value,
449
- data,
450
- config
451
- );
452
- SearchSuggestion.update(queryDataResult);
453
- SearchSuggestion.updateStyleSheet();
454
- },
455
- option
456
- );
457
- SearchSuggestion.$evt.offInputChangeEvtHandler.push(listenerHandler.off);
458
- },
459
- /**
460
- * 移除输入框内容改变的监听
461
- */
462
- removeInputChangeEvent() {
463
- for (let index = 0; index < SearchSuggestion.$evt.offInputChangeEvtHandler.length; index++) {
464
- const handler = SearchSuggestion.$evt.offInputChangeEvtHandler[index];
465
- handler();
466
- SearchSuggestion.$evt.offInputChangeEvtHandler.splice(index, 1);
467
- index--;
468
- }
469
- },
470
- /**
471
- * 显示搜索建议框的事件
472
- */
473
- showEvent() {
474
- SearchSuggestion.updateStyleSheet();
475
- if (config.toHideWithNotResult) {
476
- if (SearchSuggestion.$data.isEmpty) {
477
- SearchSuggestion.hide(true);
478
- } else {
479
- SearchSuggestion.show();
480
- }
481
- } else {
482
- SearchSuggestion.show();
483
- }
484
- },
485
- /**
486
- * 设置显示搜索建议框的事件
487
- */
488
- setShowEvent(option: AddEventListenerOptions = defaultListenerOption) {
489
- /* 焦点|点击事件*/
490
- if (config.followPosition === "target") {
491
- popsDOMUtils.on([config.$target], ["focus", "click"], SearchSuggestion.showEvent, option);
492
- } else if (config.followPosition === "input") {
493
- popsDOMUtils.on([config.$inputTarget], ["focus", "click"], SearchSuggestion.showEvent, option);
494
- } else if (config.followPosition === "inputCursor") {
495
- popsDOMUtils.on([config.$inputTarget], ["focus", "click", "input"], SearchSuggestion.showEvent, option);
496
- } else {
497
- throw new Error("未知followPosition:" + config.followPosition);
498
- }
499
- },
500
- /**
501
- * 移除显示搜索建议框的事件
502
- */
503
- removeShowEvent(option: AddEventListenerOptions = defaultListenerOption) {
504
- /* 焦点|点击事件*/
505
- popsDOMUtils.off([config.$target, config.$inputTarget], ["focus", "click"], SearchSuggestion.showEvent, option);
506
- // 内容改变事件
507
- popsDOMUtils.off([config.$inputTarget], ["input"], SearchSuggestion.showEvent, option);
508
- },
509
- /**
510
- * 隐藏搜索建议框的事件
511
- * @param event
512
- */
513
- hideEvent(event: PointerEvent | MouseEvent) {
514
- if (event.target instanceof Node) {
515
- if ($shadowContainer.contains(event.target)) {
516
- // 点击在shadow上的
517
- return;
518
- }
519
- if (config.$target.contains(event.target)) {
520
- // 点击在目标元素内
521
- return;
522
- }
523
- if (config.$inputTarget.contains(event.target)) {
524
- // 点击在目标input内
525
- return;
526
- }
527
- SearchSuggestion.hide(true);
528
- }
529
- },
530
- /**
531
- * 设置隐藏搜索建议框的事件
532
- */
533
- setHideEvent(option: AddEventListenerOptions = defaultListenerOption) {
534
- // 全局点击事件
535
- // 全局触摸屏点击事件
536
- if (Array.isArray(SearchSuggestion.selfDocument)) {
537
- SearchSuggestion.selfDocument.forEach(($checkParent) => {
538
- popsDOMUtils.on($checkParent, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
539
- });
540
- } else {
541
- popsDOMUtils.on(SearchSuggestion.selfDocument, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
542
- }
543
- },
544
- /**
545
- * 移除隐藏搜索建议框的事件
546
- */
547
- removeHideEvent(option: AddEventListenerOptions = defaultListenerOption) {
548
- if (Array.isArray(SearchSuggestion.selfDocument)) {
549
- SearchSuggestion.selfDocument.forEach(($checkParent) => {
550
- popsDOMUtils.off($checkParent, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
551
- });
552
- } else {
553
- popsDOMUtils.off(SearchSuggestion.selfDocument, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
554
- }
555
- },
556
- /**
557
- * 设置所有监听,包括(input值改变、全局点击判断显示/隐藏建议框)
558
- */
559
- setAllEvent(option: AddEventListenerOptions = defaultListenerOption) {
560
- SearchSuggestion.setInputChangeEvent(option);
561
- SearchSuggestion.setHideEvent(option);
562
- SearchSuggestion.setShowEvent(option);
563
- },
564
- /**
565
- * 移除所有监听
566
- */
567
- removeAllEvent(option: AddEventListenerOptions = defaultListenerOption) {
568
- SearchSuggestion.removeInputChangeEvent();
569
- SearchSuggestion.removeHideEvent(option);
570
- SearchSuggestion.removeShowEvent(option);
571
- },
572
- /**
573
- * 获取删除按钮的html
574
- */
575
- createItemDeleteIcon(size = 16, fill = "#bababa") {
576
- const $svg = popsDOMUtils.parseTextToDOM(/*html*/ `
577
- <svg class="pops-${popsType}-delete-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="${fill}">
578
- <path d="M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z"></path>
579
- <path d="M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z"></path>
580
- </svg>
581
- `);
582
- return $svg;
583
- },
584
- /**
585
- * 设置当前正在搜索中的提示
586
- */
587
- setPromptsInSearch() {
588
- const $isSearching = popsDOMUtils.createElement("li", {
589
- className: `pops-${popsType}-search-suggestion-dropdown-searching-item`,
590
- innerHTML: config.searchingTip,
591
- });
592
- SearchSuggestion.addItem($isSearching);
593
- },
594
- /**
595
- * 移除正在搜索中的提示
596
- */
597
- removePromptsInSearch() {
598
- SearchSuggestion.$el.$dropdownContainer
599
- .querySelector<HTMLLIElement>(`li.pops-${popsType}-search-suggestion-dropdown-searching-item`)
600
- ?.remove();
601
- },
602
- /**
603
- * 更新搜索建议框的位置(top、left)
604
- * 因为目标元素可能是动态隐藏的
605
- * @param target 目标元素
606
- * @param checkPositonAgain 是否在更新位置信息后检测更新位置信息,默认true
607
- */
608
- changeHintULElementPosition(target = config.$target ?? config.$inputTarget, checkPositonAgain: boolean = true) {
609
- let targetRect: DOMRect | null = null;
610
- if (config.followPosition === "inputCursor") {
611
- targetRect = popsDOMUtils.getTextBoundingRect(
612
- config.$inputTarget,
613
- config.$inputTarget.selectionStart || 0,
614
- config.$inputTarget.selectionEnd || 0,
615
- false
616
- );
617
- } else {
618
- targetRect = config.isAbsolute ? popsDOMUtils.offset(target) : target.getBoundingClientRect();
619
- }
620
- if (targetRect == null) {
621
- return;
622
- }
623
- // 文档最大高度
624
- let documentHeight = document.documentElement.clientHeight;
625
- if (config.isAbsolute) {
626
- // 绝对定位
627
- documentHeight = popsDOMUtils.height(document);
628
- }
629
- // 文档最大宽度
630
- const documentWidth = popsDOMUtils.width(document);
631
- // 箭头
632
- const arrowHeight = config.useArrow ? popsDOMUtils.height(SearchSuggestion.$el.$arrow) : 0;
633
-
634
- let position = config.position;
635
- if (config.position === "auto") {
636
- // 需目标高度+搜索建议框高度大于文档高度,则显示在上面
637
- const targetBottom = targetRect.bottom;
638
- // 容器整体的高度
639
- const searchSuggestionContainerHeight =
640
- popsDOMUtils.height(SearchSuggestion.$el.$dropdownWrapper) + arrowHeight;
641
- if (targetBottom + searchSuggestionContainerHeight > documentHeight) {
642
- // 在上面
643
- position = "top";
644
- } else {
645
- // 在下面
646
- position = "bottom";
647
- }
648
- }
649
- if (position === "top") {
650
- // 在上面
651
- if (config.positionTopToReverse) {
652
- // 自动翻转
653
- SearchSuggestion.$el.root.setAttribute("data-top-reverse", "true");
654
- }
655
- if (config.useFoldAnimation) {
656
- // 翻转折叠
657
- SearchSuggestion.$el.root.setAttribute("data-popper-placement", "top");
658
- }
659
- const bottom = documentHeight - targetRect.top + config.topDistance + arrowHeight;
660
- SearchSuggestion.$el.root.style.top = "";
661
- SearchSuggestion.$el.root.style.bottom = bottom + "px";
662
- } else if (position === "bottom") {
663
- // 在下面
664
- if (config.useFoldAnimation) {
665
- SearchSuggestion.$el.root.setAttribute("data-popper-placement", "bottom-center");
666
- }
667
- const top = targetRect.height + targetRect.top + config.topDistance + arrowHeight;
668
- SearchSuggestion.$el.root.removeAttribute("data-top-reverse");
669
- SearchSuggestion.$el.root.style.bottom = "";
670
- SearchSuggestion.$el.root.style.top = top + "px";
671
- }
672
- let left = targetRect.left;
673
- const hintUIWidth = popsDOMUtils.width(SearchSuggestion.$el.$dropdownWrapper);
674
- if (hintUIWidth > documentWidth) {
675
- // 超出宽度
676
- left = left + documentWidth - hintUIWidth;
677
- }
678
- SearchSuggestion.$el.root.style.left = left + "px";
679
-
680
- // 如果更新前在下面的话且高度超出了屏幕
681
- // 这时候会有滚动条,会造成位置偏移
682
- // 更新后的位置却在上面,这时候的位置信息不对齐
683
- // 需重新更新位置
684
- // 此情况一般是config.position === "auto"
685
- if (checkPositonAgain) {
686
- SearchSuggestion.changeHintULElementPosition(target, !checkPositonAgain);
687
- }
688
- },
689
- /**
690
- * 更新搜索建议框的width
691
- * 因为目标元素可能是动态隐藏的
692
- * @param target 目标元素
693
- */
694
- changeHintULElementWidth(target = config.$target ?? config.$inputTarget) {
695
- const targetRect = target.getBoundingClientRect();
696
- if (config.followTargetWidth) {
697
- SearchSuggestion.$el.$dropdownWrapper.style.width = targetRect.width + "px";
698
- } else {
699
- SearchSuggestion.$el.$dropdownWrapper.style.width = config.width;
700
- }
701
- },
702
- /**
703
- * 动态更新CSS
704
- */
705
- updateDynamicCSS() {
706
- const cssText = SearchSuggestion.getDynamicCSS();
707
- PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$dynamicCSS, cssText);
708
- },
709
- /**
710
- * 数据项的数量改变时调用
711
- *
712
- * - 更新css
713
- * - 更新建议框的宽度
714
- * - 更新建议框的位置
715
- */
716
- updateStyleSheet() {
717
- // 更新z-index
718
- SearchSuggestion.updateDynamicCSS();
719
- // 更新宽度
720
- SearchSuggestion.changeHintULElementWidth();
721
- // 更新位置
722
- SearchSuggestion.changeHintULElementPosition();
723
- },
724
- /**
725
- * 添加搜索结果元素
726
- * @param $item 项元素
727
- */
728
- addItem($item: HTMLElement | DocumentFragment) {
729
- SearchSuggestion.$el.$dropdownContainer.appendChild($item);
730
- },
731
- /**
732
- * 更新页面显示的搜索结果
733
- * @param updateData
734
- */
735
- update(updateData: PopsSearchSuggestionData<T>[] = []) {
736
- if (!Array.isArray(updateData)) {
737
- throw new TypeError("传入的数据不是数组");
738
- }
739
- const data = updateData;
740
- // 清空已有的搜索结果
741
- if (data.length) {
742
- SearchSuggestion.$data.isEmpty = false;
743
- if (config.toHideWithNotResult) {
744
- SearchSuggestion.show();
745
- }
746
- SearchSuggestion.clear(true);
747
- // 添加进ul中
748
- const fragment = document.createDocumentFragment();
749
- data.forEach((item, index) => {
750
- const $item = SearchSuggestion.createSearchItemLiElement(item, index);
751
- SearchSuggestion.setSearchItemClickEvent($item);
752
- SearchSuggestion.setSearchItemSelectEvent($item);
753
- fragment.appendChild($item);
754
- });
755
- SearchSuggestion.addItem(fragment);
756
- } else {
757
- // 清空
758
- SearchSuggestion.clear();
759
- }
760
- },
761
- /**
762
- * 清空当前的搜索结果并显示无结果
763
- * @param [onlyClearView=false] 是否仅清空元素,默认false
764
- */
765
- clear(onlyClearView: boolean = false) {
766
- PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$dropdownContainer, "");
767
- if (onlyClearView) {
768
- return;
769
- }
770
- SearchSuggestion.$data.isEmpty = true;
771
- let $noResult;
772
- if (typeof config.toSearhNotResultHTML === "string") {
773
- $noResult = popsDOMUtils.parseTextToDOM(config.toSearhNotResultHTML);
774
- } else {
775
- $noResult = config.toSearhNotResultHTML();
776
- }
777
- SearchSuggestion.addItem($noResult);
778
- if (config.toHideWithNotResult) {
779
- SearchSuggestion.hide();
780
- }
781
- },
782
- /**
783
- * 隐藏搜索建议框
784
- * @param useAnimationToHide 是否使用动画隐藏
785
- */
786
- hide(useAnimationToHide: boolean = false) {
787
- if (config.useFoldAnimation) {
788
- if (!useAnimationToHide) {
789
- // 去掉动画
790
- popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
791
- }
792
- popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
793
- popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
794
- popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
795
- } else {
796
- SearchSuggestion.$el.root.style.display = "none";
797
- }
798
- },
799
- /**
800
- * 显示搜索建议框
801
- */
802
- show() {
803
- SearchSuggestion.$el.root.style.display = "";
804
- if (config.useFoldAnimation) {
805
- popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
806
- popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
807
- popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
808
- }
809
- },
810
- };
811
- return SearchSuggestion;
812
- },
813
- };
1
+ import { PopsHandler } from "../../handler/PopsHandler";
2
+ import { popsDOMUtils } from "../../utils/PopsDOMUtils";
3
+ import { popsUtils } from "../../utils/PopsUtils";
4
+ import { PopsSearchSuggestionDefaultConfig } from "./defaultConfig";
5
+ import { GlobalConfig } from "../../config/GlobalConfig";
6
+ import { PopsSafeUtils } from "../../utils/PopsSafeUtils";
7
+ import type { PopsSearchSuggestionData, PopsSearchSuggestionConfig } from "./types/index";
8
+ import { PopsCSS } from "../../PopsCSS";
9
+ import type { PopsType } from "../../types/main";
10
+ import { PopsCommonCSSClassName } from "../../config/CommonCSSClassName";
11
+
12
+ export const PopsSearchSuggestion = {
13
+ init<T>(__config__: PopsSearchSuggestionConfig<T>) {
14
+ const guid = popsUtils.getRandomGUID();
15
+ // 设置当前类型
16
+ const popsType: PopsType = "searchSuggestion";
17
+
18
+ let config = PopsSearchSuggestionDefaultConfig();
19
+ config = popsUtils.assign(config, GlobalConfig.getGlobalConfig());
20
+ config = popsUtils.assign(config, __config__);
21
+ // 如果$inputTarget为空,则根据$target
22
+ if (config.$inputTarget == null) {
23
+ config.$inputTarget = config.$target as HTMLInputElement;
24
+ }
25
+
26
+ const { $shadowContainer, $shadowRoot } = PopsHandler.handlerShadow(config);
27
+ PopsHandler.handleInit($shadowRoot, [
28
+ {
29
+ name: "index",
30
+ css: PopsCSS.index,
31
+ },
32
+ {
33
+ name: "anim",
34
+ css: PopsCSS.anim,
35
+ },
36
+ {
37
+ name: "common",
38
+ css: PopsCSS.common,
39
+ },
40
+ ]);
41
+
42
+ if (config.style != null) {
43
+ const $css = popsDOMUtils.createElement("style", {
44
+ type: "text/css",
45
+ innerHTML: config.style,
46
+ });
47
+ $shadowRoot.appendChild($css);
48
+ }
49
+ /**
50
+ * 监听器的默认配置
51
+ */
52
+ const defaultListenerOption: AddEventListenerOptions = {
53
+ capture: true,
54
+ passive: true,
55
+ };
56
+ const SearchSuggestion = {
57
+ /**
58
+ * 当前的环境,可以是document,可以是shadowroot,默认是document
59
+ */
60
+ selfDocument: config.$selfDocument,
61
+ $el: {
62
+ /** 根元素 */
63
+ root: null as any as HTMLElement,
64
+ /**
65
+ * 包裹ul的容器元素
66
+ */
67
+ $dropdownWrapper: null as any as HTMLElement,
68
+ /** ul元素 */
69
+ $dropdownContainer: null as any as HTMLUListElement,
70
+ /**
71
+ * 箭头元素
72
+ */
73
+ $arrow: null as any as HTMLDivElement,
74
+ /** 动态更新CSS */
75
+ $dynamicCSS: null as any as HTMLStyleElement,
76
+ },
77
+ $evt: {
78
+ offInputChangeEvtHandler: [] as ((...args: any[]) => any)[],
79
+ },
80
+ $data: {
81
+ /** 是否结果为空 */
82
+ isEmpty: true,
83
+ /**
84
+ * 存储在元素上的操作的键名
85
+ */
86
+ storeNodeHandlerKey: "data-SearchSuggestion",
87
+ },
88
+ /**
89
+ * 初始化
90
+ * @param $parent 父元素
91
+ * @example
92
+ * .init();
93
+ * .setAllEvent();
94
+ */
95
+ init($parent = document.body || document.documentElement) {
96
+ SearchSuggestion.initEl();
97
+ SearchSuggestion.update(SearchSuggestion.getData());
98
+ SearchSuggestion.updateStyleSheet();
99
+
100
+ SearchSuggestion.hide();
101
+ $shadowRoot.appendChild(SearchSuggestion.$el.root);
102
+ $parent.appendChild($shadowContainer);
103
+ },
104
+ /**
105
+ * 初始化元素变量
106
+ */
107
+ initEl() {
108
+ SearchSuggestion.$el.root = SearchSuggestion.createSearchSelectElement();
109
+ Reflect.set(SearchSuggestion.$el.root, this.$data.storeNodeHandlerKey, SearchSuggestion);
110
+ SearchSuggestion.$el.$dynamicCSS =
111
+ SearchSuggestion.$el.root.querySelector<HTMLStyleElement>("style[data-dynamic]")!;
112
+ SearchSuggestion.$el.$dropdownWrapper = SearchSuggestion.$el.root.querySelector<HTMLElement>(
113
+ `.pops-${popsType}-search-suggestion-dropdown-wrapper`
114
+ )!;
115
+ SearchSuggestion.$el.$dropdownContainer = SearchSuggestion.$el.root.querySelector<HTMLUListElement>(
116
+ `ul.pops-${popsType}-search-suggestion-dropdown-container`
117
+ )!;
118
+ SearchSuggestion.$el.$arrow = SearchSuggestion.$el.root.querySelector<HTMLDivElement>(
119
+ `.pops-${popsType}-search-suggestion-arrow`
120
+ )!;
121
+ },
122
+ /**
123
+ * 获取数据
124
+ */
125
+ getData(): PopsSearchSuggestionData<T>[] {
126
+ return typeof config.data === "function" ? config.data() : config.data;
127
+ },
128
+ /**
129
+ * 更新数据
130
+ * @param data 数据
131
+ */
132
+ setData(data: PopsSearchSuggestionData<T>[]) {
133
+ (<PopsSearchSuggestionConfig<T>["data"]>config.data) = data;
134
+ },
135
+ /**
136
+ * 获取显示出搜索建议框的html
137
+ */
138
+ createSearchSelectElement() {
139
+ const $el = popsDOMUtils.createElement(
140
+ "div",
141
+ {
142
+ className: `pops pops-${popsType}-search-suggestion`,
143
+ innerHTML: /*html*/ `
144
+ <style type="text/css">
145
+ .pops-${popsType}-animation{
146
+ -moz-animation: searchSelectFalIn 0.5s 1 linear;
147
+ -webkit-animation: searchSelectFalIn 0.5s 1 linear;
148
+ -o-animation: searchSelectFalIn 0.5s 1 linear;
149
+ -ms-animation: searchSelectFalIn 0.5s 1 linear;
150
+ }
151
+ </style>
152
+ <style type="text/css">
153
+ .pops-${popsType}-search-suggestion-arrow{
154
+ --suggestion-arrow-box-shadow-left-color: rgba(0, 0, 0, 0.24);
155
+ --suggestion-arrow-box-shadow-right-color: rgba(0, 0, 0, 0.12);
156
+ --suggestion-arrow--after-color: rgb(78, 78, 78);
157
+ --suggestion-arrow--after-bg-color: rgb(255, 255, 255, var(--pops-bg-opacity));
158
+ --suggestion-arrow--after-width: 10px;
159
+ --suggestion-arrow--after-height: 10px;
160
+ }
161
+ .pops-${popsType}-search-suggestion-arrow{
162
+ position: absolute;
163
+ top: 100%;
164
+ left: 50%;
165
+ overflow: hidden;
166
+ width: 100%;
167
+ height: 12.5px;
168
+ transform: translateX(-50%);
169
+ }
170
+ .pops-${popsType}-search-suggestion-arrow::after{
171
+ position: absolute;
172
+ top: 0;
173
+ left: 50%;
174
+ width: var(--suggestion-arrow--after-width);
175
+ height: var(--suggestion-arrow--after-height);
176
+ background: var(--suggestion-arrow--after-bg-color);
177
+ color: var(--suggestion-arrow--after-color);
178
+ box-shadow:
179
+ 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
180
+ 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
181
+ content: "";
182
+ transform: translateX(-50%) translateY(-50%) rotate(45deg);
183
+ }
184
+ .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow{
185
+ position: absolute;
186
+ top: 100%;
187
+ left: 50%;
188
+ overflow: hidden;
189
+ width: 100%;
190
+ height: 12.5px;
191
+ transform: translateX(-50%);
192
+ }
193
+ .pops-${popsType}-search-suggestion[data-popper-placement^="top"] .pops-${popsType}-search-suggestion-arrow::after{
194
+ position: absolute;
195
+ top: 0;
196
+ left: 50%;
197
+ width: var(--suggestion-arrow--after-width);
198
+ height: var(--suggestion-arrow--after-height);
199
+ background: var(--suggestion-arrow--after-bg-color);
200
+ box-shadow:
201
+ 0 1px 7px var(--suggestion-arrow-box-shadow-left-color),
202
+ 0 1px 7px var(--suggestion-arrow-box-shadow-right-color);
203
+ content: "";
204
+ transform: translateX(-50%) translateY(-50%) rotate(45deg);
205
+ }
206
+ .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow{
207
+ top: -12.5px;
208
+ left: 50%;
209
+ transform: translateX(-50%);
210
+ }
211
+ .pops-${popsType}-search-suggestion[data-popper-placement^="bottom"] .pops-${popsType}-search-suggestion-arrow::after{
212
+ position: absolute;
213
+ top: 100%;
214
+ left: 50%;
215
+ content: "";
216
+ }
217
+ </style>
218
+ <style type="text/css" data-dynamic="true">
219
+ ${SearchSuggestion.getDynamicCSS()}
220
+ </style>
221
+ <style>
222
+ .el-zoom-in-top-animation{
223
+ --el-transition-md-fade: transform 0.3s cubic-bezier(0.23, 1, 0.32, 1),
224
+ opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1);
225
+ transition: var(--el-transition-md-fade);
226
+ transform-origin: center top;
227
+ }
228
+ .el-zoom-in-top-animation[data-popper-placement^="top"] {
229
+ transform-origin: center bottom;
230
+ }
231
+ .el-zoom-in-top-animation-hide{
232
+ opacity: 0;
233
+ transform: scaleY(0);
234
+ }
235
+ .el-zoom-in-top-animation-show{
236
+ opacity: 1;
237
+ transform: scaleY(1);
238
+ }
239
+ </style>
240
+ <style type="text/css" data-user-css>
241
+ ${config.style || ""}
242
+ </style>
243
+ <div class="pops-${popsType}-search-suggestion-dropdown-wrapper">
244
+ <ul class="pops-${popsType}-search-suggestion-dropdown-container ${PopsCommonCSSClassName.userSelectNone}">${
245
+ config.toSearhNotResultHTML
246
+ }</ul>
247
+ </div>
248
+ <!-- 箭头 -->
249
+ ${config.useArrow ? /*html*/ `<div class="pops-${popsType}-search-suggestion-arrow"></div>` : ""}
250
+ `,
251
+ },
252
+ {
253
+ "data-guid": guid,
254
+ "type-value": popsType,
255
+ }
256
+ );
257
+ if (config.className !== "" && config.className != null) {
258
+ popsDOMUtils.addClassName($el, config.className);
259
+ }
260
+ if (config.isAnimation) {
261
+ popsDOMUtils.addClassName($el, `pops-${popsType}-animation`);
262
+ }
263
+ if (config.useFoldAnimation) {
264
+ popsDOMUtils.addClassName($el, "el-zoom-in-top-animation");
265
+ }
266
+ return $el;
267
+ },
268
+ /**
269
+ * 动态获取CSS
270
+ */
271
+ getDynamicCSS() {
272
+ return /*css*/ `
273
+ .pops-${popsType}-search-suggestion{
274
+ --search-suggestion-bg-color: #ffffff;
275
+ --search-suggestion-box-shadow-color: rgb(0 0 0 / 20%);
276
+ --search-suggestion-item-color: #515a6e;
277
+ --search-suggestion-item-none-color: #8e8e8e;
278
+ --search-suggestion-item-is-hover-bg-color: #f5f7fa;
279
+ --search-suggestion-item-is-select-bg-color: #409eff;
280
+ }
281
+ .pops-${popsType}-search-suggestion{
282
+ border: initial;
283
+ overflow: initial;
284
+ position: ${config.isAbsolute ? "absolute" : "fixed"};
285
+ z-index: ${PopsHandler.handleZIndex(config.zIndex)};
286
+ }
287
+ .pops-${popsType}-search-suggestion-dropdown-wrapper{
288
+ max-height: ${config.maxHeight};
289
+ border-radius: 4px;
290
+ box-shadow: 0 1px 6px var(--search-suggestion-box-shadow-color);
291
+ background-color: var(--search-suggestion-bg-color);
292
+ padding: 5px 0;
293
+ overflow-x: hidden;
294
+ overflow-y: auto;
295
+ }
296
+ .pops-${popsType}-search-suggestion-dropdown-wrapper ul.pops-${popsType}-search-suggestion-dropdown-container{
297
+ box-sizing: border-box;
298
+ }
299
+ // 建议框在上面时
300
+ .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-dropdown-container{
301
+ display: flex;
302
+ flex-direction: column-reverse;
303
+ }
304
+ .pops-${popsType}-search-suggestion[data-top-reverse] ul.pops-${popsType}-search-suggestion-dropdown-container li{
305
+ flex-shrink: 0;
306
+ }
307
+ ul.pops-${popsType}-search-suggestion-dropdown-container li{
308
+ padding: 7px;
309
+ margin: 0;
310
+ clear: both;
311
+ color: var(--search-suggestion-item-color);
312
+ font-size: 14px;
313
+ list-style: none;
314
+ cursor: pointer;
315
+ transition: background .2s ease-in-out;
316
+ overflow: hidden;
317
+ text-overflow: ellipsis;
318
+ width: 100%;
319
+ }
320
+ ul.pops-${popsType}-search-suggestion-dropdown-container li[data-none]{
321
+ text-align: center;
322
+ font-size: 12px;
323
+ color: var(--search-suggestion-item-none-color);
324
+ }
325
+ ul.pops-${popsType}-search-suggestion-dropdown-container li:not([data-none]):hover{
326
+ background-color: var(--search-suggestion-item-is-hover-bg-color);
327
+ }
328
+ @media (prefers-color-scheme: dark){
329
+ .pops-${popsType}-search-suggestion{
330
+ --search-suggestion-bg-color: #1d1e1f;
331
+ --search-suggestion-item-color: #cfd3d4;
332
+ --search-suggestion-item-is-hover-bg-color: rgba(175, 175, 175, .1);
333
+ }
334
+ }
335
+ `;
336
+ },
337
+ /**
338
+ * 获取data-value值
339
+ * @param data 数据项
340
+ */
341
+ getItemDataValue(data: PopsSearchSuggestionData<T>) {
342
+ return data;
343
+ },
344
+ /**
345
+ * 获取显示出搜索建议框的每一项的html
346
+ * @param dataItem 当前项的值
347
+ * @param dateItemIndex 当前项的下标
348
+ */
349
+ createSearchItemLiElement(dataItem: PopsSearchSuggestionData<T>, dateItemIndex: number) {
350
+ const dataValue = SearchSuggestion.getItemDataValue(dataItem);
351
+ const $li = popsDOMUtils.createElement("li", {
352
+ className: `pops-${popsType}-search-suggestion-dropdown-item`,
353
+ "data-index": dateItemIndex,
354
+ "data-value": dataValue,
355
+ });
356
+ Reflect.set($li, "data-index", dateItemIndex);
357
+ Reflect.set($li, "data-value", dataValue);
358
+ // 项内容
359
+ const $itemInner = dataItem.itemView(dataItem, $li, config);
360
+ if (typeof $itemInner === "string") {
361
+ PopsSafeUtils.setSafeHTML($li, $itemInner);
362
+ } else {
363
+ popsDOMUtils.append($li, $itemInner);
364
+ }
365
+ // 删除按钮
366
+ const enableDeleteButton = dataItem.enableDeleteButton;
367
+ if (typeof enableDeleteButton === "boolean" && enableDeleteButton) {
368
+ const $deleteIcon = SearchSuggestion.createItemDeleteIcon();
369
+ popsDOMUtils.append($li, $deleteIcon);
370
+ }
371
+ popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexCenter);
372
+ popsDOMUtils.addClassName($li, PopsCommonCSSClassName.flexYCenter);
373
+ return $li;
374
+ },
375
+ /**
376
+ * 设置搜索建议框每一项的点击事件
377
+ * @param $searchItem 当前项的元素
378
+ */
379
+ setSearchItemClickEvent($searchItem: HTMLLIElement) {
380
+ popsDOMUtils.on(
381
+ $searchItem,
382
+ "click",
383
+ async (event) => {
384
+ popsDOMUtils.preventEvent(event);
385
+ const $click = event.target as HTMLLIElement;
386
+ const data = SearchSuggestion.getData();
387
+ const dataItem = Reflect.get($searchItem, "data-value") as PopsSearchSuggestionData<T>;
388
+ const isDelete = Boolean($click.closest(`.pops-${popsType}-delete-icon`));
389
+ if (isDelete) {
390
+ // 删除
391
+ if (typeof dataItem.deleteButtonClickCallback === "function") {
392
+ const result = await dataItem.deleteButtonClickCallback(event, $searchItem, dataItem, config);
393
+ if (typeof result === "boolean" && result) {
394
+ data.splice(data.indexOf(dataItem), 1);
395
+ $searchItem.remove();
396
+ }
397
+ }
398
+ if (!SearchSuggestion.$el.$dropdownContainer.children.length) {
399
+ // 全删完了
400
+ SearchSuggestion.clear();
401
+ }
402
+ SearchSuggestion.updateStyleSheet();
403
+ } else {
404
+ // 点击选择项
405
+ if (typeof dataItem.clickCallback === "function") {
406
+ const result = await dataItem.clickCallback(event, $searchItem, dataItem, config);
407
+ if (typeof result === "boolean" && result) {
408
+ if (
409
+ config.$inputTarget instanceof HTMLInputElement ||
410
+ config.$inputTarget instanceof HTMLTextAreaElement
411
+ ) {
412
+ config.$inputTarget.value = String(dataItem.value);
413
+ }
414
+ }
415
+ }
416
+ }
417
+ },
418
+ {
419
+ capture: true,
420
+ }
421
+ );
422
+ },
423
+ /**
424
+ * 设置搜索建议框每一项的选中事件
425
+ * @param $li 每一项元素
426
+ */
427
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
428
+ setSearchItemSelectEvent($li: HTMLLIElement) {
429
+ // TODO
430
+ },
431
+ /**
432
+ * 监听输入框内容改变
433
+ */
434
+ setInputChangeEvent(option: AddEventListenerOptions = defaultListenerOption) {
435
+ // 必须是input或者textarea才有input事件
436
+ if (!(config.$inputTarget instanceof HTMLInputElement || config.$inputTarget instanceof HTMLTextAreaElement)) {
437
+ return;
438
+ }
439
+ // 是input输入框
440
+ // 禁用输入框自动提示
441
+ config.$inputTarget.setAttribute("autocomplete", "off");
442
+ // 内容改变事件
443
+ const listenerHandler = popsDOMUtils.onInput(
444
+ config.$inputTarget,
445
+ async () => {
446
+ const data = SearchSuggestion.getData();
447
+ const queryDataResult = await config.inputTargetChangeRefreshShowDataCallback(
448
+ config.$inputTarget.value,
449
+ data,
450
+ config
451
+ );
452
+ SearchSuggestion.update(queryDataResult);
453
+ SearchSuggestion.updateStyleSheet();
454
+ },
455
+ option
456
+ );
457
+ SearchSuggestion.$evt.offInputChangeEvtHandler.push(listenerHandler.off);
458
+ },
459
+ /**
460
+ * 移除输入框内容改变的监听
461
+ */
462
+ removeInputChangeEvent() {
463
+ for (let index = 0; index < SearchSuggestion.$evt.offInputChangeEvtHandler.length; index++) {
464
+ const handler = SearchSuggestion.$evt.offInputChangeEvtHandler[index];
465
+ handler();
466
+ SearchSuggestion.$evt.offInputChangeEvtHandler.splice(index, 1);
467
+ index--;
468
+ }
469
+ },
470
+ /**
471
+ * 显示搜索建议框的事件
472
+ */
473
+ showEvent() {
474
+ SearchSuggestion.updateStyleSheet();
475
+ if (config.toHideWithNotResult) {
476
+ if (SearchSuggestion.$data.isEmpty) {
477
+ SearchSuggestion.hide(true);
478
+ } else {
479
+ SearchSuggestion.show();
480
+ }
481
+ } else {
482
+ SearchSuggestion.show();
483
+ }
484
+ },
485
+ /**
486
+ * 设置显示搜索建议框的事件
487
+ */
488
+ setShowEvent(option: AddEventListenerOptions = defaultListenerOption) {
489
+ /* 焦点|点击事件*/
490
+ if (config.followPosition === "target") {
491
+ popsDOMUtils.on([config.$target], ["focus", "click"], SearchSuggestion.showEvent, option);
492
+ } else if (config.followPosition === "input") {
493
+ popsDOMUtils.on([config.$inputTarget], ["focus", "click"], SearchSuggestion.showEvent, option);
494
+ } else if (config.followPosition === "inputCursor") {
495
+ popsDOMUtils.on([config.$inputTarget], ["focus", "click", "input"], SearchSuggestion.showEvent, option);
496
+ } else {
497
+ throw new Error("未知followPosition:" + config.followPosition);
498
+ }
499
+ },
500
+ /**
501
+ * 移除显示搜索建议框的事件
502
+ */
503
+ removeShowEvent(option: AddEventListenerOptions = defaultListenerOption) {
504
+ /* 焦点|点击事件*/
505
+ popsDOMUtils.off([config.$target, config.$inputTarget], ["focus", "click"], SearchSuggestion.showEvent, option);
506
+ // 内容改变事件
507
+ popsDOMUtils.off([config.$inputTarget], ["input"], SearchSuggestion.showEvent, option);
508
+ },
509
+ /**
510
+ * 隐藏搜索建议框的事件
511
+ * @param event
512
+ */
513
+ hideEvent(event: PointerEvent | MouseEvent) {
514
+ if (event.target instanceof Node) {
515
+ if ($shadowContainer.contains(event.target)) {
516
+ // 点击在shadow上的
517
+ return;
518
+ }
519
+ if (config.$target.contains(event.target)) {
520
+ // 点击在目标元素内
521
+ return;
522
+ }
523
+ if (config.$inputTarget.contains(event.target)) {
524
+ // 点击在目标input内
525
+ return;
526
+ }
527
+ SearchSuggestion.hide(true);
528
+ }
529
+ },
530
+ /**
531
+ * 设置隐藏搜索建议框的事件
532
+ */
533
+ setHideEvent(option: AddEventListenerOptions = defaultListenerOption) {
534
+ // 全局点击事件
535
+ // 全局触摸屏点击事件
536
+ if (Array.isArray(SearchSuggestion.selfDocument)) {
537
+ SearchSuggestion.selfDocument.forEach(($checkParent) => {
538
+ popsDOMUtils.on($checkParent, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
539
+ });
540
+ } else {
541
+ popsDOMUtils.on(SearchSuggestion.selfDocument, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
542
+ }
543
+ },
544
+ /**
545
+ * 移除隐藏搜索建议框的事件
546
+ */
547
+ removeHideEvent(option: AddEventListenerOptions = defaultListenerOption) {
548
+ if (Array.isArray(SearchSuggestion.selfDocument)) {
549
+ SearchSuggestion.selfDocument.forEach(($checkParent) => {
550
+ popsDOMUtils.off($checkParent, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
551
+ });
552
+ } else {
553
+ popsDOMUtils.off(SearchSuggestion.selfDocument, ["click", "touchstart"], SearchSuggestion.hideEvent, option);
554
+ }
555
+ },
556
+ /**
557
+ * 设置所有监听,包括(input值改变、全局点击判断显示/隐藏建议框)
558
+ */
559
+ setAllEvent(option: AddEventListenerOptions = defaultListenerOption) {
560
+ SearchSuggestion.setInputChangeEvent(option);
561
+ SearchSuggestion.setHideEvent(option);
562
+ SearchSuggestion.setShowEvent(option);
563
+ },
564
+ /**
565
+ * 移除所有监听
566
+ */
567
+ removeAllEvent(option: AddEventListenerOptions = defaultListenerOption) {
568
+ SearchSuggestion.removeInputChangeEvent();
569
+ SearchSuggestion.removeHideEvent(option);
570
+ SearchSuggestion.removeShowEvent(option);
571
+ },
572
+ /**
573
+ * 获取删除按钮的html
574
+ */
575
+ createItemDeleteIcon(size = 16, fill = "#bababa") {
576
+ const $svg = popsDOMUtils.parseTextToDOM(/*html*/ `
577
+ <svg class="pops-${popsType}-delete-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" fill="${fill}">
578
+ <path d="M512 883.2A371.2 371.2 0 1 0 140.8 512 371.2 371.2 0 0 0 512 883.2z m0 64a435.2 435.2 0 1 1 435.2-435.2 435.2 435.2 0 0 1-435.2 435.2z"></path>
579
+ <path d="M557.056 512l122.368 122.368a31.744 31.744 0 1 1-45.056 45.056L512 557.056l-122.368 122.368a31.744 31.744 0 1 1-45.056-45.056L466.944 512 344.576 389.632a31.744 31.744 0 1 1 45.056-45.056L512 466.944l122.368-122.368a31.744 31.744 0 1 1 45.056 45.056z"></path>
580
+ </svg>
581
+ `);
582
+ return $svg;
583
+ },
584
+ /**
585
+ * 设置当前正在搜索中的提示
586
+ */
587
+ setPromptsInSearch() {
588
+ const $isSearching = popsDOMUtils.createElement("li", {
589
+ className: `pops-${popsType}-search-suggestion-dropdown-searching-item`,
590
+ innerHTML: config.searchingTip,
591
+ });
592
+ SearchSuggestion.addItem($isSearching);
593
+ },
594
+ /**
595
+ * 移除正在搜索中的提示
596
+ */
597
+ removePromptsInSearch() {
598
+ SearchSuggestion.$el.$dropdownContainer
599
+ .querySelector<HTMLLIElement>(`li.pops-${popsType}-search-suggestion-dropdown-searching-item`)
600
+ ?.remove();
601
+ },
602
+ /**
603
+ * 更新搜索建议框的位置(top、left)
604
+ * 因为目标元素可能是动态隐藏的
605
+ * @param target 目标元素
606
+ * @param checkPositonAgain 是否在更新位置信息后检测更新位置信息,默认true
607
+ */
608
+ changeHintULElementPosition(target = config.$target ?? config.$inputTarget, checkPositonAgain: boolean = true) {
609
+ let targetRect: DOMRect | null = null;
610
+ if (config.followPosition === "inputCursor") {
611
+ targetRect = popsDOMUtils.getTextBoundingRect(
612
+ config.$inputTarget,
613
+ config.$inputTarget.selectionStart || 0,
614
+ config.$inputTarget.selectionEnd || 0,
615
+ false
616
+ );
617
+ } else {
618
+ targetRect = config.isAbsolute ? popsDOMUtils.offset(target) : target.getBoundingClientRect();
619
+ }
620
+ if (targetRect == null) {
621
+ return;
622
+ }
623
+ // 文档最大高度
624
+ let documentHeight = document.documentElement.clientHeight;
625
+ if (config.isAbsolute) {
626
+ // 绝对定位
627
+ documentHeight = popsDOMUtils.height(document);
628
+ }
629
+ // 文档最大宽度
630
+ const documentWidth = popsDOMUtils.width(document);
631
+ // 箭头
632
+ const arrowHeight = config.useArrow ? popsDOMUtils.height(SearchSuggestion.$el.$arrow) : 0;
633
+
634
+ let position = config.position;
635
+ if (config.position === "auto") {
636
+ // 需目标高度+搜索建议框高度大于文档高度,则显示在上面
637
+ const targetBottom = targetRect.bottom;
638
+ // 容器整体的高度
639
+ const searchSuggestionContainerHeight =
640
+ popsDOMUtils.height(SearchSuggestion.$el.$dropdownWrapper) + arrowHeight;
641
+ if (targetBottom + searchSuggestionContainerHeight > documentHeight) {
642
+ // 在上面
643
+ position = "top";
644
+ } else {
645
+ // 在下面
646
+ position = "bottom";
647
+ }
648
+ }
649
+ if (position === "top") {
650
+ // 在上面
651
+ if (config.positionTopToReverse) {
652
+ // 自动翻转
653
+ SearchSuggestion.$el.root.setAttribute("data-top-reverse", "true");
654
+ }
655
+ if (config.useFoldAnimation) {
656
+ // 翻转折叠
657
+ SearchSuggestion.$el.root.setAttribute("data-popper-placement", "top");
658
+ }
659
+ const bottom = documentHeight - targetRect.top + config.topDistance + arrowHeight;
660
+ SearchSuggestion.$el.root.style.top = "";
661
+ SearchSuggestion.$el.root.style.bottom = bottom + "px";
662
+ } else if (position === "bottom") {
663
+ // 在下面
664
+ if (config.useFoldAnimation) {
665
+ SearchSuggestion.$el.root.setAttribute("data-popper-placement", "bottom-center");
666
+ }
667
+ const top = targetRect.height + targetRect.top + config.topDistance + arrowHeight;
668
+ SearchSuggestion.$el.root.removeAttribute("data-top-reverse");
669
+ SearchSuggestion.$el.root.style.bottom = "";
670
+ SearchSuggestion.$el.root.style.top = top + "px";
671
+ }
672
+ let left = targetRect.left;
673
+ const hintUIWidth = popsDOMUtils.width(SearchSuggestion.$el.$dropdownWrapper);
674
+ if (hintUIWidth > documentWidth) {
675
+ // 超出宽度
676
+ left = left + documentWidth - hintUIWidth;
677
+ }
678
+ SearchSuggestion.$el.root.style.left = left + "px";
679
+
680
+ // 如果更新前在下面的话且高度超出了屏幕
681
+ // 这时候会有滚动条,会造成位置偏移
682
+ // 更新后的位置却在上面,这时候的位置信息不对齐
683
+ // 需重新更新位置
684
+ // 此情况一般是config.position === "auto"
685
+ if (checkPositonAgain) {
686
+ SearchSuggestion.changeHintULElementPosition(target, !checkPositonAgain);
687
+ }
688
+ },
689
+ /**
690
+ * 更新搜索建议框的width
691
+ * 因为目标元素可能是动态隐藏的
692
+ * @param target 目标元素
693
+ */
694
+ changeHintULElementWidth(target = config.$target ?? config.$inputTarget) {
695
+ const targetRect = target.getBoundingClientRect();
696
+ if (config.followTargetWidth) {
697
+ SearchSuggestion.$el.$dropdownWrapper.style.width = targetRect.width + "px";
698
+ } else {
699
+ SearchSuggestion.$el.$dropdownWrapper.style.width = config.width;
700
+ }
701
+ },
702
+ /**
703
+ * 动态更新CSS
704
+ */
705
+ updateDynamicCSS() {
706
+ const cssText = SearchSuggestion.getDynamicCSS();
707
+ PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$dynamicCSS, cssText);
708
+ },
709
+ /**
710
+ * 数据项的数量改变时调用
711
+ *
712
+ * - 更新css
713
+ * - 更新建议框的宽度
714
+ * - 更新建议框的位置
715
+ */
716
+ updateStyleSheet() {
717
+ // 更新z-index
718
+ SearchSuggestion.updateDynamicCSS();
719
+ // 更新宽度
720
+ SearchSuggestion.changeHintULElementWidth();
721
+ // 更新位置
722
+ SearchSuggestion.changeHintULElementPosition();
723
+ },
724
+ /**
725
+ * 添加搜索结果元素
726
+ * @param $item 项元素
727
+ */
728
+ addItem($item: HTMLElement | DocumentFragment) {
729
+ SearchSuggestion.$el.$dropdownContainer.appendChild($item);
730
+ },
731
+ /**
732
+ * 更新页面显示的搜索结果
733
+ * @param updateData
734
+ */
735
+ update(updateData: PopsSearchSuggestionData<T>[] = []) {
736
+ if (!Array.isArray(updateData)) {
737
+ throw new TypeError("传入的数据不是数组");
738
+ }
739
+ const data = updateData;
740
+ // 清空已有的搜索结果
741
+ if (data.length) {
742
+ SearchSuggestion.$data.isEmpty = false;
743
+ if (config.toHideWithNotResult) {
744
+ SearchSuggestion.show();
745
+ }
746
+ SearchSuggestion.clear(true);
747
+ // 添加进ul中
748
+ const fragment = document.createDocumentFragment();
749
+ data.forEach((item, index) => {
750
+ const $item = SearchSuggestion.createSearchItemLiElement(item, index);
751
+ SearchSuggestion.setSearchItemClickEvent($item);
752
+ SearchSuggestion.setSearchItemSelectEvent($item);
753
+ fragment.appendChild($item);
754
+ });
755
+ SearchSuggestion.addItem(fragment);
756
+ } else {
757
+ // 清空
758
+ SearchSuggestion.clear();
759
+ }
760
+ },
761
+ /**
762
+ * 清空当前的搜索结果并显示无结果
763
+ * @param [onlyClearView=false] 是否仅清空元素,默认false
764
+ */
765
+ clear(onlyClearView: boolean = false) {
766
+ PopsSafeUtils.setSafeHTML(SearchSuggestion.$el.$dropdownContainer, "");
767
+ if (onlyClearView) {
768
+ return;
769
+ }
770
+ SearchSuggestion.$data.isEmpty = true;
771
+ let $noResult;
772
+ if (typeof config.toSearhNotResultHTML === "string") {
773
+ $noResult = popsDOMUtils.parseTextToDOM(config.toSearhNotResultHTML);
774
+ } else {
775
+ $noResult = config.toSearhNotResultHTML();
776
+ }
777
+ SearchSuggestion.addItem($noResult);
778
+ if (config.toHideWithNotResult) {
779
+ SearchSuggestion.hide();
780
+ }
781
+ },
782
+ /**
783
+ * 隐藏搜索建议框
784
+ * @param useAnimationToHide 是否使用动画隐藏
785
+ */
786
+ hide(useAnimationToHide: boolean = false) {
787
+ if (config.useFoldAnimation) {
788
+ if (!useAnimationToHide) {
789
+ // 去掉动画
790
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
791
+ }
792
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
793
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
794
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
795
+ } else {
796
+ SearchSuggestion.$el.root.style.display = "none";
797
+ }
798
+ },
799
+ /**
800
+ * 显示搜索建议框
801
+ */
802
+ show() {
803
+ SearchSuggestion.$el.root.style.display = "";
804
+ if (config.useFoldAnimation) {
805
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation");
806
+ popsDOMUtils.removeClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-hide");
807
+ popsDOMUtils.addClassName(SearchSuggestion.$el.root, "el-zoom-in-top-animation-show");
808
+ }
809
+ },
810
+ };
811
+ return SearchSuggestion;
812
+ },
813
+ };