Blame view

src/components/cascader/cascader.vue 16.9 KB
0a48ac45   梁灏   Input add readonl...
1
  <template>
26369639   Graham Fairweather   Update v-click-ou...
2
      <div :class="classes" v-click-outside="handleClose">
a9cd43b3   梁灏   Cascader add tran...
3
          <div :class="[prefixCls + '-rel']" @click="toggleOpen" ref="reference">
0460a1e8   梁灏   fixed #812
4
              <input type="hidden" :name="name" :value="currentValue">
75e5c6a5   梁灏   Cascader support ...
5
6
              <slot>
                  <i-input
acb79ba3   梁灏   fixed #433
7
                      :element-id="elementId"
3ae11e85   梁灏   update Cascader
8
                      ref="input"
5a9a12cd   梁灏   update Cascader
9
                      :readonly="!filterable"
75e5c6a5   梁灏   Cascader support ...
10
                      :disabled="disabled"
3ae11e85   梁灏   update Cascader
11
                      :value="displayInputRender"
7ec0b533   梁灏   Cascader support ...
12
                      @on-change="handleInput"
75e5c6a5   梁灏   Cascader support ...
13
                      :size="size"
3ae11e85   梁灏   update Cascader
14
15
16
17
18
                      :placeholder="inputPlaceholder"></i-input>
                  <div
                      :class="[prefixCls + '-label']"
                      v-show="filterable && query === ''"
                      @click="handleFocus">{{ displayRender }}</div>
207d6b07   梁灏   update Cascader I...
19
                  <Icon type="ios-close-circle" :class="[prefixCls + '-arrow']" v-show="showCloseIcon" @click.native.stop="clearSelect"></Icon>
47afd12e   梁灏   Cascader add gloa...
20
                  <Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-arrow']"></Icon>
75e5c6a5   梁灏   Cascader support ...
21
22
              </slot>
          </div>
e09b07b7   huanghong   解决drop弹出动画异常
23
          <transition name="transition-drop">
a9cd43b3   梁灏   Cascader add tran...
24
25
26
27
28
              <Drop
                  v-show="visible"
                  :class="{ [prefixCls + '-transfer']: transfer }"
                  ref="drop"
                  :data-transfer="transfer"
7bafe9d9   梁灏   fixes #4453 #4480...
29
                  :transfer="transfer"
a9cd43b3   梁灏   Cascader add tran...
30
                  v-transfer-dom>
47a7f21d   梁灏   support Cascader
31
32
                  <div>
                      <Caspanel
7ec0b533   梁灏   Cascader support ...
33
                          v-show="!filterable || (filterable && query === '')"
47a7f21d   梁灏   support Cascader
34
35
36
37
38
39
                          ref="caspanel"
                          :prefix-cls="prefixCls"
                          :data="data"
                          :disabled="disabled"
                          :change-on-select="changeOnSelect"
                          :trigger="trigger"></Caspanel>
952ddb51   梁灏   update Cascader
40
                      <div :class="[prefixCls + '-dropdown']" v-show="filterable && query !== '' && querySelections.length">
7ec0b533   梁灏   Cascader support ...
41
42
43
44
45
46
                          <ul :class="[selectPrefixCls + '-dropdown-list']">
                              <li
                                  :class="[selectPrefixCls + '-item', {
                                      [selectPrefixCls + '-item-disabled']: item.disabled
                                  }]"
                                  v-for="(item, index) in querySelections"
4e23e47c   梁灏   update Cascader
47
                                  @click="handleSelectItem(index)" v-html="item.display"></li>
7ec0b533   梁灏   Cascader support ...
48
49
                          </ul>
                      </div>
707898f2   梁灏   fix #5514 close #...
50
                      <ul v-show="(filterable && query !== '' && !querySelections.length) || !data.length" :class="[prefixCls + '-not-found-tip']"><li>{{ localeNotFoundText }}</li></ul>
47a7f21d   梁灏   support Cascader
51
52
53
                  </div>
              </Drop>
          </transition>
6ff31952   梁灏   optimize Input sh...
54
      </div>
0a48ac45   梁灏   Input add readonl...
55
56
  </template>
  <script>
6ff31952   梁灏   optimize Input sh...
57
      import iInput from '../input/input.vue';
47a7f21d   梁灏   support Cascader
58
      import Drop from '../select/dropdown.vue';
c463ab87   梁灏   add Cascader
59
60
      import Icon from '../icon/icon.vue';
      import Caspanel from './caspanel.vue';
26369639   Graham Fairweather   Update v-click-ou...
61
      import {directive as clickOutside} from 'v-click-outside-x';
a9cd43b3   梁灏   Cascader add tran...
62
      import TransferDom from '../../directives/transfer-dom';
c463ab87   梁灏   add Cascader
63
      import { oneOf } from '../../utils/assist';
47a7f21d   梁灏   support Cascader
64
      import Emitter from '../../mixins/emitter';
3ae11e85   梁灏   update Cascader
65
      import Locale from '../../mixins/locale';
6ff31952   梁灏   optimize Input sh...
66
67
  
      const prefixCls = 'ivu-cascader';
7ec0b533   梁灏   Cascader support ...
68
      const selectPrefixCls = 'ivu-select';
6ff31952   梁灏   optimize Input sh...
69
  
0a48ac45   梁灏   Input add readonl...
70
      export default {
34ee7b4a   梁灏   support Tree & ad...
71
          name: 'Cascader',
3ae11e85   梁灏   update Cascader
72
          mixins: [ Emitter, Locale ],
47a7f21d   梁灏   support Cascader
73
          components: { iInput, Drop, Icon, Caspanel },
26369639   Graham Fairweather   Update v-click-ou...
74
          directives: { clickOutside, TransferDom },
0a48ac45   梁灏   Input add readonl...
75
          props: {
6ff31952   梁灏   optimize Input sh...
76
77
78
              data: {
                  type: Array,
                  default () {
b0893113   jingsam   :art: add eslint
79
                      return [];
6ff31952   梁灏   optimize Input sh...
80
81
82
                  }
              },
              value: {
9ec927b1   梁灏   update Cascader
83
84
                  type: Array,
                  default () {
b0893113   jingsam   :art: add eslint
85
                      return [];
9ec927b1   梁灏   update Cascader
86
                  }
6ff31952   梁灏   optimize Input sh...
87
88
89
90
91
92
93
              },
              disabled: {
                  type: Boolean,
                  default: false
              },
              clearable: {
                  type: Boolean,
c463ab87   梁灏   add Cascader
94
                  default: true
6ff31952   梁灏   optimize Input sh...
95
96
              },
              placeholder: {
3ae11e85   梁灏   update Cascader
97
                  type: String
6ff31952   梁灏   optimize Input sh...
98
99
100
              },
              size: {
                  validator (value) {
a7e1c2d6   梁灏   Cascader support ...
101
102
103
                      return oneOf(value, ['small', 'large', 'default']);
                  },
                  default () {
fe5ffd7f   梁灏   fixed #4196 #4165
104
                      return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
6ff31952   梁灏   optimize Input sh...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
                  }
              },
              trigger: {
                  validator (value) {
                      return oneOf(value, ['click', 'hover']);
                  },
                  default: 'click'
              },
              changeOnSelect: {
                  type: Boolean,
                  default: false
              },
              renderFormat: {
                  type: Function,
05b5dd7b   梁灏   update Cascader
119
                  default (label) {
bd4e3b9b   梁灏   update Cascader
120
                      return label.join(' / ');
6ff31952   梁灏   optimize Input sh...
121
                  }
f7ffdac5   梁灏   Cascader support ...
122
123
124
              },
              loadData: {
                  type: Function
5a9a12cd   梁灏   update Cascader
125
126
127
128
              },
              filterable: {
                  type: Boolean,
                  default: false
952ddb51   梁灏   update Cascader
129
130
131
              },
              notFoundText: {
                  type: String
a9cd43b3   梁灏   Cascader add tran...
132
133
134
              },
              transfer: {
                  type: Boolean,
a7e1c2d6   梁灏   Cascader support ...
135
                  default () {
fe5ffd7f   梁灏   fixed #4196 #4165
136
                      return !this.$IVIEW || this.$IVIEW.transfer === '' ? false : this.$IVIEW.transfer;
a7e1c2d6   梁灏   Cascader support ...
137
                  }
0460a1e8   梁灏   fixed #812
138
139
140
              },
              name: {
                  type: String
acb79ba3   梁灏   fixed #433
141
142
143
              },
              elementId: {
                  type: String
6ff31952   梁灏   optimize Input sh...
144
              }
0a48ac45   梁灏   Input add readonl...
145
146
147
          },
          data () {
              return {
6ff31952   梁灏   optimize Input sh...
148
                  prefixCls: prefixCls,
7ec0b533   梁灏   Cascader support ...
149
                  selectPrefixCls: selectPrefixCls,
c463ab87   梁灏   add Cascader
150
151
                  visible: false,
                  selected: [],
2810d8c7   梁灏   fixed #183
152
                  tmpSelected: [],
47a7f21d   梁灏   support Cascader
153
                  updatingValue: false,    // to fix set value in changeOnSelect type
7ec0b533   梁灏   Cascader support ...
154
                  currentValue: this.value,
933afc7a   梁灏   fixed #950
155
156
157
                  query: '',
                  validDataStr: '',
                  isLoadedChildren: false    // #950
b0893113   jingsam   :art: add eslint
158
              };
0a48ac45   梁灏   Input add readonl...
159
160
          },
          computed: {
c463ab87   梁灏   add Cascader
161
162
163
164
              classes () {
                  return [
                      `${prefixCls}`,
                      {
165bb7c9   梁灏   update Cascader
165
                          [`${prefixCls}-show-clear`]: this.showCloseIcon,
3ae11e85   梁灏   update Cascader
166
                          [`${prefixCls}-size-${this.size}`]: !!this.size,
05b5dd7b   梁灏   update Cascader
167
                          [`${prefixCls}-visible`]: this.visible,
952ddb51   梁灏   update Cascader
168
169
                          [`${prefixCls}-disabled`]: this.disabled,
                          [`${prefixCls}-not-found`]: this.filterable && this.query !== '' && !this.querySelections.length
c463ab87   梁灏   add Cascader
170
                      }
b0893113   jingsam   :art: add eslint
171
                  ];
c463ab87   梁灏   add Cascader
172
173
              },
              showCloseIcon () {
65b41a2d   梁灏   fixed #635
174
                  return this.currentValue && this.currentValue.length && this.clearable && !this.disabled;
c463ab87   梁灏   add Cascader
175
              },
6ff31952   梁灏   optimize Input sh...
176
177
178
179
180
181
              displayRender () {
                  let label = [];
                  for (let i = 0; i < this.selected.length; i++) {
                      label.push(this.selected[i].label);
                  }
  
165bb7c9   梁灏   update Cascader
182
                  return this.renderFormat(label, this.selected);
7ec0b533   梁灏   Cascader support ...
183
              },
3ae11e85   梁灏   update Cascader
184
185
186
187
188
189
190
191
192
193
194
195
196
              displayInputRender () {
                  return this.filterable ? '' : this.displayRender;
              },
              localePlaceholder () {
                  if (this.placeholder === undefined) {
                      return this.t('i.select.placeholder');
                  } else {
                      return this.placeholder;
                  }
              },
              inputPlaceholder () {
                  return this.filterable && this.currentValue.length ? null : this.localePlaceholder;
              },
952ddb51   梁灏   update Cascader
197
198
199
200
201
202
203
              localeNotFoundText () {
                  if (this.notFoundText === undefined) {
                      return this.t('i.select.noMatch');
                  } else {
                      return this.notFoundText;
                  }
              },
7ec0b533   梁灏   Cascader support ...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
              querySelections () {
                  let selections = [];
                  function getSelections (arr, label, value) {
                      for (let i = 0; i < arr.length; i++) {
                          let item = arr[i];
                          item.__label = label ? label + ' / ' + item.label : item.label;
                          item.__value = value ? value + ',' + item.value : item.value;
  
                          if (item.children && item.children.length) {
                              getSelections(item.children, item.__label, item.__value);
                              delete item.__label;
                              delete item.__value;
                          } else {
                              selections.push({
                                  label: item.__label,
                                  value: item.__value,
4e23e47c   梁灏   update Cascader
220
                                  display: item.__label,
7ec0b533   梁灏   Cascader support ...
221
222
223
224
225
226
227
                                  item: item,
                                  disabled: !!item.disabled
                              });
                          }
                      }
                  }
                  getSelections(this.data);
f7caa832   GLChen   Update cascader.vue
228
                  selections = selections.filter(item => {
3288b530   梁灏   update
229
                      return item.label ? item.label.indexOf(this.query) > -1 : false;
f7caa832   GLChen   Update cascader.vue
230
                  }).map(item => {
4e23e47c   梁灏   update Cascader
231
232
233
                      item.display = item.display.replace(new RegExp(this.query, 'g'), `<span>${this.query}</span>`);
                      return item;
                  });
7ec0b533   梁灏   Cascader support ...
234
                  return selections;
47afd12e   梁灏   Cascader add gloa...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
              },
              // 3.4.0, global setting customArrow 有值时,arrow 赋值空
              arrowType () {
                  let type = 'ios-arrow-down';
  
                  if (this.$IVIEW) {
                      if (this.$IVIEW.cascader.customArrow) {
                          type = '';
                      } else if (this.$IVIEW.cascader.arrow) {
                          type = this.$IVIEW.cascader.arrow;
                      }
                  }
                  return type;
              },
              // 3.4.0, global setting
              customArrowType () {
                  let type = '';
  
                  if (this.$IVIEW) {
                      if (this.$IVIEW.cascader.customArrow) {
                          type = this.$IVIEW.cascader.customArrow;
                      }
                  }
                  return type;
              },
              // 3.4.0, global setting
              arrowSize () {
                  let size = '';
  
                  if (this.$IVIEW) {
                      if (this.$IVIEW.cascader.arrowSize) {
                          size = this.$IVIEW.cascader.arrowSize;
                      }
                  }
                  return size;
6ff31952   梁灏   optimize Input sh...
270
              }
0a48ac45   梁灏   Input add readonl...
271
272
          },
          methods: {
c463ab87   梁灏   add Cascader
273
              clearSelect () {
65b41a2d   梁灏   fixed #635
274
                  if (this.disabled) return false;
47a7f21d   梁灏   support Cascader
275
276
                  const oldVal = JSON.stringify(this.currentValue);
                  this.currentValue = this.selected = this.tmpSelected = [];
165bb7c9   梁灏   update Cascader
277
                  this.handleClose();
47a7f21d   梁灏   support Cascader
278
279
280
                  this.emitValue(this.currentValue, oldVal);
  //                this.$broadcast('on-clear');
                  this.broadcast('Caspanel', 'on-clear');
c463ab87   梁灏   add Cascader
281
282
283
284
              },
              handleClose () {
                  this.visible = false;
              },
75e5c6a5   梁灏   Cascader support ...
285
              toggleOpen () {
2aa0aa6e   Rijn   fix bug: cascader...
286
                  if (this.disabled) return false;
75e5c6a5   梁灏   Cascader support ...
287
                  if (this.visible) {
7ec0b533   梁灏   Cascader support ...
288
                      if (!this.filterable) this.handleClose();
75e5c6a5   梁灏   Cascader support ...
289
290
291
292
                  } else {
                      this.onFocus();
                  }
              },
c463ab87   梁灏   add Cascader
293
294
              onFocus () {
                  this.visible = true;
47a7f21d   梁灏   support Cascader
295
296
                  if (!this.currentValue.length) {
                      this.broadcast('Caspanel', 'on-clear');
165bb7c9   梁灏   update Cascader
297
                  }
c463ab87   梁灏   add Cascader
298
299
              },
              updateResult (result) {
bd4e3b9b   梁灏   update Cascader
300
301
                  this.tmpSelected = result;
              },
5dc44ccf   梁灏   fixed #2793
302
303
304
              updateSelected (init = false, changeOnSelectDataChange = false) {
                  // #2793 changeOnSelectDataChange used for changeOnSelect when data changed and set value
                  if (!this.changeOnSelect || init || changeOnSelectDataChange) {
47a7f21d   梁灏   support Cascader
305
306
307
                      this.broadcast('Caspanel', 'on-find-selected', {
                          value: this.currentValue
                      });
165bb7c9   梁灏   update Cascader
308
309
310
311
                  }
              },
              emitValue (val, oldVal) {
                  if (JSON.stringify(val) !== oldVal) {
47a7f21d   梁灏   support Cascader
312
                      this.$emit('on-change', this.currentValue, JSON.parse(JSON.stringify(this.selected)));
cc419499   梁灏   fixed #525
313
314
315
316
317
                      this.$nextTick(() => {
                          this.dispatch('FormItem', 'on-form-change', {
                              value: this.currentValue,
                              selected: JSON.parse(JSON.stringify(this.selected))
                          });
cd78c9c4   梁灏   some comps suppor...
318
                      });
165bb7c9   梁灏   update Cascader
319
                  }
7ec0b533   梁灏   Cascader support ...
320
321
322
323
324
325
326
327
              },
              handleInput (event) {
                  this.query = event.target.value;
              },
              handleSelectItem (index) {
                  const item = this.querySelections[index];
  
                  if (item.item.disabled) return false;
7ec0b533   梁灏   Cascader support ...
328
                  this.query = '';
3ae11e85   梁灏   update Cascader
329
                  this.$refs.input.currentValue = '';
7ec0b533   梁灏   Cascader support ...
330
331
                  const oldVal = JSON.stringify(this.currentValue);
                  this.currentValue = item.value.split(',');
2b6e6d4c   梁灏   fix #4786
332
333
334
335
336
                  // use setTimeout for #4786, can not use nextTick, because @on-find-selected use nextTick
                  setTimeout(() => {
                      this.emitValue(this.currentValue, oldVal);
                      this.handleClose();
                  }, 0);
3ae11e85   梁灏   update Cascader
337
338
339
              },
              handleFocus () {
                  this.$refs.input.focus();
933afc7a   梁灏   fixed #950
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
              },
              // 排除 loading 后的 data,避免重复触发 updateSelect
              getValidData (data) {
                  function deleteData (item) {
                      const new_item = Object.assign({}, item);
                      if ('loading' in new_item) {
                          delete new_item.loading;
                      }
                      if ('__value' in new_item) {
                          delete new_item.__value;
                      }
                      if ('__label' in new_item) {
                          delete new_item.__label;
                      }
                      if ('children' in new_item && new_item.children.length) {
                          new_item.children = new_item.children.map(i => deleteData(i));
                      }
                      return new_item;
                  }
  
                  return data.map(item => deleteData(item));
c463ab87   梁灏   add Cascader
361
362
              }
          },
687c4562   梁灏   fixed #810
363
          created () {
933afc7a   梁灏   fixed #950
364
              this.validDataStr = JSON.stringify(this.getValidData(this.data));
47a7f21d   梁灏   support Cascader
365
366
367
368
369
370
371
              this.$on('on-result-change', (params) => {
                  // lastValue: is click the final val
                  // fromInit: is this emit from update value
                  const lastValue = params.lastValue;
                  const changeOnSelect = params.changeOnSelect;
                  const fromInit = params.fromInit;
  
bd4e3b9b   梁灏   update Cascader
372
                  if (lastValue || changeOnSelect) {
47a7f21d   梁灏   support Cascader
373
                      const oldVal = JSON.stringify(this.currentValue);
bd4e3b9b   梁灏   update Cascader
374
375
376
377
378
379
                      this.selected = this.tmpSelected;
  
                      let newVal = [];
                      this.selected.forEach((item) => {
                          newVal.push(item.value);
                      });
c463ab87   梁灏   add Cascader
380
  
165bb7c9   梁灏   update Cascader
381
                      if (!fromInit) {
2810d8c7   梁灏   fixed #183
382
                          this.updatingValue = true;
47a7f21d   梁灏   support Cascader
383
384
                          this.currentValue = newVal;
                          this.emitValue(this.currentValue, oldVal);
bd4e3b9b   梁灏   update Cascader
385
386
387
388
389
                      }
                  }
                  if (lastValue && !fromInit) {
                      this.handleClose();
                  }
47a7f21d   梁灏   support Cascader
390
              });
bd4e3b9b   梁灏   update Cascader
391
          },
687c4562   梁灏   fixed #810
392
393
394
          mounted () {
              this.updateSelected(true);
          },
bd4e3b9b   梁灏   update Cascader
395
396
397
          watch: {
              visible (val) {
                  if (val) {
47a7f21d   梁灏   support Cascader
398
                      if (this.currentValue.length) {
bd4e3b9b   梁灏   update Cascader
399
400
                          this.updateSelected();
                      }
a9cd43b3   梁灏   Cascader add tran...
401
402
403
                      if (this.transfer) {
                          this.$refs.drop.update();
                      }
605bd2ae   huanghong   解决Cascader 下拉弹出位置问题
404
                      this.broadcast('Drop', 'on-update-popper');
3ae11e85   梁灏   update Cascader
405
406
407
408
409
                  } else {
                      if (this.filterable) {
                          this.query = '';
                          this.$refs.input.currentValue = '';
                      }
a9cd43b3   梁灏   Cascader add tran...
410
411
412
                      if (this.transfer) {
                          this.$refs.drop.destroy();
                      }
605bd2ae   huanghong   解决Cascader 下拉弹出位置问题
413
                      this.broadcast('Drop', 'on-destroy-popper');
bd4e3b9b   梁灏   update Cascader
414
                  }
bb1a3c38   梁灏   fixed #593
415
                  this.$emit('on-visible-change', val);
f46ebc38   梁灏   fixed #130
416
              },
47a7f21d   梁灏   support Cascader
417
418
              value (val) {
                  this.currentValue = val;
3bbb6b5f   梁灏   fixed #488
419
                  if (!val.length) this.selected = [];
47a7f21d   梁灏   support Cascader
420
421
422
              },
              currentValue () {
                  this.$emit('input', this.currentValue);
2810d8c7   梁灏   fixed #183
423
424
425
426
427
                  if (this.updatingValue) {
                      this.updatingValue = false;
                      return;
                  }
                  this.updateSelected(true);
48af1359   梁灏   fixed #553
428
              },
f7ffdac5   梁灏   Cascader support ...
429
430
431
              data: {
                  deep: true,
                  handler () {
933afc7a   梁灏   fixed #950
432
433
434
435
                      const validDataStr = JSON.stringify(this.getValidData(this.data));
                      if (validDataStr !== this.validDataStr) {
                          this.validDataStr = validDataStr;
                          if (!this.isLoadedChildren) {
5dc44ccf   梁灏   fixed #2793
436
                              this.$nextTick(() => this.updateSelected(false, this.changeOnSelect));
933afc7a   梁灏   fixed #950
437
438
439
                          }
                          this.isLoadedChildren = false;
                      }
f7ffdac5   梁灏   Cascader support ...
440
                  }
bd4e3b9b   梁灏   update Cascader
441
              }
0a48ac45   梁灏   Input add readonl...
442
          }
b0893113   jingsam   :art: add eslint
443
444
      };
  </script>