Merge branch 'master' of github.com:9th-js/wcui
						commit
						8f77c0ed30
					
				|  | @ -4,15 +4,27 @@ | ||||||
|  * @date 2023/03/06 15:17:25 |  * @date 2023/03/06 15:17:25 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { nextTick, css, html, Component } from '@bd/core' | import { | ||||||
|  |   nextTick, | ||||||
|  |   css, | ||||||
|  |   html, | ||||||
|  |   Component, | ||||||
|  |   classMap, | ||||||
|  |   outsideClick | ||||||
|  | } from '@bd/core' | ||||||
| import '../icon/index.js' | import '../icon/index.js' | ||||||
|  | import '../scroll/index.js' | ||||||
| 
 | 
 | ||||||
|  | const ANIMATION = { | ||||||
|  |   duration: 100, | ||||||
|  |   custom: [{ transform: 'scaleY(0)' }, { transform: 'scaleY(1)' }] | ||||||
|  | } | ||||||
| class Input extends Component { | class Input extends Component { | ||||||
|   static props = { |   static props = { | ||||||
|     readOnly: false, |     readOnly: false, | ||||||
|     autofocus: false, |     autofocus: false, | ||||||
|     disabled: false, |     disabled: false, | ||||||
|     closeable: false, |     clearable: false, | ||||||
|     icon: '', |     icon: '', | ||||||
|     size: 'l', |     size: 'l', | ||||||
|     placeholder: '', |     placeholder: '', | ||||||
|  | @ -25,11 +37,16 @@ class Input extends Component { | ||||||
|     }, |     }, | ||||||
|     lazy: 0 // 并发拦截时间, 单位毫秒
 |     lazy: 0 // 并发拦截时间, 单位毫秒
 | ||||||
|   } |   } | ||||||
| 
 |   #list = [] | ||||||
|  |   #originList = [] | ||||||
|  |   #isComposing = false | ||||||
|  |   #selectIndex = -1 | ||||||
|  |   #listShowing = false | ||||||
|  |   #stamp = 0 | ||||||
|   static styles = [ |   static styles = [ | ||||||
|     css` |     css` | ||||||
|       :host { |       :host { | ||||||
|         overflow: hidden; |         position: relative; | ||||||
|         display: inline-flex; |         display: inline-flex; | ||||||
|         min-width: 228px; |         min-width: 228px; | ||||||
|         height: 36px; |         height: 36px; | ||||||
|  | @ -109,25 +126,28 @@ class Input extends Component { | ||||||
| 
 | 
 | ||||||
|       .suggestion { |       .suggestion { | ||||||
|         overflow: hidden; |         overflow: hidden; | ||||||
|         display: none; |         position: absolute; | ||||||
|         position: fixed; |         z-index: 1; | ||||||
|         z-index: 10240; |  | ||||||
|         left: 0; |         left: 0; | ||||||
|         top: 0; |         top: calc(100% + 4px); | ||||||
|         width: 200px; |         width: 100%; | ||||||
|         height: auto; |         height: auto; | ||||||
|         max-height: 200px; |         max-height: 200px; | ||||||
|         min-height: 46px; |  | ||||||
|         padding: 4px 0; |         padding: 4px 0; | ||||||
|         border-radius: 4px; |         border-radius: 4px; | ||||||
|         background: var(--color-plain-1); |         // background: var(--color-plain-1);
 | ||||||
|         box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); |         box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); | ||||||
| 
 |         transform-origin: top; | ||||||
|  |         // transition: transform linear 00s;
 | ||||||
|  |         // transform: scaleY(0);
 | ||||||
|  |         wc-scroll { | ||||||
|  |           max-height: 200px; | ||||||
|  |         } | ||||||
|         .list { |         .list { | ||||||
|           width: 100%; |           width: 100%; | ||||||
|         } |         } | ||||||
|         &.show { |         &.hide { | ||||||
|           display: flex; |           display: none; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         li { |         li { | ||||||
|  | @ -349,6 +369,11 @@ class Input extends Component { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|  |     let classes = classMap({ | ||||||
|  |       suggestion: true, | ||||||
|  |       hide: !this.#list.length | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|     return html` |     return html` | ||||||
|       <div class="label"> |       <div class="label"> | ||||||
|         <slot class="prepend" name="prepend"></slot> |         <slot class="prepend" name="prepend"></slot> | ||||||
|  | @ -356,7 +381,10 @@ class Input extends Component { | ||||||
|           ref="input" |           ref="input" | ||||||
|           @input=${this.onInput} |           @input=${this.onInput} | ||||||
|           @change=${this.onChange} |           @change=${this.onChange} | ||||||
|  |           @compositionstart=${this.onCompositionstart} | ||||||
|  |           @compositionend=${this.onCompositionend} | ||||||
|           @keydown=${this.onKeyDown} |           @keydown=${this.onKeyDown} | ||||||
|  |           @focus=${this.onFocus} | ||||||
|           placeholder=${this.placeholder} |           placeholder=${this.placeholder} | ||||||
|           maxlength=${this.maxlength} |           maxlength=${this.maxlength} | ||||||
|           minlength=${this.minlength} |           minlength=${this.minlength} | ||||||
|  | @ -365,26 +393,129 @@ class Input extends Component { | ||||||
|           autofocus=${this.autofocus} |           autofocus=${this.autofocus} | ||||||
|           :value=${this.value} |           :value=${this.value} | ||||||
|         /> |         /> | ||||||
|         ${this.closeable && this.value ? this.renderClose() : ''} |         ${this.clearable && this.value ? this.renderClose() : ''} | ||||||
|         ${this.icon |         ${this.icon | ||||||
|           ? html`<wc-icon class="icon" name=${this.icon} />` |           ? html`<wc-icon class="icon" name=${this.icon} />` | ||||||
|           : html`<slot class="append" name="append" />`} |           : html`<slot class="append" name="append" />`} | ||||||
|  |         <div class=${classes} ref="suggestion" #animation=${ANIMATION}> | ||||||
|  |           <wc-scroll ref="scroller"> | ||||||
|  |             <ul class="list" @click=${this.onClick} ref="list"> | ||||||
|  |               ${this.#list.map( | ||||||
|  |                 (li, idx) => | ||||||
|  |                   html`<li
 | ||||||
|  |                     focus=${this.#selectIndex === idx ? true : null} | ||||||
|  |                     index=${idx} | ||||||
|  |                   > | ||||||
|  |                     ${li.value} | ||||||
|  |                   </li>` | ||||||
|  |               )} | ||||||
|  |             </ul> | ||||||
|  |           </wc-scroll> | ||||||
|  |         </div> | ||||||
|       </div> |       </div> | ||||||
|     ` |     ` | ||||||
|   } |   } | ||||||
|  |   onCompositionstart() { | ||||||
|  |     this.#isComposing = true | ||||||
|  |   } | ||||||
|  |   onCompositionend() { | ||||||
|  |     this.#isComposing = false | ||||||
|  |     this.filterSuggestList() | ||||||
|  |   } | ||||||
|  |   filterSuggestList() { | ||||||
|  |     if (!this.#originList.length) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     if (!this.value) { | ||||||
|  |       this.#list = this.#originList | ||||||
|  |     } else { | ||||||
|  |       this.#list = this.#originList.filter(li => | ||||||
|  |         li.value.startsWith(this.value) | ||||||
|  |       ) | ||||||
|  |     } | ||||||
|  |     if (!this.#listShowing) { | ||||||
|  |       this.#listShowing = true | ||||||
|  |       this.$refs.suggestion.$animate() | ||||||
|  |     } | ||||||
|  |     this.$requestUpdate() | ||||||
|  |   } | ||||||
|   onInput(e) { |   onInput(e) { | ||||||
|  |     let { lazy } = this | ||||||
|     this.value = e.currentTarget.value |     this.value = e.currentTarget.value | ||||||
|  |     if (lazy && Date.now() - this.#stamp < lazy) { | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     this.#stamp = Date.now() | ||||||
|  |     if (!this.#isComposing) { | ||||||
|  |       this.filterSuggestList() | ||||||
|  |       this.$emit('fetch-suggest', { | ||||||
|  |         value: this.value, | ||||||
|  |         send: list => { | ||||||
|  |           this.#originList = this.#list = list | ||||||
|  |           this.$requestUpdate() | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   onClick(e) { | ||||||
|  |     let index = e.target.getAttribute('index') | ||||||
|  |     this.value = this.#list[index].value | ||||||
|  |     this.#list = [this.#list[index]] | ||||||
|  |     this.$refs.suggestion.$animate(true) | ||||||
|  |     this.#listShowing = false | ||||||
|   } |   } | ||||||
|   onClickClose() { |   onClickClose() { | ||||||
|     this.$refs.input.value = '' |     this.$refs.input.value = '' | ||||||
|     this.value = '' |     this.value = '' | ||||||
|  |     if (this.#originList.length) { | ||||||
|  |       this.filterSuggestList() | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   onChange() { |   onChange() { | ||||||
|     this.$emit('change') |     this.$emit('change') | ||||||
|   } |   } | ||||||
|   onKeyDown(e) { |   onKeyDown(e) { | ||||||
|  |     let { lazy, minlength, value } = this | ||||||
|     if (e.keyCode === 13) { |     if (e.keyCode === 13) { | ||||||
|       this.$emit('submit') |       e.preventDefault() | ||||||
|  |       if (this.#selectIndex > -1 && this.#listShowing) { | ||||||
|  |         this.value = this.#list[this.#selectIndex].value | ||||||
|  |         this.#list = [this.#list[this.#selectIndex]] | ||||||
|  |         this.#selectIndex = 0 | ||||||
|  |         this.$requestUpdate() | ||||||
|  |         this.$refs.suggestion.$animate(true) | ||||||
|  |         this.#listShowing = false | ||||||
|  |         return this.$emit('select') //输入建议存在,则第1次回车的时候, 不触发提交
 | ||||||
|  |       } | ||||||
|  |       if (lazy && Date.now() - this.#stamp < lazy) { | ||||||
|  |         return | ||||||
|  |       } | ||||||
|  |       this.#stamp = Date.now() | ||||||
|  |       if (minlength && value.length < minlength) { | ||||||
|  |         return | ||||||
|  |       } | ||||||
|  |       return this.$emit('submit') | ||||||
|  |     } | ||||||
|  |     if (e.keyCode === 38 || e.keyCode === 40) { | ||||||
|  |       e.preventDefault() | ||||||
|  |       let step = e.keyCode === 38 ? -1 : 1 | ||||||
|  | 
 | ||||||
|  |       this.#selectIndex += step | ||||||
|  |       if (this.#selectIndex < 0) { | ||||||
|  |         this.#selectIndex = 0 | ||||||
|  |       } | ||||||
|  |       if (this.#selectIndex > this.#list.length - 1) { | ||||||
|  |         this.#selectIndex = this.#list.length - 1 | ||||||
|  |       } | ||||||
|  |       let target = this.$refs.list.children[this.#selectIndex] | ||||||
|  |       this.$refs.scroller.scrollTop = target.offsetTop - 150 | ||||||
|  |       this.$requestUpdate() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   onFocus() { | ||||||
|  |     if (!this.#listShowing) { | ||||||
|  |       this.#listShowing = true | ||||||
|  |       this.$refs.suggestion.$animate() | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   mounted() { |   mounted() { | ||||||
|  | @ -392,6 +523,10 @@ class Input extends Component { | ||||||
|       // 火狐浏览器需要手动focus()才能聚焦成功
 |       // 火狐浏览器需要手动focus()才能聚焦成功
 | ||||||
|       nextTick(_ => this.$refs.input.focus()) |       nextTick(_ => this.$refs.input.focus()) | ||||||
|     } |     } | ||||||
|  |     outsideClick(this, () => { | ||||||
|  |       this.#listShowing = false | ||||||
|  |       this.$refs.suggestion.$animate(true) | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue