151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
| 
 | |
| import PropTypes from '../_util/vue-types'
 | |
| import arrayTreeFilter from 'array-tree-filter'
 | |
| import BaseMixin from '../_util/BaseMixin'
 | |
| 
 | |
| export default {
 | |
|   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,
 | |
|   },
 | |
|   data () {
 | |
|     this.menuItems = {}
 | |
|     return {}
 | |
|   },
 | |
|   mounted () {
 | |
|     this.$nextTick(() => {
 | |
|       this.scrollActiveItemToView()
 | |
|     })
 | |
|   },
 | |
|   watch: {
 | |
|     visible (val) {
 | |
|       if (val) {
 | |
|         this.$nextTick(() => {
 | |
|           this.scrollActiveItemToView()
 | |
|         })
 | |
|       }
 | |
|     },
 | |
|   },
 | |
|   methods: {
 | |
|     getOption (option, menuIndex) {
 | |
|       const { prefixCls, expandTrigger } = this
 | |
|       const onSelect = (e) => {
 | |
|         this.__emit('select', option, menuIndex, e)
 | |
|       }
 | |
|       const expandProps = {
 | |
|         attrs: {
 | |
|         },
 | |
|         on: {
 | |
|           click: onSelect,
 | |
|         },
 | |
|         key: option.value.toString(),
 | |
|       }
 | |
|       let menuItemCls = `${prefixCls}-menu-item`
 | |
|       const hasChildren = option.children && option.children.length > 0
 | |
|       if (hasChildren || option.isLeaf === false) {
 | |
|         menuItemCls += ` ${prefixCls}-menu-item-expand`
 | |
|       }
 | |
|       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`
 | |
|       }
 | |
|       if (option.loading) {
 | |
|         menuItemCls += ` ${prefixCls}-menu-item-loading`
 | |
|       }
 | |
|       let title = ''
 | |
|       if (option.title) {
 | |
|         title = option.title
 | |
|       } else if (typeof option.label === 'string') {
 | |
|         title = option.label
 | |
|       }
 | |
|       expandProps.attrs.title = title
 | |
|       expandProps.class = menuItemCls
 | |
|       return (
 | |
|         <li {...expandProps}>
 | |
|           {option.label}
 | |
|         </li>
 | |
|       )
 | |
|     },
 | |
| 
 | |
|     getActiveOptions (values) {
 | |
|       const activeValue = values || this.activeValue
 | |
|       const options = this.options
 | |
|       return arrayTreeFilter(options, (o, level) => o.value === activeValue[level])
 | |
|     },
 | |
| 
 | |
|     getShowOptions () {
 | |
|       const { options } = this
 | |
|       const result = this.getActiveOptions()
 | |
|         .map(activeOption => activeOption.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.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>
 | |
|     )
 | |
|   },
 | |
| }
 | |
| 
 |