Merge branch 'master' of github.com:9th-js/wcui
						commit
						8f77c0ed30
					
				|  | @ -4,15 +4,27 @@ | |||
|  * @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 '../scroll/index.js' | ||||
| 
 | ||||
| const ANIMATION = { | ||||
|   duration: 100, | ||||
|   custom: [{ transform: 'scaleY(0)' }, { transform: 'scaleY(1)' }] | ||||
| } | ||||
| class Input extends Component { | ||||
|   static props = { | ||||
|     readOnly: false, | ||||
|     autofocus: false, | ||||
|     disabled: false, | ||||
|     closeable: false, | ||||
|     clearable: false, | ||||
|     icon: '', | ||||
|     size: 'l', | ||||
|     placeholder: '', | ||||
|  | @ -25,11 +37,16 @@ class Input extends Component { | |||
|     }, | ||||
|     lazy: 0 // 并发拦截时间, 单位毫秒
 | ||||
|   } | ||||
| 
 | ||||
|   #list = [] | ||||
|   #originList = [] | ||||
|   #isComposing = false | ||||
|   #selectIndex = -1 | ||||
|   #listShowing = false | ||||
|   #stamp = 0 | ||||
|   static styles = [ | ||||
|     css` | ||||
|       :host { | ||||
|         overflow: hidden; | ||||
|         position: relative; | ||||
|         display: inline-flex; | ||||
|         min-width: 228px; | ||||
|         height: 36px; | ||||
|  | @ -109,25 +126,28 @@ class Input extends Component { | |||
| 
 | ||||
|       .suggestion { | ||||
|         overflow: hidden; | ||||
|         display: none; | ||||
|         position: fixed; | ||||
|         z-index: 10240; | ||||
|         position: absolute; | ||||
|         z-index: 1; | ||||
|         left: 0; | ||||
|         top: 0; | ||||
|         width: 200px; | ||||
|         top: calc(100% + 4px); | ||||
|         width: 100%; | ||||
|         height: auto; | ||||
|         max-height: 200px; | ||||
|         min-height: 46px; | ||||
|         padding: 4px 0; | ||||
|         border-radius: 4px; | ||||
|         background: var(--color-plain-1); | ||||
|         // background: var(--color-plain-1);
 | ||||
|         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 { | ||||
|           width: 100%; | ||||
|         } | ||||
|         &.show { | ||||
|           display: flex; | ||||
|         &.hide { | ||||
|           display: none; | ||||
|         } | ||||
| 
 | ||||
|         li { | ||||
|  | @ -349,6 +369,11 @@ class Input extends Component { | |||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     let classes = classMap({ | ||||
|       suggestion: true, | ||||
|       hide: !this.#list.length | ||||
|     }) | ||||
| 
 | ||||
|     return html` | ||||
|       <div class="label"> | ||||
|         <slot class="prepend" name="prepend"></slot> | ||||
|  | @ -356,7 +381,10 @@ class Input extends Component { | |||
|           ref="input" | ||||
|           @input=${this.onInput} | ||||
|           @change=${this.onChange} | ||||
|           @compositionstart=${this.onCompositionstart} | ||||
|           @compositionend=${this.onCompositionend} | ||||
|           @keydown=${this.onKeyDown} | ||||
|           @focus=${this.onFocus} | ||||
|           placeholder=${this.placeholder} | ||||
|           maxlength=${this.maxlength} | ||||
|           minlength=${this.minlength} | ||||
|  | @ -365,26 +393,129 @@ class Input extends Component { | |||
|           autofocus=${this.autofocus} | ||||
|           :value=${this.value} | ||||
|         /> | ||||
|         ${this.closeable && this.value ? this.renderClose() : ''} | ||||
|         ${this.clearable && this.value ? this.renderClose() : ''} | ||||
|         ${this.icon | ||||
|           ? html`<wc-icon class="icon" name=${this.icon} />` | ||||
|           : 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> | ||||
|     ` | ||||
|   } | ||||
|   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) { | ||||
|     let { lazy } = this | ||||
|     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() { | ||||
|     this.$refs.input.value = '' | ||||
|     this.value = '' | ||||
|     if (this.#originList.length) { | ||||
|       this.filterSuggestList() | ||||
|     } | ||||
|   } | ||||
|   onChange() { | ||||
|     this.$emit('change') | ||||
|   } | ||||
|   onKeyDown(e) { | ||||
|     let { lazy, minlength, value } = this | ||||
|     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() { | ||||
|  | @ -392,6 +523,10 @@ class Input extends Component { | |||
|       // 火狐浏览器需要手动focus()才能聚焦成功
 | ||||
|       nextTick(_ => this.$refs.input.focus()) | ||||
|     } | ||||
|     outsideClick(this, () => { | ||||
|       this.#listShowing = false | ||||
|       this.$refs.suggestion.$animate(true) | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue