update the master branch to the latest
This commit is contained in:
parent
67d534df27
commit
23a0ba9831
611 changed files with 122648 additions and 0 deletions
10
src/components/menu/index.js
Normal file
10
src/components/menu/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import Menu from './menu.vue';
|
||||
import MenuGroup from './menu-group.vue';
|
||||
import MenuItem from './menu-item.vue';
|
||||
import Submenu from './submenu.vue';
|
||||
|
||||
Menu.Group = MenuGroup;
|
||||
Menu.Item = MenuItem;
|
||||
Menu.Sub = Submenu;
|
||||
|
||||
export default Menu;
|
33
src/components/menu/menu-group.vue
Normal file
33
src/components/menu/menu-group.vue
Normal file
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<li :class="[prefixCls + '-item-group']">
|
||||
<div :class="[prefixCls + '-item-group-title']" :style="groupStyle">{{ title }}</div>
|
||||
<ul><slot></slot></ul>
|
||||
</li>
|
||||
</template>
|
||||
<script>
|
||||
import mixin from './mixin';
|
||||
const prefixCls = 'ivu-menu';
|
||||
|
||||
export default {
|
||||
name: 'MenuGroup',
|
||||
mixins: [ mixin ],
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
prefixCls: prefixCls
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
groupStyle () {
|
||||
return this.hasParentSubmenu && this.mode !== 'horizontal' ? {
|
||||
paddingLeft: 43 + (this.parentSubmenuNum - 1) * 28 + 'px'
|
||||
} : {};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
89
src/components/menu/menu-item.vue
Normal file
89
src/components/menu/menu-item.vue
Normal file
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<a
|
||||
v-if="to"
|
||||
:href="linkUrl"
|
||||
:target="target"
|
||||
:class="classes"
|
||||
@click.exact="handleClickItem($event, false)"
|
||||
@click.ctrl="handleClickItem($event, true)"
|
||||
@click.meta="handleClickItem($event, true)"
|
||||
:style="itemStyle"><slot></slot></a>
|
||||
<li v-else :class="classes" @click.stop="handleClickItem" :style="itemStyle"><slot></slot></li>
|
||||
</template>
|
||||
<script>
|
||||
import Emitter from '../../mixins/emitter';
|
||||
import { findComponentUpward } from '../../utils/assist';
|
||||
import mixin from './mixin';
|
||||
import mixinsLink from '../../mixins/link';
|
||||
|
||||
const prefixCls = 'ivu-menu';
|
||||
|
||||
export default {
|
||||
name: 'MenuItem',
|
||||
mixins: [ Emitter, mixin, mixinsLink ],
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
return [
|
||||
`${prefixCls}-item`,
|
||||
{
|
||||
[`${prefixCls}-item-active`]: this.active,
|
||||
[`${prefixCls}-item-selected`]: this.active,
|
||||
[`${prefixCls}-item-disabled`]: this.disabled
|
||||
}
|
||||
];
|
||||
},
|
||||
itemStyle () {
|
||||
return this.hasParentSubmenu && this.mode !== 'horizontal' ? {
|
||||
paddingLeft: 43 + (this.parentSubmenuNum - 1) * 24 + 'px'
|
||||
} : {};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClickItem (event, new_window = false) {
|
||||
if (this.disabled) return;
|
||||
|
||||
if (new_window || this.target === '_blank') {
|
||||
// 如果是 new_window,直接新开窗口就行,无需发送状态
|
||||
this.handleCheckClick(event, new_window);
|
||||
let parentMenu = findComponentUpward(this, 'Menu');
|
||||
if (parentMenu) parentMenu.handleEmitSelectEvent(this.name);
|
||||
} else {
|
||||
let parent = findComponentUpward(this, 'Submenu');
|
||||
|
||||
if (parent) {
|
||||
this.dispatch('Submenu', 'on-menu-item-select', this.name);
|
||||
} else {
|
||||
this.dispatch('Menu', 'on-menu-item-select', this.name);
|
||||
}
|
||||
|
||||
this.handleCheckClick(event, new_window);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$on('on-update-active-name', (name) => {
|
||||
if (this.name === name) {
|
||||
this.active = true;
|
||||
this.dispatch('Submenu', 'on-update-active-name', name);
|
||||
} else {
|
||||
this.active = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
156
src/components/menu/menu.vue
Normal file
156
src/components/menu/menu.vue
Normal file
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<ul :class="classes" :style="styles"><slot></slot></ul>
|
||||
</template>
|
||||
<script>
|
||||
import { oneOf, findComponentsDownward, findComponentsUpward } from '../../utils/assist';
|
||||
import Emitter from '../../mixins/emitter';
|
||||
|
||||
const prefixCls = 'ivu-menu';
|
||||
|
||||
export default {
|
||||
name: 'Menu',
|
||||
mixins: [ Emitter ],
|
||||
props: {
|
||||
mode: {
|
||||
validator (value) {
|
||||
return oneOf(value, ['horizontal', 'vertical']);
|
||||
},
|
||||
default: 'vertical'
|
||||
},
|
||||
theme: {
|
||||
validator (value) {
|
||||
return oneOf(value, ['light', 'dark', 'primary']);
|
||||
},
|
||||
default: 'light'
|
||||
},
|
||||
activeName: {
|
||||
type: [String, Number]
|
||||
},
|
||||
openNames: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
accordion: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '240px'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentActiveName: this.activeName,
|
||||
openedNames: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
let theme = this.theme;
|
||||
if (this.mode === 'vertical' && this.theme === 'primary') theme = 'light';
|
||||
|
||||
return [
|
||||
`${prefixCls}`,
|
||||
`${prefixCls}-${theme}`,
|
||||
{
|
||||
[`${prefixCls}-${this.mode}`]: this.mode
|
||||
}
|
||||
];
|
||||
},
|
||||
styles () {
|
||||
let style = {};
|
||||
|
||||
if (this.mode === 'vertical') style.width = this.width;
|
||||
|
||||
return style;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateActiveName () {
|
||||
if (this.currentActiveName === undefined) {
|
||||
this.currentActiveName = -1;
|
||||
}
|
||||
this.broadcast('Submenu', 'on-update-active-name', false);
|
||||
this.broadcast('MenuItem', 'on-update-active-name', this.currentActiveName);
|
||||
},
|
||||
updateOpenKeys (name) {
|
||||
let names = [...this.openedNames];
|
||||
const index = names.indexOf(name);
|
||||
if (this.accordion) findComponentsDownward(this, 'Submenu').forEach(item => {
|
||||
item.opened = false;
|
||||
});
|
||||
if (index >= 0) {
|
||||
let currentSubmenu = null;
|
||||
findComponentsDownward(this, 'Submenu').forEach(item => {
|
||||
if (item.name === name) {
|
||||
currentSubmenu = item;
|
||||
item.opened = false;
|
||||
}
|
||||
});
|
||||
findComponentsUpward(currentSubmenu, 'Submenu').forEach(item => {
|
||||
item.opened = true;
|
||||
});
|
||||
findComponentsDownward(currentSubmenu, 'Submenu').forEach(item => {
|
||||
item.opened = false;
|
||||
});
|
||||
} else {
|
||||
if (this.accordion) {
|
||||
let currentSubmenu = null;
|
||||
findComponentsDownward(this, 'Submenu').forEach(item => {
|
||||
if (item.name === name) {
|
||||
currentSubmenu = item;
|
||||
item.opened = true;
|
||||
}
|
||||
});
|
||||
findComponentsUpward(currentSubmenu, 'Submenu').forEach(item => {
|
||||
item.opened = true;
|
||||
});
|
||||
} else {
|
||||
findComponentsDownward(this, 'Submenu').forEach(item => {
|
||||
if (item.name === name) item.opened = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
let openedNames = findComponentsDownward(this, 'Submenu').filter(item => item.opened).map(item => item.name);
|
||||
this.openedNames = [...openedNames];
|
||||
this.$emit('on-open-change', openedNames);
|
||||
},
|
||||
updateOpened () {
|
||||
const items = findComponentsDownward(this, 'Submenu');
|
||||
|
||||
if (items.length) {
|
||||
items.forEach(item => {
|
||||
if (this.openedNames.indexOf(item.name) > -1) item.opened = true;
|
||||
else item.opened = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
handleEmitSelectEvent (name) {
|
||||
this.$emit('on-select', name);
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.openedNames = [...this.openNames];
|
||||
this.updateOpened();
|
||||
this.$nextTick(() => this.updateActiveName());
|
||||
this.$on('on-menu-item-select', (name) => {
|
||||
this.currentActiveName = name;
|
||||
this.$emit('on-select', name);
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
openNames (names) {
|
||||
this.openedNames = names;
|
||||
},
|
||||
activeName (val) {
|
||||
this.currentActiveName = val;
|
||||
},
|
||||
currentActiveName () {
|
||||
this.updateActiveName();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
19
src/components/menu/mixin.js
Normal file
19
src/components/menu/mixin.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { findComponentUpward, findComponentsUpward } from '../../utils/assist';
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
menu: findComponentUpward(this, 'Menu')
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasParentSubmenu () {
|
||||
return !!findComponentUpward(this, 'Submenu');
|
||||
},
|
||||
parentSubmenuNum () {
|
||||
return findComponentsUpward(this, 'Submenu').length;
|
||||
},
|
||||
mode () {
|
||||
return this.menu.mode;
|
||||
}
|
||||
}
|
||||
};
|
181
src/components/menu/submenu.vue
Normal file
181
src/components/menu/submenu.vue
Normal file
|
@ -0,0 +1,181 @@
|
|||
<template>
|
||||
<li :class="classes" @mouseenter="handleMouseenter" @mouseleave="handleMouseleave">
|
||||
<div :class="[prefixCls + '-submenu-title']" ref="reference" @click.stop="handleClick" :style="titleStyle">
|
||||
<slot name="title"></slot>
|
||||
<Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-submenu-title-icon']" />
|
||||
</div>
|
||||
<collapse-transition v-if="mode === 'vertical'">
|
||||
<ul :class="[prefixCls]" v-show="opened"><slot></slot></ul>
|
||||
</collapse-transition>
|
||||
<transition name="slide-up" v-else>
|
||||
<Drop
|
||||
v-show="opened"
|
||||
placement="bottom"
|
||||
ref="drop"
|
||||
:style="dropStyle"><ul :class="[prefixCls + '-drop-list']"><slot></slot></ul>
|
||||
</Drop>
|
||||
</transition>
|
||||
</li>
|
||||
</template>
|
||||
<script>
|
||||
import Drop from '../select/dropdown.vue';
|
||||
import Icon from '../icon/icon.vue';
|
||||
import CollapseTransition from '../base/collapse-transition';
|
||||
import { getStyle, findComponentUpward, findComponentsDownward } from '../../utils/assist';
|
||||
import Emitter from '../../mixins/emitter';
|
||||
import mixin from './mixin';
|
||||
|
||||
const prefixCls = 'ivu-menu';
|
||||
|
||||
export default {
|
||||
name: 'Submenu',
|
||||
mixins: [ Emitter, mixin ],
|
||||
components: { Icon, Drop, CollapseTransition },
|
||||
props: {
|
||||
name: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
prefixCls: prefixCls,
|
||||
active: false,
|
||||
opened: false,
|
||||
dropWidth: parseFloat(getStyle(this.$el, 'width'))
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
return [
|
||||
`${prefixCls}-submenu`,
|
||||
{
|
||||
[`${prefixCls}-item-active`]: this.active && !this.hasParentSubmenu,
|
||||
[`${prefixCls}-opened`]: this.opened,
|
||||
[`${prefixCls}-submenu-disabled`]: this.disabled,
|
||||
[`${prefixCls}-submenu-has-parent-submenu`]: this.hasParentSubmenu,
|
||||
[`${prefixCls}-child-item-active`]: this.active
|
||||
}
|
||||
];
|
||||
},
|
||||
accordion () {
|
||||
return this.menu.accordion;
|
||||
},
|
||||
dropStyle () {
|
||||
let style = {};
|
||||
|
||||
if (this.dropWidth) style.minWidth = `${this.dropWidth}px`;
|
||||
return style;
|
||||
},
|
||||
titleStyle () {
|
||||
return this.hasParentSubmenu && this.mode !== 'horizontal' ? {
|
||||
paddingLeft: 43 + (this.parentSubmenuNum - 1) * 24 + 'px'
|
||||
} : {};
|
||||
},
|
||||
// 3.4.0, global setting customArrow 有值时,arrow 赋值空
|
||||
arrowType () {
|
||||
let type = 'ios-arrow-down';
|
||||
|
||||
if (this.$IVIEW) {
|
||||
if (this.$IVIEW.menu.customArrow) {
|
||||
type = '';
|
||||
} else if (this.$IVIEW.menu.arrow) {
|
||||
type = this.$IVIEW.menu.arrow;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
},
|
||||
// 3.4.0, global setting
|
||||
customArrowType () {
|
||||
let type = '';
|
||||
|
||||
if (this.$IVIEW) {
|
||||
if (this.$IVIEW.menu.customArrow) {
|
||||
type = this.$IVIEW.menu.customArrow;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
},
|
||||
// 3.4.0, global setting
|
||||
arrowSize () {
|
||||
let size = '';
|
||||
|
||||
if (this.$IVIEW) {
|
||||
if (this.$IVIEW.menu.arrowSize) {
|
||||
size = this.$IVIEW.menu.arrowSize;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleMouseenter () {
|
||||
if (this.disabled) return;
|
||||
if (this.mode === 'vertical') return;
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.menu.updateOpenKeys(this.name);
|
||||
this.opened = true;
|
||||
}, 250);
|
||||
},
|
||||
handleMouseleave () {
|
||||
if (this.disabled) return;
|
||||
if (this.mode === 'vertical') return;
|
||||
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.menu.updateOpenKeys(this.name);
|
||||
this.opened = false;
|
||||
}, 150);
|
||||
},
|
||||
handleClick () {
|
||||
if (this.disabled) return;
|
||||
if (this.mode === 'horizontal') return;
|
||||
const opened = this.opened;
|
||||
if (this.accordion) {
|
||||
this.$parent.$children.forEach(item => {
|
||||
if (item.$options.name === 'Submenu') item.opened = false;
|
||||
});
|
||||
}
|
||||
this.opened = !opened;
|
||||
this.menu.updateOpenKeys(this.name);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
mode (val) {
|
||||
if (val === 'horizontal') {
|
||||
this.$refs.drop.update();
|
||||
}
|
||||
},
|
||||
opened (val) {
|
||||
if (this.mode === 'vertical') return;
|
||||
if (val) {
|
||||
// set drop a width to fixed when menu has fixed position
|
||||
this.dropWidth = parseFloat(getStyle(this.$el, 'width'));
|
||||
this.$refs.drop.update();
|
||||
} else {
|
||||
this.$refs.drop.destroy();
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$on('on-menu-item-select', (name) => {
|
||||
if (this.mode === 'horizontal') this.opened = false;
|
||||
this.dispatch('Menu', 'on-menu-item-select', name);
|
||||
return true;
|
||||
});
|
||||
this.$on('on-update-active-name', (status) => {
|
||||
if (findComponentUpward(this, 'Submenu')) this.dispatch('Submenu', 'on-update-active-name', status);
|
||||
if (findComponentsDownward(this, 'Submenu')) findComponentsDownward(this, 'Submenu').forEach(item => {
|
||||
item.active = false;
|
||||
});
|
||||
this.active = status;
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue