260 lines
6.2 KiB
Vue
260 lines
6.2 KiB
Vue
<template>
|
|
<div class="md-drop-menu">
|
|
<div class="md-drop-menu-bar">
|
|
<template v-for="(item, index) in data">
|
|
<div
|
|
class="bar-item"
|
|
:class="{
|
|
active: index === activeMenuBarIndex,
|
|
selected: $_checkBarItemSelect(index),
|
|
disabled: item.disabled
|
|
}"
|
|
:key="index"
|
|
@click="$_onBarItemClick(item, index)"
|
|
>
|
|
<span
|
|
v-text="$_getBarItemText(item, index)"
|
|
></span>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
<md-popup
|
|
v-model="isPopupShow"
|
|
position="top"
|
|
prevent-scroll
|
|
:prevent-scroll-exclude="scroller"
|
|
@show="$_onListShow"
|
|
@hide="$_onListHide"
|
|
@before-hide="$_onListBeforeHide"
|
|
>
|
|
<div class="md-drop-menu-list">
|
|
<md-radio-list
|
|
v-model="selectedMenuListValue[activeMenuBarIndex]"
|
|
:options="activeMenuListData"
|
|
:is-slot-scope="hasSlot"
|
|
align-center
|
|
@change="$_onListItemClick"
|
|
>
|
|
<div slot-scope="{ option }">
|
|
<slot :option="option"></slot>
|
|
</div>
|
|
</md-radio-list>
|
|
</div>
|
|
</md-popup>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Popup from '../popup'
|
|
import RadioList from '../radio-list'
|
|
import {traverse, compareObjects} from '../_util'
|
|
|
|
export default {
|
|
name: 'md-drop-menu',
|
|
|
|
components: {
|
|
[Popup.name]: Popup,
|
|
[RadioList.name]: RadioList,
|
|
},
|
|
|
|
props: {
|
|
data: {
|
|
type: Array,
|
|
default() {
|
|
/* istanbul ignore next */
|
|
return []
|
|
},
|
|
},
|
|
defaultValue: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
},
|
|
},
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
isPopupShow: false,
|
|
selectedMenuListItem: [],
|
|
selectedMenuListValue: [],
|
|
selectedMenuListIndex: [],
|
|
activeMenuBarIndex: -1,
|
|
scroller: '',
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
hasSlot() {
|
|
return !!this.$scopedSlots.default
|
|
},
|
|
activeMenuListData() {
|
|
if (this.activeMenuBarIndex < 0 || !this.data[this.activeMenuBarIndex]) {
|
|
return []
|
|
}
|
|
|
|
return this.data[this.activeMenuBarIndex].options
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
data(val, oldVal) {
|
|
// Avoid Literals
|
|
/* istanbul ignore if */
|
|
if (!compareObjects(val, oldVal)) {
|
|
this.$_initSelectedBar()
|
|
}
|
|
},
|
|
defaultValue(val, oldVal) {
|
|
/* istanbul ignore if */
|
|
if (!compareObjects(val, oldVal)) {
|
|
this.$_initSelectedBar()
|
|
}
|
|
},
|
|
},
|
|
|
|
mounted() {
|
|
this.$_initSelectedBar()
|
|
},
|
|
|
|
methods: {
|
|
// MARK: private methods
|
|
$_initSelectedBar() {
|
|
this.selectedMenuListValue = this.defaultValue
|
|
traverse(this.data, ['options'], (item, level, indexs) => {
|
|
const barItemIndex = indexs[0]
|
|
const defaultValue = this.defaultValue[barItemIndex]
|
|
if (
|
|
defaultValue !== undefined &&
|
|
(item.value === defaultValue || item.text === defaultValue || item.label === defaultValue)
|
|
) {
|
|
this.$set(this.selectedMenuListItem, barItemIndex, item)
|
|
return 2
|
|
}
|
|
})
|
|
},
|
|
$_checkBarItemSelect(index) {
|
|
return !!(this.selectedMenuListItem[index] !== undefined || this.defaultValue[index])
|
|
},
|
|
$_getBarItemText(item, index) {
|
|
return this.selectedMenuListItem[index] !== undefined ? this.selectedMenuListItem[index].text : item.text
|
|
},
|
|
$_setScroller() {
|
|
const boxer = this.$el ? this.$el.querySelector('.md-popup-box') : null
|
|
/* istanbul ignore else */
|
|
if (boxer && boxer.clientHeight >= this.$el.clientHeight) {
|
|
this.scroller = '.md-drop-menu-list'
|
|
} else {
|
|
return ''
|
|
}
|
|
},
|
|
|
|
// MARK: events handler
|
|
$_onBarItemClick(barItem, index) {
|
|
/* istanbul ignore if */
|
|
if (!barItem || barItem.disabled) {
|
|
return
|
|
}
|
|
|
|
if (!this.isPopupShow) {
|
|
this.isPopupShow = true
|
|
this.activeMenuBarIndex = index
|
|
} else {
|
|
this.isPopupShow = false
|
|
}
|
|
},
|
|
$_onListItemClick(listItem) {
|
|
const activeMenuBarIndex = this.activeMenuBarIndex
|
|
const barItem = this.data[activeMenuBarIndex]
|
|
this.isPopupShow = false
|
|
this.selectedMenuListValue[activeMenuBarIndex] = listItem.value
|
|
this.$set(this.selectedMenuListItem, activeMenuBarIndex, listItem)
|
|
this.$emit('change', barItem, listItem)
|
|
},
|
|
$_onListShow() {
|
|
/* istanbul ignore next */
|
|
this.$_setScroller()
|
|
this.$emit('show')
|
|
},
|
|
$_onListHide() {
|
|
/* istanbul ignore next */
|
|
this.$emit('hide')
|
|
},
|
|
$_onListBeforeHide() {
|
|
/* istanbul ignore next */
|
|
this.activeMenuBarIndex = -1
|
|
},
|
|
|
|
// MARK: public methods
|
|
getSelectedValues() {
|
|
return this.selectedMenuListItem
|
|
},
|
|
getSelectedValue(index) {
|
|
return this.selectedMenuListItem[index]
|
|
},
|
|
},
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="stylus">
|
|
.md-drop-menu
|
|
position fixed
|
|
z-index drop-menu-zindex
|
|
top 0
|
|
left 0
|
|
right 0
|
|
height drop-menu-height
|
|
box-sizing border-box
|
|
color color-text-minor
|
|
font-size drop-menu-font-size
|
|
font-weight drop-menu-font-weight
|
|
|
|
.md-drop-menu-bar
|
|
position relative
|
|
z-index drop-menu-zindex
|
|
display flex
|
|
height 100%
|
|
background drop-menu-bar-bg
|
|
hairline(bottom, drop-menu-bar-border-color)
|
|
.bar-item
|
|
display flex
|
|
flex 1
|
|
margin 2% 0
|
|
align-items center
|
|
justify-content center
|
|
span
|
|
position relative
|
|
padding-right 30px
|
|
&:after
|
|
content ""
|
|
position absolute
|
|
right 0
|
|
top 50%
|
|
width 0
|
|
height 0
|
|
margin-top -4px
|
|
border-left solid 8px transparent
|
|
border-right solid 8px transparent
|
|
border-top solid 9px color-border-element
|
|
transition transform .3s ease-in-out-quint
|
|
&.active
|
|
color drop-menu-color
|
|
span:after
|
|
transform rotate(180deg)
|
|
border-top-color drop-menu-color
|
|
&.selected
|
|
color drop-menu-color
|
|
&.disabled
|
|
opacity drop-menu-disabled-opacity
|
|
|
|
.md-drop-menu-list
|
|
width 100%
|
|
padding-top drop-menu-height
|
|
background drop-menu-list-bg
|
|
box-sizing border-box
|
|
.md-radio-item
|
|
font-weight font-weight-normal
|
|
&.is-selected .md-cell-item-title
|
|
color color-primary
|
|
|
|
</style>
|