import { createNamespace, addUnit } from '../utils'; import { deepClone } from '../utils/deep-clone'; import { preventDefault } from '../utils/dom/event'; import { range, addNumber } from '../utils/format/number'; import { TouchMixin } from '../mixins/touch'; import { FieldMixin } from '../mixins/field'; var _createNamespace = createNamespace('slider'), createComponent = _createNamespace[0], bem = _createNamespace[1]; var isSameValue = function isSameValue(newValue, oldValue) { return JSON.stringify(newValue) === JSON.stringify(oldValue); }; export default createComponent({ mixins: [TouchMixin, FieldMixin], props: { disabled: Boolean, vertical: Boolean, range: Boolean, barHeight: [Number, String], buttonSize: [Number, String], activeColor: String, inactiveColor: String, min: { type: [Number, String], default: 0 }, max: { type: [Number, String], default: 100 }, step: { type: [Number, String], default: 1 }, value: { type: [Number, Array], default: 0 } }, data: function data() { return { dragStatus: '' }; }, computed: { scope: function scope() { return this.max - this.min; }, buttonStyle: function buttonStyle() { if (this.buttonSize) { var size = addUnit(this.buttonSize); return { width: size, height: size }; } } }, created: function created() { // format initial value this.updateValue(this.value); }, mounted: function mounted() { if (this.range) { this.bindTouchEvent(this.$refs.wrapper0); this.bindTouchEvent(this.$refs.wrapper1); } else { this.bindTouchEvent(this.$refs.wrapper); } }, methods: { onTouchStart: function onTouchStart(event) { if (this.disabled) { return; } this.touchStart(event); this.currentValue = this.value; if (this.range) { this.startValue = this.value.map(this.format); } else { this.startValue = this.format(this.value); } this.dragStatus = 'start'; }, onTouchMove: function onTouchMove(event) { if (this.disabled) { return; } if (this.dragStatus === 'start') { this.$emit('drag-start'); } preventDefault(event, true); this.touchMove(event); this.dragStatus = 'draging'; var rect = this.$el.getBoundingClientRect(); var delta = this.vertical ? this.deltaY : this.deltaX; var total = this.vertical ? rect.height : rect.width; var diff = delta / total * this.scope; if (this.range) { this.currentValue[this.index] = this.startValue[this.index] + diff; } else { this.currentValue = this.startValue + diff; } this.updateValue(this.currentValue); }, onTouchEnd: function onTouchEnd() { if (this.disabled) { return; } if (this.dragStatus === 'draging') { this.updateValue(this.currentValue, true); this.$emit('drag-end'); } this.dragStatus = ''; }, onClick: function onClick(event) { event.stopPropagation(); if (this.disabled) return; var rect = this.$el.getBoundingClientRect(); var delta = this.vertical ? event.clientY - rect.top : event.clientX - rect.left; var total = this.vertical ? rect.height : rect.width; var value = +this.min + delta / total * this.scope; if (this.range) { var _this$value = this.value, left = _this$value[0], right = _this$value[1]; var middle = (left + right) / 2; if (value <= middle) { left = value; } else { right = value; } value = [left, right]; } this.startValue = this.value; this.updateValue(value, true); }, // 处理两个滑块重叠之后的情况 handleOverlap: function handleOverlap(value) { if (value[0] > value[1]) { value = deepClone(value); return value.reverse(); } return value; }, updateValue: function updateValue(value, end) { if (this.range) { value = this.handleOverlap(value).map(this.format); } else { value = this.format(value); } if (!isSameValue(value, this.value)) { this.$emit('input', value); } if (end && !isSameValue(value, this.startValue)) { this.$emit('change', value); } }, format: function format(value) { var min = +this.min; var max = +this.max; var step = +this.step; value = range(value, min, max); var diff = Math.round((value - min) / step) * step; return addNumber(min, diff); } }, render: function render() { var _wrapperStyle, _this = this, _barStyle; var h = arguments[0]; var vertical = this.vertical; var mainAxis = vertical ? 'height' : 'width'; var crossAxis = vertical ? 'width' : 'height'; var wrapperStyle = (_wrapperStyle = { background: this.inactiveColor }, _wrapperStyle[crossAxis] = addUnit(this.barHeight), _wrapperStyle); // 计算选中条的长度百分比 var calcMainAxis = function calcMainAxis() { var value = _this.value, min = _this.min, range = _this.range, scope = _this.scope; if (range) { return (value[1] - value[0]) * 100 / scope + "%"; } return (value - min) * 100 / scope + "%"; }; // 计算选中条的开始位置的偏移量 var calcOffset = function calcOffset() { var value = _this.value, min = _this.min, range = _this.range, scope = _this.scope; if (range) { return (value[0] - min) * 100 / scope + "%"; } return null; }; var barStyle = (_barStyle = {}, _barStyle[mainAxis] = calcMainAxis(), _barStyle.left = this.vertical ? null : calcOffset(), _barStyle.top = this.vertical ? calcOffset() : null, _barStyle.background = this.activeColor, _barStyle); if (this.dragStatus) { barStyle.transition = 'none'; } var renderButton = function renderButton(i) { var map = ['left', 'right']; var isNumber = typeof i === 'number'; var current = isNumber ? _this.value[i] : _this.value; var getClassName = function getClassName() { if (isNumber) { return "button-wrapper-" + map[i]; } return "button-wrapper"; }; var getRefName = function getRefName() { if (isNumber) { return "wrapper" + i; } return "wrapper"; }; var renderButtonContent = function renderButtonContent() { if (isNumber) { var slot = _this.slots(i === 0 ? 'left-button' : 'right-button', { value: current }); if (slot) { return slot; } } if (_this.slots('button')) { return _this.slots('button'); } return h("div", { "class": bem('button'), "style": _this.buttonStyle }); }; return h("div", { "ref": getRefName(), "attrs": { "role": "slider", "tabindex": _this.disabled ? -1 : 0, "aria-valuemin": _this.min, "aria-valuenow": _this.value, "aria-valuemax": _this.max, "aria-orientation": _this.vertical ? 'vertical' : 'horizontal' }, "class": bem(getClassName()), "on": { "touchstart": function touchstart() { if (isNumber) { // 保存当前按钮的索引 _this.index = i; } }, "click": function click(e) { return e.stopPropagation(); } } }, [renderButtonContent()]); }; return h("div", { "style": wrapperStyle, "class": bem({ disabled: this.disabled, vertical: vertical }), "on": { "click": this.onClick } }, [h("div", { "class": bem('bar'), "style": barStyle }, [this.range ? [renderButton(0), renderButton(1)] : renderButton()])]); } });