Blame view

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