Commit 2b87ffa91a0340c757f99c286ca42b398dd6a00d

Authored by Sergio Crisostomo
1 parent e6a09eee

refactor and DRY Slider

Showing 1 changed file with 115 additions and 300 deletions   Show diff stats
src/components/slider/slider.vue
... ... @@ -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,43 @@
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 + const style = {
  174 + left: (this.currentValue[0] - this.min) / (this.max - this.min) * 100 + '%'
  175 + };
183 176  
184 177 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   - };
  178 + style.width = (this.currentValue[1] - this.currentValue[0]) / (this.max - this.min) * 100 + '%';
193 179 }
194 180  
195 181 return style;
196 182 },
197   - stops() {
  183 + stops () {
198 184 let stopCount = (this.max - this.min) / this.step;
199 185 let result = [];
200 186 let stepWidth = 100 * this.step / (this.max - this.min);
... ... @@ -211,268 +197,97 @@
211 197 }
212 198 },
213 199 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   - }
  200 + getPointerX (e) {
  201 + return e.type.indexOf('touch') !== -1 ? e.touches[0].clientX : e.clientX;
256 202 },
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;
  203 + checkLimits ([min, max]) {
  204 + min = Math.max(0, min);
  205 + min = Math.min(100, min);
262 206  
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   - }
  207 + max = Math.max(0, min, max);
  208 + max = Math.min(100, max);
  209 + return [min, max];
280 210 },
281   - // for single use
282   - onSingleButtonDown (event) {
  211 + onPointerDown (event, type) {
283 212 if (this.disabled) return;
284 213 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);
  214 + this.pointerDown = type;
  215 +
  216 + this.onPointerDragStart(event);
  217 + on(window, 'mousemove', this.onPointerDrag);
  218 + on(window, 'touchmove', this.onPointerDrag);
  219 + on(window, 'mouseup', this.onPointerDragEnd);
  220 + on(window, 'touchend', this.onPointerDragEnd);
290 221 },
291   - onSingleDragStart (event) {
  222 + onPointerDragStart (event) {
292 223 this.dragging = false;
293   - this.startX = event.clientX;
294   - this.startPos = parseInt(this.singlePosition, 10);
  224 + this.startX = this.getPointerX(event);
  225 + this.startPos = parseInt(this[`${this.pointerDown}Position`], 10);
295 226 },
296   - onSingleDragging (event) {
  227 + onPointerDrag (event) {
297 228 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   - }
  229 + this.$refs[`${this.pointerDown}Tooltip`].visible = true;
  230 + this.currentX = this.getPointerX(event);
  231 +
  232 + const diff = (this.currentX - this.startX) / this.sliderWidth * 100;
  233 + this.newPos = this.startPos + diff;
  234 + this.changeButtonPosition(this.newPos);
305 235 },
306   - onSingleDragEnd () {
  236 + onPointerDragEnd () {
307 237 if (this.dragging) {
308 238 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);
  239 + this.$refs[`${this.pointerDown}Tooltip`].visible = false;
  240 + this.changeButtonPosition(this.newPos);
313 241 }
314   - off(window, 'mousemove', this.onSingleDragging);
315   - off(window, 'mouseup', this.onSingleDragEnd);
  242 +
  243 + this.pointerDown = '';
  244 + off(window, 'mousemove', this.onPointerDrag);
  245 + off(window, 'touchmove', this.onPointerDrag);
  246 + off(window, 'mouseup', this.onPointerDragEnd);
  247 + off(window, 'touchend', this.onPointerDragEnd);
316 248 },
317   - changeSinglePosition (newPos) {
318   - if (newPos < 0) {
319   - newPos = 0;
320   - } else if (newPos > 100) {
321   - newPos = 100;
322   - }
  249 + changeButtonPosition (newPos, forceType) {
  250 +
  251 + const type = forceType || this.pointerDown;
  252 + const index = type === 'min' ? 0 : 1;
  253 + if (type === 'min') newPos = this.checkLimits([newPos, this.maxPosition])[0];
  254 + else newPos = this.checkLimits([this.minPosition, newPos])[1];
  255 +
323 256 const lengthPerStep = 100 / ((this.max - this.min) / this.step);
324 257 const steps = Math.round(newPos / lengthPerStep);
325 258  
326   - this.currentValue = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
327   - this.setSinglePosition(this.currentValue);
  259 + const value = this.currentValue;
  260 + value[index] = Math.round(steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min);
  261 + this.currentValue = [...value];
  262 +
328 263 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;
  264 + if (this.currentValue[index] !== this.oldValue[index]) {
  265 + const exportValue = this.range ? this.currentValue : this.currentValue[0];
  266 + this.$emit('on-change', exportValue);
  267 + this.dispatch('FormItem', 'on-form-change', exportValue);
  268 + this.oldValue[index] = this.currentValue[index];
333 269 }
334 270 }
335 271 },
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 272  
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) {
  273 +
  274 + sliderClick: function (event) {
405 275 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);
  276 + const currentX = this.getPointerX(event);
  277 + const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
  278 + const newPos = (currentX - sliderOffsetLeft) / this.sliderWidth * 100;
  279 +
  280 + if (!this.range || newPos <= this.minPosition) this.changeButtonPosition(newPos, 'min');
  281 + else if (newPos >= this.maxPosition) this.changeButtonPosition(newPos, 'max');
  282 + else this.changeButtonPosition(newPos, ((newPos - this.firstPosition) <= (this.secondPosition - newPos)) ? 'min' : 'max');
438 283 },
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 284  
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   - }
  285 + handleInputChange (val) {
  286 + this.currentValue = [val, this.currentValue[1]];
  287 + const exportValue = this.range ? this.currentValue : this.currentValue[0];
  288 + this.$emit('on-change', exportValue);
  289 + this.dispatch('FormItem', 'on-form-change', exportValue);
457 290 },
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 291 }
477 292 };
478 293 </script>
... ...