refactor(select): empty status & data utils

This commit is contained in:
07akioni 2020-01-21 21:32:42 +08:00
parent 554052e1fe
commit 3b9e318887
9 changed files with 42 additions and 101 deletions

View File

@ -6,6 +6,7 @@
'n-base-select-menu--multiple': multiple, 'n-base-select-menu--multiple': multiple,
[`n-${theme}-theme`]: theme [`n-${theme}-theme`]: theme
}" }"
:style="{ :style="{
width: width && (width + 'px') width: width && (width + 'px')
}" }"
@ -14,6 +15,7 @@
@mousedown.prevent="() => {}" @mousedown.prevent="() => {}"
> >
<n-scrollbar <n-scrollbar
v-show="!empty"
ref="scrollbar" ref="scrollbar"
:theme="theme" :theme="theme"
:without-scrollbar="withoutScrollbar" :without-scrollbar="withoutScrollbar"
@ -22,7 +24,7 @@
@scroll="handleMenuScroll" @scroll="handleMenuScroll"
> >
<div class="n-base-select-menu-option-wrapper"> <div class="n-base-select-menu-option-wrapper">
<template v-if="!loading"> <template v-show="empty">
<recycle-scroller <recycle-scroller
ref="virtualScroller" ref="virtualScroller"
class="n-virtual-scroller" class="n-virtual-scroller"
@ -54,39 +56,30 @@
</div> </div>
</n-scrollbar> </n-scrollbar>
<div <div
v-if="loading" v-if="empty"
class="n-base-select-option n-base-select-option--loading" style="padding: 14px 0;"
> >
loading <slot name="empty">
</div> <n-empty description="No Data" />
<div </slot>
v-else-if="noData"
class="n-base-select-option n-base-select-option--no-data"
>
{{ noDataContent }}
</div>
<div
v-else-if="notFound"
class="n-base-select-option n-base-select-option--not-found"
>
{{ notFoundContent }}
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import NScrollbar from '../../../common/Scrollbar' import NScrollbar from '../../../common/Scrollbar'
import NSelectOption from './SelectOption.vue'
import NSelectGroupHeader from './SelectGroupHeader.vue'
import NBaseLightBar from '../../LightBar'
import NEmpty from '../../../common/Empty'
import { RecycleScroller } from 'vue-virtual-scroller'
import debounce from 'lodash-es/debounce'
import { import {
getPrevAvailableIndex, getPrevAvailableIndex,
getNextAvailableIndex, getNextAvailableIndex,
flattenOptions, flattenOptions,
OPTION_TYPE OPTION_TYPE
} from '../../../utils/data/flattenedOptions' } from '../../../utils/component/select'
import NSelectOption from './SelectOption.vue'
import NSelectGroupHeader from './SelectGroupHeader.vue'
import NBaseLightBar from '../../LightBar'
import debounce from 'lodash-es/debounce'
import { RecycleScroller } from 'vue-virtual-scroller'
export default { export default {
name: 'NBaseSelectMenu', name: 'NBaseSelectMenu',
@ -99,6 +92,7 @@ export default {
NScrollbar, NScrollbar,
NBaseLightBar, NBaseLightBar,
NSelectOption, NSelectOption,
NEmpty,
NSelectGroupHeader, NSelectGroupHeader,
RecycleScroller RecycleScroller
}, },
@ -131,10 +125,6 @@ export default {
type: String, type: String,
default: 'default' default: 'default'
}, },
loading: {
type: Boolean,
default: false
},
pattern: { pattern: {
type: String, type: String,
default: null default: null
@ -155,14 +145,6 @@ export default {
emitOption: { emitOption: {
type: Boolean, type: Boolean,
default: false default: false
},
noDataContent: {
type: [String, Function],
default: 'no data'
},
notFoundContent: {
type: [String, Function],
default: 'none result matched'
} }
}, },
data () { data () {
@ -182,11 +164,9 @@ export default {
const flattenedOptions = flattenOptions(this.options) const flattenedOptions = flattenOptions(this.options)
return flattenedOptions return flattenedOptions
}, },
notFound () { empty () {
return this.filterable && (this.pattern.length && !this.flattenedOptions.length) const flattenedOptions = this.flattenedOptions
}, return flattenedOptions && flattenedOptions.length === 0
noData () {
return this.flattenedOptions && this.flattenedOptions.length === 0
}, },
itemSize () { itemSize () {
return ({ return ({
@ -197,17 +177,7 @@ export default {
} }
}, },
watch: { watch: {
notFound (value) { empty (value) {
if (value) {
this.hideLightBar(0)
}
},
noData (value) {
if (value) {
this.hideLightBar(0)
}
},
loading (value) {
if (value) { if (value) {
this.hideLightBar(0) this.hideLightBar(0)
} }

View File

@ -1,10 +0,0 @@
export const createValueAttribute = function createValueAttribute (value) {
if (typeof value === 'string') {
return 's-' + value
} else if (typeof value === 'number') {
return 'd-' + String(value)
} else {
console.error(['[naive-ui/select-option]: option value is neither string or number'])
return 'invalid'
}
}

View File

@ -7,7 +7,7 @@
:style="synthesizedStyle" :style="synthesizedStyle"
> >
<div class="n-empty__icon"> <div class="n-empty__icon">
<empty-icon /> <ios-remove-circle-outline />
</div> </div>
<div v-if="showDescription" class="n-empty__description"> <div v-if="showDescription" class="n-empty__description">
<slot> <slot>
@ -21,14 +21,14 @@
</template> </template>
<script> <script>
import EmptyIcon from './EmptyIcon'
import withapp from '../../../mixins/withapp' import withapp from '../../../mixins/withapp'
import themeable from '../../../mixins/themeable' import themeable from '../../../mixins/themeable'
import iosRemoveCircleOutline from '../../../icons/ios-remove-circle-outline'
export default { export default {
name: 'NEmpty', name: 'NEmpty',
components: { components: {
EmptyIcon iosRemoveCircleOutline
}, },
mixins: [ withapp, themeable ], mixins: [ withapp, themeable ],
props: { props: {

View File

@ -1,10 +1,8 @@
/* istanbul ignore file */ /* istanbul ignore file */
import Select from './src/Select.vue' import Select from './src/Select.vue'
import SelectOption from './src/SelectOption.vue'
Select.install = function (Vue) { Select.install = function (Vue) {
Vue.component(Select.name, Select) Vue.component(Select.name, Select)
Vue.component('NSelectOption', SelectOption)
} }
export default Select export default Select

View File

@ -31,6 +31,7 @@
:disabled="disabled" :disabled="disabled"
:size="size" :size="size"
:theme="synthesizedTheme" :theme="synthesizedTheme"
:loading="loading"
@click="handleActivatorClick" @click="handleActivatorClick"
@delete-last-option="handleDeleteLastOption" @delete-last-option="handleDeleteLastOption"
@delete-option="handleToggleOption" @delete-option="handleToggleOption"
@ -64,16 +65,23 @@
:options="filteredOptions" :options="filteredOptions"
:multiple="multiple" :multiple="multiple"
:size="size" :size="size"
:loading="loading"
:no-data-content="noDataContent"
:not-found-content="notFoundContent"
:filterable="filterable" :filterable="filterable"
:is-option-selected="isOptionSelected" :is-option-selected="isOptionSelected"
:mirror="false" :mirror="false"
@menu-toggle-option="handleToggleOption" @menu-toggle-option="handleToggleOption"
@menu-scroll="handleMenuScroll" @menu-scroll="handleMenuScroll"
@menu-visible="handleMenuVisible" @menu-visible="handleMenuVisible"
/> >
<template v-if="$slots.empty" v-slot:empty>
<slot name="empty" />
</template>
<template v-if="$slots.unmatch" v-slot:unmatch>
<slot name="unmatch" />
</template>
<template v-if="$slots.action" v-slot:action>
<slot name="action" />
</template>
</n-base-select-menu>
</transition> </transition>
</div> </div>
</div> </div>
@ -91,7 +99,7 @@ import {
import { import {
filterOptions, filterOptions,
valueToOptionMap valueToOptionMap
} from '../../../utils/data/flattenedOptions' } from '../../../utils/component/select'
import NBasePicker from '../../../base/Picker' import NBasePicker from '../../../base/Picker'
import withapp from '../../../mixins/withapp' import withapp from '../../../mixins/withapp'
import themeable from '../../../mixins/themeable' import themeable from '../../../mixins/themeable'
@ -193,14 +201,6 @@ export default {
items: { items: {
type: Array, type: Array,
default: undefined default: undefined
},
noDataContent: {
type: [String, Function],
default: 'No Data'
},
notFoundContent: {
type: [String, Function],
default: 'No Result'
} }
}, },
data () { data () {
@ -208,8 +208,7 @@ export default {
active: false, active: false,
scrolling: false, scrolling: false,
pattern: '', pattern: '',
memorizedValueToOptionMap: new Map(), memorizedValueToOptionMap: new Map()
disablePlaceableTracingWhenActive: true
} }
}, },
computed: { computed: {
@ -273,7 +272,6 @@ export default {
methods: { methods: {
activate () { activate () {
this.active = true this.active = true
this.disablePlaceableTracingWhenActive = true
}, },
deactivate () { deactivate () {
this.active = false this.active = false
@ -442,7 +440,6 @@ export default {
} }
}, },
handleMenuVisible () { handleMenuVisible () {
this.disablePlaceableTracingWhenActive = false
this.updatePosition() this.updatePosition()
}, },
/** /**

View File

@ -1,5 +0,0 @@
<script>
import NBaseSelectOption from '../../../base/SelectMenu/src/SelectOption.vue'
export default NBaseSelectOption
</script>

View File

@ -86,17 +86,6 @@
} }
cursor: not-allowed; cursor: not-allowed;
} }
@include m(no-data) {
color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
text-align: center;
pointer-events: none;
}
@include m(not-found) {
color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
text-align: center;
pointer-events: none;
}
@include m(loading) { @include m(loading) {
color: map-get($map: $--base-select-menu-option-color, $key: "disabled"); color: map-get($map: $--base-select-menu-option-color, $key: "disabled");
text-align: center; text-align: center;

View File

@ -10,20 +10,22 @@
@include e(icon) { @include e(icon) {
@include once { @include once {
transition: fill .3s $--n-ease-in-out-cubic-bezier; transition: fill .3s $--n-ease-in-out-cubic-bezier;
width: 40px; width: 28px;
height: 40px; height: 28px;
} }
fill: $--empty-icon-fill; fill: $--empty-icon-fill;
} }
@include e(description) { @include e(description) {
@include once { @include once {
margin-top: 8px; font-size: 14px;
margin-top: 4px;
transition: color .3s $--n-ease-in-out-cubic-bezier; transition: color .3s $--n-ease-in-out-cubic-bezier;
} }
color: $--empty-text-color; color: $--empty-text-color;
} }
@include e(extra) { @include e(extra) {
@include once { @include once {
font-size: 14px;;
text-align: center; text-align: center;
transition: color .3s $--n-ease-in-out-cubic-bezier; transition: color .3s $--n-ease-in-out-cubic-bezier;
margin-top: 16px; margin-top: 16px;