refactor(select): using new scrollbar

This commit is contained in:
07akioni 2019-07-31 17:35:37 +08:00
parent f1cea3cf14
commit 2d7ff80d14
5 changed files with 150 additions and 98 deletions

View File

@ -73,6 +73,7 @@
</div>
<div
ref="contentWrapper"
v-clickoutside="handleClickOutsideMenu"
class="n-select-menu__content-wrapper"
>
<div
@ -90,26 +91,33 @@
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
>
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in items"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
isSelected(item)
}"
@click.stop="toggleItemInMultipleSelect(item)"
@mouseenter="showLightBarTop"
<scrollbar
@scrollstart="handleMenuScrollStart"
@scrollend="handleMenuScrollEnd"
>
{{ item.label }}
</div>
<div class="n-select-menu__item-wrapper">
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in items"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
isSelected(item)
}"
@click.stop="toggleItemInMultipleSelect(item)"
@mouseenter="showLightBarTop"
>
{{ item.label }}
</div>
</div>
</scrollbar>
</div>
</div>
</transition>
@ -124,11 +132,17 @@ import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import toggleable from '../../../mixins/toggleable'
import zindexable from '../../../mixins/zindexable'
import Scrollbar from '../../Scrollbar'
import clickoutside from '../../../directives/clickoutside'
export default {
name: 'NMultipleSelect',
components: {
NIcon
NIcon,
Scrollbar
},
directives: {
clickoutside
},
mixins: [detachable, toggleable, placeable, zindexable],
model: {
@ -168,7 +182,6 @@ export default {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
@ -179,7 +192,7 @@ export default {
lightBarTop: null,
showLightBar: false,
label: '',
labelPlaceholder: 'Please Select'
scrolling: false
}
},
computed: {
@ -214,26 +227,8 @@ export default {
} else {
this.label = ''
}
},
active (newValue) {
if (newValue === true) {
this.$nextTick().then(
() => {
document.addEventListener('click', this.nativeCloseMenu)
}
)
} else {
this.$nextTick().then(
() => {
document.removeEventListener('click', this.nativeCloseMenu)
}
)
}
}
},
beforeDestroy () {
document.removeEventListener('click', this.nativeCloseMenu)
},
methods: {
/**
* @param {string} value
@ -263,8 +258,8 @@ export default {
if (!Array.isArray(this.selectedValue)) return false
return 1 + this.selectedValue.findIndex(value => value === item.value)
},
nativeCloseMenu (e) {
if (!this.$refs.select.contains(e.target)) {
handleClickOutsideMenu (e) {
if (!this.$refs.activator.contains(e.target) && !this.scrolling) {
this.deactivate()
}
},
@ -292,6 +287,14 @@ export default {
}
this.$emit('input', newSelectedValues)
this.$nextTick().then(this.updatePosition)
},
handleMenuScrollStart () {
this.scrolling = true
},
handleMenuScrollEnd () {
window.setTimeout(() => {
this.scrolling = false
}, 0)
}
}
}

View File

@ -38,6 +38,7 @@
<transition name="n-select-menu--transition">
<div
v-if="active"
v-clickoutside="handleClickOutsideMenu"
class="n-select-menu-wrapper"
>
<div
@ -46,40 +47,48 @@
:class="{[`n-select-menu--${size}-size`]: true}"
@mouseleave="hideLightBar"
>
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in filteredItems"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
selectedValue ===
item.value
}"
@click.stop="toggleItemInSingleSelect(item)"
@mouseenter="showLightBarTop"
<scrollbar
ref="scrollbar"
@scrollstart="handleMenuScrollStart"
@scrollend="handleMenuScrollEnd"
>
{{ item.label }}
</div>
<div
v-if="label.length && !filteredItems.length"
class="n-select-menu__item n-select-menu__item--not-found"
>
{{
/**
* This method to activate hideLightBar is ridiculous, however using
* event handler still has some problem.
*/
hideLightBar()
}}
none result matched
</div>
<div class="n-select-menu__item-wrapper">
<transition name="n-select-menu__light-bar--transition">
<div
v-if="showLightBar"
class="n-select-menu__light-bar"
:style="{ top: `${lightBarTop}px` }"
/>
</transition>
<div
v-for="item in filteredItems"
:key="item.value"
class="n-select-menu__item"
:class="{
'n-select-menu__item--selected':
selectedValue ===
item.value
}"
@click.stop="toggleItemInSingleSelect(item)"
@mouseenter="showLightBarTop"
>
{{ item.label }}
</div>
<div
v-if="label.length && !filteredItems.length"
class="n-select-menu__item n-select-menu__item--not-found"
>
{{
/**
* This method to activate hideLightBar is ridiculous, however using
* event handler still has some problem.
*/
hideLightBar()
}}
none result matched
</div>
</div>
</scrollbar>
</div>
</div>
</transition>
@ -94,9 +103,17 @@ import detachable from '../../../mixins/detachable'
import placeable from '../../../mixins/placeable'
import toggleable from '../../../mixins/toggleable'
import zindexable from '../../../mixins/zindexable'
import Scrollbar from '../../Scrollbar'
import clickoutside from '../../../directives/clickoutside'
export default {
name: 'NSingleSelect',
components: {
Scrollbar
},
directives: {
clickoutside
},
mixins: [detachable, toggleable, placeable, zindexable, Emitter],
model: {
prop: 'selectedValue',
@ -146,7 +163,8 @@ export default {
lightBarTop: null,
showLightBar: false,
label: '',
labelPlaceholder: 'Please Select'
labelPlaceholder: 'Please Select',
scrolling: false
}
},
computed: {
@ -170,6 +188,14 @@ export default {
}
},
watch: {
label () {
this.$nextTick().then(() => {
this.updatePosition()
if (this.$refs.scrollbar) {
this.$refs.scrollbar.updateParameters()
}
})
},
selectedItem (n, o) {
if (this.selectedItem !== null) {
this.label = this.selectedItem.label
@ -186,11 +212,6 @@ export default {
this.labelPlaceholder = this.selectedItem.label
this.label = ''
}
this.$nextTick().then(
() => {
document.addEventListener('click', this.handleClickOutsideMenu)
}
)
} else {
this.$refs.singleSelectInput.blur()
if (this.selectedItem) {
@ -199,11 +220,6 @@ export default {
this.label = ''
this.labelPlaceholder = this.placeholder
}
this.$nextTick().then(
() => {
document.removeEventListener('click', this.handleClickOutsideMenu)
}
)
}
}
},
@ -213,9 +229,6 @@ export default {
this.label = this.selectedItem.label
}
},
beforeDestroy () {
document.removeEventListener('click', this.handleClickOutsideMenu)
},
methods: {
/**
* @param {string} value
@ -245,7 +258,7 @@ export default {
return item.value === this.selectedValue
},
handleClickOutsideMenu (e) {
if (!this.$refs.select.contains(e.target)) {
if (!this.$refs.activator.contains(e.target) && !this.scrolling) {
this.deactivate()
}
},
@ -266,6 +279,14 @@ export default {
this.$emit('input', item.value)
this.emitChangeEvent(item, true)
this.closeMenu()
},
handleMenuScrollStart () {
this.scrolling = true
},
handleMenuScrollEnd () {
window.setTimeout(() => {
this.scrolling = false
}, 0)
}
}
}

View File

@ -260,16 +260,18 @@
border-radius: 6px;
margin-top: 4px;
margin-bottom: 4px;
@include fade-in-transition(select-menu);
@include fade-in-scale-up-transition(select-menu);
.n-select-menu {
z-index: 0;
position: relative;
overflow-x: hidden;
overflow-y: auto;
overflow: hidden;
border-radius: 6px;
background-color: rgba(75, 81, 106, 1);
box-shadow: 0px 2px 20px 0px rgba(0,0,0,0.16);
@include scrollbar;
.n-select-menu__item-wrapper {
position: relative;
width: 100%;
}
.n-select-menu__item {
cursor: pointer;
position: relative;
@ -292,14 +294,18 @@
transition: top .15s $default-cubic-bezier;
}
&.n-select-menu--small-size {
max-height: $small-height * 8;
.n-scrollbar-container {
max-height: $small-height * 8;
}
.n-select-menu__item, .n-select-menu__light-bar {
height: $small-height;
line-height: $small-height;
}
}
&.n-select-menu--default-size, &.n-select-menu--medium-size {
max-height: $default-height * 8;
.n-scrollbar-container {
max-height: $default-height * 8;
}
.n-select-menu__item, .n-select-menu__light-bar {
height: $default-height;
line-height: $default-height;
@ -310,7 +316,9 @@
height: $large-height;
line-height: $large-height;
}
max-height: $large-height * 8;
.n-scrollbar-container {
max-height: $large-height * 8;
}
}
&.n-select-menu--multiple {
.n-select-menu__item {

View File

@ -23,6 +23,7 @@
@import './Radio.scss';
@import './Form.scss';
@import './TimePicker.scss';
@import './Scrollbar.scss';
@import "./NimbusServiceLayout.scss";
@import "./Popover.scss";

View File

@ -122,6 +122,9 @@ $default-cubic-bezier: cubic-bezier(.4, 0, .2, 1);
$default-font-family: 'Lato';
$scrollbar-color: rgba(255,255,255,0.2);
$scrollbar-color--hover: rgba(255,255,255,0.3);
@mixin scrollbar {
&::-webkit-scrollbar {
width: 5px;
@ -164,7 +167,7 @@ $default-font-family: 'Lato';
}
}
@mixin fade-in-transition($block, $origin: inherit) {
@mixin fade-in-scale-up-transition($block, $origin: inherit) {
&.#{$namespace}-#{$block}--transition-enter-active,
&.#{$namespace}-#{$block}--transition-leave-active {
transform: scale(1);
@ -182,4 +185,20 @@ $default-font-family: 'Lato';
&.#{$namespace}-#{$block}--transition-leave-to {
transition: opacity .2s $slow-out-cubic-bezier, transform .2s $slow-out-cubic-bezier;
}
}
@mixin fade-in-transition($block) {
&.#{$namespace}-#{$block}--transition-enter-active,
&.#{$namespace}-#{$block}--transition-leave-active {
opacity: 1;
}
&.#{$namespace}-#{$block}--transition-enter-active {
transition: opacity .2s $fast-in-cubic-bezier;
}
&.#{$namespace}-#{$block}--transition-enter, &.#{$namespace}-#{$block}--transition-leave-to {
opacity: 0;
}
&.#{$namespace}-#{$block}--transition-leave-to {
transition: opacity .2s $slow-out-cubic-bezier;
}
}