mirror of
https://gitee.com/vant-contrib/vant-weapp.git
synced 2025-04-05 10:22:44 +08:00
feat(Slider): add range props (#4442)
* feat(Slider): add range props for support double slider button * fix(Slider): 优化代码 * fix(Slider): 优化代码 * fix(Slider): 优化代码 * docs(Slider): update doc
This commit is contained in:
parent
69cdf45958
commit
2c02069808
@ -94,7 +94,7 @@ PS:关于 `van-area` Area 省市区选择组件,地区数据初始化可以
|
||||
|
||||
## 基础库版本
|
||||
|
||||
Vant Weapp 最低支持到小程序基础库 2.2.3 版本
|
||||
Vant Weapp 最低支持到小程序基础库 2.6.5 版本
|
||||
|
||||
## 链接
|
||||
|
||||
|
@ -6,6 +6,15 @@
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="双滑块">
|
||||
<van-slider
|
||||
range
|
||||
value="{{ [20, 60 ] }}"
|
||||
custom-class="slider"
|
||||
bind:change="onChange"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="指定选择范围">
|
||||
<van-slider
|
||||
custom-class="slider"
|
||||
|
@ -41,7 +41,7 @@
|
||||
},
|
||||
"compileType": "miniprogram",
|
||||
"cloudfunctionRoot": "functions/",
|
||||
"libVersion": "2.3.2",
|
||||
"libVersion": "2.6.5",
|
||||
"appid": "wx1c01b35002d3ba14",
|
||||
"projectname": "vant-weapp",
|
||||
"debugOptions": {
|
||||
|
@ -85,16 +85,18 @@ Page({
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| -------------- | -------------------------------- | ------------------ | --------- | ---- |
|
||||
| value | 当前进度百分比,取值范围为 0-100 | _number_ | `0` | - |
|
||||
| disabled | 是否禁用滑块 | _boolean_ | `false` | - |
|
||||
| max | 最大值 | _number_ | `100` | - |
|
||||
| min | 最小值 | _number_ | `0` | - |
|
||||
| step | 步长 | _number_ | `1` | - |
|
||||
| bar-height | 进度条高度,默认单位为 `px` | _string \| number_ | `2px` | - |
|
||||
| active-color | 进度条激活态颜色 | _string_ | `#1989fa` | - |
|
||||
| inactive-color | 进度条默认颜色 | _string_ | `#e5e5e5` | - |
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------- | ---------------------------------------- | -------------------- | --------- |
|
||||
| value | 当前进度百分比,在双滑块模式下为数组格式 | _number \| number[]_ | `0` |
|
||||
| disabled | 是否禁用滑块 | _boolean_ | `false` |
|
||||
| max | 最大值 | _number_ | `100` |
|
||||
| min | 最小值 | _number_ | `0` |
|
||||
| step | 步长 | _number_ | `1` |
|
||||
| bar-height | 进度条高度,默认单位为 `px` | _string \| number_ | `2px` |
|
||||
| active-color | 进度条激活态颜色 | _string_ | `#1989fa` |
|
||||
| inactive-color | 进度条默认颜色 | _string_ | `#e5e5e5` |
|
||||
| use-slot-button | 是否使用钮插槽 | _boolean_ | `false` |
|
||||
| range `v1.8.4` | 是否开启双滑块模式 | _boolean_ | `false` |
|
||||
|
||||
### Events
|
||||
|
||||
@ -110,3 +112,11 @@ Page({
|
||||
| 类名 | 说明 |
|
||||
| ------------ | ------------ |
|
||||
| custom-class | 根节点样式类 |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 | 参数 |
|
||||
| --------------------- | ----------------------------------- | ------------------- |
|
||||
| button | 自定义滑块按钮 | _{ value: number }_ |
|
||||
| left-button `v1.8.4` | 自定义左侧滑块按钮(双滑块模式下) | _{ value: number }_ |
|
||||
| right-button `v1.8.4` | 自定义右侧滑块按钮 (双滑块模式下) | _{ value: number }_ |
|
||||
|
@ -34,12 +34,20 @@
|
||||
.theme(box-shadow, '@slider-button-box-shadow');
|
||||
.theme(background-color, '@slider-button-background-color');
|
||||
|
||||
&-wrapper {
|
||||
&-wrapper,
|
||||
&-wrapper-right {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate3d(50%, -50%, 0);
|
||||
}
|
||||
|
||||
&-wrapper-left {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
|
@ -3,10 +3,13 @@ import { touch } from '../mixins/touch';
|
||||
import { canIUseModel } from '../common/version';
|
||||
import { getRect } from '../common/utils';
|
||||
|
||||
type SliderValue = number | [number, number];
|
||||
|
||||
VantComponent({
|
||||
mixins: [touch],
|
||||
|
||||
props: {
|
||||
range: Boolean,
|
||||
disabled: Boolean,
|
||||
useButtonSlot: Boolean,
|
||||
activeColor: String,
|
||||
@ -26,6 +29,7 @@ VantComponent({
|
||||
value: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
optionalTypes: [Array],
|
||||
observer(val) {
|
||||
if (val !== this.value) {
|
||||
this.updateValue(val);
|
||||
@ -43,8 +47,23 @@ VantComponent({
|
||||
onTouchStart(event: WechatMiniprogram.TouchEvent) {
|
||||
if (this.data.disabled) return;
|
||||
|
||||
const { index } = event.currentTarget.dataset;
|
||||
if (typeof index === 'number') {
|
||||
this.buttonIndex = index;
|
||||
}
|
||||
|
||||
this.touchStart(event);
|
||||
this.startValue = this.format(this.value);
|
||||
this.newValue = this.value;
|
||||
|
||||
if (this.isRange(this.newValue)) {
|
||||
this.startValue = this.newValue.map((val) => this.format(val)) as [
|
||||
number,
|
||||
number
|
||||
];
|
||||
} else {
|
||||
this.startValue = this.format(this.newValue);
|
||||
}
|
||||
this.dragStatus = 'start';
|
||||
},
|
||||
|
||||
@ -60,7 +79,13 @@ VantComponent({
|
||||
|
||||
getRect(this, '.van-slider').then((rect) => {
|
||||
const diff = (this.deltaX / rect.width) * this.getRange();
|
||||
this.newValue = this.startValue + diff;
|
||||
|
||||
if (this.isRange(this.startValue)) {
|
||||
(this.newValue as [number, number])[this.buttonIndex] =
|
||||
this.startValue[this.buttonIndex] + diff;
|
||||
} else {
|
||||
this.newValue = this.startValue + diff;
|
||||
}
|
||||
this.updateValue(this.newValue, false, true);
|
||||
});
|
||||
},
|
||||
@ -82,20 +107,50 @@ VantComponent({
|
||||
getRect(this, '.van-slider').then((rect) => {
|
||||
const value =
|
||||
((event.detail.x - rect.left) / rect.width) * this.getRange() + min;
|
||||
this.updateValue(value, true);
|
||||
|
||||
if (this.isRange(this.value)) {
|
||||
const [left, right] = this.value;
|
||||
const middle = (left + right) / 2;
|
||||
|
||||
if (value <= middle) {
|
||||
this.updateValue([value, right], true);
|
||||
} else {
|
||||
this.updateValue([left, value], true);
|
||||
}
|
||||
} else {
|
||||
this.updateValue(value, true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateValue(value: number, end?: boolean, drag?: boolean) {
|
||||
value = this.format(value);
|
||||
const { min } = this.data;
|
||||
const width = `${((value - min) * 100) / this.getRange()}%`;
|
||||
isRange(val: unknown): val is [number, number] {
|
||||
const { range } = this.data;
|
||||
return range && Array.isArray(val);
|
||||
},
|
||||
|
||||
handleOverlap(value: [number, number]) {
|
||||
if (value[0] > value[1]) {
|
||||
return value.slice(0).reverse();
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
updateValue(value: SliderValue, end?: boolean, drag?: boolean) {
|
||||
if (this.isRange(value)) {
|
||||
value = this.handleOverlap(value).map((val) => this.format(val)) as [
|
||||
number,
|
||||
number
|
||||
];
|
||||
} else {
|
||||
value = this.format(value);
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
|
||||
this.setData({
|
||||
barStyle: `
|
||||
width: ${width};
|
||||
width: ${this.calcMainAxis()};
|
||||
left: ${this.isRange(value) ? `${value[0]}%` : 0};
|
||||
${drag ? 'transition: none;' : ''}
|
||||
`,
|
||||
});
|
||||
@ -113,11 +168,26 @@ VantComponent({
|
||||
}
|
||||
},
|
||||
|
||||
getScope() {
|
||||
return Number(this.data.max) - Number(this.data.min);
|
||||
},
|
||||
|
||||
getRange() {
|
||||
const { max, min } = this.data;
|
||||
return max - min;
|
||||
},
|
||||
|
||||
// 计算选中条的长度百分比
|
||||
calcMainAxis() {
|
||||
const { value } = this;
|
||||
const { min } = this.data;
|
||||
const scope = this.getScope();
|
||||
if (this.isRange(value)) {
|
||||
return `${((value[1] - value[0]) * 100) / scope}%`;
|
||||
}
|
||||
return `${((value - Number(min)) * 100) / scope}%`;
|
||||
},
|
||||
|
||||
format(value: number) {
|
||||
const { max, min, step } = this.data;
|
||||
return Math.round(Math.max(min, Math.min(value, max)) / step) * step;
|
||||
|
@ -11,6 +11,44 @@
|
||||
style="{{ barStyle }}; {{ style({ backgroundColor: activeColor }) }}"
|
||||
>
|
||||
<view
|
||||
wx:if="{{ range }}"
|
||||
class="{{ utils.bem('slider__button-wrapper-left') }}"
|
||||
data-index="{{ 0 }}"
|
||||
bind:touchstart="onTouchStart"
|
||||
catch:touchmove="onTouchMove"
|
||||
bind:touchend="onTouchEnd"
|
||||
bind:touchcancel="onTouchEnd"
|
||||
>
|
||||
<slot
|
||||
wx:if="{{ useButtonSlot }}"
|
||||
name="left-button"
|
||||
/>
|
||||
<view
|
||||
wx:else
|
||||
class="{{ utils.bem('slider__button') }}"
|
||||
/>
|
||||
</view>
|
||||
<view
|
||||
wx:if="{{ range }}"
|
||||
class="{{ utils.bem('slider__button-wrapper-right') }}"
|
||||
data-index="{{ 1 }}"
|
||||
bind:touchstart="onTouchStart"
|
||||
catch:touchmove="onTouchMove"
|
||||
bind:touchend="onTouchEnd"
|
||||
bind:touchcancel="onTouchEnd"
|
||||
>
|
||||
<slot
|
||||
wx:if="{{ useButtonSlot }}"
|
||||
name="right-button"
|
||||
/>
|
||||
<view
|
||||
wx:else
|
||||
class="{{ utils.bem('slider__button') }}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view
|
||||
wx:if="{{ !range }}"
|
||||
class="{{ utils.bem('slider__button-wrapper') }}"
|
||||
bind:touchstart="onTouchStart"
|
||||
catch:touchmove="onTouchMove"
|
||||
|
Loading…
x
Reference in New Issue
Block a user