mirror of
https://gitee.com/vant-contrib/vant.git
synced 2026-07-08 07:31:06 +08:00
Compare commits
2 Commits
a1d95e685c
...
d6663464c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6663464c9 | ||
|
|
d72c7ddf48 |
@ -150,7 +150,7 @@ export default {
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model | Current value | _number \| number[]_ | `0` |
|
||||
| v-model | Current value | _number \| [number, number]_ | `0` |
|
||||
| max | Max value | _number \| string_ | `100` |
|
||||
| min | Min value | _number \| string_ | `0` |
|
||||
| step | Step size | _number \| string_ | `1` |
|
||||
@ -167,16 +167,18 @@ export default {
|
||||
|
||||
| Event | Description | Arguments |
|
||||
| ------------------ | ------------------------------ | ------------------- |
|
||||
| update:model-value | Emitted when value is changing | value: current rate |
|
||||
| change | Emitted after value changed | value: current rate |
|
||||
| drag-start | Emitted when start draging | - |
|
||||
| drag-end | Emitted when end draging | - |
|
||||
| update:model-value | Emitted when value is changing | _value: number_ |
|
||||
| change | Emitted after value changed | _value: number_ |
|
||||
| drag-start | Emitted when start draging | _event: TouchEvent_ |
|
||||
| drag-end | Emitted when end draging | _event: TouchEvent_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------ | ------------- |
|
||||
| button | Custom button |
|
||||
| Name | Description | SlotProps |
|
||||
| --- | --- | --- |
|
||||
| button | Custom button | _{ value: number }_ |
|
||||
| left-button `v3.1.3` | Custom left button in range mode | _{ value: number }_ |
|
||||
| right-button `v3.1.3` | Custom right button in range mode | _{ value: number }_ |
|
||||
|
||||
### CSS Variables
|
||||
|
||||
|
||||
@ -152,12 +152,12 @@ export default {
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model | 当前进度百分比 | _number \| number[]_ | `0` |
|
||||
| v-model | 当前进度百分比,在双滑块模式下为数组格式 | _number \| [number, number]_ | `0` |
|
||||
| max | 最大值 | _number \| string_ | `100` |
|
||||
| min | 最小值 | _number \| string_ | `0` |
|
||||
| step | 步长 | _number \| string_ | `1` |
|
||||
| bar-height | 进度条高度,默认单位为`px` | _number \| string_ | `2px` |
|
||||
| button-size | 滑块按钮大小,默认单位为`px` | _number \| string_ | `24px` |
|
||||
| bar-height | 进度条高度,默认单位为 `px` | _number \| string_ | `2px` |
|
||||
| button-size | 滑块按钮大小,默认单位为 `px` | _number \| string_ | `24px` |
|
||||
| active-color | 进度条激活态颜色 | _string_ | `#1989fa` |
|
||||
| inactive-color | 进度条非激活态颜色 | _string_ | `#e5e5e5` |
|
||||
| range | 是否开启双滑块模式 | _boolean_ | `false` |
|
||||
@ -167,18 +167,20 @@ export default {
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| ------------------ | ------------------------ | --------------- |
|
||||
| update:model-value | 进度变化时实时触发 | value: 当前进度 |
|
||||
| change | 进度变化且结束拖动后触发 | value: 当前进度 |
|
||||
| drag-start | 开始拖动时触发 | - |
|
||||
| drag-end | 结束拖动时触发 | - |
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| ------------------ | ------------------------ | ------------------- |
|
||||
| update:model-value | 进度变化时实时触发 | _value: number_ |
|
||||
| change | 进度变化且结束拖动后触发 | _value: number_ |
|
||||
| drag-start | 开始拖动时触发 | _event: TouchEvent_ |
|
||||
| drag-end | 结束拖动时触发 | _event: TouchEvent_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ------ | -------------- |
|
||||
| button | 自定义滑动按钮 |
|
||||
| 名称 | 说明 | 参数 |
|
||||
| --- | --- | --- |
|
||||
| button | 自定义滑块按钮 | _{ value: number }_ |
|
||||
| left-button `v3.1.3` | 自定义左侧滑块按钮(双滑块模式下) | _{ value: number }_ |
|
||||
| right-button `v3.1.3` | 自定义右侧滑块按钮 (双滑块模式下) | _{ value: number }_ |
|
||||
|
||||
### 样式变量
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import { useLinkField } from '../composables/use-link-field';
|
||||
|
||||
const [name, bem] = createNamespace('slider');
|
||||
|
||||
type SliderValue = number | number[];
|
||||
type SliderValue = number | [number, number];
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
@ -53,7 +53,7 @@ export default defineComponent({
|
||||
emits: ['change', 'drag-end', 'drag-start', 'update:modelValue'],
|
||||
|
||||
setup(props, { emit, slots }) {
|
||||
let buttonIndex: number;
|
||||
let buttonIndex: 0 | 1;
|
||||
let startValue: SliderValue;
|
||||
let currentValue: SliderValue;
|
||||
|
||||
@ -71,8 +71,8 @@ export default defineComponent({
|
||||
};
|
||||
});
|
||||
|
||||
const isRange = (val: unknown): val is number[] =>
|
||||
!!props.range && Array.isArray(val);
|
||||
const isRange = (val: unknown): val is [number, number] =>
|
||||
props.range && Array.isArray(val);
|
||||
|
||||
// 计算选中条的长度百分比
|
||||
const calcMainAxis = () => {
|
||||
@ -117,7 +117,7 @@ export default defineComponent({
|
||||
JSON.stringify(newValue) === JSON.stringify(oldValue);
|
||||
|
||||
// 处理两个滑块重叠之后的情况
|
||||
const handleOverlap = (value: number[]) => {
|
||||
const handleOverlap = (value: [number, number]) => {
|
||||
if (value[0] > value[1]) {
|
||||
return value.slice(0).reverse();
|
||||
}
|
||||
@ -126,7 +126,7 @@ export default defineComponent({
|
||||
|
||||
const updateValue = (value: SliderValue, end?: boolean) => {
|
||||
if (isRange(value)) {
|
||||
value = handleOverlap(value).map(format);
|
||||
value = handleOverlap(value).map(format) as [number, number];
|
||||
} else {
|
||||
value = format(value);
|
||||
}
|
||||
@ -178,7 +178,7 @@ export default defineComponent({
|
||||
currentValue = props.modelValue;
|
||||
|
||||
if (isRange(currentValue)) {
|
||||
startValue = currentValue.map(format);
|
||||
startValue = currentValue.map(format) as [number, number];
|
||||
} else {
|
||||
startValue = format(currentValue);
|
||||
}
|
||||
@ -192,7 +192,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
if (dragStatus.value === 'start') {
|
||||
emit('drag-start');
|
||||
emit('drag-start', event);
|
||||
}
|
||||
|
||||
preventDefault(event, true);
|
||||
@ -205,7 +205,7 @@ export default defineComponent({
|
||||
const diff = (delta / total) * scope.value;
|
||||
|
||||
if (isRange(startValue)) {
|
||||
(currentValue as number[])[buttonIndex] =
|
||||
(currentValue as [number, number])[buttonIndex] =
|
||||
startValue[buttonIndex] + diff;
|
||||
} else {
|
||||
currentValue = startValue + diff;
|
||||
@ -213,59 +213,72 @@ export default defineComponent({
|
||||
updateValue(currentValue);
|
||||
};
|
||||
|
||||
const onTouchEnd = () => {
|
||||
const onTouchEnd = (event: TouchEvent) => {
|
||||
if (props.disabled || props.readonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dragStatus.value === 'draging') {
|
||||
updateValue(currentValue, true);
|
||||
emit('drag-end');
|
||||
emit('drag-end', event);
|
||||
}
|
||||
|
||||
dragStatus.value = '';
|
||||
};
|
||||
|
||||
const renderButton = (index?: number) => {
|
||||
const getClassName = () => {
|
||||
if (typeof index === 'number') {
|
||||
const position = ['left', 'right'];
|
||||
return `button-wrapper-${position[index]}`;
|
||||
}
|
||||
return `button-wrapper`;
|
||||
};
|
||||
const getButtonClassName = (index?: 0 | 1) => {
|
||||
if (typeof index === 'number') {
|
||||
const position = ['left', 'right'];
|
||||
return bem(`button-wrapper-${position[index]}`);
|
||||
}
|
||||
return bem('button-wrapper');
|
||||
};
|
||||
|
||||
const renderButtonContent = (value: number, index?: 0 | 1) => {
|
||||
if (typeof index === 'number') {
|
||||
const slot = slots[index === 0 ? 'left-button' : 'right-button'];
|
||||
if (slot) {
|
||||
return slot({ value });
|
||||
}
|
||||
}
|
||||
|
||||
if (slots.button) {
|
||||
return slots.button({ value });
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={bem('button')} style={getSizeStyle(props.buttonSize)} />
|
||||
);
|
||||
};
|
||||
|
||||
const renderButton = (index?: 0 | 1) => {
|
||||
const currentValue =
|
||||
typeof index === 'number'
|
||||
? (props.modelValue as number[])[index]
|
||||
? (props.modelValue as [number, number])[index]
|
||||
: (props.modelValue as number);
|
||||
|
||||
return (
|
||||
<div
|
||||
role="slider"
|
||||
class={bem(getClassName())}
|
||||
class={getButtonClassName(index)}
|
||||
tabindex={props.disabled || props.readonly ? -1 : 0}
|
||||
aria-valuemin={+props.min}
|
||||
aria-valuenow={currentValue}
|
||||
aria-valuemax={+props.max}
|
||||
aria-orientation={props.vertical ? 'vertical' : 'horizontal'}
|
||||
onTouchstart={(e) => {
|
||||
onTouchstart={(event) => {
|
||||
if (typeof index === 'number') {
|
||||
// save index of current button
|
||||
buttonIndex = index;
|
||||
}
|
||||
onTouchStart(e);
|
||||
onTouchStart(event);
|
||||
}}
|
||||
onTouchmove={onTouchMove}
|
||||
onTouchend={onTouchEnd}
|
||||
onTouchcancel={onTouchEnd}
|
||||
onClick={stopPropagation}
|
||||
>
|
||||
{slots.button ? (
|
||||
slots.button()
|
||||
) : (
|
||||
<div class={bem('button')} style={getSizeStyle(props.buttonSize)} />
|
||||
)}
|
||||
{renderButtonContent(currentValue, index)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
30
src/slider/test/__snapshots__/index.spec.ts.snap
Normal file
30
src/slider/test/__snapshots__/index.spec.ts.snap
Normal file
@ -0,0 +1,30 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render left-button、right-button slot correctly 1`] = `
|
||||
<div class="van-slider">
|
||||
<div class="van-slider__bar"
|
||||
style="width: 50%; left: 30%;"
|
||||
>
|
||||
<div role="slider"
|
||||
class="van-slider__button-wrapper-left"
|
||||
tabindex="0"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="30"
|
||||
aria-valuemax="100"
|
||||
aria-orientation="horizontal"
|
||||
>
|
||||
left-30
|
||||
</div>
|
||||
<div role="slider"
|
||||
class="van-slider__button-wrapper-right"
|
||||
tabindex="0"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="80"
|
||||
aria-valuemax="100"
|
||||
aria-orientation="horizontal"
|
||||
>
|
||||
right-80
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -203,3 +203,19 @@ test('should format v-model with step correctly', async () => {
|
||||
await later();
|
||||
expect(wrapper.emitted('update:modelValue')![0]).toEqual([31]);
|
||||
});
|
||||
|
||||
test('should render left-button、right-button slot correctly', async () => {
|
||||
const wrapper = mount(Slider, {
|
||||
props: {
|
||||
range: true,
|
||||
modelValue: [30, 80],
|
||||
},
|
||||
slots: {
|
||||
'left-button': ({ value }) => `left-${value}`,
|
||||
'right-button': ({ value }) => `right-${value}`,
|
||||
},
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user