mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-17 13:20:52 +08:00
refactor(base-picker): make keyboard events work
This commit is contained in:
parent
00dfa036c3
commit
6bba332083
@ -7,17 +7,20 @@
|
||||
'n-base-picker--disabled': disabled,
|
||||
[`n-base-picker--${size}-size`]: true,
|
||||
'n-base-picker--multiple': multiple,
|
||||
'n-base-picker--focus': false
|
||||
'n-base-picker--focus': patternInputFocused
|
||||
}"
|
||||
@click="handleActivatorClick"
|
||||
@click="handleClick"
|
||||
>
|
||||
<template v-if="multiple && !filterable">
|
||||
<!-- multiple -->
|
||||
<div
|
||||
class="n-base-picker-tags"
|
||||
:class="{
|
||||
'n-base-picker-tags--selected': selected
|
||||
'n-base-picker-tags--selected': selected,
|
||||
'n-base-picker-tags--focused': patternInputFocused
|
||||
}"
|
||||
:tabindex="disabled ? false : '0'"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<div
|
||||
v-for="option in selectedOptions"
|
||||
@ -30,22 +33,64 @@
|
||||
<n-icon
|
||||
class="n-base-picker-tag__icon"
|
||||
type="md-close"
|
||||
@click.stop="handleOptionToggle(option)"
|
||||
@click.stop="handleDeleteOption(option)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="n-base-picker__placeholder"
|
||||
>
|
||||
{{ placeholder }}
|
||||
</div>
|
||||
<n-base-cancel-mark
|
||||
class="n-base-picker__mark"
|
||||
arrow
|
||||
:show="!remote"
|
||||
:disabled="disabled"
|
||||
:active="active"
|
||||
:clearable="clearable && selected"
|
||||
@clear="handleClear"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="multiple && filterable">
|
||||
<!-- multiple filterable -->
|
||||
<div
|
||||
class="n-base-picker-tags"
|
||||
:class="{
|
||||
'n-base-picker-tags--selected': selected
|
||||
}"
|
||||
:tabindex="(disabled || active) ? false : '0'"
|
||||
>
|
||||
<div
|
||||
v-for="option in selectedOptions"
|
||||
:key="option.value"
|
||||
class="n-base-picker-tag"
|
||||
>
|
||||
<div class="n-base-picker-tag__content">
|
||||
{{ option.label }}
|
||||
</div>
|
||||
<n-icon
|
||||
class="n-base-picker-tag__icon"
|
||||
type="md-close"
|
||||
@click.stop="handleDeleteOption(option)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="filterable && active"
|
||||
class="n-base-picker-input-tag"
|
||||
>
|
||||
<input
|
||||
ref="inputTagInput"
|
||||
ref="patternInput"
|
||||
tabindex="-1"
|
||||
:disabled="disabled"
|
||||
:value="pattern"
|
||||
class="n-base-picker-input-tag__input"
|
||||
@keydown.delete="handlePatternInputDelete"
|
||||
@input="handlePatternInput"
|
||||
@blur="handlePatternInputBlur"
|
||||
@focus="handlePatternInputFocus"
|
||||
@keydown.delete="handlePatternKeyDownDelete"
|
||||
@input="handlePatternInputInput"
|
||||
>
|
||||
<span
|
||||
ref="inputTagMirror"
|
||||
ref="patternInputMirror"
|
||||
class="n-base-picker-input-tag__mirror"
|
||||
>{{ pattern ? pattern : ' ' }}</span>
|
||||
</div>
|
||||
@ -66,14 +111,24 @@
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="!multiple && filterable">
|
||||
<input
|
||||
ref="singleInput"
|
||||
:value="(active && filterable) ? pattern : (selectedOption && selectedOption.label)"
|
||||
<!-- single filterable -->
|
||||
<div
|
||||
class="n-base-picker-label"
|
||||
:placeholder="selectedOption ? selectedOption.label : placeholder"
|
||||
:readonly="!disabled && filterable ? false : 'readonly'"
|
||||
@input="handlePatternInput"
|
||||
:tabindex="(!disabled && !active) ? '0' : false"
|
||||
>
|
||||
<input
|
||||
ref="patternInput"
|
||||
class="n-base-picker-label__input"
|
||||
:value="(patternInputFocused && active) ? pattern : label"
|
||||
:placeholder="selectedOption ? label : placeholder"
|
||||
:readonly="!disabled && filterable && active ? false : 'readonly'"
|
||||
:disabled="disabled"
|
||||
tabindex="-1"
|
||||
@focus="handlePatternInputFocus"
|
||||
@blur="handlePatternInputBlur"
|
||||
@input="handlePatternInputInput"
|
||||
>
|
||||
</div>
|
||||
<n-base-cancel-mark
|
||||
class="n-base-picker__mark"
|
||||
arrow
|
||||
@ -85,20 +140,25 @@
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="!multiple && !filterable">
|
||||
<!-- single -->
|
||||
<div
|
||||
ref="singleInput"
|
||||
:tabindex="disabled ? false : '0'"
|
||||
class="n-base-picker-label"
|
||||
:class="{
|
||||
'n-base-picker-label--placeholder': !(label && label.length)
|
||||
}"
|
||||
:tabindex="disabled ? false : '0'"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<template v-if="label && label.length">
|
||||
{{ label }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ labelPlaceholder }}
|
||||
</template>
|
||||
<div
|
||||
class="n-base-picker-label__input"
|
||||
:class="{
|
||||
'n-base-picker-label__input--placeholder': !(label && label.length)
|
||||
}"
|
||||
>
|
||||
<template v-if="label && label.length">
|
||||
{{ label }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ labelPlaceholder }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<n-base-cancel-mark
|
||||
class="n-base-picker__mark"
|
||||
@ -177,12 +237,17 @@ export default {
|
||||
default: 'medium'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
patternInputFocused: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labelPlaceholder () {
|
||||
return this.selectedOption ? this.selectedOption.label : this.placeholder
|
||||
},
|
||||
label () {
|
||||
const label = (this.active && this.filterable) ? this.pattern : (this.selectedOption && this.selectedOption.label)
|
||||
const label = (this.selectedOption && this.selectedOption.label) || ''
|
||||
console.log(label)
|
||||
return label
|
||||
},
|
||||
@ -195,54 +260,68 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
active (active) {
|
||||
if (!active) {
|
||||
if (active) {
|
||||
this.$nextTick().then(() => {
|
||||
this.blurSingleInput()
|
||||
if (this.$refs.singleInput) {
|
||||
this.$refs.singleInput.focus()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleOptionToggle (option) {
|
||||
this.toggleOption(option)
|
||||
handleBlur () {
|
||||
this.$emit('blur')
|
||||
},
|
||||
handleClear (e) {
|
||||
this.$emit('clear', e)
|
||||
},
|
||||
handleActivatorClick () {
|
||||
this.$emit('activator-click')
|
||||
if (this.multiple && this.filterable) {
|
||||
this.$nextTick().then(() => {
|
||||
this.focusInputTag()
|
||||
})
|
||||
handleClick () {
|
||||
this.$emit('click')
|
||||
if (this.filterable) {
|
||||
this.focusPatternInput()
|
||||
}
|
||||
},
|
||||
handlePatternInputDelete (e) {
|
||||
handleDeleteOption (option) {
|
||||
this.$emit('delete-option')
|
||||
this.toggleOption(option)
|
||||
},
|
||||
handlePatternKeyDownDelete (option) {
|
||||
if (!this.pattern.length) {
|
||||
// console.log(e)
|
||||
this.$emit('pattern-input-delete')
|
||||
this.$emit('delete-last-option')
|
||||
}
|
||||
},
|
||||
handlePatternInput (e) {
|
||||
handlePatternInputInput (e) {
|
||||
// console.log('NBasePicker, handlePatternInput', e)
|
||||
if (this.multiple) {
|
||||
this.$nextTick().then(() => {
|
||||
const textWidth = this.$refs.inputTagMirror.getBoundingClientRect().width
|
||||
this.$refs.inputTagInput.style.width = textWidth + 'px'
|
||||
const textWidth = this.$refs.patternInputMirror.getBoundingClientRect().width
|
||||
this.$refs.patternInput.style.width = textWidth + 'px'
|
||||
this.$emit('pattern-input', e)
|
||||
})
|
||||
} else {
|
||||
this.$emit('pattern-input', e)
|
||||
}
|
||||
},
|
||||
blurSingleInput () {
|
||||
if (this.$refs.singleInput) {
|
||||
this.$refs.singleInput.blur()
|
||||
handlePatternInputFocus (e) {
|
||||
console.log('handlePatternInputFocus')
|
||||
this.patternInputFocused = true
|
||||
},
|
||||
handlePatternInputBlur (e) {
|
||||
console.log('handlePatternInputBlur')
|
||||
this.patternInputFocused = false
|
||||
this.handleBlur()
|
||||
},
|
||||
focusPatternInput () {
|
||||
if (this.$refs.patternInput) {
|
||||
console.log('focusPatternInput')
|
||||
this.$refs.patternInput.focus()
|
||||
}
|
||||
},
|
||||
focusInputTag () {
|
||||
if (this.$refs.inputTagInput) {
|
||||
this.$refs.inputTagInput.focus()
|
||||
blurPatternInput () {
|
||||
if (this.$refs.patternInput) {
|
||||
console.log('blurPatternInput')
|
||||
this.$refs.patternInput.blur()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
[`n-base-select-menu--${size}-size`]: true,
|
||||
'n-base-select-menu--multiple': multiple
|
||||
}"
|
||||
tabindex="0"
|
||||
@keyup.up.stop="handleKeyUpUp"
|
||||
@keyup.down.stop="handleKeyUpDown"
|
||||
@mousedown.prevent="() => {}"
|
||||
>
|
||||
<n-scrollbar
|
||||
ref="scrollbar"
|
||||
|
@ -4,7 +4,7 @@
|
||||
class="n-select"
|
||||
@keydown.up.prevent="() => {}"
|
||||
@keydown.down.prevent="() => {}"
|
||||
@keydown.space.prevent="() => {}"
|
||||
@keydown.space="handleKeyDownSpace"
|
||||
@keyup.up="handleKeyUpUp"
|
||||
@keyup.down="handleKeyUpDown"
|
||||
@keyup.enter="handleKeyUpEnter"
|
||||
@ -26,10 +26,11 @@
|
||||
:disabled="disabled"
|
||||
:on-search="onSearch"
|
||||
:size="size"
|
||||
@activator-click="handleActivatorClick"
|
||||
@pattern-input-delete="handlePatternInputDelete"
|
||||
@click="handleActivatorClick"
|
||||
@delete-last-option="handleDeleteLastOption"
|
||||
@pattern-input="handlePatternInput"
|
||||
@clear="handleClear"
|
||||
@blur="handlePickerBlur"
|
||||
/>
|
||||
<div
|
||||
ref="contentContainer"
|
||||
@ -293,34 +294,34 @@ export default {
|
||||
}
|
||||
},
|
||||
handleClickOutsideMenu (e) {
|
||||
if (!this.$refs.activator.$el.contains(e.target) && !this.scrolling) {
|
||||
this.deactivate()
|
||||
if (this.filterable && !this.multiple) {
|
||||
this.pattern = ''
|
||||
if (this.active) {
|
||||
if (!this.$refs.activator.$el.contains(e.target) && !this.scrolling) {
|
||||
console.log('handleClickOutsideMenu')
|
||||
this.closeMenu()
|
||||
}
|
||||
}
|
||||
},
|
||||
closeMenu () {
|
||||
this.deactivate()
|
||||
if (!this.multiple) {
|
||||
this.$refs.activator.blurSingleInput()
|
||||
openMenu () {
|
||||
console.log('openMenu')
|
||||
this.pattern = ''
|
||||
this.activate()
|
||||
if (this.filterable) {
|
||||
this.$refs.activator.focusPatternInput()
|
||||
}
|
||||
},
|
||||
closeMenu () {
|
||||
console.log('closeMenu')
|
||||
this.deactivate()
|
||||
},
|
||||
handleActivatorClick () {
|
||||
if (this.disabled) return
|
||||
if (!this.active) {
|
||||
this.pattern = ''
|
||||
this.activate()
|
||||
this.openMenu()
|
||||
} else {
|
||||
if (!this.filterable) {
|
||||
this.deactivate()
|
||||
this.closeMenu()
|
||||
}
|
||||
}
|
||||
if (this.multiple && this.filterable) {
|
||||
this.$nextTick().then(() => {
|
||||
this.$refs.activator.focusInputTag()
|
||||
})
|
||||
}
|
||||
},
|
||||
toggleOption (option) {
|
||||
if (this.disabled) return
|
||||
@ -342,12 +343,6 @@ export default {
|
||||
// this.emitChangeEvent(item, true)
|
||||
this.pattern = ''
|
||||
}
|
||||
this.$nextTick().then(() => {
|
||||
if (this.filterable) {
|
||||
// console.log('toggleOption inputTagInput')
|
||||
this.$refs.activator.focusInputTag()
|
||||
}
|
||||
})
|
||||
this.$emit('input', newValue)
|
||||
this.emitChangeEvent(newValue)
|
||||
} else {
|
||||
@ -370,7 +365,7 @@ export default {
|
||||
handleMenuScroll (e, scrollContainer, scrollContent) {
|
||||
this.$emit('scroll', e, scrollContainer, scrollContent)
|
||||
},
|
||||
handlePatternInputDelete (e) {
|
||||
handleDeleteLastOption (e) {
|
||||
if (!this.pattern.length) {
|
||||
const newValue = this.value
|
||||
if (Array.isArray(newValue)) {
|
||||
@ -385,15 +380,21 @@ export default {
|
||||
this.onSearch(e.target.value)
|
||||
}
|
||||
},
|
||||
handleKeyUpEnter () {
|
||||
// console.log('keyup enter')
|
||||
const pendingOption = this.$refs.contentInner && this.$refs.contentInner.pendingOption
|
||||
if (pendingOption) {
|
||||
this.toggleOption(pendingOption)
|
||||
handleKeyUpEnter (e) {
|
||||
if (this.active) {
|
||||
const pendingOption = this.$refs.contentInner && this.$refs.contentInner.pendingOption
|
||||
if (pendingOption) {
|
||||
this.toggleOption(pendingOption)
|
||||
} else {
|
||||
this.closeMenu()
|
||||
}
|
||||
} else {
|
||||
this.openMenu()
|
||||
}
|
||||
e.preventDefault()
|
||||
},
|
||||
handleKeyUpSpace () {
|
||||
this.handleKeyUpEnter()
|
||||
handleKeyUpSpace (e) {
|
||||
this.handleKeyUpEnter(e)
|
||||
},
|
||||
handleKeyUpUp () {
|
||||
// console.log('keyup up')
|
||||
@ -409,11 +410,19 @@ export default {
|
||||
this.$refs.contentInner.next()
|
||||
}
|
||||
},
|
||||
handleKeyDownSpace (e) {
|
||||
if (!this.filterable) {
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
handleClear (e) {
|
||||
e.stopPropagation()
|
||||
// e.stopPropagation()
|
||||
this.closeMenu()
|
||||
this.$emit('input', null)
|
||||
this.emitChangeEvent(null)
|
||||
},
|
||||
handlePickerBlur () {
|
||||
this.closeMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,9 @@
|
||||
@import './theme/default.scss';
|
||||
|
||||
@include b(base-picker) {
|
||||
outline: none;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
border-radius: $select-border-radius;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
@ -24,29 +23,32 @@
|
||||
opacity: 1;
|
||||
}
|
||||
.n-base-picker-label, .n-base-picker-tags {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
// outline: none;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
transition: box-shadow .3s $default-cubic-bezier, background-color .3s $default-cubic-bezier;
|
||||
box-sizing: border-box;
|
||||
border-radius: $select-border-radius;
|
||||
background-color: $select-background-color;
|
||||
}
|
||||
.n-base-picker-label {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
vertical-align: baseline;
|
||||
display: inline-block;
|
||||
border:none;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
cursor: inherit;
|
||||
color: $select-text-color;
|
||||
padding: 0 32px 0 14px;
|
||||
&::placeholder {
|
||||
color: $select-placeholder-color;
|
||||
}
|
||||
&.n-base-picker-label--placeholder {
|
||||
color: $select-placeholder-color;
|
||||
.n-base-picker-label__input {
|
||||
box-sizing: border-box;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
border:none;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
color: $select-text-color;
|
||||
padding: 0 32px 0 14px;
|
||||
background-color: transparent;
|
||||
height: 100%;
|
||||
&::placeholder {
|
||||
color: $select-placeholder-color;
|
||||
}
|
||||
&.n-base-picker-label__input--placeholder {
|
||||
color: $select-placeholder-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.n-base-picker-tags {
|
||||
@ -176,22 +178,22 @@
|
||||
.n-base-picker__placeholder {
|
||||
color: rgba(255, 255, 255, 0.20);
|
||||
}
|
||||
.n-base-picker-label {
|
||||
.n-base-picker-label__input {
|
||||
color: rgba(255, 255, 255, 0.20);
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.20);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.n-base-picker--focus {
|
||||
.n-base-picker-label, .n-base-picker-tags {
|
||||
box-shadow: inset 0 0 0 1px $select-border-color--active;
|
||||
}
|
||||
}
|
||||
&:not(.n-base-picker--disabled) {
|
||||
.n-base-picker-label:hover, .n-base-picker-tags:hover {
|
||||
box-shadow: inset 0 0 0 1px $select-border-color--active;
|
||||
}
|
||||
.n-base-picker-label[readonly="readonly"] {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
&:not(.n-base-picker--disabled) {
|
||||
.n-base-picker-label:focus, .n-base-picker-tags:focus {
|
||||
box-shadow: inset 0 0 0 1px $select-border-color--active;
|
||||
}
|
||||
@ -207,7 +209,7 @@
|
||||
.n-base-picker-input-tag__input {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
// outline: none;
|
||||
border: none;
|
||||
max-width: 100%;
|
||||
caret-color: $input-caret-color;
|
||||
|
Loading…
Reference in New Issue
Block a user