mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-05-21 13:59:15 +08:00
feat(Radio): support dot shape (#12057)
* feat(Radio): support dot shape * chore: update test * chore: format code
This commit is contained in:
parent
3319d1e5cd
commit
39a54a8d9a
@ -1,7 +1,13 @@
|
|||||||
import { watch, computed, defineComponent, type ExtractPropTypes } from 'vue';
|
import { watch, computed, defineComponent, type ExtractPropTypes } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { createNamespace, extend, pick, truthProp } from '../utils';
|
import {
|
||||||
|
pick,
|
||||||
|
extend,
|
||||||
|
truthProp,
|
||||||
|
makeStringProp,
|
||||||
|
createNamespace,
|
||||||
|
} from '../utils';
|
||||||
import { CHECKBOX_GROUP_KEY } from '../checkbox-group/CheckboxGroup';
|
import { CHECKBOX_GROUP_KEY } from '../checkbox-group/CheckboxGroup';
|
||||||
|
|
||||||
// Composables
|
// Composables
|
||||||
@ -9,7 +15,7 @@ import { useParent, useCustomFieldValue } from '@vant/use';
|
|||||||
import { useExpose } from '../composables/use-expose';
|
import { useExpose } from '../composables/use-expose';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import Checker, { checkerProps } from './Checker';
|
import Checker, { checkerProps, type CheckerShape } from './Checker';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { CheckboxExpose } from './types';
|
import type { CheckboxExpose } from './types';
|
||||||
@ -17,6 +23,7 @@ import type { CheckboxExpose } from './types';
|
|||||||
const [name, bem] = createNamespace('checkbox');
|
const [name, bem] = createNamespace('checkbox');
|
||||||
|
|
||||||
export const checkboxProps = extend({}, checkerProps, {
|
export const checkboxProps = extend({}, checkerProps, {
|
||||||
|
shape: makeStringProp<CheckerShape>('round'),
|
||||||
bindGroup: truthProp,
|
bindGroup: truthProp,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ import {
|
|||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { Icon } from '../icon';
|
import { Icon } from '../icon';
|
||||||
|
|
||||||
|
import type { RadioShape } from '../radio';
|
||||||
|
|
||||||
export type CheckerShape = 'square' | 'round';
|
export type CheckerShape = 'square' | 'round';
|
||||||
export type CheckerDirection = 'horizontal' | 'vertical';
|
export type CheckerDirection = 'horizontal' | 'vertical';
|
||||||
export type CheckerLabelPosition = 'left' | 'right';
|
export type CheckerLabelPosition = 'left' | 'right';
|
||||||
@ -27,7 +29,6 @@ export type CheckerParent = {
|
|||||||
|
|
||||||
export const checkerProps = {
|
export const checkerProps = {
|
||||||
name: unknownProp,
|
name: unknownProp,
|
||||||
shape: makeStringProp<CheckerShape>('round'),
|
|
||||||
disabled: Boolean,
|
disabled: Boolean,
|
||||||
iconSize: numericProp,
|
iconSize: numericProp,
|
||||||
modelValue: unknownProp,
|
modelValue: unknownProp,
|
||||||
@ -40,6 +41,7 @@ export default defineComponent({
|
|||||||
props: extend({}, checkerProps, {
|
props: extend({}, checkerProps, {
|
||||||
bem: makeRequiredProp(Function),
|
bem: makeRequiredProp(Function),
|
||||||
role: String,
|
role: String,
|
||||||
|
shape: makeStringProp<CheckerShape | RadioShape>('round'),
|
||||||
parent: Object as PropType<CheckerParent | null>,
|
parent: Object as PropType<CheckerParent | null>,
|
||||||
checked: Boolean,
|
checked: Boolean,
|
||||||
bindGroup: truthProp,
|
bindGroup: truthProp,
|
||||||
@ -107,12 +109,25 @@ export default defineComponent({
|
|||||||
<div
|
<div
|
||||||
ref={iconRef}
|
ref={iconRef}
|
||||||
class={bem('icon', [shape, { disabled: disabled.value, checked }])}
|
class={bem('icon', [shape, { disabled: disabled.value, checked }])}
|
||||||
style={{ fontSize: addUnit(iconSize) }}
|
style={
|
||||||
|
shape !== 'dot'
|
||||||
|
? { fontSize: addUnit(iconSize) }
|
||||||
|
: {
|
||||||
|
width: addUnit(iconSize),
|
||||||
|
height: addUnit(iconSize),
|
||||||
|
borderColor: iconStyle.value?.borderColor,
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{slots.icon ? (
|
{slots.icon ? (
|
||||||
slots.icon({ checked, disabled: disabled.value })
|
slots.icon({ checked, disabled: disabled.value })
|
||||||
) : (
|
) : shape !== 'dot' ? (
|
||||||
<Icon name="success" style={iconStyle.value} />
|
<Icon name="success" style={iconStyle.value} />
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
class={bem('icon--dot__icon')}
|
||||||
|
style={{ backgroundColor: iconStyle.value?.backgroundColor }}
|
||||||
|
></div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -66,6 +66,11 @@ export default {
|
|||||||
<van-radio name="1" shape="square">Radio 1</van-radio>
|
<van-radio name="1" shape="square">Radio 1</van-radio>
|
||||||
<van-radio name="2" shape="square">Radio 2</van-radio>
|
<van-radio name="2" shape="square">Radio 2</van-radio>
|
||||||
</van-radio-group>
|
</van-radio-group>
|
||||||
|
|
||||||
|
<van-radio-group v-model="checked">
|
||||||
|
<van-radio name="1" shape="dot">Radio 1</van-radio>
|
||||||
|
<van-radio name="2" shape="dot">Radio 2</van-radio>
|
||||||
|
</van-radio-group>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom Color
|
### Custom Color
|
||||||
@ -190,7 +195,7 @@ import type {
|
|||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| name | Radio name, usually a unique string or number | _any_ | - |
|
| name | Radio name, usually a unique string or number | _any_ | - |
|
||||||
| shape | Can be set to `square` | _string_ | `round` |
|
| shape | Can be set to `square` `dot` | _string_ | `round` |
|
||||||
| disabled | Whether to disable radio | _boolean_ | `false` |
|
| disabled | Whether to disable radio | _boolean_ | `false` |
|
||||||
| label-disabled | Whether to disable label click | _boolean_ | `false` |
|
| label-disabled | Whether to disable label click | _boolean_ | `false` |
|
||||||
| label-position | Can be set to `left` | _string_ | `right` |
|
| label-position | Can be set to `left` | _string_ | `right` |
|
||||||
@ -235,6 +240,7 @@ The component provides the following CSS variables, which can be used to customi
|
|||||||
| Name | Default Value | Description |
|
| Name | Default Value | Description |
|
||||||
| -------------------------------- | -------------------------- | ----------- |
|
| -------------------------------- | -------------------------- | ----------- |
|
||||||
| --van-radio-size | _20px_ | - |
|
| --van-radio-size | _20px_ | - |
|
||||||
|
| --van-radio-dot-size | _8px_ | - |
|
||||||
| --van-radio-border-color | _var(--van-gray-5)_ | - |
|
| --van-radio-border-color | _var(--van-gray-5)_ | - |
|
||||||
| --van-radio-duration | _var(--van-duration-fast)_ | - |
|
| --van-radio-duration | _var(--van-duration-fast)_ | - |
|
||||||
| --van-radio-label-margin | _var(--van-padding-xs)_ | - |
|
| --van-radio-label-margin | _var(--van-padding-xs)_ | - |
|
||||||
|
@ -65,13 +65,18 @@ export default {
|
|||||||
|
|
||||||
### 自定义形状
|
### 自定义形状
|
||||||
|
|
||||||
将 `shape` 属性设置为 `square`,单选框的形状会变成方形。
|
`shape` 属性可选值为 `square` 和 `dot`,单选框形状分别对应方形和圆形。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-radio-group v-model="checked">
|
<van-radio-group v-model="checked">
|
||||||
<van-radio name="1" shape="square">单选框 1</van-radio>
|
<van-radio name="1" shape="square">单选框 1</van-radio>
|
||||||
<van-radio name="2" shape="square">单选框 2</van-radio>
|
<van-radio name="2" shape="square">单选框 2</van-radio>
|
||||||
</van-radio-group>
|
</van-radio-group>
|
||||||
|
|
||||||
|
<van-radio-group v-model="checked">
|
||||||
|
<van-radio name="1" shape="dot">Radio 1</van-radio>
|
||||||
|
<van-radio name="2" shape="dot">Radio 2</van-radio>
|
||||||
|
</van-radio-group>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 自定义颜色
|
### 自定义颜色
|
||||||
@ -190,7 +195,7 @@ export default {
|
|||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| name | 标识符,通常为一个唯一的字符串或数字 | _any_ | - |
|
| name | 标识符,通常为一个唯一的字符串或数字 | _any_ | - |
|
||||||
| shape | 形状,可选值为 `square` | _string_ | `round` |
|
| shape | 形状,可选值为 `square` `dot` | _string_ | `round` |
|
||||||
| disabled | 是否为禁用状态 | _boolean_ | `false` |
|
| disabled | 是否为禁用状态 | _boolean_ | `false` |
|
||||||
| label-disabled | 是否禁用文本内容点击 | _boolean_ | `false` |
|
| label-disabled | 是否禁用文本内容点击 | _boolean_ | `false` |
|
||||||
| label-position | 文本位置,可选值为 `left` | _string_ | `right` |
|
| label-position | 文本位置,可选值为 `left` | _string_ | `right` |
|
||||||
@ -249,6 +254,7 @@ import type {
|
|||||||
| 名称 | 默认值 | 描述 |
|
| 名称 | 默认值 | 描述 |
|
||||||
| -------------------------------- | -------------------------- | ---- |
|
| -------------------------------- | -------------------------- | ---- |
|
||||||
| --van-radio-size | _20px_ | - |
|
| --van-radio-size | _20px_ | - |
|
||||||
|
| --van-radio-dot-size | _8px_ | - |
|
||||||
| --van-radio-border-color | _var(--van-gray-5)_ | - |
|
| --van-radio-border-color | _var(--van-gray-5)_ | - |
|
||||||
| --van-radio-duration | _var(--van-duration-fast)_ | - |
|
| --van-radio-duration | _var(--van-duration-fast)_ | - |
|
||||||
| --van-radio-label-margin | _var(--van-padding-xs)_ | - |
|
| --van-radio-label-margin | _var(--van-padding-xs)_ | - |
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { defineComponent, type ExtractPropTypes } from 'vue';
|
import { defineComponent, type ExtractPropTypes } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { pick, createNamespace } from '../utils';
|
import { pick, extend, createNamespace, makeStringProp } from '../utils';
|
||||||
import { RADIO_KEY } from '../radio-group/RadioGroup';
|
import { RADIO_KEY } from '../radio-group/RadioGroup';
|
||||||
|
|
||||||
// Composables
|
// Composables
|
||||||
@ -10,13 +10,16 @@ import { useParent } from '@vant/use';
|
|||||||
// Components
|
// Components
|
||||||
import Checker, {
|
import Checker, {
|
||||||
checkerProps,
|
checkerProps,
|
||||||
CheckerShape,
|
type CheckerShape,
|
||||||
CheckerLabelPosition,
|
type CheckerLabelPosition,
|
||||||
} from '../checkbox/Checker';
|
} from '../checkbox/Checker';
|
||||||
|
|
||||||
export const radioProps = checkerProps;
|
export type RadioShape = CheckerShape | 'dot';
|
||||||
|
|
||||||
|
export const radioProps = extend({}, checkerProps, {
|
||||||
|
shape: makeStringProp<RadioShape>('round'),
|
||||||
|
});
|
||||||
|
|
||||||
export type RadioShape = CheckerShape;
|
|
||||||
export type RadioLabelPosition = CheckerLabelPosition;
|
export type RadioLabelPosition = CheckerLabelPosition;
|
||||||
export type RadioProps = ExtractPropTypes<typeof radioProps>;
|
export type RadioProps = ExtractPropTypes<typeof radioProps>;
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ const [name, bem] = createNamespace('radio');
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name,
|
name,
|
||||||
|
|
||||||
props: checkerProps,
|
props: radioProps,
|
||||||
|
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ const radio3 = ref('1');
|
|||||||
const radio4 = ref('1');
|
const radio4 = ref('1');
|
||||||
const radio5 = ref('1');
|
const radio5 = ref('1');
|
||||||
const radioLabel = ref('1');
|
const radioLabel = ref('1');
|
||||||
const radioShape = ref('1');
|
const radioSquare = ref('1');
|
||||||
|
const radioDot = ref('1');
|
||||||
const radioIconSize = ref('1');
|
const radioIconSize = ref('1');
|
||||||
const radioHorizontal = ref('1');
|
const radioHorizontal = ref('1');
|
||||||
const radioLeftLabel = ref('1');
|
const radioLeftLabel = ref('1');
|
||||||
@ -76,10 +77,18 @@ const inactiveIcon = cdnURL('user-inactive.png');
|
|||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block :title="t('customShape')">
|
<demo-block :title="t('customShape')">
|
||||||
<van-radio-group v-model="radioShape" class="demo-radio-group">
|
<van-radio-group v-model="radioSquare" class="demo-radio-group">
|
||||||
<van-radio name="1" shape="square">{{ t('radio') }} 1</van-radio>
|
<van-radio name="1" shape="square">{{ t('radio') }} 1</van-radio>
|
||||||
<van-radio name="2" shape="square">{{ t('radio') }} 2</van-radio>
|
<van-radio name="2" shape="square">{{ t('radio') }} 2</van-radio>
|
||||||
</van-radio-group>
|
</van-radio-group>
|
||||||
|
<van-radio-group
|
||||||
|
v-model="radioDot"
|
||||||
|
class="demo-radio-group"
|
||||||
|
style="margin-top: 20px"
|
||||||
|
>
|
||||||
|
<van-radio name="1" shape="dot">{{ t('radio') }} 1</van-radio>
|
||||||
|
<van-radio name="2" shape="dot">{{ t('radio') }} 2</van-radio>
|
||||||
|
</van-radio-group>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block :title="t('customColor')">
|
<demo-block :title="t('customColor')">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--van-radio-size: 20px;
|
--van-radio-size: 20px;
|
||||||
|
--van-radio-dot-size: 8px;
|
||||||
--van-radio-border-color: var(--van-gray-5);
|
--van-radio-border-color: var(--van-gray-5);
|
||||||
--van-radio-duration: var(--van-duration-fast);
|
--van-radio-duration: var(--van-duration-fast);
|
||||||
--van-radio-label-margin: var(--van-padding-xs);
|
--van-radio-label-margin: var(--van-padding-xs);
|
||||||
@ -56,12 +57,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--dot {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: var(--van-radio-size);
|
||||||
|
height: var(--van-radio-size);
|
||||||
|
border: 1px solid var(--van-radio-border-color);
|
||||||
|
transition-duration: var(--van-radio-duration);
|
||||||
|
transition-property: border-color;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
border-radius: 100%;
|
||||||
|
height: calc(100% - var(--van-radio-dot-size));
|
||||||
|
width: calc(100% - var(--van-radio-dot-size));
|
||||||
|
transition-duration: var(--van-radio-duration);
|
||||||
|
transition-property: border-color, background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&--checked {
|
&--checked {
|
||||||
.van-icon {
|
.van-icon {
|
||||||
color: var(--van-white);
|
color: var(--van-white);
|
||||||
background-color: var(--van-radio-checked-icon-color);
|
background-color: var(--van-radio-checked-icon-color);
|
||||||
border-color: var(--van-radio-checked-icon-color);
|
border-color: var(--van-radio-checked-icon-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.van-radio__icon--dot {
|
||||||
|
border-color: var(--van-radio-checked-icon-color);
|
||||||
|
.van-radio__icon--dot__icon {
|
||||||
|
background: var(--van-radio-checked-icon-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&--disabled {
|
&--disabled {
|
||||||
|
@ -191,6 +191,50 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="van-radio-group demo-radio-group"
|
||||||
|
role="radiogroup"
|
||||||
|
style="margin-top:20px;"
|
||||||
|
>
|
||||||
|
<!--[-->
|
||||||
|
<div role="radio"
|
||||||
|
class="van-radio"
|
||||||
|
tabindex="0"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<!--[-->
|
||||||
|
<div class="van-radio__icon van-radio__icon--dot van-radio__icon--checked"
|
||||||
|
style
|
||||||
|
>
|
||||||
|
<div class="van-radio__icon--dot__icon"
|
||||||
|
style
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="van-radio__label">
|
||||||
|
<!--[-->
|
||||||
|
Radio 1
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-radio"
|
||||||
|
tabindex="0"
|
||||||
|
aria-checked="false"
|
||||||
|
>
|
||||||
|
<!--[-->
|
||||||
|
<div class="van-radio__icon van-radio__icon--dot"
|
||||||
|
style
|
||||||
|
>
|
||||||
|
<div class="van-radio__icon--dot__icon"
|
||||||
|
style
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="van-radio__label">
|
||||||
|
<!--[-->
|
||||||
|
Radio 2
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<!--[-->
|
<!--[-->
|
||||||
|
@ -126,6 +126,37 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="van-radio-group demo-radio-group"
|
||||||
|
role="radiogroup"
|
||||||
|
style="margin-top: 20px;"
|
||||||
|
>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-radio"
|
||||||
|
tabindex="0"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<div class="van-radio__icon van-radio__icon--dot van-radio__icon--checked">
|
||||||
|
<div class="van-radio__icon--dot__icon">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="van-radio__label">
|
||||||
|
Radio 1
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-radio"
|
||||||
|
tabindex="0"
|
||||||
|
aria-checked="false"
|
||||||
|
>
|
||||||
|
<div class="van-radio__icon van-radio__icon--dot">
|
||||||
|
<div class="van-radio__icon--dot__icon">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="van-radio__label">
|
||||||
|
Radio 2
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="van-radio-group demo-radio-group"
|
<div class="van-radio-group demo-radio-group"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export type RadioThemeVars = {
|
export type RadioThemeVars = {
|
||||||
radioSize?: string;
|
radioSize?: string;
|
||||||
|
radioDotSize?: string;
|
||||||
radioBorderColor?: string;
|
radioBorderColor?: string;
|
||||||
radioDuration?: string;
|
radioDuration?: string;
|
||||||
radioLabelMargin?: string;
|
radioLabelMargin?: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user