ant-design-vue/components/vc-cascader/Menus.jsx

179 lines
5.2 KiB
Vue

import { getComponentFromProp } from '../_util/props-util'
import PropTypes from '../_util/vue-types'
import arrayTreeFilter from 'array-tree-filter'
import BaseMixin from '../_util/BaseMixin'
export default {
name: 'CascaderMenus',
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,
defaultFieldNames: PropTypes.object,
fieldNames: PropTypes.object,
expandIcon: PropTypes.any,
loadingIcon: PropTypes.any,
},
data () {
this.menuItems = {}
return {}
},
mounted () {
this.$nextTick(() => {
this.scrollActiveItemToView()
})
},
watch: {
visible (val) {
if (val) {
this.$nextTick(() => {
this.scrollActiveItemToView()
})
}
},
},
methods: {
getFieldName (name) {
const { fieldNames, defaultFieldNames } = this.$props
// 防止只设置单个属性的名字
return fieldNames[name] || defaultFieldNames[name]
},
getOption (option, menuIndex) {
const { prefixCls, expandTrigger } = this
const loadingIcon = getComponentFromProp(this, 'loadingIcon')
const expandIcon = getComponentFromProp(this, 'expandIcon')
const onSelect = (e) => {
this.__emit('select', option, menuIndex, e)
}
const key = option[this.getFieldName('value')]
const expandProps = {
attrs: {
},
on: {
click: onSelect,
},
key: Array.isArray(key) ? key.join('__ant__') : key,
}
let menuItemCls = `${prefixCls}-menu-item`
let expandIconNode = null
const hasChildren = option[this.getFieldName('children')] &&
option[this.getFieldName('children')].length > 0
if (hasChildren || option.isLeaf === false) {
menuItemCls += ` ${prefixCls}-menu-item-expand`
if (!option.loading) {
expandIconNode = (
<span class={`${prefixCls}-menu-item-expand-icon`}>
{expandIcon}
</span>
)
}
}
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`
}
let loadingIconNode = null
if (option.loading) {
menuItemCls += ` ${prefixCls}-menu-item-loading`
loadingIconNode = loadingIcon || null
}
let title = ''
if (option.title) {
title = option.title
} else if (typeof option[this.getFieldName('label')] === 'string') {
title = option[this.getFieldName('label')]
}
expandProps.attrs.title = title
expandProps.class = menuItemCls
return (
<li {...expandProps}>
{option[this.getFieldName('label')]}
{expandIconNode}
{loadingIconNode}
</li>
)
},
getActiveOptions (values) {
const activeValue = values || this.activeValue
const options = this.options
return arrayTreeFilter(options,
(o, level) => o[this.getFieldName('value')] === activeValue[level],
{ childrenKeyName: this.getFieldName('children') })
},
getShowOptions () {
const { options } = this
const result = this.getActiveOptions()
.map(activeOption => activeOption[this.getFieldName('children')])
.filter(activeOption => !!activeOption)
result.unshift(options)
return result
},
delayOnSelect (onSelect, ...args) {
if (this.delayTimer) {
clearTimeout(this.delayTimer)
this.delayTimer = null
}
if (typeof onSelect === 'function') {
this.delayTimer = setTimeout(() => {
onSelect(args)
this.delayTimer = null
}, 150)
}
},
scrollActiveItemToView () {
// scroll into view
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
}
}
},
isActiveOption (option, menuIndex) {
const { activeValue = [] } = this
return activeValue[menuIndex] === option[this.getFieldName('value')]
},
getMenuItemRef (index) {
return `menuItems_${index}`
},
},
render () {
const { prefixCls, dropdownMenuColumnStyle } = this
return (
<div>
{this.getShowOptions().map((options, menuIndex) =>
<ul class={`${prefixCls}-menu`} key={menuIndex} style={dropdownMenuColumnStyle}>
{options.map(option => this.getOption(option, menuIndex))}
</ul>
)}
</div>
)
},
}