123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- <template>
- <div
- class="el-slider__button-wrapper"
- @mouseenter="handleMouseEnter"
- @mouseleave="handleMouseLeave"
- @mousedown="onButtonDown"
- @touchstart="onButtonDown"
- :class="{ 'hover': hovering, 'dragging': dragging }"
- :style="wrapperStyle"
- ref="button"
- tabindex="0"
- @focus="handleMouseEnter"
- @blur="handleMouseLeave"
- @keydown.left="onLeftKeyDown"
- @keydown.right="onRightKeyDown"
- @keydown.down.prevent="onLeftKeyDown"
- @keydown.up.prevent="onRightKeyDown"
- >
- <el-tooltip
- placement="top"
- ref="tooltip"
- :popper-class="tooltipClass"
- :disabled="!showTooltip">
- <span slot="content">{{ formatValue }}</span>
- <div class="el-slider__button" :class="{ 'hover': hovering, 'dragging': dragging }"></div>
- </el-tooltip>
- </div>
- </template>
- <script>
- import ElTooltip from 'element-ui/packages/tooltip';
- export default {
- name: 'ElSliderButton',
- components: {
- ElTooltip
- },
- props: {
- value: {
- type: Number,
- default: 0
- },
- vertical: {
- type: Boolean,
- default: false
- },
- tooltipClass: String
- },
- data() {
- return {
- hovering: false,
- dragging: false,
- isClick: false,
- startX: 0,
- currentX: 0,
- startY: 0,
- currentY: 0,
- startPosition: 0,
- newPosition: null,
- oldValue: this.value
- };
- },
- computed: {
- disabled() {
- return this.$parent.sliderDisabled;
- },
- max() {
- return this.$parent.max;
- },
- min() {
- return this.$parent.min;
- },
- step() {
- return this.$parent.step;
- },
- showTooltip() {
- return this.$parent.showTooltip;
- },
- precision() {
- return this.$parent.precision;
- },
- currentPosition() {
- return `${ (this.value - this.min) / (this.max - this.min) * 100 }%`;
- },
- enableFormat() {
- return this.$parent.formatTooltip instanceof Function;
- },
- formatValue() {
- return this.enableFormat && this.$parent.formatTooltip(this.value) || this.value;
- },
- wrapperStyle() {
- return this.vertical ? { bottom: this.currentPosition } : { left: this.currentPosition };
- }
- },
- watch: {
- dragging(val) {
- this.$parent.dragging = val;
- }
- },
- methods: {
- displayTooltip() {
- this.$refs.tooltip && (this.$refs.tooltip.showPopper = true);
- },
- hideTooltip() {
- this.$refs.tooltip && (this.$refs.tooltip.showPopper = false);
- },
- handleMouseEnter() {
- this.hovering = true;
- this.displayTooltip();
- },
- handleMouseLeave() {
- this.hovering = false;
- this.hideTooltip();
- },
- onButtonDown(event) {
- if (this.disabled) return;
- event.preventDefault();
- this.onDragStart(event);
- window.addEventListener('mousemove', this.onDragging);
- window.addEventListener('touchmove', this.onDragging);
- window.addEventListener('mouseup', this.onDragEnd);
- window.addEventListener('touchend', this.onDragEnd);
- window.addEventListener('contextmenu', this.onDragEnd);
- },
- onLeftKeyDown() {
- if (this.disabled) return;
- this.newPosition = parseFloat(this.currentPosition) - this.step / (this.max - this.min) * 100;
- this.setPosition(this.newPosition);
- this.$parent.emitChange();
- },
- onRightKeyDown() {
- if (this.disabled) return;
- this.newPosition = parseFloat(this.currentPosition) + this.step / (this.max - this.min) * 100;
- this.setPosition(this.newPosition);
- this.$parent.emitChange();
- },
- onDragStart(event) {
- this.dragging = true;
- this.isClick = true;
- if (event.type === 'touchstart') {
- event.clientY = event.touches[0].clientY;
- event.clientX = event.touches[0].clientX;
- }
- if (this.vertical) {
- this.startY = event.clientY;
- } else {
- this.startX = event.clientX;
- }
- this.startPosition = parseFloat(this.currentPosition);
- this.newPosition = this.startPosition;
- },
- onDragging(event) {
- if (this.dragging) {
- this.isClick = false;
- this.displayTooltip();
- this.$parent.resetSize();
- let diff = 0;
- if (event.type === 'touchmove') {
- event.clientY = event.touches[0].clientY;
- event.clientX = event.touches[0].clientX;
- }
- if (this.vertical) {
- this.currentY = event.clientY;
- diff = (this.startY - this.currentY) / this.$parent.sliderSize * 100;
- } else {
- this.currentX = event.clientX;
- diff = (this.currentX - this.startX) / this.$parent.sliderSize * 100;
- }
- this.newPosition = this.startPosition + diff;
- this.setPosition(this.newPosition);
- }
- },
- onDragEnd() {
- if (this.dragging) {
- /*
- * 防止在 mouseup 后立即触发 click,导致滑块有几率产生一小段位移
- * 不使用 preventDefault 是因为 mouseup 和 click 没有注册在同一个 DOM 上
- */
- setTimeout(() => {
- this.dragging = false;
- this.hideTooltip();
- if (!this.isClick) {
- this.setPosition(this.newPosition);
- this.$parent.emitChange();
- }
- }, 0);
- window.removeEventListener('mousemove', this.onDragging);
- window.removeEventListener('touchmove', this.onDragging);
- window.removeEventListener('mouseup', this.onDragEnd);
- window.removeEventListener('touchend', this.onDragEnd);
- window.removeEventListener('contextmenu', this.onDragEnd);
- }
- },
- setPosition(newPosition) {
- if (newPosition === null || isNaN(newPosition)) return;
- if (newPosition < 0) {
- newPosition = 0;
- } else if (newPosition > 100) {
- newPosition = 100;
- }
- const lengthPerStep = 100 / ((this.max - this.min) / this.step);
- const steps = Math.round(newPosition / lengthPerStep);
- let value = steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min;
- value = parseFloat(value.toFixed(this.precision));
- this.$emit('input', value);
- this.$nextTick(() => {
- this.displayTooltip();
- this.$refs.tooltip && this.$refs.tooltip.updatePopper();
- });
- if (!this.dragging && this.value !== this.oldValue) {
- this.oldValue = this.value;
- }
- }
- }
- };
- </script>
|