Blame view

src/components/slider/slider.vue 13.8 KB
36febc3c   梁灏   add Slider
1
2
  <template>
      <div :class="classes">
69576f47   梁灏   add Slider component
3
4
5
6
7
          <Input-number
              v-if="!range && showInput"
              :min="min"
              :max="max"
              :step="step"
e3549149   Sergio Crisostomo   normalise public ...
8
              :value="exportValue[0]"
69576f47   梁灏   add Slider component
9
10
              :disabled="disabled"
              @on-change="handleInputChange"></Input-number>
791d254e   Graham Fairweather   Slider: Keyboard ...
11
12
13
14
          <div
              :class="[prefixCls + '-wrap']"
              ref="slider" @click.self="sliderClick"
          >
e3549149   Sergio Crisostomo   normalise public ...
15
              <input type="hidden" :name="name" :value="exportValue">
36febc3c   梁灏   add Slider
16
              <template v-if="showStops">
791d254e   Graham Fairweather   Slider: Keyboard ...
17
18
19
20
21
22
                  <div
                      :class="[prefixCls + '-stop']"
                      v-for="item in stops"
                      :style="{ 'left': item + '%' }"
                      @click.self="sliderClick"
                  ></div>
36febc3c   梁灏   add Slider
23
              </template>
791d254e   Graham Fairweather   Slider: Keyboard ...
24
25
26
27
              <div
                  :class="[prefixCls + '-bar']"
                  :style="barStyle"
                  @click.self="sliderClick"></div>
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
28
29
30
31
32
              <div
                  :class="[prefixCls + '-button-wrap']"
                  :style="{left: minPosition + '%'}"
                  @touchstart="onPointerDown($event, 'min')"
                  @mousedown="onPointerDown($event, 'min')">
791d254e   Graham Fairweather   Slider: Keyboard ...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
                  <Tooltip
                      :controlled="pointerDown === 'min'"
                      placement="top"
                      :content="tipFormat(exportValue[0])"
                      :disabled="tipDisabled"
                      :always="showTip === 'always'"
                      ref="minTooltip"
                  >
                      <div
                          :class="minButtonClasses"
                          tabindex="0"
                          @keydown.left="onKeyLeft($event, 'min')"
                          @keydown.down="onKeyLeft($event, 'min')"
                          @keydown.right="onKeyRight($event, 'min')"
                          @keydown.up="onKeyRight($event, 'min')"
                      ></div>
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
49
50
51
52
53
54
55
                  </Tooltip>
              </div>
              <div v-if="range"
                   :class="[prefixCls + '-button-wrap']"
                   :style="{left: maxPosition + '%'}"
                   @touchstart="onPointerDown($event, 'max')"
                   @mousedown="onPointerDown($event, 'max')">
791d254e   Graham Fairweather   Slider: Keyboard ...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
                  <Tooltip
                      :controlled="pointerDown === 'max'"
                      placement="top"
                      :content="tipFormat(exportValue[1])"
                      :disabled="tipDisabled"
                      :always="showTip === 'always'"
                      ref="maxTooltip"
                  >
                      <div
                          :class="maxButtonClasses"
                          tabindex="0"
                          @keydown.left="onKeyLeft($event, 'max')"
                          @keydown.down="onKeyLeft($event, 'max')"
                          @keydown.right="onKeyRight($event, 'max')"
                          @keydown.up="onKeyRight($event, 'max')"
                      ></div>
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
72
73
                  </Tooltip>
              </div>
36febc3c   梁灏   add Slider
74
75
76
77
78
79
          </div>
      </div>
  </template>
  <script>
      import InputNumber from '../../components/input-number/input-number.vue';
      import Tooltip from '../../components/tooltip/tooltip.vue';
59872199   Rijn   added show-tip to...
80
      import { getStyle, oneOf } from '../../utils/assist';
825ed580   梁灏   fixed bug
81
      import { on, off } from '../../utils/dom';
cd78c9c4   梁灏   some comps suppor...
82
      import Emitter from '../../mixins/emitter';
36febc3c   梁灏   add Slider
83
84
85
86
  
      const prefixCls = 'ivu-slider';
  
      export default {
b1c118d8   梁灏   support Dropdown
87
          name: 'Slider',
cd78c9c4   梁灏   some comps suppor...
88
          mixins: [ Emitter ],
36febc3c   梁灏   add Slider
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
          components: { InputNumber, Tooltip },
          props: {
              min: {
                  type: Number,
                  default: 0
              },
              max: {
                  type: Number,
                  default: 100
              },
              step: {
                  type: Number,
                  default: 1
              },
              range: {
                  type: Boolean,
                  default: false
              },
              value: {
                  type: [Number, Array],
                  default: 0
              },
              disabled: {
                  type: Boolean,
                  default: false
              },
              showInput: {
                  type: Boolean,
                  default: false
              },
              showStops: {
                  type: Boolean,
                  default: false
              },
              tipFormat: {
                  type: Function,
                  default (val) {
                      return val;
                  }
59872199   Rijn   added show-tip to...
128
129
130
131
132
133
134
              },
              showTip: {
                  type: String,
                  default: 'hover',
                  validator (value) {
                      return oneOf(value, ['hover', 'always', 'never']);
                  }
0460a1e8   梁灏   fixed #812
135
136
137
              },
              name: {
                  type: String
36febc3c   梁灏   add Slider
138
139
140
              }
          },
          data () {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
141
              const val = this.checkLimits(Array.isArray(this.value) ? this.value : [this.value]);
36febc3c   梁灏   add Slider
142
              return {
69576f47   梁灏   add Slider component
143
                  prefixCls: prefixCls,
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
144
                  currentValue: val,
69576f47   梁灏   add Slider component
145
                  dragging: false,
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
146
                  pointerDown: '',
69576f47   梁灏   add Slider component
147
148
149
                  startX: 0,
                  currentX: 0,
                  startPos: 0,
791d254e   Graham Fairweather   Slider: Keyboard ...
150
151
152
153
154
                  oldValue: val,
                  valueIndex: {
                      min: 0,
                      max: 1,
                  },
b0893113   jingsam   :art: add eslint
155
              };
36febc3c   梁灏   add Slider
156
          },
1c803cdf   梁灏   support Slider
157
158
          watch: {
              value (val) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
159
160
161
162
                  val = this.checkLimits(Array.isArray(val) ? val : [val]);
                  if (val[0] !== this.currentValue[0] || val[1] !== this.currentValue[1]) {
                      this.currentValue = val;
                  }
1c803cdf   梁灏   support Slider
163
              },
e3549149   Sergio Crisostomo   normalise public ...
164
              exportValue (values) {
1c803cdf   梁灏   support Slider
165
                  this.$nextTick(() => {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
166
                      this.$refs.minTooltip.updatePopper();
1c803cdf   梁灏   support Slider
167
                      if (this.range) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
168
                          this.$refs.maxTooltip.updatePopper();
1c803cdf   梁灏   support Slider
169
170
                      }
                  });
e3549149   Sergio Crisostomo   normalise public ...
171
172
173
                  const value = this.range ? values : values[0];
                  this.$emit('input', value);
                  this.$emit('on-input', value);
1c803cdf   梁灏   support Slider
174
175
              }
          },
36febc3c   梁灏   add Slider
176
177
178
179
180
          computed: {
              classes () {
                  return [
                      `${prefixCls}`,
                      {
69576f47   梁灏   add Slider component
181
                          [`${prefixCls}-input`]: this.showInput && !this.range,
36febc3c   梁灏   add Slider
182
183
184
                          [`${prefixCls}-range`]: this.range,
                          [`${prefixCls}-disabled`]: this.disabled
                      }
b0893113   jingsam   :art: add eslint
185
                  ];
36febc3c   梁灏   add Slider
186
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
187
              minButtonClasses () {
69576f47   梁灏   add Slider component
188
189
190
                  return [
                      `${prefixCls}-button`,
                      {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
191
                          [`${prefixCls}-button-dragging`]: this.pointerDown === 'min'
69576f47   梁灏   add Slider component
192
193
194
                      }
                  ];
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
195
              maxButtonClasses () {
69576f47   梁灏   add Slider component
196
197
198
                  return [
                      `${prefixCls}-button`,
                      {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
199
                          [`${prefixCls}-button-dragging`]: this.pointerDown === 'max'
69576f47   梁灏   add Slider component
200
201
202
                      }
                  ];
              },
e3549149   Sergio Crisostomo   normalise public ...
203
204
205
206
              exportValue(){
                  const decimalCases = (String(this.step).split('.')[1] || '').length;
                  return this.currentValue.map(nr => Number(nr.toFixed(decimalCases)));
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
207
208
              minPosition () {
                  const val = this.currentValue;
965b6d8e   Sergio Crisostomo   Fix slider for m...
209
                  return (val[0] - this.min) / this.valueRange * 100;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
210
211
212
213
              },
              maxPosition: function () {
                  const val = this.currentValue;
  
965b6d8e   Sergio Crisostomo   Fix slider for m...
214
                  return (val[1] - this.min) / this.valueRange * 100;
69576f47   梁灏   add Slider component
215
              },
36febc3c   梁灏   add Slider
216
              barStyle () {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
217
                  const style = {
965b6d8e   Sergio Crisostomo   Fix slider for m...
218
                      width: (this.currentValue[0] - this.min) / this.valueRange * 100 + '%'
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
219
                  };
36febc3c   梁灏   add Slider
220
221
  
                  if (this.range) {
965b6d8e   Sergio Crisostomo   Fix slider for m...
222
223
                      style.left = (this.currentValue[0] - this.min) / this.valueRange * 100 + '%';
                      style.width = (this.currentValue[1] - this.currentValue[0]) / this.valueRange * 100 + '%';
36febc3c   梁灏   add Slider
224
225
226
227
                  }
  
                  return style;
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
228
              stops () {
965b6d8e   Sergio Crisostomo   Fix slider for m...
229
                  let stopCount = this.valueRange / this.step;
41d90ccf   梁灏   Slider can show s...
230
                  let result = [];
965b6d8e   Sergio Crisostomo   Fix slider for m...
231
                  let stepWidth = 100 * this.step / this.valueRange;
41d90ccf   梁灏   Slider can show s...
232
233
234
235
                  for (let i = 1; i < stopCount; i++) {
                      result.push(i * stepWidth);
                  }
                  return result;
69576f47   梁灏   add Slider component
236
237
              },
              sliderWidth () {
1c803cdf   梁灏   support Slider
238
                  return parseInt(getStyle(this.$refs.slider, 'width'), 10);
59872199   Rijn   added show-tip to...
239
240
              },
              tipDisabled () {
1c803cdf   梁灏   support Slider
241
                  return this.tipFormat(this.currentValue[0]) === null || this.showTip === 'never';
965b6d8e   Sergio Crisostomo   Fix slider for m...
242
243
244
              },
              valueRange(){
                  return this.max - this.min;
36febc3c   梁灏   add Slider
245
246
247
              }
          },
          methods: {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
248
249
              getPointerX (e) {
                  return e.type.indexOf('touch') !== -1 ? e.touches[0].clientX : e.clientX;
69576f47   梁灏   add Slider component
250
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
251
              checkLimits ([min, max]) {
965b6d8e   Sergio Crisostomo   Fix slider for m...
252
253
                  min = Math.max(this.min, min);
                  min = Math.min(this.max, min);
36febc3c   梁灏   add Slider
254
  
965b6d8e   Sergio Crisostomo   Fix slider for m...
255
256
                  max = Math.max(this.min, min, max);
                  max = Math.min(this.max, max);
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
257
                  return [min, max];
69576f47   梁灏   add Slider component
258
              },
791d254e   Graham Fairweather   Slider: Keyboard ...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
              getCurrentValue (event, type) {
                if (this.disabled) {
                  return;
                }
  
                const index = this.valueIndex[type];
                if (typeof index === 'undefined') {
                  return;
                }
  
                return this.currentValue[index];
              },
              onKeyLeft (event, type) {
                const value = this.getCurrentValue(event, type);
                if (Number.isFinite(value)) {
                  this.changeButtonPosition(value - this.step, type);
                }
              },
              onKeyRight (event, type) {
                const value = this.getCurrentValue(event, type);
                if (Number.isFinite(value)) {
                  this.changeButtonPosition(value + this.step, type);
                }
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
283
              onPointerDown (event, type) {
69576f47   梁灏   add Slider component
284
                  if (this.disabled) return;
f2be585e   梁灏   optimize Slider w...
285
                  event.preventDefault();
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
286
287
288
289
290
291
292
                  this.pointerDown = type;
  
                  this.onPointerDragStart(event);
                  on(window, 'mousemove', this.onPointerDrag);
                  on(window, 'touchmove', this.onPointerDrag);
                  on(window, 'mouseup', this.onPointerDragEnd);
                  on(window, 'touchend', this.onPointerDragEnd);
69576f47   梁灏   add Slider component
293
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
294
              onPointerDragStart (event) {
ce4c0faa   oustn   修复 Slider 滑动按钮单击时...
295
                  this.dragging = false;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
296
                  this.startX = this.getPointerX(event);
965b6d8e   Sergio Crisostomo   Fix slider for m...
297
                  this.startPos = (this[`${this.pointerDown}Position`] * this.valueRange / 100) + this.min;
69576f47   梁灏   add Slider component
298
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
299
              onPointerDrag (event) {
ce4c0faa   oustn   修复 Slider 滑动按钮单击时...
300
                  this.dragging = true;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
301
302
                  this.$refs[`${this.pointerDown}Tooltip`].visible = true;
                  this.currentX = this.getPointerX(event);
965b6d8e   Sergio Crisostomo   Fix slider for m...
303
                  const diff = (this.currentX - this.startX) / this.sliderWidth * this.valueRange;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
304
  
965b6d8e   Sergio Crisostomo   Fix slider for m...
305
                  this.changeButtonPosition(this.startPos + diff);
69576f47   梁灏   add Slider component
306
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
307
              onPointerDragEnd () {
69576f47   梁灏   add Slider component
308
309
                  if (this.dragging) {
                      this.dragging = false;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
310
                      this.$refs[`${this.pointerDown}Tooltip`].visible = false;
b964efae   Sergio Crisostomo   Emit change on po...
311
                      this.emitChange();
69576f47   梁灏   add Slider component
312
                  }
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
313
314
315
316
317
318
  
                  this.pointerDown = '';
                  off(window, 'mousemove', this.onPointerDrag);
                  off(window, 'touchmove', this.onPointerDrag);
                  off(window, 'mouseup', this.onPointerDragEnd);
                  off(window, 'touchend', this.onPointerDragEnd);
69576f47   梁灏   add Slider component
319
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
320
              changeButtonPosition (newPos, forceType) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
321
322
323
324
325
                  const type = forceType || this.pointerDown;
                  const index = type === 'min' ? 0 : 1;
                  if (type === 'min') newPos = this.checkLimits([newPos, this.maxPosition])[0];
                  else newPos = this.checkLimits([this.minPosition, newPos])[1];
  
eb8c6cd9   Sergio Crisostomo   Correct steps cal...
326
                  const modulus = newPos % this.step;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
327
                  const value = this.currentValue;
eb8c6cd9   Sergio Crisostomo   Correct steps cal...
328
                  value[index] = newPos - modulus;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
329
330
                  this.currentValue = [...value];
  
a6fc9438   梁灏   fixed #461
331
                  if (!this.dragging) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
332
                      if (this.currentValue[index] !== this.oldValue[index]) {
b964efae   Sergio Crisostomo   Emit change on po...
333
                          this.emitChange();
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
334
                          this.oldValue[index] = this.currentValue[index];
69576f47   梁灏   add Slider component
335
336
337
                      }
                  }
              },
69576f47   梁灏   add Slider component
338
  
b964efae   Sergio Crisostomo   Emit change on po...
339
              emitChange(){
e3549149   Sergio Crisostomo   normalise public ...
340
341
342
                  const value = this.range ? this.exportValue : this.exportValue[0];
                  this.$emit('on-change', value);
                  this.dispatch('FormItem', 'on-form-change', value);
b964efae   Sergio Crisostomo   Emit change on po...
343
344
              },
  
2eccfc99   梁灏   fixed #2852
345
              sliderClick (event) {
69576f47   梁灏   add Slider component
346
                  if (this.disabled) return;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
347
348
                  const currentX = this.getPointerX(event);
                  const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
965b6d8e   Sergio Crisostomo   Fix slider for m...
349
                  let newPos = ((currentX - sliderOffsetLeft) / this.sliderWidth * this.valueRange) + this.min;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
350
351
352
353
  
                  if (!this.range || newPos <= this.minPosition) this.changeButtonPosition(newPos, 'min');
                  else if (newPos >= this.maxPosition) this.changeButtonPosition(newPos, 'max');
                  else this.changeButtonPosition(newPos, ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) ? 'min' : 'max');
69576f47   梁灏   add Slider component
354
              },
69576f47   梁灏   add Slider component
355
  
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
356
357
              handleInputChange (val) {
                  this.currentValue = [val, this.currentValue[1]];
e3549149   Sergio Crisostomo   normalise public ...
358
                  this.emitChange();
69576f47   梁灏   add Slider component
359
              },
2eccfc99   梁灏   fixed #2852
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
          },
          mounted () {
              // #2852
              this.$on('on-visible-change', (val) => {
                  if (val && this.showTip === 'always') {
                      this.$refs.minTooltip.doDestroy();
                      if (this.range) {
                          this.$refs.maxTooltip.doDestroy();
                      }
                      this.$nextTick(() => {
                          this.$refs.minTooltip.updatePopper();
                          if (this.range) {
                              this.$refs.maxTooltip.updatePopper();
                          }
                      });
                  }
              });
36febc3c   梁灏   add Slider
377
          }
b0893113   jingsam   :art: add eslint
378
379
      };
  </script>