mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-25 19:06:36 +08:00
[new component] add Slider component #721
This commit is contained in:
parent
d92edf871e
commit
19f4c9c028
@ -59,6 +59,7 @@ export default {
|
|||||||
'radio': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/radio'), 'radio')), 'radio')),
|
'radio': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/radio'), 'radio')), 'radio')),
|
||||||
'search': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/search'), 'search')), 'search')),
|
'search': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/search'), 'search')), 'search')),
|
||||||
'sku': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/sku'), 'sku')), 'sku')),
|
'sku': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/sku'), 'sku')), 'sku')),
|
||||||
|
'slider': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/slider'), 'slider')), 'slider')),
|
||||||
'stepper': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/stepper'), 'stepper')), 'stepper')),
|
'stepper': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/stepper'), 'stepper')), 'stepper')),
|
||||||
'steps': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/steps'), 'steps')), 'steps')),
|
'steps': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/steps'), 'steps')), 'steps')),
|
||||||
'submit-bar': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/submit-bar'), 'submit-bar')), 'submit-bar')),
|
'submit-bar': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/submit-bar'), 'submit-bar')), 'submit-bar')),
|
||||||
|
90
docs/demos/views/slider.vue
Normal file
90
docs/demos/views/slider.vue
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<demo-section>
|
||||||
|
<demo-block :title="$t('title1')">
|
||||||
|
<van-slider v-model="value1"/>
|
||||||
|
<van-row>
|
||||||
|
<van-col span="24">
|
||||||
|
<van-stepper v-model="value1" />
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="$t('title2')">
|
||||||
|
<van-slider
|
||||||
|
v-model="value2"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="$t('title3')">
|
||||||
|
<van-slider v-model="value3" disabled />
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="$t('title4')">
|
||||||
|
<van-slider
|
||||||
|
v-model="value4"
|
||||||
|
@change="handleChange"
|
||||||
|
@after-change="handleAfterChange"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="$t('title5')">
|
||||||
|
<van-slider
|
||||||
|
v-model="value5"
|
||||||
|
pivot-color="#333"
|
||||||
|
loaded-bar-color="red"
|
||||||
|
bar-color="blue"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
</demo-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
i18n: {
|
||||||
|
'zh-CN': {
|
||||||
|
title1: '基本用法',
|
||||||
|
title2: '最大最小值',
|
||||||
|
title3: '禁用',
|
||||||
|
title4: '事件',
|
||||||
|
title5: '自定义样式'
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
title1: 'Basic Usage',
|
||||||
|
title2: 'Max && Min',
|
||||||
|
title3: 'Disabed',
|
||||||
|
title4: 'Event',
|
||||||
|
title5: 'Customized style'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value1: 50,
|
||||||
|
value2: 50,
|
||||||
|
value3: 50,
|
||||||
|
value4: 50,
|
||||||
|
value5: 50,
|
||||||
|
min: 10,
|
||||||
|
max: 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(value) {
|
||||||
|
console.log('handleChange:', value)
|
||||||
|
},
|
||||||
|
handleAfterChange(value) {
|
||||||
|
console.log('handleAfterChange:', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.van-row {
|
||||||
|
padding-top: 20px;
|
||||||
|
.van-col {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
109
docs/markdown/en-US/slider.md
Normal file
109
docs/markdown/en-US/slider.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
## Slider
|
||||||
|
|
||||||
|
### Install
|
||||||
|
``` javascript
|
||||||
|
import { Slider } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Slider);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
#### Basic Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider v-model="value1"/>
|
||||||
|
<van-row>
|
||||||
|
<van-col span="12">
|
||||||
|
<van-stepper v-model="value1" />
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value1: 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Max && Min
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value2"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value2: 50,
|
||||||
|
min: 10,
|
||||||
|
max: 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Disabed
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider v-model="value3" disabled />
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Customized style
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value4"
|
||||||
|
@change="handleChange"
|
||||||
|
@after-change="handleAfterChange"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value4: 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(value) {
|
||||||
|
console.log('handleChange:', value)
|
||||||
|
},
|
||||||
|
handleAfterChange(value) {
|
||||||
|
console.log('handleAfterChange:', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customized style
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value5"
|
||||||
|
pivot-color="#333"
|
||||||
|
loaded-bar-color="red"
|
||||||
|
bar-color="blue"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
| Attribute | Description | Type | Default | Accepted Values |
|
||||||
|
|-----------|-----------|-----------|-------------|-------------|
|
||||||
|
| value | current value | Number | 0 | - |
|
||||||
|
| disabled | disabled | Boolean | false | - |
|
||||||
|
| bar-color | bar-color | string | `#cacaca` | - |
|
||||||
|
| loaded-bar-color | loaded-bar-color | string | `#4b0` | - |
|
||||||
|
| pivot-color | pivot-color | string | `#4b0` | - |
|
||||||
|
| max | max | Number | 100 | - |
|
||||||
|
| min | min | Number | 0 | - |
|
||||||
|
|
||||||
|
### Event
|
||||||
|
|
||||||
|
| Event | Description | Arguments |
|
||||||
|
|-----------|-----------|-----------|
|
||||||
|
| change | touchmove emit | value |
|
||||||
|
| after-change | touchend emit | value |
|
@ -56,6 +56,7 @@ export default {
|
|||||||
'zh-CN/radio': wrapper(r => require.ensure([], () => r(require('./zh-CN/radio.md')), 'zh-CN/radio')),
|
'zh-CN/radio': wrapper(r => require.ensure([], () => r(require('./zh-CN/radio.md')), 'zh-CN/radio')),
|
||||||
'zh-CN/search': wrapper(r => require.ensure([], () => r(require('./zh-CN/search.md')), 'zh-CN/search')),
|
'zh-CN/search': wrapper(r => require.ensure([], () => r(require('./zh-CN/search.md')), 'zh-CN/search')),
|
||||||
'zh-CN/sku': wrapper(r => require.ensure([], () => r(require('./zh-CN/sku.md')), 'zh-CN/sku')),
|
'zh-CN/sku': wrapper(r => require.ensure([], () => r(require('./zh-CN/sku.md')), 'zh-CN/sku')),
|
||||||
|
'zh-CN/slider': wrapper(r => require.ensure([], () => r(require('./zh-CN/slider.md')), 'zh-CN/slider')),
|
||||||
'zh-CN/stepper': wrapper(r => require.ensure([], () => r(require('./zh-CN/stepper.md')), 'zh-CN/stepper')),
|
'zh-CN/stepper': wrapper(r => require.ensure([], () => r(require('./zh-CN/stepper.md')), 'zh-CN/stepper')),
|
||||||
'zh-CN/steps': wrapper(r => require.ensure([], () => r(require('./zh-CN/steps.md')), 'zh-CN/steps')),
|
'zh-CN/steps': wrapper(r => require.ensure([], () => r(require('./zh-CN/steps.md')), 'zh-CN/steps')),
|
||||||
'zh-CN/submit-bar': wrapper(r => require.ensure([], () => r(require('./zh-CN/submit-bar.md')), 'zh-CN/submit-bar')),
|
'zh-CN/submit-bar': wrapper(r => require.ensure([], () => r(require('./zh-CN/submit-bar.md')), 'zh-CN/submit-bar')),
|
||||||
@ -112,6 +113,7 @@ export default {
|
|||||||
'en-US/radio': wrapper(r => require.ensure([], () => r(require('./en-US/radio.md')), 'en-US/radio')),
|
'en-US/radio': wrapper(r => require.ensure([], () => r(require('./en-US/radio.md')), 'en-US/radio')),
|
||||||
'en-US/search': wrapper(r => require.ensure([], () => r(require('./en-US/search.md')), 'en-US/search')),
|
'en-US/search': wrapper(r => require.ensure([], () => r(require('./en-US/search.md')), 'en-US/search')),
|
||||||
'en-US/sku': wrapper(r => require.ensure([], () => r(require('./en-US/sku.md')), 'en-US/sku')),
|
'en-US/sku': wrapper(r => require.ensure([], () => r(require('./en-US/sku.md')), 'en-US/sku')),
|
||||||
|
'en-US/slider': wrapper(r => require.ensure([], () => r(require('./en-US/slider.md')), 'en-US/slider')),
|
||||||
'en-US/stepper': wrapper(r => require.ensure([], () => r(require('./en-US/stepper.md')), 'en-US/stepper')),
|
'en-US/stepper': wrapper(r => require.ensure([], () => r(require('./en-US/stepper.md')), 'en-US/stepper')),
|
||||||
'en-US/steps': wrapper(r => require.ensure([], () => r(require('./en-US/steps.md')), 'en-US/steps')),
|
'en-US/steps': wrapper(r => require.ensure([], () => r(require('./en-US/steps.md')), 'en-US/steps')),
|
||||||
'en-US/submit-bar': wrapper(r => require.ensure([], () => r(require('./en-US/submit-bar.md')), 'en-US/submit-bar')),
|
'en-US/submit-bar': wrapper(r => require.ensure([], () => r(require('./en-US/submit-bar.md')), 'en-US/submit-bar')),
|
||||||
|
108
docs/markdown/zh-CN/slider.md
Normal file
108
docs/markdown/zh-CN/slider.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
## Slider 滑块
|
||||||
|
|
||||||
|
### 使用指南
|
||||||
|
``` javascript
|
||||||
|
import { Slider } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Slider);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 基本用法
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider v-model="value1"/>
|
||||||
|
<van-row>
|
||||||
|
<van-col span="12">
|
||||||
|
<van-stepper v-model="value1" />
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value1: 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 最大最小值
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value2"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value2: 50,
|
||||||
|
min: 10,
|
||||||
|
max: 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 禁用
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider v-model="value3" disabled />
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 事件
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value4"
|
||||||
|
@change="handleChange"
|
||||||
|
@after-change="handleAfterChange"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value4: 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleChange(value) {
|
||||||
|
console.log('handleChange:', value)
|
||||||
|
},
|
||||||
|
handleAfterChange(value) {
|
||||||
|
console.log('handleAfterChange:', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义样式
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-slider
|
||||||
|
v-model="value5"
|
||||||
|
pivot-color="#333"
|
||||||
|
loaded-bar-color="red"
|
||||||
|
bar-color="blue"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 必须 |
|
||||||
|
|-----------|-----------|-----------|-------------|-------------|
|
||||||
|
| value | 当前进度百分比 | Number | 0 | 否 |
|
||||||
|
| disabled | 滑块是否禁用 | Boolean | false | 否 |
|
||||||
|
| bar-color | 进度条颜色 | string | `#cacaca` | 否 |
|
||||||
|
| loaded-bar-color | 已加载条颜色 | string | `#4b0` | 否 |
|
||||||
|
| pivot-color | 滑块颜色 | string | `#4b0` | 否 |
|
||||||
|
| max | 最大值 | Number | 100 | - |
|
||||||
|
| min | 最小值 | Number | 0 | - |
|
||||||
|
|
||||||
|
### Event
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 参数 |
|
||||||
|
|-----------|-----------|-----------|
|
||||||
|
| change | 拖动时触发 | value |
|
||||||
|
| after-change | 拖动停止后触发 | value |
|
@ -148,6 +148,10 @@ module.exports = {
|
|||||||
path: '/swipe',
|
path: '/swipe',
|
||||||
title: 'Swipe - 轮播'
|
title: 'Swipe - 轮播'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/slider',
|
||||||
|
title: 'Slider - 滑块'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/tab',
|
path: '/tab',
|
||||||
title: 'Tab - 标签页'
|
title: 'Tab - 标签页'
|
||||||
@ -442,6 +446,10 @@ module.exports = {
|
|||||||
path: '/swipe',
|
path: '/swipe',
|
||||||
title: 'Swipe'
|
title: 'Swipe'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/slider',
|
||||||
|
title: 'Slider'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/tab',
|
path: '/tab',
|
||||||
title: 'Tab'
|
title: 'Tab'
|
||||||
|
@ -48,6 +48,7 @@ import RadioGroup from './radio-group';
|
|||||||
import Row from './row';
|
import Row from './row';
|
||||||
import Search from './search';
|
import Search from './search';
|
||||||
import Sku from './sku';
|
import Sku from './sku';
|
||||||
|
import Slider from './slider';
|
||||||
import Step from './step';
|
import Step from './step';
|
||||||
import Stepper from './stepper';
|
import Stepper from './stepper';
|
||||||
import Steps from './steps';
|
import Steps from './steps';
|
||||||
@ -116,6 +117,7 @@ const components = [
|
|||||||
Row,
|
Row,
|
||||||
Search,
|
Search,
|
||||||
Sku,
|
Sku,
|
||||||
|
Slider,
|
||||||
Step,
|
Step,
|
||||||
Stepper,
|
Stepper,
|
||||||
Steps,
|
Steps,
|
||||||
@ -196,6 +198,7 @@ export {
|
|||||||
Row,
|
Row,
|
||||||
Search,
|
Search,
|
||||||
Sku,
|
Sku,
|
||||||
|
Slider,
|
||||||
Step,
|
Step,
|
||||||
Stepper,
|
Stepper,
|
||||||
Steps,
|
Steps,
|
||||||
|
170
packages/slider/index.vue
Normal file
170
packages/slider/index.vue
Normal file
@ -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 './stepper.css';
|
||||||
@import './progress.css';
|
@import './progress.css';
|
||||||
@import './swipe.css';
|
@import './swipe.css';
|
||||||
|
@import './slider.css';
|
||||||
|
|
||||||
/* form components */
|
/* form components */
|
||||||
@import './checkbox.css';
|
@import './checkbox.css';
|
||||||
|
41
packages/vant-css/src/slider.css
Normal file
41
packages/vant-css/src/slider.css
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
98
test/specs/slider.spec.js
Normal file
98
test/specs/slider.spec.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import Slider from 'packages/slider';
|
||||||
|
import { mount } from 'avoriaz';
|
||||||
|
import { triggerTouch } from '../utils';
|
||||||
|
|
||||||
|
describe('Slider', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper && wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create a simple slider', () => {
|
||||||
|
wrapper = mount(Slider, {
|
||||||
|
propsData: {
|
||||||
|
value: 50,
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.hasClass('van-slider')).to.be.true;
|
||||||
|
expect(wrapper.find('.van-slider__bar').length).to.equal(1);
|
||||||
|
expect(wrapper.find('.van-slider__finished-portion').length).to.equal(1);
|
||||||
|
expect(wrapper.vm.value).to.equal(50);
|
||||||
|
expect(wrapper.hasClass('van-slider--disabled')).to.equal(true);
|
||||||
|
|
||||||
|
wrapper.setProps({
|
||||||
|
value: 100
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
|
||||||
|
expect(wrapper.vm.value).to.equal(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('test click bar', () => {
|
||||||
|
wrapper = mount(Slider, {
|
||||||
|
propsData: {
|
||||||
|
disabled: true,
|
||||||
|
value: 50
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const eventStub = sinon.stub(wrapper.vm, '$emit');
|
||||||
|
const $bar = wrapper.find('.van-slider__bar')[0];
|
||||||
|
$bar.trigger('click');
|
||||||
|
|
||||||
|
expect(eventStub.called).to.equal(false);
|
||||||
|
|
||||||
|
wrapper.setData({
|
||||||
|
disabled: false
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
$bar.trigger('click');
|
||||||
|
|
||||||
|
expect(wrapper.vm.disabled).to.equal(false);
|
||||||
|
expect(eventStub.called).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Customized style', () => {
|
||||||
|
const COLOR = '#123';
|
||||||
|
wrapper = mount(Slider, {
|
||||||
|
propsData: {
|
||||||
|
pivotColor: COLOR,
|
||||||
|
barColor: COLOR,
|
||||||
|
loadedBarColor: COLOR,
|
||||||
|
value: 50
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.vm.barStyle.backgroundColor).to.equal(COLOR);
|
||||||
|
expect(wrapper.vm.pivotStyle.backgroundColor).to.equal(COLOR);
|
||||||
|
expect(wrapper.vm.finishedStyle.backgroundColor).to.equal(COLOR);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('drag pivot', () => {
|
||||||
|
wrapper = mount(Slider, {
|
||||||
|
propsData: {
|
||||||
|
value: 50
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const pivot = wrapper.find('.van-slider__pivot')[0];
|
||||||
|
triggerTouch(pivot, 'touchstart', 0, 0);
|
||||||
|
expect(wrapper.vm.startX).to.equal(0);
|
||||||
|
|
||||||
|
triggerTouch(pivot, 'touchmove', 50, 0);
|
||||||
|
expect(wrapper.vm.offsetX).to.equal(50);
|
||||||
|
|
||||||
|
triggerTouch(pivot, 'touchend', 50, 0);
|
||||||
|
expect(wrapper.vm.offsetX).to.equal(50);
|
||||||
|
|
||||||
|
wrapper.setData({
|
||||||
|
disabled: true
|
||||||
|
});
|
||||||
|
|
||||||
|
triggerTouch(pivot, 'touchstart', 0, 0);
|
||||||
|
expect(wrapper.vm.startX).to.equal(0);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user