2018-10-29 20:48:58 +08:00
|
|
|
import { getComponentFromProp } from '../_util/props-util'
|
2018-03-02 22:12:52 +08:00
|
|
|
import PropTypes from '../_util/vue-types'
|
2018-03-02 16:54:22 +08:00
|
|
|
import arrayTreeFilter from 'array-tree-filter'
|
2018-03-02 22:12:52 +08:00
|
|
|
import BaseMixin from '../_util/BaseMixin'
|
|
|
|
|
|
|
|
export default {
|
2018-10-12 19:22:01 +08:00
|
|
|
name: 'CascaderMenus',
|
2018-03-02 22:12:52 +08:00
|
|
|
mixins: [BaseMixin],
|
|
|
|
props: {
|
|
|
|
value: PropTypes.array.def([]),
|
|
|
|
activeValue: PropTypes.array.def([]),
|
|
|
|
options: PropTypes.array.isRequired,
|
|
|
|
prefixCls: PropTypes.string.def('rc-cascader-menus'),
|
|
|
|
expandTrigger: PropTypes.string.def('click'),
|
|
|
|
// onSelect: PropTypes.func,
|
|
|
|
visible: PropTypes.bool.def(false),
|
|
|
|
dropdownMenuColumnStyle: PropTypes.object,
|
2018-09-05 21:28:54 +08:00
|
|
|
defaultFieldNames: PropTypes.object,
|
|
|
|
fieldNames: PropTypes.object,
|
2018-10-29 20:48:58 +08:00
|
|
|
expandIcon: PropTypes.any,
|
|
|
|
loadingIcon: PropTypes.any,
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
|
|
|
data () {
|
2018-03-02 16:54:22 +08:00
|
|
|
this.menuItems = {}
|
2018-03-02 22:12:52 +08:00
|
|
|
return {}
|
|
|
|
},
|
|
|
|
mounted () {
|
|
|
|
this.$nextTick(() => {
|
2018-03-02 16:54:22 +08:00
|
|
|
this.scrollActiveItemToView()
|
2018-03-02 22:12:52 +08:00
|
|
|
})
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
visible (val) {
|
|
|
|
if (val) {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.scrollActiveItemToView()
|
|
|
|
})
|
2018-03-02 16:54:22 +08:00
|
|
|
}
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
2018-09-05 21:28:54 +08:00
|
|
|
getFieldName (name) {
|
|
|
|
const { fieldNames, defaultFieldNames } = this.$props
|
|
|
|
// 防止只设置单个属性的名字
|
|
|
|
return fieldNames[name] || defaultFieldNames[name]
|
|
|
|
},
|
2018-03-02 22:12:52 +08:00
|
|
|
getOption (option, menuIndex) {
|
|
|
|
const { prefixCls, expandTrigger } = this
|
2018-10-29 20:48:58 +08:00
|
|
|
const loadingIcon = getComponentFromProp(this, 'loadingIcon')
|
|
|
|
const expandIcon = getComponentFromProp(this, 'expandIcon')
|
2018-03-02 22:12:52 +08:00
|
|
|
const onSelect = (e) => {
|
|
|
|
this.__emit('select', option, menuIndex, e)
|
|
|
|
}
|
2018-10-12 19:22:01 +08:00
|
|
|
const key = option[this.getFieldName('value')]
|
2018-03-02 22:12:52 +08:00
|
|
|
const expandProps = {
|
|
|
|
attrs: {
|
|
|
|
},
|
|
|
|
on: {
|
|
|
|
click: onSelect,
|
|
|
|
},
|
2018-10-12 19:22:01 +08:00
|
|
|
key: Array.isArray(key) ? key.join('__ant__') : key,
|
2018-03-02 22:12:52 +08:00
|
|
|
}
|
|
|
|
let menuItemCls = `${prefixCls}-menu-item`
|
2018-10-29 20:48:58 +08:00
|
|
|
let expandIconNode = null
|
2018-09-05 21:28:54 +08:00
|
|
|
const hasChildren = option[this.getFieldName('children')] &&
|
|
|
|
option[this.getFieldName('children')].length > 0
|
2018-03-02 22:12:52 +08:00
|
|
|
if (hasChildren || option.isLeaf === false) {
|
|
|
|
menuItemCls += ` ${prefixCls}-menu-item-expand`
|
2018-10-29 20:48:58 +08:00
|
|
|
if (!option.loading) {
|
|
|
|
expandIconNode = (
|
|
|
|
<span class={`${prefixCls}-menu-item-expand-icon`}>
|
|
|
|
{expandIcon}
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
}
|
2018-03-02 22:12:52 +08:00
|
|
|
}
|
|
|
|
if (expandTrigger === 'hover' && hasChildren) {
|
|
|
|
expandProps.on = {
|
|
|
|
mouseenter: this.delayOnSelect.bind(this, onSelect),
|
|
|
|
mouseleave: this.delayOnSelect.bind(this),
|
|
|
|
click: onSelect,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.isActiveOption(option, menuIndex)) {
|
|
|
|
menuItemCls += ` ${prefixCls}-menu-item-active`
|
|
|
|
expandProps.ref = this.getMenuItemRef(menuIndex)
|
|
|
|
}
|
|
|
|
if (option.disabled) {
|
|
|
|
menuItemCls += ` ${prefixCls}-menu-item-disabled`
|
|
|
|
}
|
2018-10-29 20:48:58 +08:00
|
|
|
let loadingIconNode = null
|
2018-03-02 22:12:52 +08:00
|
|
|
if (option.loading) {
|
|
|
|
menuItemCls += ` ${prefixCls}-menu-item-loading`
|
2018-10-29 20:48:58 +08:00
|
|
|
loadingIconNode = loadingIcon || null
|
2018-03-02 22:12:52 +08:00
|
|
|
}
|
|
|
|
let title = ''
|
|
|
|
if (option.title) {
|
|
|
|
title = option.title
|
2018-09-05 21:28:54 +08:00
|
|
|
} else if (typeof option[this.getFieldName('label')] === 'string') {
|
|
|
|
title = option[this.getFieldName('label')]
|
2018-03-02 22:12:52 +08:00
|
|
|
}
|
|
|
|
expandProps.attrs.title = title
|
|
|
|
expandProps.class = menuItemCls
|
|
|
|
return (
|
|
|
|
<li {...expandProps}>
|
2018-09-05 21:28:54 +08:00
|
|
|
{option[this.getFieldName('label')]}
|
2018-10-29 20:48:58 +08:00
|
|
|
{expandIconNode}
|
|
|
|
{loadingIconNode}
|
2018-03-02 22:12:52 +08:00
|
|
|
</li>
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
getActiveOptions (values) {
|
|
|
|
const activeValue = values || this.activeValue
|
|
|
|
const options = this.options
|
2018-09-05 21:28:54 +08:00
|
|
|
return arrayTreeFilter(options,
|
|
|
|
(o, level) => o[this.getFieldName('value')] === activeValue[level],
|
|
|
|
{ childrenKeyName: this.getFieldName('children') })
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
getShowOptions () {
|
|
|
|
const { options } = this
|
|
|
|
const result = this.getActiveOptions()
|
2018-09-05 21:28:54 +08:00
|
|
|
.map(activeOption => activeOption[this.getFieldName('children')])
|
2018-03-02 22:12:52 +08:00
|
|
|
.filter(activeOption => !!activeOption)
|
|
|
|
result.unshift(options)
|
|
|
|
return result
|
|
|
|
},
|
|
|
|
|
|
|
|
delayOnSelect (onSelect, ...args) {
|
|
|
|
if (this.delayTimer) {
|
|
|
|
clearTimeout(this.delayTimer)
|
2018-03-02 16:54:22 +08:00
|
|
|
this.delayTimer = null
|
2018-03-02 22:12:52 +08:00
|
|
|
}
|
|
|
|
if (typeof onSelect === 'function') {
|
|
|
|
this.delayTimer = setTimeout(() => {
|
|
|
|
onSelect(args)
|
|
|
|
this.delayTimer = null
|
|
|
|
}, 150)
|
|
|
|
}
|
|
|
|
},
|
2018-03-02 16:54:22 +08:00
|
|
|
|
2018-03-02 22:12:52 +08:00
|
|
|
scrollActiveItemToView () {
|
2018-03-02 16:54:22 +08:00
|
|
|
// scroll into view
|
2018-03-02 22:12:52 +08:00
|
|
|
const optionsLength = this.getShowOptions().length
|
|
|
|
for (let i = 0; i < optionsLength; i++) {
|
|
|
|
const itemComponent = this.$refs[`menuItems_${i}`]
|
|
|
|
if (itemComponent) {
|
|
|
|
const target = itemComponent
|
|
|
|
target.parentNode.scrollTop = target.offsetTop
|
|
|
|
}
|
2018-03-02 16:54:22 +08:00
|
|
|
}
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
2018-03-02 16:54:22 +08:00
|
|
|
|
2018-03-02 22:12:52 +08:00
|
|
|
isActiveOption (option, menuIndex) {
|
|
|
|
const { activeValue = [] } = this
|
2018-09-05 21:28:54 +08:00
|
|
|
return activeValue[menuIndex] === option[this.getFieldName('value')]
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
2018-03-02 16:54:22 +08:00
|
|
|
|
2018-03-02 22:12:52 +08:00
|
|
|
getMenuItemRef (index) {
|
|
|
|
return `menuItems_${index}`
|
|
|
|
},
|
|
|
|
},
|
2018-03-02 16:54:22 +08:00
|
|
|
|
|
|
|
render () {
|
2018-03-02 22:12:52 +08:00
|
|
|
const { prefixCls, dropdownMenuColumnStyle } = this
|
2018-03-02 16:54:22 +08:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
{this.getShowOptions().map((options, menuIndex) =>
|
2018-03-02 22:12:52 +08:00
|
|
|
<ul class={`${prefixCls}-menu`} key={menuIndex} style={dropdownMenuColumnStyle}>
|
2018-03-02 16:54:22 +08:00
|
|
|
{options.map(option => this.getOption(option, menuIndex))}
|
|
|
|
</ul>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
)
|
2018-03-02 22:12:52 +08:00
|
|
|
},
|
2018-03-02 16:54:22 +08:00
|
|
|
}
|
2018-03-19 10:16:27 +08:00
|
|
|
|