add Dropdown component
add Dropdown component
This commit is contained in:
parent
0f4ccf4486
commit
ab8aaf958a
13 changed files with 235 additions and 4 deletions
50
src/components/dropdown/dropdown-item.vue
Normal file
50
src/components/dropdown/dropdown-item.vue
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<li :class="classes" @click="handleClick"><slot></slot></li>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
const prefixCls = 'ivu-dropdown-item';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
key: {
|
||||||
|
type: [String, Number]
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
divided: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
classes () {
|
||||||
|
return [
|
||||||
|
`${prefixCls}`,
|
||||||
|
{
|
||||||
|
[`${prefixCls}-disabled`]: this.disabled,
|
||||||
|
[`${prefixCls}-selected`]: this.selected,
|
||||||
|
[`${prefixCls}-divided`]: this.divided
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick () {
|
||||||
|
if (this.disabled) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$parent.$parent.visible = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$parent.$parent.visible = false;
|
||||||
|
}
|
||||||
|
this.$parent.$parent.$emit('on-click', this.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
6
src/components/dropdown/dropdown-menu.vue
Normal file
6
src/components/dropdown/dropdown-menu.vue
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<template>
|
||||||
|
<ul class="ivu-dropdown-menu"><slot></slot></ul>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
89
src/components/dropdown/dropdown.vue
Normal file
89
src/components/dropdown/dropdown.vue
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="[prefixCls]"
|
||||||
|
@click="handleClick"
|
||||||
|
@mouseenter="handleMouseenter"
|
||||||
|
@mouseleave="handleMouseleave"
|
||||||
|
v-clickoutside="handleClose">
|
||||||
|
<div :class="[prefixCls-rel]" v-el:reference><slot></slot></div>
|
||||||
|
<Drop v-show="visible" :placement="placement" transition="slide-up"><slot name="list"></slot></Drop>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Drop from '../select/dropdown.vue';
|
||||||
|
import clickoutside from '../../directives/clickoutside';
|
||||||
|
import { oneOf } from '../../utils/assist';
|
||||||
|
|
||||||
|
const prefixCls = 'ivu-dropdown';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directives: { clickoutside },
|
||||||
|
components: { Drop },
|
||||||
|
props: {
|
||||||
|
trigger: {
|
||||||
|
validator (value) {
|
||||||
|
return oneOf(value, ['click', 'hover']);
|
||||||
|
},
|
||||||
|
default: 'hover'
|
||||||
|
},
|
||||||
|
align: {
|
||||||
|
validator (value) {
|
||||||
|
return oneOf(value, ['left', 'center', 'right']);
|
||||||
|
},
|
||||||
|
default: 'center'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
prefixCls: prefixCls,
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
placement () {
|
||||||
|
return this.align === 'left' ? 'bottom-start' : this.align === 'center' ? 'bottom' : 'bottom-end';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick () {
|
||||||
|
if (this.trigger !== 'click') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.visible = !this.visible;
|
||||||
|
},
|
||||||
|
handleMouseenter () {
|
||||||
|
if (this.trigger !== 'hover') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.visible = true;
|
||||||
|
}, 250);
|
||||||
|
},
|
||||||
|
handleMouseleave () {
|
||||||
|
if (this.trigger !== 'hover') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.visible = false;
|
||||||
|
}, 150);
|
||||||
|
},
|
||||||
|
handleClose () {
|
||||||
|
if (this.trigger !== 'click') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.visible = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
visible (val) {
|
||||||
|
if (val) {
|
||||||
|
this.$broadcast('on-update-popper');
|
||||||
|
} else {
|
||||||
|
this.$broadcast('on-destroy-popper');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
7
src/components/dropdown/index.js
Normal file
7
src/components/dropdown/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Dropdown from './dropdown.vue';
|
||||||
|
import DropdownMenu from './dropdown-menu.vue';
|
||||||
|
import DropdownItem from './dropdown-item.vue';
|
||||||
|
|
||||||
|
Dropdown.Menu = DropdownMenu;
|
||||||
|
Dropdown.Item = DropdownItem;
|
||||||
|
export default Dropdown;
|
|
@ -5,6 +5,12 @@
|
||||||
import Popper from 'popper.js';
|
import Popper from 'popper.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
placement: {
|
||||||
|
type: String,
|
||||||
|
default: 'bottom-start'
|
||||||
|
}
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
popper: null
|
popper: null
|
||||||
|
@ -20,7 +26,7 @@
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.popper = new Popper(this.$parent.$els.reference, this.$el, {
|
this.popper = new Popper(this.$parent.$els.reference, this.$el, {
|
||||||
gpuAcceleration: false,
|
gpuAcceleration: false,
|
||||||
placement: 'bottom-start',
|
placement: this.placement,
|
||||||
boundariesPadding: 0,
|
boundariesPadding: 0,
|
||||||
forceAbsolute: true,
|
forceAbsolute: true,
|
||||||
boundariesElement: 'body'
|
boundariesElement: 'body'
|
||||||
|
|
|
@ -12,6 +12,7 @@ import Cascader from './components/cascader';
|
||||||
import Checkbox from './components/checkbox';
|
import Checkbox from './components/checkbox';
|
||||||
import Circle from './components/circle';
|
import Circle from './components/circle';
|
||||||
import Collapse from './components/collapse';
|
import Collapse from './components/collapse';
|
||||||
|
import Dropdown from './components/dropdown';
|
||||||
import Icon from './components/icon';
|
import Icon from './components/icon';
|
||||||
import Input from './components/input';
|
import Input from './components/input';
|
||||||
import InputNumber from './components/input-number';
|
import InputNumber from './components/input-number';
|
||||||
|
@ -49,6 +50,9 @@ const iview = {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
CheckboxGroup: Checkbox.Group,
|
CheckboxGroup: Checkbox.Group,
|
||||||
Circle,
|
Circle,
|
||||||
|
Dropdown,
|
||||||
|
DropdownItem: Dropdown.Item,
|
||||||
|
DropdownMenu: Dropdown.Menu,
|
||||||
iCol: Col,
|
iCol: Col,
|
||||||
Collapse,
|
Collapse,
|
||||||
Icon,
|
Icon,
|
||||||
|
|
17
src/styles/components/dropdown.less
Normal file
17
src/styles/components/dropdown.less
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
@dropdown-prefix-cls: ~"@{css-prefix}dropdown";
|
||||||
|
@dropdown-item-prefix-cls: ~"@{dropdown-prefix-cls}-item";
|
||||||
|
|
||||||
|
.@{dropdown-prefix-cls} {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-rel{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-menu{
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-item(@dropdown-prefix-cls, @dropdown-item-prefix-cls);
|
|
@ -29,3 +29,4 @@
|
||||||
@import "cascader";
|
@import "cascader";
|
||||||
@import "transfer";
|
@import "transfer";
|
||||||
@import "table";
|
@import "table";
|
||||||
|
@import "dropdown";
|
|
@ -27,7 +27,7 @@
|
||||||
.input-small() {
|
.input-small() {
|
||||||
padding: @input-padding-vertical-small @input-padding-horizontal;
|
padding: @input-padding-vertical-small @input-padding-horizontal;
|
||||||
height: @input-height-small;
|
height: @input-height-small;
|
||||||
border-radius: @border-radius-small;
|
border-radius: @btn-border-radius-small;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input() {
|
.input() {
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
padding: @input-padding-vertical-base @input-padding-horizontal;
|
padding: @input-padding-vertical-base @input-padding-horizontal;
|
||||||
font-size: @font-size-small;
|
font-size: @font-size-small;
|
||||||
border: 1px solid @input-border-color;
|
border: 1px solid @input-border-color;
|
||||||
border-radius: @border-radius-base;
|
border-radius: @btn-border-radius;
|
||||||
color: @input-color;
|
color: @input-color;
|
||||||
background-color: @input-bg;
|
background-color: @input-bg;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
|
|
|
@ -37,6 +37,18 @@
|
||||||
&-selected&-focus {
|
&-selected&-focus {
|
||||||
background: shade(@selected-color, 10%);
|
background: shade(@selected-color, 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-divided{
|
||||||
|
margin-top: 5px;
|
||||||
|
border-top: 1px solid @border-color-split;
|
||||||
|
&:before{
|
||||||
|
content: '';
|
||||||
|
height: 5px;
|
||||||
|
display: block;
|
||||||
|
margin: -7px -16px 0;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{size-class}-large .@{item-class} {
|
.@{size-class}-large .@{item-class} {
|
||||||
|
|
|
@ -42,6 +42,7 @@ li + li {
|
||||||
<li><a v-link="'/cascader'">Cascader</a></li>
|
<li><a v-link="'/cascader'">Cascader</a></li>
|
||||||
<li><a v-link="'/transfer'">Transfer</a></li>
|
<li><a v-link="'/transfer'">Transfer</a></li>
|
||||||
<li><a v-link="'/table'">Table</a></li>
|
<li><a v-link="'/table'">Table</a></li>
|
||||||
|
<li><a v-link="'/dropdown'">Dropdown</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
|
|
@ -107,6 +107,11 @@ router.map({
|
||||||
component: function (resolve) {
|
component: function (resolve) {
|
||||||
require(['./routers/table.vue'], resolve);
|
require(['./routers/table.vue'], resolve);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'/dropdown': {
|
||||||
|
component: function (resolve) {
|
||||||
|
require(['./routers/dropdown.vue'], resolve);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
33
test/routers/dropdown.vue
Normal file
33
test/routers/dropdown.vue
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
padding: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<Dropdown trigger="click" align="right" @on-click="click">
|
||||||
|
<i-button type="primary">
|
||||||
|
下拉菜单
|
||||||
|
<Icon type="arrow-down-b"></Icon>
|
||||||
|
</i-button>
|
||||||
|
<Dropdown-menu slot="list">
|
||||||
|
<Dropdown-item>张三</Dropdown-item>
|
||||||
|
<Dropdown-item disabled>李四</Dropdown-item>
|
||||||
|
<Dropdown-item>王五</Dropdown-item>
|
||||||
|
<Dropdown-item divided>周六</Dropdown-item>
|
||||||
|
</Dropdown-menu>
|
||||||
|
</Dropdown>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {},
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
click (key) {
|
||||||
|
console.log(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Add table
Reference in a new issue