Merge branch 'master' of github.com:9th-js/wcui

master
yutent 2023-04-10 14:24:24 +08:00
commit 8f77c0ed30
1 changed files with 151 additions and 16 deletions

View File

@ -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)
})
} }
} }