Commit 7ec0b5330b4893d32d949532b1ad02c506c05e4e
1 parent
7959adf7
Cascader support search
Showing
3 changed files
with
82 additions
and
19 deletions
Show diff stats
examples/routers/cascader.vue
| @@ -2,8 +2,9 @@ | @@ -2,8 +2,9 @@ | ||
| 2 | <Row> | 2 | <Row> |
| 3 | <i-col span="4"> | 3 | <i-col span="4"> |
| 4 | <Button @click="handleLoad">load</Button> | 4 | <Button @click="handleLoad">load</Button> |
| 5 | + {{ v1 }} | ||
| 5 | </i-col> | 6 | </i-col> |
| 6 | - <i-col span="6"> | 7 | + <i-col span="4"> |
| 7 | <Cascader :data="data3" filterable v-model="v1"></Cascader> | 8 | <Cascader :data="data3" filterable v-model="v1"></Cascader> |
| 8 | <!--<Cascader :data="data2" filterable v-model="v1" :loadData="loadData"></Cascader>--> | 9 | <!--<Cascader :data="data2" filterable v-model="v1" :loadData="loadData"></Cascader>--> |
| 9 | </i-col> | 10 | </i-col> |
| @@ -14,23 +15,26 @@ | @@ -14,23 +15,26 @@ | ||
| 14 | data () { | 15 | data () { |
| 15 | return { | 16 | return { |
| 16 | v1: [], | 17 | v1: [], |
| 17 | - data2: [{ | ||
| 18 | - value: 'zhejiang', | ||
| 19 | - label: '浙江', | ||
| 20 | - children: [], | ||
| 21 | - loading: false | ||
| 22 | - }, { | ||
| 23 | - value: 'jiangsu', | ||
| 24 | - label: '江苏', | ||
| 25 | - children: [{ | ||
| 26 | - value: 'nanjing', | ||
| 27 | - label: '南京', | 18 | + data2: [ |
| 19 | + { | ||
| 20 | + value: 'zhejiang', | ||
| 21 | + label: '浙江', | ||
| 22 | + children: [], | ||
| 23 | + loading: false | ||
| 24 | + }, | ||
| 25 | + { | ||
| 26 | + value: 'jiangsu', | ||
| 27 | + label: '江苏', | ||
| 28 | children: [{ | 28 | children: [{ |
| 29 | - value: 'zhonghuamen', | ||
| 30 | - label: '中华门' | 29 | + value: 'nanjing', |
| 30 | + label: '南京', | ||
| 31 | + children: [{ | ||
| 32 | + value: 'zhonghuamen', | ||
| 33 | + label: '中华门' | ||
| 34 | + }] | ||
| 31 | }] | 35 | }] |
| 32 | - }] | ||
| 33 | - }], | 36 | + } |
| 37 | + ], | ||
| 34 | data3: [{ | 38 | data3: [{ |
| 35 | value: 'beijing', | 39 | value: 'beijing', |
| 36 | label: '北京', | 40 | label: '北京', |
| @@ -67,6 +71,7 @@ | @@ -67,6 +71,7 @@ | ||
| 67 | label: '苏州', | 71 | label: '苏州', |
| 68 | children: [ | 72 | children: [ |
| 69 | { | 73 | { |
| 74 | + disabled: true, | ||
| 70 | value: 'zhuozhengyuan', | 75 | value: 'zhuozhengyuan', |
| 71 | label: '拙政园', | 76 | label: '拙政园', |
| 72 | }, | 77 | }, |
src/components/cascader/cascader.vue
| @@ -5,7 +5,8 @@ | @@ -5,7 +5,8 @@ | ||
| 5 | <i-input | 5 | <i-input |
| 6 | :readonly="!filterable" | 6 | :readonly="!filterable" |
| 7 | :disabled="disabled" | 7 | :disabled="disabled" |
| 8 | - v-model="displayRender" | 8 | + :value="displayRender" |
| 9 | + @on-change="handleInput" | ||
| 9 | :size="size" | 10 | :size="size" |
| 10 | :placeholder="placeholder"></i-input> | 11 | :placeholder="placeholder"></i-input> |
| 11 | <Icon type="ios-close" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSelect"></Icon> | 12 | <Icon type="ios-close" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSelect"></Icon> |
| @@ -16,12 +17,23 @@ | @@ -16,12 +17,23 @@ | ||
| 16 | <Drop v-show="visible"> | 17 | <Drop v-show="visible"> |
| 17 | <div> | 18 | <div> |
| 18 | <Caspanel | 19 | <Caspanel |
| 20 | + v-show="!filterable || (filterable && query === '')" | ||
| 19 | ref="caspanel" | 21 | ref="caspanel" |
| 20 | :prefix-cls="prefixCls" | 22 | :prefix-cls="prefixCls" |
| 21 | :data="data" | 23 | :data="data" |
| 22 | :disabled="disabled" | 24 | :disabled="disabled" |
| 23 | :change-on-select="changeOnSelect" | 25 | :change-on-select="changeOnSelect" |
| 24 | :trigger="trigger"></Caspanel> | 26 | :trigger="trigger"></Caspanel> |
| 27 | + <div :class="[prefixCls + '-dropdown']" v-show="filterable && query !== ''"> | ||
| 28 | + <ul :class="[selectPrefixCls + '-dropdown-list']"> | ||
| 29 | + <li | ||
| 30 | + :class="[selectPrefixCls + '-item', { | ||
| 31 | + [selectPrefixCls + '-item-disabled']: item.disabled | ||
| 32 | + }]" | ||
| 33 | + v-for="(item, index) in querySelections" | ||
| 34 | + @click="handleSelectItem(index)">{{ item.label }}</li> | ||
| 35 | + </ul> | ||
| 36 | + </div> | ||
| 25 | </div> | 37 | </div> |
| 26 | </Drop> | 38 | </Drop> |
| 27 | </transition> | 39 | </transition> |
| @@ -37,6 +49,7 @@ | @@ -37,6 +49,7 @@ | ||
| 37 | import Emitter from '../../mixins/emitter'; | 49 | import Emitter from '../../mixins/emitter'; |
| 38 | 50 | ||
| 39 | const prefixCls = 'ivu-cascader'; | 51 | const prefixCls = 'ivu-cascader'; |
| 52 | + const selectPrefixCls = 'ivu-select'; | ||
| 40 | 53 | ||
| 41 | export default { | 54 | export default { |
| 42 | name: 'Cascader', | 55 | name: 'Cascader', |
| @@ -100,11 +113,13 @@ | @@ -100,11 +113,13 @@ | ||
| 100 | data () { | 113 | data () { |
| 101 | return { | 114 | return { |
| 102 | prefixCls: prefixCls, | 115 | prefixCls: prefixCls, |
| 116 | + selectPrefixCls: selectPrefixCls, | ||
| 103 | visible: false, | 117 | visible: false, |
| 104 | selected: [], | 118 | selected: [], |
| 105 | tmpSelected: [], | 119 | tmpSelected: [], |
| 106 | updatingValue: false, // to fix set value in changeOnSelect type | 120 | updatingValue: false, // to fix set value in changeOnSelect type |
| 107 | - currentValue: this.value | 121 | + currentValue: this.value, |
| 122 | + query: '' | ||
| 108 | }; | 123 | }; |
| 109 | }, | 124 | }, |
| 110 | computed: { | 125 | computed: { |
| @@ -128,6 +143,32 @@ | @@ -128,6 +143,32 @@ | ||
| 128 | } | 143 | } |
| 129 | 144 | ||
| 130 | return this.renderFormat(label, this.selected); | 145 | return this.renderFormat(label, this.selected); |
| 146 | + }, | ||
| 147 | + querySelections () { | ||
| 148 | + let selections = []; | ||
| 149 | + function getSelections (arr, label, value) { | ||
| 150 | + for (let i = 0; i < arr.length; i++) { | ||
| 151 | + let item = arr[i]; | ||
| 152 | + item.__label = label ? label + ' / ' + item.label : item.label; | ||
| 153 | + item.__value = value ? value + ',' + item.value : item.value; | ||
| 154 | + | ||
| 155 | + if (item.children && item.children.length) { | ||
| 156 | + getSelections(item.children, item.__label, item.__value); | ||
| 157 | + delete item.__label; | ||
| 158 | + delete item.__value; | ||
| 159 | + } else { | ||
| 160 | + selections.push({ | ||
| 161 | + label: item.__label, | ||
| 162 | + value: item.__value, | ||
| 163 | + item: item, | ||
| 164 | + disabled: !!item.disabled | ||
| 165 | + }); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | + getSelections(this.data); | ||
| 170 | + selections = selections.filter(item => item.label.indexOf(this.query) > -1); | ||
| 171 | + return selections; | ||
| 131 | } | 172 | } |
| 132 | }, | 173 | }, |
| 133 | methods: { | 174 | methods: { |
| @@ -146,7 +187,7 @@ | @@ -146,7 +187,7 @@ | ||
| 146 | toggleOpen () { | 187 | toggleOpen () { |
| 147 | if (this.disabled) return false; | 188 | if (this.disabled) return false; |
| 148 | if (this.visible) { | 189 | if (this.visible) { |
| 149 | - this.handleClose(); | 190 | + if (!this.filterable) this.handleClose(); |
| 150 | } else { | 191 | } else { |
| 151 | this.onFocus(); | 192 | this.onFocus(); |
| 152 | } | 193 | } |
| @@ -177,6 +218,19 @@ | @@ -177,6 +218,19 @@ | ||
| 177 | }); | 218 | }); |
| 178 | }); | 219 | }); |
| 179 | } | 220 | } |
| 221 | + }, | ||
| 222 | + handleInput (event) { | ||
| 223 | + this.query = event.target.value; | ||
| 224 | + }, | ||
| 225 | + handleSelectItem (index) { | ||
| 226 | + const item = this.querySelections[index]; | ||
| 227 | + | ||
| 228 | + if (item.item.disabled) return false; | ||
| 229 | + this.query = ''; | ||
| 230 | + const oldVal = JSON.stringify(this.currentValue); | ||
| 231 | + this.currentValue = item.value.split(','); | ||
| 232 | + this.emitValue(this.currentValue, oldVal); | ||
| 233 | + this.handleClose(); | ||
| 180 | } | 234 | } |
| 181 | }, | 235 | }, |
| 182 | created () { | 236 | created () { |
src/styles/components/cascader.less
| @@ -49,6 +49,10 @@ | @@ -49,6 +49,10 @@ | ||
| 49 | 49 | ||
| 50 | .select-item(@cascader-prefix-cls, @cascader-item-prefix-cls); | 50 | .select-item(@cascader-prefix-cls, @cascader-item-prefix-cls); |
| 51 | 51 | ||
| 52 | + &-dropdown{ | ||
| 53 | + padding: 5px 0; | ||
| 54 | + } | ||
| 55 | + | ||
| 52 | &-menu{ | 56 | &-menu{ |
| 53 | display: inline-block; | 57 | display: inline-block; |
| 54 | min-width: 100px; | 58 | min-width: 100px; |