diff --git a/src/components/cascader/cascader.vue b/src/components/cascader/cascader.vue index 4ec4d83..6b2078e 100644 --- a/src/components/cascader/cascader.vue +++ b/src/components/cascader/cascader.vue @@ -1,22 +1,39 @@ <template> - <div :class="[prefixCls]"> + <div :class="classes" v-clickoutside="handleClose"> <i-input readonly :disabled="disabled" :value.sync="displayRender" :size="size" - :placeholder="placeholder"></i-input> + :placeholder="placeholder" + @on-focus="onFocus"></i-input> + <Icon type="ios-close" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.stop="clearSelect"></Icon> + <Icon type="arrow-down-b" :class="[prefixCls + '-arrow']"></Icon> + <Dropdown v-show="visible" transition="slide-up"> + <div> + <Caspanel + :prefix-cls="prefixCls" + :data.sync="data" + :disabled="disabled" + :trigger="trigger" + @on-update-result="updateResult"></Caspanel> + </div> + </Dropdown> </div> </template> <script> import iInput from '../input/input.vue'; import Dropdown from '../select/dropdown.vue'; + import Icon from '../icon/icon.vue'; + import Caspanel from './caspanel.vue'; import clickoutside from '../../directives/clickoutside'; - import { oneOf, MutationObserver } from '../../utils/assist'; + import { oneOf } from '../../utils/assist'; const prefixCls = 'ivu-cascader'; export default { + components: { iInput, Dropdown, Icon, Caspanel }, + directives: { clickoutside }, props: { data: { type: Array, @@ -33,7 +50,7 @@ }, clearable: { type: Boolean, - default: false + default: true }, placeholder: { type: String, @@ -56,18 +73,31 @@ }, renderFormat: { type: Function, - default: (label, selectedData) => { - label.join('/'); + default (label, selectedData) { + return label.join('/'); } } }, data () { return { prefixCls: prefixCls, - selected: [] + visible: false, + selected: [], + tmpSelected: [] } }, computed: { + classes () { + return [ + `${prefixCls}`, + { + [`${prefixCls}-show-clear`]: this.showCloseIcon + } + ] + }, + showCloseIcon () { + return this.value && this.value.length && this.clearable; + }, displayRender () { let label = []; for (let i = 0; i < this.selected.length; i++) { @@ -78,7 +108,22 @@ } }, methods: { - + clearSelect () { + + }, + handleClose () { + this.visible = false; + }, + onFocus () { + this.visible = true; + }, + updateResult (result) { + console.log(JSON.stringify(result)) + this.selected = result; + } + }, + ready () { + } } </script> \ No newline at end of file diff --git a/src/components/cascader/casitem.vue b/src/components/cascader/casitem.vue new file mode 100644 index 0000000..599b59a --- /dev/null +++ b/src/components/cascader/casitem.vue @@ -0,0 +1,25 @@ +<template> + <li :class="classes">{{ data.label }}<i v-if="data.children && data.children.length" class="ivu-icon ivu-icon-ios-arrow-right"></i></li> +</template> +<script> + export default { + props: { + data: Object, + prefixCls: String, + tmpItem: Object + }, + computed: { + classes () { + return [ + `${this.prefixCls}-menu-item`, + { + [`${this.prefixCls}-menu-item-active`]: this.tmpItem.value === this.data.value + } + ] + } + }, + ready () { + + } + } +</script> \ No newline at end of file diff --git a/src/components/cascader/caspanel.vue b/src/components/cascader/caspanel.vue new file mode 100644 index 0000000..c781649 --- /dev/null +++ b/src/components/cascader/caspanel.vue @@ -0,0 +1,95 @@ +<template> + <ul v-if="data && data.length" :class="[prefixCls + '-menu']"> + <Casitem + v-for="item in data" + :prefix-cls="prefixCls" + :data.sync="item" + :tmp-item="tmpItem" + @click.stop="handleClickItem(item)" + @mouseenter.stop="handleHoverItem(item)"></Casitem> + </ul><Caspanel v-if="sublist && sublist.length" :prefix-cls="prefixCls" :data.sync="sublist" :disabled="disabled" :trigger="trigger" @on-update-result="updateResult"></Caspanel> +</template> +<script> + import Casitem from './casitem.vue'; + import { oneOf } from '../../utils/assist'; + + export default { + name: 'Caspanel', + components: { Casitem }, + props: { + data: { + type: Array, + default () { + return [] + } + }, + sublist: { + type: Array, + default () { + return [] + } + }, + disabled: Boolean, + changeOnSelect: Boolean, + trigger: { + validator (value) { + return oneOf(value, ['click', 'hover']); + } + }, + prefixCls: String + }, + data () { + return { + tmpItem: {}, + result: [] + } + }, + methods: { + handleClickItem (item) { + if (this.trigger !== 'click') return; + this.handleTriggerItem(item); + }, + handleHoverItem (item) { + if (this.trigger !== 'hover') return; + this.handleTriggerItem(item); + }, + handleTriggerItem (item) { + if (item.disabled) return; + + if (item.children && item.children.length){ + this.sublist = item.children; + // todo 实时选择 + } else { + this.sublist = []; + // todo 选择 + } + + // return value back + const backItem = this.getBaseItem(item); + + this.tmpItem = backItem; + this.$emit('on-update-result', [backItem]); + }, + updateResult (item) { + this.result = [this.tmpItem].concat(item); + this.$emit('on-update-result', this.result); + }, + getBaseItem (item) { + let backItem = Object.assign({}, item); + if (backItem.children) { + delete backItem.children; + } + + return backItem; + } + }, + watch: { + data () { + this.sublist = []; + } + }, + ready () { + // todo 初始化时,判断预设的值 + } + } +</script> \ No newline at end of file diff --git a/src/styles/components/cascader.less b/src/styles/components/cascader.less new file mode 100644 index 0000000..a87d4ee --- /dev/null +++ b/src/styles/components/cascader.less @@ -0,0 +1,85 @@ +@cascader-prefix-cls: ~"@{css-prefix}cascader"; +@cascader-item-prefix-cls: ~"@{css-prefix}cascader-menu-item"; + +.@{cascader-prefix-cls} { + position: relative; + + .@{css-prefix}input{ + display: block; + cursor: pointer; + } + + .@{cascader-prefix-cls}-arrow:nth-of-type(1) { + display: none; + cursor: pointer; + } + + &:hover { + .@{cascader-prefix-cls}-arrow:nth-of-type(1) { + display: inline-block; + } + } + &-show-clear:hover .@{cascader-prefix-cls}-arrow:nth-of-type(2){ + display: none; + } + + &-arrow { + position: absolute; + top: 50%; + right: 8px; + line-height: 1; + margin-top: -6px; + font-size: @font-size-base; + color: @subsidiary-color; + .transition(all @transition-time @ease-in-out); + } + + .@{select-dropdown-prefix-cls} { + padding: 0; + white-space: nowrap; + } + + .select-item(@cascader-prefix-cls, @cascader-item-prefix-cls); + + &-menu{ + display: inline-block; + min-width: 100px; + height: 180px; + margin: 0; + padding: 5px 0; + vertical-align: top; + list-style: none; + border-right: 1px solid @border-color-split; + overflow: auto; + + &:first-child { + + } + &:last-child { + border-right-color: transparent; + margin-right: -1px; + } + &:only-child { + + } + + & &-item{ + position: relative; + padding-right: 24px; + .transition(all @transition-time @ease-in-out); + + i{ + font-size: @font-size-small; + position: absolute; + right: 15px; + top: 50%; + margin-top: -6px; + } + + &-active{ + background-color: @background-color-select-hover; + font-weight: bold; + } + } + } +} \ No newline at end of file diff --git a/src/styles/components/index.less b/src/styles/components/index.less index 3f67faf..168358b 100644 --- a/src/styles/components/index.less +++ b/src/styles/components/index.less @@ -25,4 +25,5 @@ @import "tooltip"; @import "poptip"; @import "input"; -@import "slider"; \ No newline at end of file +@import "slider"; +@import "cascader"; \ No newline at end of file diff --git a/src/styles/components/select.less b/src/styles/components/select.less index 9d3bb23..2bca4f7 100644 --- a/src/styles/components/select.less +++ b/src/styles/components/select.less @@ -183,50 +183,7 @@ } } -.@{select-item-prefix-cls} { - margin: 0; - padding: 7px 16px; - clear: both; - color: @text-color; - font-size: @font-size-small !important; - //border-radius: @btn-border-radius-small; - white-space: nowrap; - cursor: pointer; - .transition(background @transition-time @ease-in-out); - - &:hover{ - background: @background-color-select-hover; - } - - &-focus { - background: @background-color-select-hover; - } - - &-disabled { - color: @btn-disable-color; - cursor: @cursor-disabled; - - &:hover { - color: @btn-disable-color; - background-color: #fff; - cursor: @cursor-disabled; - } - } - - &-selected ,&-selected:hover{ - color: #fff; - background: @selected-color; - } - - &-selected&-focus { - background: shade(@selected-color, 10%); - } -} - -.@{select-prefix-cls}-large .@{select-item-prefix-cls}{ - padding: 7px 16px 8px; - font-size: @font-size-base !important; -} +.select-item(@select-prefix-cls, @select-item-prefix-cls); .@{select-prefix-cls}-multiple .@{select-item-prefix-cls} { &-selected{ diff --git a/src/styles/mixins/index.less b/src/styles/mixins/index.less index 4e7933c..759663b 100644 --- a/src/styles/mixins/index.less +++ b/src/styles/mixins/index.less @@ -14,4 +14,5 @@ @import "breadcrumb"; @import "mask"; @import "content"; // card、modal -@import "tooltip"; \ No newline at end of file +@import "tooltip"; +@import "select"; \ No newline at end of file diff --git a/src/styles/mixins/select.less b/src/styles/mixins/select.less new file mode 100644 index 0000000..ee34af2 --- /dev/null +++ b/src/styles/mixins/select.less @@ -0,0 +1,46 @@ +.select-item(@size-class, @item-class) { + .@{item-class} { + margin: 0; + padding: 7px 16px; + clear: both; + color: @text-color; + font-size: @font-size-small !important; + white-space: nowrap; + list-style: none; + cursor: pointer; + .transition(background @transition-time @ease-in-out); + + &:hover{ + background: @background-color-select-hover; + } + + &-focus { + background: @background-color-select-hover; + } + + &-disabled { + color: @btn-disable-color; + cursor: @cursor-disabled; + + &:hover { + color: @btn-disable-color; + background-color: #fff; + cursor: @cursor-disabled; + } + } + + &-selected ,&-selected:hover{ + color: #fff; + background: @selected-color; + } + + &-selected&-focus { + background: shade(@selected-color, 10%); + } + } + + .@{size-class}-large .@{item-class} { + padding: 7px 16px 8px; + font-size: @font-size-base !important; + } +} \ No newline at end of file diff --git a/test/routers/cascader.vue b/test/routers/cascader.vue index 7f43f60..82006a0 100644 --- a/test/routers/cascader.vue +++ b/test/routers/cascader.vue @@ -1,24 +1,54 @@ <template> - <div style="margin: 150px;width:300px"> - <Cascader></Cascader> + <div style="margin: 50px;width:300px"> + <Cascader :data="data" :value="value"></Cascader> </div> </template> <script> import { Cascader } from 'iview'; export default { props: { - + }, data () { return { - + value: [], + data: [{ + value: 'zhejiang', + label: 'Zhejiang', + children: [{ + value: 'hangzhou', + label: 'Hangzhou' + }], + }, { + value: 'jiangsu', + label: 'Jiangsu', + children: [{ + value: 'nanjing', + label: 'Nanjing', + children: [{ + value: 'zhonghuamen', + label: 'Zhong Hua Men', + children: [{ + value: 'abc', + label: 'ABC' + }] + }] + }, { + value: 'hhh', + label: 'HHH', + children: [{ + value: 'ddd', + label: 'DDD' + }] + }] + }] } }, computed: { - + }, methods: { - + } } </script> \ No newline at end of file -- libgit2 0.21.4