Blame view

src/components/slider/slider.vue 11.2 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"
adc203b9   Sergio Crisostomo   correct input dis...
8
              :value="currentValue[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">
0460a1e8   梁灏   fixed #812
12
              <input type="hidden" :name="name" :value="currentValue">
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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
              <div
                  :class="[prefixCls + '-button-wrap']"
                  :style="{left: minPosition + '%'}"
                  @touchstart="onPointerDown($event, 'min')"
                  @mousedown="onPointerDown($event, 'min')">
                  <Tooltip :controlled="pointerDown === 'min'" placement="top" :content="tipFormat(currentValue[0])"
                           :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')">
                  <Tooltip :controlled="pointerDown === 'max'" placement="top" :content="tipFormat(currentValue[1])"
                           :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
113
                  startX: 0,
                  currentX: 0,
                  startPos: 0,
                  newPos: null,
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
114
                  oldValue: val
b0893113   jingsam   :art: add eslint
115
              };
36febc3c   梁灏   add Slider
116
          },
1c803cdf   梁灏   support Slider
117
118
          watch: {
              value (val) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
119
120
121
122
                  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
123
124
125
              },
              currentValue (val) {
                  this.$nextTick(() => {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
126
                      this.$refs.minTooltip.updatePopper();
1c803cdf   梁灏   support Slider
127
                      if (this.range) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
128
                          this.$refs.maxTooltip.updatePopper();
1c803cdf   梁灏   support Slider
129
130
                      }
                  });
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
131
132
133
                  const exportValue = this.range ? val : val[0];
                  this.$emit('input', exportValue);
                  this.$emit('on-input', exportValue);
1c803cdf   梁灏   support Slider
134
135
              }
          },
36febc3c   梁灏   add Slider
136
137
138
139
140
          computed: {
              classes () {
                  return [
                      `${prefixCls}`,
                      {
69576f47   梁灏   add Slider component
141
                          [`${prefixCls}-input`]: this.showInput && !this.range,
36febc3c   梁灏   add Slider
142
143
144
                          [`${prefixCls}-range`]: this.range,
                          [`${prefixCls}-disabled`]: this.disabled
                      }
b0893113   jingsam   :art: add eslint
145
                  ];
36febc3c   梁灏   add Slider
146
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
147
              minButtonClasses () {
69576f47   梁灏   add Slider component
148
149
150
                  return [
                      `${prefixCls}-button`,
                      {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
151
                          [`${prefixCls}-button-dragging`]: this.pointerDown === 'min'
69576f47   梁灏   add Slider component
152
153
154
                      }
                  ];
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
155
              maxButtonClasses () {
69576f47   梁灏   add Slider component
156
157
158
                  return [
                      `${prefixCls}-button`,
                      {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
159
                          [`${prefixCls}-button-dragging`]: this.pointerDown === 'max'
69576f47   梁灏   add Slider component
160
161
162
                      }
                  ];
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
163
164
165
166
167
168
169
170
              minPosition () {
                  const val = this.currentValue;
                  return (val[0] - this.min) / (this.max - this.min) * 100;
              },
              maxPosition: function () {
                  const val = this.currentValue;
  
                  return (val[1] - this.min) / (this.max - this.min) * 100;
69576f47   梁灏   add Slider component
171
              },
36febc3c   梁灏   add Slider
172
              barStyle () {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
173
174
175
                  const style = {
                      left: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%'
                  };
36febc3c   梁灏   add Slider
176
177
  
                  if (this.range) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
178
                      style.width = (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%';
36febc3c   梁灏   add Slider
179
180
181
182
                  }
  
                  return style;
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
183
              stops () {
41d90ccf   梁灏   Slider can show s...
184
185
186
187
188
189
190
                  let stopCount = (this.max - this.min) / this.step;
                  let result = [];
                  let stepWidth = 100 * this.step / (this.max - this.min);
                  for (let i = 1; i < stopCount; i++) {
                      result.push(i * stepWidth);
                  }
                  return result;
69576f47   梁灏   add Slider component
191
192
              },
              sliderWidth () {
1c803cdf   梁灏   support Slider
193
                  return parseInt(getStyle(this.$refs.slider, 'width'), 10);
59872199   Rijn   added show-tip to...
194
195
              },
              tipDisabled () {
1c803cdf   梁灏   support Slider
196
                  return this.tipFormat(this.currentValue[0]) === null || this.showTip === 'never';
36febc3c   梁灏   add Slider
197
198
199
              }
          },
          methods: {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
200
201
              getPointerX (e) {
                  return e.type.indexOf('touch') !== -1 ? e.touches[0].clientX : e.clientX;
69576f47   梁灏   add Slider component
202
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
203
204
205
              checkLimits ([min, max]) {
                  min = Math.max(0, min);
                  min = Math.min(100, min);
36febc3c   梁灏   add Slider
206
  
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
207
208
209
                  max = Math.max(0, min, max);
                  max = Math.min(100, max);
                  return [min, max];
69576f47   梁灏   add Slider component
210
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
211
              onPointerDown (event, type) {
69576f47   梁灏   add Slider component
212
                  if (this.disabled) return;
f2be585e   梁灏   optimize Slider w...
213
                  event.preventDefault();
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
214
215
216
217
218
219
220
                  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
221
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
222
              onPointerDragStart (event) {
ce4c0faa   oustn   修复 Slider 滑动按钮单击时...
223
                  this.dragging = false;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
224
225
                  this.startX = this.getPointerX(event);
                  this.startPos = parseInt(this[`${this.pointerDown}Position`], 10);
69576f47   梁灏   add Slider component
226
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
227
              onPointerDrag (event) {
ce4c0faa   oustn   修复 Slider 滑动按钮单击时...
228
                  this.dragging = true;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
229
230
231
232
233
234
                  this.$refs[`${this.pointerDown}Tooltip`].visible = true;
                  this.currentX = this.getPointerX(event);
  
                  const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
                  this.newPos = this.startPos + diff;
                  this.changeButtonPosition(this.newPos);
69576f47   梁灏   add Slider component
235
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
236
              onPointerDragEnd () {
69576f47   梁灏   add Slider component
237
238
                  if (this.dragging) {
                      this.dragging = false;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
239
240
                      this.$refs[`${this.pointerDown}Tooltip`].visible = false;
                      this.changeButtonPosition(this.newPos);
69576f47   梁灏   add Slider component
241
                  }
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
242
243
244
245
246
247
  
                  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
248
              },
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
249
250
251
252
253
254
255
              changeButtonPosition (newPos, forceType) {
  
                  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];
  
a6fc9438   梁灏   fixed #461
256
257
                  const lengthPerStep = 100 / ((this.max - this.min) / this.step);
                  const steps = Math.round(newPos / lengthPerStep);
69576f47   梁灏   add Slider component
258
  
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
259
260
261
262
                  const value = this.currentValue;
                  value[index] = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
                  this.currentValue = [...value];
  
a6fc9438   梁灏   fixed #461
263
                  if (!this.dragging) {
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
264
265
266
267
268
                      if (this.currentValue[index] !== this.oldValue[index]) {
                          const exportValue = this.range ? this.currentValue : this.currentValue[0];
                          this.$emit('on-change', exportValue);
                          this.dispatch('FormItem', 'on-form-change', exportValue);
                          this.oldValue[index] = this.currentValue[index];
69576f47   梁灏   add Slider component
269
270
271
                      }
                  }
              },
69576f47   梁灏   add Slider component
272
  
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
273
274
  
              sliderClick: function (event) {
69576f47   梁灏   add Slider component
275
                  if (this.disabled) return;
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
276
277
278
279
280
281
282
                  const currentX = this.getPointerX(event);
                  const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
                  const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100;
  
                  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
283
              },
69576f47   梁灏   add Slider component
284
  
2b87ffa9   Sergio Crisostomo   refactor and DRY ...
285
286
287
288
289
              handleInputChange (val) {
                  this.currentValue = [val, this.currentValue[1]];
                  const exportValue = this.range ? this.currentValue : this.currentValue[0];
                  this.$emit('on-change', exportValue);
                  this.dispatch('FormItem', 'on-form-change', exportValue);
69576f47   梁灏   add Slider component
290
              },
36febc3c   梁灏   add Slider
291
          }
b0893113   jingsam   :art: add eslint
292
293
      };
  </script>