Commit 01b54e302194cbb6f889df126551c9d94fca0924

Authored by 梁灏
1 parent 28587238

Select support remote search

examples/routers/select.vue
1 1 <template>
2 2 <div style="width: 200px;margin: 100px;">
3   - <i-select v-model="model" filterable clearable style="width:200px">
4   - <i-option :value="option.value" v-for="option in options" :key="option">{{option.label}}</i-option>
  3 + <i-select v-model="model" filterable remote :remote-method="remoteMethod" :loading="loading" clearable style="width:200px">
  4 + <i-option v-for="option in options" :value="option.value" :key="option">{{option.label}}</i-option>
5 5 </i-select>
  6 + <!--<Button @click="handleAdd">+</Button>-->
6 7 </div>
7 8 </template>
8 9  
... ... @@ -10,26 +11,85 @@
10 11 export default {
11 12 data () {
12 13 return {
13   - model: 1,
  14 + model: '',
14 15 options: [
15 16  
  17 + ],
  18 + list: [],
  19 + loading: false,
  20 + states: ["Alabama", "Alaska", "Arizona",
  21 + "Arkansas", "California", "Colorado",
  22 + "Connecticut", "Delaware", "Florida",
  23 + "Georgia", "Hawaii", "Idaho", "Illinois",
  24 + "Indiana", "Iowa", "Kansas", "Kentucky",
  25 + "Louisiana", "Maine", "Maryland",
  26 + "Massachusetts", "Michigan", "Minnesota",
  27 + "Mississippi", "Missouri", "Montana",
  28 + "Nebraska", "Nevada", "New Hampshire",
  29 + "New Jersey", "New Mexico", "New York",
  30 + "North Carolina", "North Dakota", "Ohio",
  31 + "Oklahoma", "Oregon", "Pennsylvania",
  32 + "Rhode Island", "South Carolina",
  33 + "South Dakota", "Tennessee", "Texas",
  34 + "Utah", "Vermont", "Virginia",
  35 + "Washington", "West Virginia", "Wisconsin",
  36 + "Wyoming"]
  37 + }
  38 + },
  39 + mounted () {
  40 + this.options = [
  41 +// {
  42 +// label: '全部',
  43 +// value: 0
  44 +// },{
  45 +// label: '苹果',
  46 +// value: 1
  47 +// },{
  48 +// label: '香蕉',
  49 +// value: 2
  50 +// },{
  51 +// label: '西瓜',
  52 +// value: 3
  53 +// }
  54 + ];
  55 + },
  56 + methods: {
  57 + handleAdd () {
  58 + this.options = [
  59 + {
  60 + label: '全部',
  61 + value: 0
  62 + },{
  63 + label: '苹果',
  64 + value: 1
  65 + },{
  66 + label: '香蕉',
  67 + value: 2
  68 + },{
  69 + label: '西瓜',
  70 + value: 3
  71 + }
16 72 ]
  73 + },
  74 + remoteMethod (query) {
  75 + if (query !== '') {
  76 + this.loading = true;
  77 + setTimeout(() => {
  78 + this.loading = false;
  79 + this.options = this.list.filter(item => {
  80 + return item.label.toLowerCase()
  81 + .indexOf(query.toLowerCase()) > -1;
  82 + });
  83 + }, 200);
  84 + } else {
  85 + this.options = [];
  86 + }
17 87 }
18 88 },
19 89 mounted () {
20   - this.options = [{
21   - label: '全部',
22   - value: 0
23   - },{
24   - label: '苹果',
25   - value: 1
26   - },{
27   - label: '香蕉',
28   - value: 2
29   - },{
30   - label: '西瓜',
31   - value: 3
32   - }];
  90 + this.list = this.states.map(item => {
  91 + return { value: item, label: item };
  92 + });
33 93 }
34 94 }
35 95 </script>
36 96 \ No newline at end of file
... ...
src/components/select/select.vue
... ... @@ -22,12 +22,16 @@
22 22 @keydown.delete="handleInputDelete"
23 23 ref="input">
24 24 <Icon type="ios-close" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSingleSelect"></Icon>
25   - <Icon type="arrow-down-b" :class="[prefixCls + '-arrow']"></Icon>
  25 + <Icon type="arrow-down-b" :class="[prefixCls + '-arrow']" v-if="!remote"></Icon>
26 26 </div>
27 27 <transition :name="transitionName">
28   - <Drop v-show="visible" :placement="placement" ref="dropdown">
29   - <ul v-show="notFound" :class="[prefixCls + '-not-found']"><li>{{ localeNotFoundText }}</li></ul>
30   - <ul v-show="!notFound" :class="[prefixCls + '-dropdown-list']" ref="options"><slot></slot></ul>
  28 + <Drop v-show="(visible && options.length) ||
  29 + (visible && !options.length && loading) ||
  30 + (visible && remote && !loading && !options.length && query !== '')" :placement="placement" ref="dropdown">
  31 + <!--<Drop v-show="visible" :placement="placement" ref="dropdown">-->
  32 + <ul v-show="(notFound && !remote) || (remote && !loading && !options.length)" :class="[prefixCls + '-not-found']"><li>{{ localeNotFoundText }}</li></ul>
  33 + <ul v-show="(!notFound && !remote) || (remote && !loading && !notFound)" :class="[prefixCls + '-dropdown-list']" ref="options"><slot></slot></ul>
  34 + <ul v-show="loading" :class="[prefixCls + '-loading']">{{ localeLoadingText }}</ul>
31 35 </Drop>
32 36 </transition>
33 37 </div>
... ... @@ -74,6 +78,20 @@
74 78 filterMethod: {
75 79 type: Function
76 80 },
  81 + remote: {
  82 + type: Boolean,
  83 + default: false
  84 + },
  85 + remoteMethod: {
  86 + type: Function
  87 + },
  88 + loading: {
  89 + type: Boolean,
  90 + default: false
  91 + },
  92 + loadingText: {
  93 + type: String
  94 + },
77 95 size: {
78 96 validator (value) {
79 97 return oneOf(value, ['small', 'large', 'default']);
... ... @@ -103,6 +121,7 @@
103 121 selectedMultiple: [],
104 122 focusIndex: 0,
105 123 query: '',
  124 + selectToChangeQuery: false, // when select an option, set this first and set query, because query is watching, it will emit event
106 125 inputLength: 20,
107 126 notFound: false,
108 127 slotChangeDuration: false, // if slot change duration and in multiple, set true and after slot change, set false
... ... @@ -168,6 +187,13 @@
168 187 return this.notFoundText;
169 188 }
170 189 },
  190 + localeLoadingText () {
  191 + if (this.loadingText === undefined) {
  192 + return this.t('i.select.loading');
  193 + } else {
  194 + return this.loadingText;
  195 + }
  196 + },
171 197 transitionName () {
172 198 return this.placement === 'bottom' ? 'slide-up' : 'slide-down';
173 199 }
... ... @@ -187,15 +213,18 @@
187 213 },
188 214 // find option component
189 215 findChild (cb) {
  216 + const _this = this;
190 217 const find = function (child) {
191 218 const name = child.$options.componentName;
192 219  
193 220 if (name) {
194 221 cb(child);
195 222 } else if (child.$children.length) {
196   - child.$children.forEach((innerChild) => {
197   - find(innerChild, cb);
198   - });
  223 + _this.$nextTick(() => {
  224 + child.$children.forEach((innerChild) => {
  225 + find(innerChild, cb);
  226 + });
  227 + })
199 228 }
200 229 };
201 230  
... ... @@ -228,8 +257,10 @@
228 257 this.options = options;
229 258  
230 259 if (init) {
231   - this.updateSingleSelected(true, slot);
232   - this.updateMultipleSelected(true, slot);
  260 + if (!this.remote) {
  261 + this.updateSingleSelected(true, slot);
  262 + this.updateMultipleSelected(true, slot);
  263 + }
233 264 }
234 265 },
235 266 updateSingleSelected (init = false, slot = false) {
... ... @@ -535,18 +566,22 @@
535 566 document.addEventListener('keydown', this.handleKeydown);
536 567  
537 568 this.$on('append', () => {
538   - this.modelToQuery();
539   - this.$nextTick(() => {
540   - this.broadcastQuery('');
541   - });
  569 + if (!this.remote) {
  570 + this.modelToQuery();
  571 + this.$nextTick(() => {
  572 + this.broadcastQuery('');
  573 + });
  574 + }
542 575 this.slotChange();
543 576 this.updateOptions(true, true);
544 577 });
545 578 this.$on('remove', () => {
546   - this.modelToQuery();
547   - this.$nextTick(() => {
548   - this.broadcastQuery('');
549   - });
  579 + if (!this.remote) {
  580 + this.modelToQuery();
  581 + this.$nextTick(() => {
  582 + this.broadcastQuery('');
  583 + });
  584 + }
550 585 this.slotChange();
551 586 this.updateOptions(true, true);
552 587 });
... ... @@ -565,6 +600,7 @@
565 600 }
566 601  
567 602 if (this.filterable) {
  603 + this.selectToChangeQuery = true;
568 604 this.query = '';
569 605 this.$refs.input.focus();
570 606 }
... ... @@ -574,6 +610,7 @@
574 610 if (this.filterable) {
575 611 this.findChild((child) => {
576 612 if (child.value === value) {
  613 + this.selectToChangeQuery = true;
577 614 this.query = child.label === undefined ? child.searchLabel : child.label;
578 615 }
579 616 });
... ... @@ -625,20 +662,29 @@
625 662 }
626 663 },
627 664 query (val) {
628   - this.$emit('on-query-change', val);
  665 + if (this.remote && this.remoteMethod) {
  666 + if (!this.selectToChangeQuery) {
  667 + this.$emit('on-query-change', val);
  668 + this.remoteMethod(val);
  669 + }
  670 + } else {
  671 + if (!this.selectToChangeQuery) {
  672 + this.$emit('on-query-change', val);
  673 + }
  674 + this.broadcastQuery(val);
629 675  
630   - this.broadcastQuery(val);
631   -
632   - let is_hidden = true;
  676 + let is_hidden = true;
633 677  
634   - this.$nextTick(() => {
635   - this.findChild((child) => {
636   - if (!child.hidden) {
637   - is_hidden = false;
638   - }
  678 + this.$nextTick(() => {
  679 + this.findChild((child) => {
  680 + if (!child.hidden) {
  681 + is_hidden = false;
  682 + }
  683 + });
  684 + this.notFound = is_hidden;
639 685 });
640   - this.notFound = is_hidden;
641   - });
  686 + }
  687 + this.selectToChangeQuery = false;
642 688 this.broadcast('Drop', 'on-update-popper');
643 689 }
644 690 }
... ...
src/locale/lang/en-US.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: 'Select',
5   - noMatch: 'No matching data'
  5 + noMatch: 'No matching data',
  6 + loading: 'Loading'
6 7 },
7 8 table: {
8 9 noDataText: 'No Data',
... ...
src/locale/lang/es-ES.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: 'Seleccionar',
5   - noMatch: 'Sin coincidencias'
  5 + noMatch: 'Sin coincidencias',
  6 + loading: 'Cargando'
6 7 },
7 8 table: {
8 9 noDataText: 'Sin Datos',
... ...
src/locale/lang/ja-JP.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: '選んでください',
5   - noMatch: 'マッチするデータなし'
  5 + noMatch: 'マッチするデータなし',
  6 + loading: 'ロード中'
6 7 },
7 8 table: {
8 9 noDataText: 'データなし',
... ...
src/locale/lang/tr-TR.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: 'Seç',
5   - noMatch: 'Eşleşen veri yok'
  5 + noMatch: 'Eşleşen veri yok',
  6 + loading: 'yükleme'
6 7 },
7 8 table: {
8 9 noDataText: 'Veri Yok',
... ...
src/locale/lang/zh-CN.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: '请选择',
5   - noMatch: '无匹配数据'
  5 + noMatch: '无匹配数据',
  6 + loading: '加载中'
6 7 },
7 8 table: {
8 9 noDataText: '暂无数据',
... ...
src/locale/lang/zh-TW.js
... ... @@ -2,7 +2,8 @@ export default {
2 2 i: {
3 3 select: {
4 4 placeholder: '請選擇',
5   - noMatch: '無匹配數據'
  5 + noMatch: '無匹配數據',
  6 + loading: '加載中'
6 7 },
7 8 table: {
8 9 noDataText: '暫無數據',
... ...
src/styles/components/select.less
... ... @@ -174,6 +174,10 @@
174 174 text-align: center;
175 175 color: @btn-disable-color;
176 176 }
  177 + &-loading{
  178 + text-align: center;
  179 + color: @btn-disable-color;
  180 + }
177 181  
178 182 &-multiple .@{css-prefix}tag{
179 183 margin: 3px 4px 2px 0;
... ...