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