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; |