Commit 3537176f984f8979f8b6c0f0ea9c3993a0f3359f

Authored by Aresn
Committed by GitHub
2 parents 41102077 3e9a7f97

Merge pull request #2393 from SergioCrisostomo/refactor-slider

Refactor slider
Showing 2 changed files with 145 additions and 308 deletions   Show diff stats
examples/routers/slider.vue
1 1 <template>
2 2 <div style="margin: 0 400px;">
3   - <Slider v-model="value" range></Slider>
4   - <Button @click="change">change</Button>
  3 + <Slider v-model="valueSingle" @on-change="updateSingleDisplayValue"></Slider>
  4 + <Button @click="randomSingle">change</Button> {{singleDisplayValue}}
  5 +
  6 + <Slider v-model="valueRange" range @on-change="updateRangeDisplayValue"></Slider>
  7 + <Button @click="randomRange">change</Button> {{rangeDisplayValue}}
5 8 </div>
6 9 </template>
7 10 <script>
8 11 export default {
9 12 data () {
10 13 return {
11   - value: [20, 50]
12   - }
  14 + valueSingle: 10,
  15 + valueRange: [20, 50],
  16 + singleDisplayValue: 10,
  17 + rangeDisplayValue: [20, 50]
  18 + };
13 19 },
14 20 methods: {
15   - change () {
16   - this.value = [30, 80];
  21 + updateSingleDisplayValue (val){
  22 + console.log('updateSingleDisplayValue', val);
  23 + this.singleDisplayValue = val;
  24 + },
  25 + updateRangeDisplayValue (val){
  26 + console.log('updateRangeDisplayValue', val);
  27 + this.rangeDisplayValue = val.join(' - ');
  28 + },
  29 + randomSingle () {
  30 + this.valueSingle = this.random(0, 100);
  31 + },
  32 + randomRange () {
  33 + this.valueRange = [this.random(0, 50), this.random(50, 100)];
  34 + },
  35 + random (min, max){
  36 + return Math.round(Math.random() * (max - min)) + min;
17 37 }
18 38 }
19   - }
  39 + };
20 40 </script>
... ...
src/components/slider/slider.vue
... ... @@ -5,7 +5,7 @@
5 5 :min="min"
6 6 :max="max"
7 7 :step="step"
8   - :value="currentValue"
  8 + :value="currentValue[0]"
9 9 :disabled="disabled"
10 10 @on-change="handleInputChange"></Input-number>
11 11 <div :class="[prefixCls + '-wrap']" ref="slider" @click.self="sliderClick">
... ... @@ -14,34 +14,26 @@
14 14 <div :class="[prefixCls + '-stop']" v-for="item in stops" :style="{ 'left': item + '%' }" @click.self="sliderClick"></div>
15 15 </template>
16 16 <div :class="[prefixCls + '-bar']" :style="barStyle" @click.self="sliderClick"></div>
17   - <template v-if="range">
18   - <div
19   - :class="[prefixCls + '-button-wrap']"
20   - :style="{left: firstPosition + '%'}"
21   - @mousedown="onFirstButtonDown">
22   - <Tooltip :controlled="firstDragging" placement="top" :content="tipFormat(currentValue[0])" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip">
23   - <div :class="button1Classes"></div>
24   - </Tooltip>
25   - </div>
26   - <div
27   - :class="[prefixCls + '-button-wrap']"
28   - :style="{left: secondPosition + '%'}"
29   - @mousedown="onSecondButtonDown">
30   - <Tooltip :controlled="secondDragging" placement="top" :content="tipFormat(currentValue[1])" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip2">
31   - <div :class="button2Classes"></div>
32   - </Tooltip>
33   - </div>
34   - </template>
35   - <template v-else>
36   - <div
37   - :class="[prefixCls + '-button-wrap']"
38   - :style="{left: singlePosition + '%'}"
39   - @mousedown="onSingleButtonDown">
40   - <Tooltip :controlled="dragging" placement="top" :content="tipFormat(currentValue)" :disabled="tipDisabled" :always="showTip === 'always'" ref="tooltip">
41   - <div :class="buttonClasses"></div>
42   - </Tooltip>
43   - </div>
44   - </template>
  17 + <div
  18 + :class="[prefixCls + '-button-wrap']"
  19 + :style="{left: minPosition + '%'}"
  20 + @touchstart="onPointerDown($event, 'min')"
  21 + @mousedown="onPointerDown($event, 'min')">
  22 + <Tooltip :controlled="pointerDown === 'min'" placement="top" :content="tipFormat(currentValue[0])"
  23 + :disabled="tipDisabled" :always="showTip === 'always'" ref="minTooltip">
  24 + <div :class="minButtonClasses"></div>
  25 + </Tooltip>
  26 + </div>
  27 + <div v-if="range"
  28 + :class="[prefixCls + '-button-wrap']"
  29 + :style="{left: maxPosition + '%'}"
  30 + @touchstart="onPointerDown($event, 'max')"
  31 + @mousedown="onPointerDown($event, 'max')">
  32 + <Tooltip :controlled="pointerDown === 'max'" placement="top" :content="tipFormat(currentValue[1])"
  33 + :disabled="tipDisabled" :always="showTip === 'always'" ref="maxTooltip">
  34 + <div :class="maxButtonClasses"></div>
  35 + </Tooltip>
  36 + </div>
45 37 </div>
46 38 </div>
47 39 </template>
... ... @@ -109,38 +101,36 @@
109 101 }
110 102 },
111 103 data () {
  104 + const val = this.checkLimits(Array.isArray(this.value) ? this.value : [this.value]);
112 105 return {
113 106 prefixCls: prefixCls,
114   - currentValue: this.value,
  107 + currentValue: val,
115 108 dragging: false,
116   - firstDragging: false,
117   - secondDragging: false,
  109 + pointerDown: '',
118 110 startX: 0,
119 111 currentX: 0,
120 112 startPos: 0,
121 113 newPos: null,
122   - oldSingleValue: this.value,
123   - oldFirstValue: this.value[0],
124   - oldSecondValue: this.value[1],
125   - singlePosition: (this.value - this.min) / (this.max - this.min) * 100,
126   - firstPosition: (this.value[0] - this.min) / (this.max - this.min) * 100,
127   - secondPosition: (this.value[1] - this.min) / (this.max - this.min) * 100
  114 + oldValue: val
128 115 };
129 116 },
130 117 watch: {
131 118 value (val) {
132   - this.currentValue = val;
  119 + val = this.checkLimits(Array.isArray(val) ? val : [val]);
  120 + if (val[0] !== this.currentValue[0] || val[1] !== this.currentValue[1]) {
  121 + this.currentValue = val;
  122 + }
133 123 },
134 124 currentValue (val) {
135 125 this.$nextTick(() => {
136   - this.$refs.tooltip.updatePopper();
  126 + this.$refs.minTooltip.updatePopper();
137 127 if (this.range) {
138   - this.$refs.tooltip2.updatePopper();
  128 + this.$refs.maxTooltip.updatePopper();
139 129 }
140 130 });
141   - this.updateValue(val);
142   - this.$emit('input', val);
143   - this.$emit('on-input', val);
  131 + const exportValue = this.range ? val : val[0];
  132 + this.$emit('input', exportValue);
  133 + this.$emit('on-input', exportValue);
144 134 }
145 135 },
146 136 computed: {
... ... @@ -154,47 +144,45 @@
154 144 }
155 145 ];
156 146 },
157   - buttonClasses () {
  147 + minButtonClasses () {
158 148 return [
159 149 `${prefixCls}-button`,
160 150 {
161   - [`${prefixCls}-button-dragging`]: this.dragging
  151 + [`${prefixCls}-button-dragging`]: this.pointerDown === 'min'
162 152 }
163 153 ];
164 154 },
165   - button1Classes () {
  155 + maxButtonClasses () {
166 156 return [
167 157 `${prefixCls}-button`,
168 158 {
169   - [`${prefixCls}-button-dragging`]: this.firstDragging
  159 + [`${prefixCls}-button-dragging`]: this.pointerDown === 'max'
170 160 }
171 161 ];
172 162 },
173   - button2Classes () {
174   - return [
175   - `${prefixCls}-button`,
176   - {
177   - [`${prefixCls}-button-dragging`]: this.secondDragging
178   - }
179   - ];
  163 + minPosition () {
  164 + const val = this.currentValue;
  165 + return (val[0] - this.min) / (this.max - this.min) * 100;
  166 + },
  167 + maxPosition: function () {
  168 + const val = this.currentValue;
  169 +
  170 + return (val[1] - this.min) / (this.max - this.min) * 100;
180 171 },
181 172 barStyle () {
182   - let style;
  173 +
  174 + const style = {
  175 + width: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%'
  176 + };
183 177  
184 178 if (this.range) {
185   - style = {
186   - width: (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%',
187   - left: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%'
188   - };
189   - } else {
190   - style = {
191   - width: (this.currentValue - this.min) / (this.max - this.min) * 100 + '%'
192   - };
  179 + style.left = (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%';
  180 + style.width = (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%';
193 181 }
194 182  
195 183 return style;
196 184 },
197   - stops() {
  185 + stops () {
198 186 let stopCount = (this.max - this.min) / this.step;
199 187 let result = [];
200 188 let stepWidth = 100 * this.step / (this.max - this.min);
... ... @@ -211,268 +199,97 @@
211 199 }
212 200 },
213 201 methods: {
214   - updateValue (val, init = false) {
215   - if (this.range) {
216   - let value = [...val];
217   - if (init) {
218   - if (value[0] > value[1]) {
219   - value = [this.min, this.max];
220   - }
221   - } else {
222   - if (value[0] > value[1]) {
223   - value[0] = value[1];
224   - }
225   - }
226   - if (value[0] < this.min) {
227   - value[0] = this.min;
228   - }
229   - if (value[0] > this.max) {
230   - value[0] = this.max;
231   - }
232   - if (value[1] < this.min) {
233   - value[1] = this.min;
234   - }
235   - if (value[1] > this.max) {
236   - value[1] = this.max;
237   - }
238   - if (this.value[0] === value[0] && this.value[1] === value[1]) {
239   - this.setFirstPosition(this.currentValue[0]);
240   - this.setSecondPosition(this.currentValue[1]);
241   - return;
242   - }
243   -
244   - this.currentValue = value;
245   - this.setFirstPosition(this.currentValue[0]);
246   - this.setSecondPosition(this.currentValue[1]);
247   - } else {
248   - if (val < this.min) {
249   - this.currentValue = this.min;
250   - }
251   - if (val > this.max) {
252   - this.currentValue = this.max;
253   - }
254   - this.setSinglePosition(this.currentValue);
255   - }
  202 + getPointerX (e) {
  203 + return e.type.indexOf('touch') !== -1 ? e.touches[0].clientX : e.clientX;
256 204 },
257   - sliderClick (event) {
258   - if (this.disabled) return;
259   - const currentX = event.clientX;
260   - const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
261   - const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100;
  205 + checkLimits ([min, max]) {
  206 + min = Math.max(0, min);
  207 + min = Math.min(100, min);
262 208  
263   - if (this.range) {
264   - let type = '';
265   - if (newPos <= this.firstPosition) {
266   - type = 'First';
267   - } else if (newPos >= this.secondPosition) {
268   - type = 'Second';
269   - } else {
270   - if ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) {
271   - type = 'First';
272   - } else {
273   - type = 'Second';
274   - }
275   - }
276   - this[`change${type}Position`](newPos);
277   - } else {
278   - this.changeSinglePosition(newPos);
279   - }
  209 + max = Math.max(0, min, max);
  210 + max = Math.min(100, max);
  211 + return [min, max];
280 212 },
281   - // for single use
282   - onSingleButtonDown (event) {
  213 + onPointerDown (event, type) {
283 214 if (this.disabled) return;
284 215 event.preventDefault();
285   - this.onSingleDragStart(event);
286   -// window.addEventListener('mousemove', this.onSingleDragging);
287   -// window.addEventListener('mouseup', this.onSingleDragEnd);
288   - on(window, 'mousemove', this.onSingleDragging);
289   - on(window, 'mouseup', this.onSingleDragEnd);
  216 + this.pointerDown = type;
  217 +
  218 + this.onPointerDragStart(event);
  219 + on(window, 'mousemove', this.onPointerDrag);
  220 + on(window, 'touchmove', this.onPointerDrag);
  221 + on(window, 'mouseup', this.onPointerDragEnd);
  222 + on(window, 'touchend', this.onPointerDragEnd);
290 223 },
291   - onSingleDragStart (event) {
  224 + onPointerDragStart (event) {
292 225 this.dragging = false;
293   - this.startX = event.clientX;
294   - this.startPos = parseInt(this.singlePosition, 10);
  226 + this.startX = this.getPointerX(event);
  227 + this.startPos = parseInt(this[`${this.pointerDown}Position`], 10);
295 228 },
296   - onSingleDragging (event) {
  229 + onPointerDrag (event) {
297 230 this.dragging = true;
298   - if (this.dragging) {
299   - this.$refs.tooltip.visible = true;
300   - this.currentX = event.clientX;
301   - const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
302   - this.newPos = this.startPos + diff;
303   - this.changeSinglePosition(this.newPos);
304   - }
  231 + this.$refs[`${this.pointerDown}Tooltip`].visible = true;
  232 + this.currentX = this.getPointerX(event);
  233 +
  234 + const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
  235 + this.newPos = this.startPos + diff;
  236 + this.changeButtonPosition(this.newPos);
305 237 },
306   - onSingleDragEnd () {
  238 + onPointerDragEnd () {
307 239 if (this.dragging) {
308 240 this.dragging = false;
309   - this.$refs.tooltip.visible = false;
310   - this.changeSinglePosition(this.newPos);
311   -// window.removeEventListener('mousemove', this.onSingleDragging);
312   -// window.removeEventListener('mouseup', this.onSingleDragEnd);
  241 + this.$refs[`${this.pointerDown}Tooltip`].visible = false;
  242 + this.changeButtonPosition(this.newPos);
313 243 }
314   - off(window, 'mousemove', this.onSingleDragging);
315   - off(window, 'mouseup', this.onSingleDragEnd);
  244 +
  245 + this.pointerDown = '';
  246 + off(window, 'mousemove', this.onPointerDrag);
  247 + off(window, 'touchmove', this.onPointerDrag);
  248 + off(window, 'mouseup', this.onPointerDragEnd);
  249 + off(window, 'touchend', this.onPointerDragEnd);
316 250 },
317   - changeSinglePosition (newPos) {
318   - if (newPos < 0) {
319   - newPos = 0;
320   - } else if (newPos > 100) {
321   - newPos = 100;
322   - }
  251 + changeButtonPosition (newPos, forceType) {
  252 +
  253 + const type = forceType || this.pointerDown;
  254 + const index = type === 'min' ? 0 : 1;
  255 + if (type === 'min') newPos = this.checkLimits([newPos, this.maxPosition])[0];
  256 + else newPos = this.checkLimits([this.minPosition, newPos])[1];
  257 +
323 258 const lengthPerStep = 100 / ((this.max - this.min) / this.step);
324 259 const steps = Math.round(newPos / lengthPerStep);
325 260  
326   - this.currentValue = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
327   - this.setSinglePosition(this.currentValue);
  261 + const value = this.currentValue;
  262 + value[index] = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
  263 + this.currentValue = [...value];
  264 +
328 265 if (!this.dragging) {
329   - if (this.currentValue !== this.oldSingleValue) {
330   - this.$emit('on-change', this.currentValue);
331   - this.dispatch('FormItem', 'on-form-change', this.currentValue);
332   - this.oldSingleValue = this.currentValue;
  266 + if (this.currentValue[index] !== this.oldValue[index]) {
  267 + const exportValue = this.range ? this.currentValue : this.currentValue[0];
  268 + this.$emit('on-change', exportValue);
  269 + this.dispatch('FormItem', 'on-form-change', exportValue);
  270 + this.oldValue[index] = this.currentValue[index];
333 271 }
334 272 }
335 273 },
336   - setSinglePosition (val) {
337   - this.singlePosition = (val - this.min) / (this.max - this.min) * 100;
338   - },
339   - handleInputChange (val) {
340   - this.currentValue = val;
341   - this.setSinglePosition(val);
342   - this.$emit('on-change', this.currentValue);
343   - this.dispatch('FormItem', 'on-form-change', this.currentValue);
344   - },
345   - // for range use first
346   - onFirstButtonDown (event) {
347   - if (this.disabled) return;
348   - event.preventDefault();
349   - this.onFirstDragStart(event);
350   -// window.addEventListener('mousemove', this.onFirstDragging);
351   -// window.addEventListener('mouseup', this.onFirstDragEnd);
352   - on(window, 'mousemove', this.onFirstDragging);
353   - on(window, 'mouseup', this.onFirstDragEnd);
354   - },
355   - onFirstDragStart (event) {
356   - this.firstDragging = false;
357   - this.startX = event.clientX;
358   - this.startPos = parseInt(this.firstPosition, 10);
359   - },
360   - onFirstDragging (event) {
361   - this.firstDragging = true;
362   - if (this.firstDragging) {
363   - this.$refs.tooltip.visible = true;
364   - this.currentX = event.clientX;
365   - const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
366   - this.newPos = this.startPos + diff;
367   - this.changeFirstPosition(this.newPos);
368   - }
369   - },
370   - onFirstDragEnd () {
371   - if (this.firstDragging) {
372   - this.firstDragging = false;
373   - this.$refs.tooltip.visible = false;
374   - this.changeFirstPosition(this.newPos);
375   -// window.removeEventListener('mousemove', this.onFirstDragging);
376   -// window.removeEventListener('mouseup', this.onFirstDragEnd);
377   - }
378   - off(window, 'mousemove', this.onFirstDragging);
379   - off(window, 'mouseup', this.onFirstDragEnd);
380   - },
381   - changeFirstPosition (newPos) {
382   - if (newPos < 0) {
383   - newPos = 0;
384   - } else if (newPos > this.secondPosition) {
385   - newPos = this.secondPosition;
386   - }
387   - const lengthPerStep = 100 / ((this.max - this.min) / this.step);
388   - const steps = Math.round(newPos / lengthPerStep);
389 274  
390   - this.currentValue = [Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min), this.currentValue[1]];
391   - this.setFirstPosition(this.currentValue[0]);
392   - if (!this.firstDragging) {
393   - if (this.currentValue[0] !== this.oldFirstValue) {
394   - this.$emit('on-change', this.currentValue);
395   - this.dispatch('FormItem', 'on-form-change', this.currentValue);
396   - this.oldFirstValue = this.currentValue[0];
397   - }
398   - }
399   - },
400   - setFirstPosition (val) {
401   - this.firstPosition = (val - this.min) / (this.max - this.min) * 100;
402   - },
403   - // for range use second
404   - onSecondButtonDown (event) {
  275 +
  276 + sliderClick: function (event) {
405 277 if (this.disabled) return;
406   - event.preventDefault();
407   - this.onSecondDragStart(event);
408   -// window.addEventListener('mousemove', this.onSecondDragging);
409   -// window.addEventListener('mouseup', this.onSecondDragEnd);
410   - on(window, 'mousemove', this.onSecondDragging);
411   - on(window, 'mouseup', this.onSecondDragEnd);
412   - },
413   - onSecondDragStart (event) {
414   - this.secondDragging = false;
415   - this.startX = event.clientX;
416   - this.startPos = parseInt(this.secondPosition, 10);
417   - },
418   - onSecondDragging (event) {
419   - this.secondDragging = true;
420   - if (this.secondDragging) {
421   - this.$refs.tooltip2.visible = true;
422   - this.currentX = event.clientX;
423   - const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
424   - this.newPos = this.startPos + diff;
425   - this.changeSecondPosition(this.newPos);
426   - }
427   - },
428   - onSecondDragEnd () {
429   - if (this.secondDragging) {
430   - this.secondDragging = false;
431   - this.$refs.tooltip2.visible = false;
432   - this.changeSecondPosition(this.newPos);
433   -// window.removeEventListener('mousemove', this.onSecondDragging);
434   -// window.removeEventListener('mouseup', this.onSecondDragEnd);
435   - }
436   - off(window, 'mousemove', this.onSecondDragging);
437   - off(window, 'mouseup', this.onSecondDragEnd);
  278 + const currentX = this.getPointerX(event);
  279 + const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
  280 + const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100;
  281 +
  282 + if (!this.range || newPos <= this.minPosition) this.changeButtonPosition(newPos, 'min');
  283 + else if (newPos >= this.maxPosition) this.changeButtonPosition(newPos, 'max');
  284 + else this.changeButtonPosition(newPos, ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) ? 'min' : 'max');
438 285 },
439   - changeSecondPosition (newPos) {
440   - if (newPos > 100) {
441   - newPos = 100;
442   - } else if (newPos < this.firstPosition) {
443   - newPos = this.firstPosition;
444   - }
445   - const lengthPerStep = 100 / ((this.max - this.min) / this.step);
446   - const steps = Math.round(newPos / lengthPerStep);
447 286  
448   - this.currentValue = [this.currentValue[0], Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min)];
449   - this.setSecondPosition(this.currentValue[1]);
450   - if (!this.secondDragging) {
451   - if (this.currentValue[1] !== this.oldSecondValue) {
452   - this.$emit('on-change', this.currentValue);
453   - this.dispatch('FormItem', 'on-form-change', this.currentValue);
454   - this.oldSecondValue = this.currentValue[1];
455   - }
456   - }
  287 + handleInputChange (val) {
  288 + this.currentValue = [val, this.currentValue[1]];
  289 + const exportValue = this.range ? this.currentValue : this.currentValue[0];
  290 + this.$emit('on-change', exportValue);
  291 + this.dispatch('FormItem', 'on-form-change', exportValue);
457 292 },
458   - setSecondPosition (val) {
459   - this.secondPosition = (val - this.min) / (this.max - this.min) * 100;
460   - }
461   - },
462   - mounted () {
463   - if (this.range) {
464   - const isArray = Array.isArray(this.currentValue);
465   - if (!isArray || (isArray && this.currentValue.length != 2) || (isArray && (isNaN(this.currentValue[0]) || isNaN(this.currentValue[1])))) {
466   - this.currentValue = [this.min, this.max];
467   - } else {
468   - this.updateValue(this.currentValue, true);
469   - }
470   - } else {
471   - if (typeof this.currentValue !== 'number') {
472   - this.currentValue = this.min;
473   - }
474   - this.updateValue(this.currentValue);
475   - }
476 293 }
477 294 };
478 295 </script>
... ...