[new component] add Slider component #721
This commit is contained in:
@@ -48,6 +48,7 @@ import RadioGroup from './radio-group';
|
||||
import Row from './row';
|
||||
import Search from './search';
|
||||
import Sku from './sku';
|
||||
import Slider from './slider';
|
||||
import Step from './step';
|
||||
import Stepper from './stepper';
|
||||
import Steps from './steps';
|
||||
@@ -116,6 +117,7 @@ const components = [
|
||||
Row,
|
||||
Search,
|
||||
Sku,
|
||||
Slider,
|
||||
Step,
|
||||
Stepper,
|
||||
Steps,
|
||||
@@ -196,6 +198,7 @@ export {
|
||||
Row,
|
||||
Search,
|
||||
Sku,
|
||||
Slider,
|
||||
Step,
|
||||
Stepper,
|
||||
Steps,
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div
|
||||
class="van-slider"
|
||||
:class="{ 'van-slider--disabled': disabled }"
|
||||
>
|
||||
<div
|
||||
class="van-slider__bar"
|
||||
ref="bar"
|
||||
:style="barStyle"
|
||||
@click.stop="onSliderClicked"
|
||||
>
|
||||
<span
|
||||
class="van-slider__finished-portion"
|
||||
:style="finishedStyle"
|
||||
/>
|
||||
<span
|
||||
class="van-slider__pivot"
|
||||
ref="pivot"
|
||||
:style="pivotStyle"
|
||||
@touchstart="onTouchStart"
|
||||
@touchmove.prevent.stop="onTouchMove"
|
||||
@touchend="onTouchEnd"
|
||||
@touchcancel="onTouchEnd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import create from '../utils/create';
|
||||
import Touch from '../mixins/touch';
|
||||
|
||||
const DEFAULT_COLOR = '#4b0';
|
||||
const DEFAULT_BG = '#cacaca';
|
||||
|
||||
export default create({
|
||||
name: 'slider',
|
||||
mixins: [Touch],
|
||||
|
||||
props: {
|
||||
max: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
|
||||
min: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
required: true
|
||||
},
|
||||
|
||||
disabled: Boolean,
|
||||
|
||||
pivotColor: {
|
||||
type: String,
|
||||
default: DEFAULT_COLOR
|
||||
},
|
||||
|
||||
barColor: {
|
||||
type: String,
|
||||
default: DEFAULT_BG
|
||||
},
|
||||
|
||||
loadedBarColor: {
|
||||
type: String,
|
||||
default: DEFAULT_COLOR
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
pivotOffset: 0
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
sliderWidth() {
|
||||
const rect = this.$refs.bar.getBoundingClientRect();
|
||||
return rect['width'];
|
||||
},
|
||||
|
||||
barStyle() {
|
||||
return {
|
||||
backgroundColor: this.barColor
|
||||
};
|
||||
},
|
||||
|
||||
finishedStyle() {
|
||||
return {
|
||||
backgroundColor: this.loadedBarColor,
|
||||
width: this.format(this.value) + '%'
|
||||
};
|
||||
},
|
||||
|
||||
pivotStyle() {
|
||||
return {
|
||||
backgroundColor: this.pivotColor,
|
||||
left: this.format(this.value) + '%',
|
||||
marginLeft: `-${this.pivotOffset}px`
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.pivotOffset = parseInt(this.$refs.pivot.getBoundingClientRect().width / 2);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onTouchStart(event) {
|
||||
if (this.disabled) return;
|
||||
|
||||
this.draging = true;
|
||||
this.touchStart(event);
|
||||
this.startValue = this.format(this.value);
|
||||
},
|
||||
|
||||
onTouchMove(event) {
|
||||
if (this.draging) {
|
||||
this.touchMove(event);
|
||||
const diff = this.deltaX / this.sliderWidth * 100;
|
||||
this.newValue = this.startValue + diff;
|
||||
this.updateValue(this.newValue);
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd() {
|
||||
if (this.draging) {
|
||||
this.$nextTick(() => {
|
||||
this.draging = false;
|
||||
this.updateValue(this.newValue, true);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onSliderClicked(e) {
|
||||
if (this.disabled || this.draging) return;
|
||||
|
||||
const sliderRect = this.$refs.bar.getBoundingClientRect();
|
||||
const sliderOffset = sliderRect.left;
|
||||
this.newValue = Math.round((e.clientX - sliderOffset) / this.sliderWidth * 100);
|
||||
this.updateValue(this.newValue, true);
|
||||
},
|
||||
|
||||
updateValue(value, isFinished) {
|
||||
if (this.disabled) return;
|
||||
|
||||
value = this.format(value);
|
||||
this.$emit('change', value);
|
||||
this.$emit('input', value);
|
||||
|
||||
if (isFinished) {
|
||||
this.$emit('after-change', value);
|
||||
}
|
||||
},
|
||||
|
||||
format(value) {
|
||||
return Math.round(this.range(value));
|
||||
},
|
||||
|
||||
range(value) {
|
||||
return Math.max(this.min, Math.min(value, this.max));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -26,6 +26,7 @@
|
||||
@import './stepper.css';
|
||||
@import './progress.css';
|
||||
@import './swipe.css';
|
||||
@import './slider.css';
|
||||
|
||||
/* form components */
|
||||
@import './checkbox.css';
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
@import './common/var.css';
|
||||
|
||||
$c-slider-background: #cacaca;
|
||||
$c-pivot-border: #fff;
|
||||
|
||||
.van-slider {
|
||||
&--disabled {
|
||||
opacity: .3;
|
||||
.van-slider__pivot {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&__bar {
|
||||
position: relative;
|
||||
margin: 0 15px;
|
||||
height: 4px;
|
||||
border-radius: 5px;
|
||||
background: $c-slider-background;
|
||||
}
|
||||
|
||||
&__loaded-portion,
|
||||
&__finished-portion {
|
||||
border-radius: 5px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&__pivot {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 3px solid $c-pivot-border;
|
||||
box-shadow: 0 1px 4px;
|
||||
border-radius: 50%;
|
||||
background-color: $c-slider-background;
|
||||
transform: translate3d(0, -50%, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user