mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-11-18 15:13:21 +08:00
82 lines
2.4 KiB
Vue
82 lines
2.4 KiB
Vue
<template>
|
|
<div @click="toggle" ref="container" class="sn-select" :class="{ 'sn-select--open': isOpen, 'sn-select--blank': !valueLabel, 'disabled': disabled }">
|
|
<slot>
|
|
<button ref="focusElement" class="sn-select__value">
|
|
<span>{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
|
|
</button>
|
|
<span class="sn-select__caret caret"></span>
|
|
</slot>
|
|
<div ref="optionsContainer" class="sn-select__options" :style="optionPositionStyle">
|
|
<div v-for="option in options" :key="option[0]" @click="setValue(option[0])" class="sn-select__option">
|
|
{{ option[1] }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'Select',
|
|
props: {
|
|
options: { type: Array, default: () => [] },
|
|
initialValue: { type: [String, Number] },
|
|
placeholder: { type: String },
|
|
disabled: { type: Boolean, default: false }
|
|
},
|
|
data() {
|
|
return {
|
|
value: null,
|
|
isOpen: false,
|
|
optionPositionStyle: ''
|
|
}
|
|
},
|
|
computed: {
|
|
valueLabel() {
|
|
let option = this.options.find((o) => o[0] === this.value);
|
|
return option && option[1];
|
|
},
|
|
focusElement() {
|
|
return this.$refs.focusElement || this.$scopedSlots.default()[0].context.$refs.focusElement;
|
|
}
|
|
},
|
|
mounted() {
|
|
this.focusElement.onblur = this.blur;
|
|
document.addEventListener("scroll", this.updateOptionPosition);
|
|
},
|
|
methods: {
|
|
blur() {
|
|
setTimeout(() => {
|
|
this.isOpen = false;
|
|
this.$emit('blur');
|
|
}, 100)
|
|
},
|
|
toggle() {
|
|
this.isOpen = !this.isOpen;
|
|
|
|
if (this.isOpen) {
|
|
this.$emit('open');
|
|
this.$nextTick(() => {
|
|
this.focusElement.focus();
|
|
});
|
|
this.$refs.optionsContainer.scrollTop = 0;
|
|
this.updateOptionPosition();
|
|
} else {
|
|
this.optionPositionStyle = '';
|
|
this.$emit('close');
|
|
}
|
|
},
|
|
setValue(value) {
|
|
this.value = value;
|
|
this.$emit('change', this.value);
|
|
},
|
|
updateOptionPosition() {
|
|
let rect = this.$refs.container.getBoundingClientRect();
|
|
let top =rect.top + rect.height;
|
|
let left = rect.left;
|
|
let width = rect.width;
|
|
|
|
this.optionPositionStyle = `position: fixed; top: ${top}px; left: ${left}px; width: ${width}px`
|
|
}
|
|
}
|
|
}
|
|
</script>
|