mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Circle): add startPosition prop (#9305)
* feat(Circle): add startPosition prop * docs(Circle): add start-position demo
This commit is contained in:
parent
5a93179b6b
commit
f24c521d26
@ -17,6 +17,8 @@ function getPath(clockwise: boolean, viewBoxSize: number) {
|
|||||||
} m 0, -500 a 500, 500 0 1, ${sweepFlag} 0, 1000 a 500, 500 0 1, ${sweepFlag} 0, -1000`;
|
} m 0, -500 a 500, 500 0 1, ${sweepFlag} 0, 1000 a 500, 500 0 1, ${sweepFlag} 0, -1000`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CircleStartPosition = 'top' | 'right' | 'bottom' | 'left';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name,
|
name,
|
||||||
|
|
||||||
@ -47,6 +49,10 @@ export default defineComponent({
|
|||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 40,
|
default: 40,
|
||||||
},
|
},
|
||||||
|
startPosition: {
|
||||||
|
type: String as PropType<CircleStartPosition>,
|
||||||
|
default: 'top',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['update:currentRate'],
|
emits: ['update:currentRate'],
|
||||||
@ -58,6 +64,22 @@ export default defineComponent({
|
|||||||
|
|
||||||
const path = computed(() => getPath(props.clockwise, viewBoxSize.value));
|
const path = computed(() => getPath(props.clockwise, viewBoxSize.value));
|
||||||
|
|
||||||
|
const svgStyle = computed(() => {
|
||||||
|
const ROTATE_ANGLE_MAP: Record<CircleStartPosition, number> = {
|
||||||
|
top: 0,
|
||||||
|
right: 90,
|
||||||
|
bottom: 180,
|
||||||
|
left: 270,
|
||||||
|
};
|
||||||
|
|
||||||
|
const angleValue = ROTATE_ANGLE_MAP[props.startPosition];
|
||||||
|
if (angleValue) {
|
||||||
|
return {
|
||||||
|
transform: `rotate(${angleValue}deg)`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.rate,
|
() => props.rate,
|
||||||
(rate) => {
|
(rate) => {
|
||||||
@ -160,7 +182,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={bem()} style={getSizeStyle(props.size)}>
|
<div class={bem()} style={getSizeStyle(props.size)}>
|
||||||
<svg viewBox={`0 0 ${viewBoxSize.value} ${viewBoxSize.value}`}>
|
<svg
|
||||||
|
viewBox={`0 0 ${viewBoxSize.value} ${viewBoxSize.value}`}
|
||||||
|
style={svgStyle.value}
|
||||||
|
>
|
||||||
{renderGradient()}
|
{renderGradient()}
|
||||||
{renderLayer()}
|
{renderLayer()}
|
||||||
{renderHover()}
|
{renderHover()}
|
||||||
|
@ -119,6 +119,29 @@ export default {
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Start Position
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
:text="Left"
|
||||||
|
start-position="left"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
text="Right"
|
||||||
|
start-position="right"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
text="Bottom"
|
||||||
|
start-position="bottom"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -136,6 +159,7 @@ export default {
|
|||||||
| stroke-width | Stroke width | _number \| string_ | `40` |
|
| stroke-width | Stroke width | _number \| string_ | `40` |
|
||||||
| stroke-linecap | Stroke linecap,can be set to `square` `butt` | _string_ | `round` |
|
| stroke-linecap | Stroke linecap,can be set to `square` `butt` | _string_ | `round` |
|
||||||
| clockwise | Whether to be clockwise | _boolean_ | `true` |
|
| clockwise | Whether to be clockwise | _boolean_ | `true` |
|
||||||
|
| start-position `v3.2.1` | Progress start position,can be set to `left`、`right`、`bottom` | _CircleStartPosition_ | `top` |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
|
@ -131,6 +131,31 @@ export default {
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 起始位置
|
||||||
|
|
||||||
|
进度条默认从顶部开始,可以通过 `start-position` 属性设置起始位置。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
:text="左侧"
|
||||||
|
start-position="left"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
text="右侧"
|
||||||
|
start-position="right"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="currentRate"
|
||||||
|
:rate="rate"
|
||||||
|
text="底部"
|
||||||
|
start-position="bottom"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -148,6 +173,7 @@ export default {
|
|||||||
| stroke-width | 进度条宽度 | _number \| string_ | `40` |
|
| stroke-width | 进度条宽度 | _number \| string_ | `40` |
|
||||||
| stroke-linecap | 进度条端点的形状,可选值为 `square` `butt` | _string_ | `round` |
|
| stroke-linecap | 进度条端点的形状,可选值为 `square` `butt` | _string_ | `round` |
|
||||||
| clockwise | 是否顺时针增加 | _boolean_ | `true` |
|
| clockwise | 是否顺时针增加 | _boolean_ | `true` |
|
||||||
|
| start-position `v3.2.1` | 进度起始位置,可选值为 `left`、`right`、`bottom` | _CircleStartPosition_ | `top` |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
|
@ -6,19 +6,27 @@ const format = (rate: number) => Math.min(Math.max(rate, 0), 100);
|
|||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
|
left: '左侧',
|
||||||
|
right: '右侧',
|
||||||
|
bottom: '底部',
|
||||||
gradient: '渐变色',
|
gradient: '渐变色',
|
||||||
customSize: '大小定制',
|
customSize: '大小定制',
|
||||||
customStyle: '样式定制',
|
customStyle: '样式定制',
|
||||||
customColor: '颜色定制',
|
customColor: '颜色定制',
|
||||||
customWidth: '宽度定制',
|
customWidth: '宽度定制',
|
||||||
|
startPosition: '起始位置',
|
||||||
counterClockwise: '逆时针',
|
counterClockwise: '逆时针',
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
|
left: 'Left',
|
||||||
|
right: 'Right',
|
||||||
|
bottom: 'Bottom',
|
||||||
gradient: 'Gradient',
|
gradient: 'Gradient',
|
||||||
customSize: 'Custom Size',
|
customSize: 'Custom Size',
|
||||||
customStyle: 'Custom Style',
|
customStyle: 'Custom Style',
|
||||||
customColor: 'Custom Color',
|
customColor: 'Custom Color',
|
||||||
customWidth: 'Custom Width',
|
customWidth: 'Custom Width',
|
||||||
|
startPosition: 'Start Position',
|
||||||
counterClockwise: 'Counter Clockwise',
|
counterClockwise: 'Counter Clockwise',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -111,6 +119,27 @@ const reduce = () => {
|
|||||||
@click="reduce"
|
@click="reduce"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<demo-block :title="t('startPosition')">
|
||||||
|
<van-circle
|
||||||
|
:current-rate="75"
|
||||||
|
:rate="rate"
|
||||||
|
:text="t('left')"
|
||||||
|
start-position="left"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
:current-rate="75"
|
||||||
|
:rate="rate"
|
||||||
|
:text="t('right')"
|
||||||
|
start-position="right"
|
||||||
|
/>
|
||||||
|
<van-circle
|
||||||
|
:current-rate="75"
|
||||||
|
:rate="rate"
|
||||||
|
:text="t('bottom')"
|
||||||
|
start-position="bottom"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@ -5,3 +5,4 @@ const Circle = withInstall<typeof _Circle>(_Circle);
|
|||||||
|
|
||||||
export default Circle;
|
export default Circle;
|
||||||
export { Circle };
|
export { Circle };
|
||||||
|
export type { CircleStartPosition } from './Circle';
|
||||||
|
@ -152,4 +152,63 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="van-circle">
|
||||||
|
<svg viewbox="0 0 1040 1040"
|
||||||
|
style="transform: rotate(270deg);"
|
||||||
|
>
|
||||||
|
<path class="van-circle__layer"
|
||||||
|
style="fill: none; stroke-width: 40px;"
|
||||||
|
d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
<path d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
style="stroke-width: 41px; stroke-dasharray: 2355px 3140px;"
|
||||||
|
class="van-circle__hover"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
<div class="van-circle__text">
|
||||||
|
Left
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-circle">
|
||||||
|
<svg viewbox="0 0 1040 1040"
|
||||||
|
style="transform: rotate(90deg);"
|
||||||
|
>
|
||||||
|
<path class="van-circle__layer"
|
||||||
|
style="fill: none; stroke-width: 40px;"
|
||||||
|
d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
<path d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
style="stroke-width: 41px; stroke-dasharray: 2355px 3140px;"
|
||||||
|
class="van-circle__hover"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
<div class="van-circle__text">
|
||||||
|
Right
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-circle">
|
||||||
|
<svg viewbox="0 0 1040 1040"
|
||||||
|
style="transform: rotate(180deg);"
|
||||||
|
>
|
||||||
|
<path class="van-circle__layer"
|
||||||
|
style="fill: none; stroke-width: 40px;"
|
||||||
|
d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
<path d="M 520 520 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000"
|
||||||
|
style="stroke-width: 41px; stroke-dasharray: 2355px 3140px;"
|
||||||
|
class="van-circle__hover"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
<div class="van-circle__text">
|
||||||
|
Bottom
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -47,3 +47,22 @@ test('should change stroke linecap when using stroke-linecap prop', () => {
|
|||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render start-position prop correctly', async () => {
|
||||||
|
const wrapper = mount(Circle, {
|
||||||
|
props: {
|
||||||
|
startPosition: 'top',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('svg').style.transform).toEqual('');
|
||||||
|
|
||||||
|
await wrapper.setProps({ startPosition: 'right' });
|
||||||
|
expect(wrapper.find('svg').style.transform).toEqual('rotate(90deg)');
|
||||||
|
|
||||||
|
await wrapper.setProps({ startPosition: 'bottom' });
|
||||||
|
expect(wrapper.find('svg').style.transform).toEqual('rotate(180deg)');
|
||||||
|
|
||||||
|
await wrapper.setProps({ startPosition: 'left' });
|
||||||
|
expect(wrapper.find('svg').style.transform).toEqual('rotate(270deg)');
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user