refactor(radio): use composition api (#4720)

* refactor(radio): use composition api

* docs: update

* chore: update

* docs: update

* Update Group.tsx

Co-authored-by: tangjinzhou <415800467@qq.com>
pull/4723/head
ajuner 2021-10-01 14:53:37 +08:00 committed by GitHub
parent f653955c97
commit cf3fe6b9e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 325 additions and 250 deletions

View File

@ -1,133 +1,133 @@
import { provide, inject, nextTick, defineComponent } from 'vue';
import { provide, nextTick, defineComponent, ref, watch, onBeforeMount } from 'vue';
import type { PropType, ExtractPropTypes } from 'vue';
import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import Radio from './Radio';
import { getOptionProps, filterEmpty, hasProp, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import useConfigInject from '../_util/hooks/useConfigInject';
import { tuple } from '../_util/type';
import type { RadioChangeEvent } from './interface';
import { useInjectFormItemContext } from '../form/FormItemContext';
export default defineComponent({
name: 'ARadioGroup',
props: {
const RadioGroupSizeTypes = tuple('large', 'default', 'small');
export type RadioGroupSize = typeof RadioGroupSizeTypes[number];
const RadioGroupOptionTypes = tuple('default', 'button');
export type RadioGroupOption = typeof RadioGroupOptionTypes[number];
export type RadioGroupChildOption = {
label: string;
value: string;
disabled?: boolean;
};
const radioGroupProps = {
prefixCls: PropTypes.string,
defaultValue: PropTypes.any,
value: PropTypes.any,
size: PropTypes.oneOf(tuple('large', 'default', 'small')).def('default'),
options: PropTypes.array,
size: PropTypes.oneOf(RadioGroupSizeTypes).def('default'),
options: {
type: Array as PropType<Array<String | RadioGroupChildOption>>,
},
disabled: PropTypes.looseBool,
name: PropTypes.string,
buttonStyle: PropTypes.string.def('outline'),
onChange: PropTypes.func,
id: PropTypes.string,
},
optionType: PropTypes.oneOf(RadioGroupOptionTypes).def('default'),
};
export type RadioGroupProps = Partial<ExtractPropTypes<typeof radioGroupProps>>;
export default defineComponent({
name: 'ARadioGroup',
props: radioGroupProps,
emits: ['update:value', 'change'],
setup() {
setup(props, { slots, emit }) {
const formItemContext = useInjectFormItemContext();
return {
formItemContext,
updatingValue: false,
configProvider: inject('configProvider', defaultConfigProvider),
radioGroupContext: null,
};
const { prefixCls } = useConfigInject('radio', props);
const stateValue = ref(props.value === undefined ? props.defaultValue : props.value);
const updatingValue = ref<boolean>(false);
watch(
() => props.value,
val => {
stateValue.value = val;
updatingValue.value = false;
},
data() {
const { value, defaultValue } = this;
return {
stateValue: value === undefined ? defaultValue : value,
};
},
watch: {
value(val) {
this.updatingValue = false;
this.stateValue = val;
},
},
// computed: {
// radioOptions() {
// const { disabled } = this;
// return this.options.map(option => {
// return typeof option === 'string'
// ? { label: option, value: option }
// : { ...option, disabled: option.disabled === undefined ? disabled : option.disabled };
// });
// },
// },
created() {
this.radioGroupContext = provide('radioGroupContext', this);
},
methods: {
onRadioChange(ev: RadioChangeEvent) {
const lastValue = this.stateValue;
);
const onRadioChange = (ev: RadioChangeEvent) => {
const lastValue = stateValue.value;
const { value } = ev.target;
if (!hasProp(this, 'value')) {
this.stateValue = value;
if (!('value' in props)) {
stateValue.value = value;
}
// nextTick for https://github.com/vueComponent/ant-design-vue/issues/1280
if (!this.updatingValue && value !== lastValue) {
this.updatingValue = true;
this.$emit('update:value', value);
this.$emit('change', ev);
this.formItemContext.onFieldChange();
if (!updatingValue.value && value !== lastValue) {
updatingValue.value = true;
emit('update:value', value);
emit('change', ev);
formItemContext.onFieldChange();
}
nextTick(() => {
this.updatingValue = false;
updatingValue.value = false;
});
},
},
render() {
const props = getOptionProps(this);
const {
prefixCls: customizePrefixCls,
options,
buttonStyle,
id = this.formItemContext.id.value,
} = props;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
};
provide('radioGroupContext', {
onRadioChange,
stateValue,
props,
});
return () => {
const { options, optionType, buttonStyle, id = formItemContext.id.value } = props;
const groupPrefixCls = `${prefixCls.value}-group`;
const groupPrefixCls = `${prefixCls}-group`;
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
[`${groupPrefixCls}-${props.size}`]: props.size,
});
let children = filterEmpty(getSlot(this));
// options, 使
let children = null;
if (options && options.length > 0) {
const optionsPrefixCls =
optionType === 'button' ? `${prefixCls.value}-button` : prefixCls.value;
children = options.map(option => {
if (typeof option === 'string') {
return (
<Radio
key={option}
prefixCls={prefixCls}
prefixCls={optionsPrefixCls}
disabled={props.disabled}
value={option}
checked={this.stateValue === option}
checked={stateValue.value === option}
>
{option}
</Radio>
);
}
const { value, disabled, label } = option as RadioGroupChildOption;
return (
<Radio
key={`radio-group-value-options-${option.value}`}
prefixCls={prefixCls}
disabled={option.disabled || props.disabled}
value={option.value}
checked={this.stateValue === option.value}
key={`radio-group-value-options-${value}`}
prefixCls={optionsPrefixCls}
disabled={disabled || props.disabled}
value={value}
checked={stateValue.value === value}
>
{option.label}
{label}
</Radio>
);
});
} else {
children = slots.default?.();
}
return (
<div class={classString} id={id}>
{children}
</div>
);
};
},
});

View File

@ -1,16 +1,14 @@
import type { ExtractPropTypes } from 'vue';
import { defineComponent, inject } from 'vue';
import { defineComponent, inject, ref } from 'vue';
import PropTypes from '../_util/vue-types';
import VcCheckbox from '../vc-checkbox';
import classNames from '../_util/classNames';
import { getOptionProps } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import type { RadioChangeEvent } from './interface';
import useConfigInject from '../_util/hooks/useConfigInject';
import type { RadioChangeEvent, RadioGroupContext } from './interface';
import { useInjectFormItemContext } from '../form/FormItemContext';
export const radioProps = {
prefixCls: PropTypes.string,
defaultChecked: PropTypes.looseBool,
checked: PropTypes.looseBool,
disabled: PropTypes.looseBool,
isGroup: PropTypes.looseBool,
@ -30,72 +28,67 @@ export default defineComponent({
name: 'ARadio',
props: radioProps,
emits: ['update:checked', 'update:value', 'change', 'blur', 'focus'],
setup() {
setup(props, { emit, expose, slots }) {
const formItemContext = useInjectFormItemContext();
return {
configProvider: inject('configProvider', defaultConfigProvider),
radioGroupContext: inject('radioGroupContext', null),
formItemContext,
};
},
methods: {
focus() {
(this.$refs.vcCheckbox as HTMLInputElement).focus();
},
blur() {
(this.$refs.vcCheckbox as HTMLInputElement).blur();
},
handleChange(event: RadioChangeEvent) {
const targetChecked = event.target.checked;
this.$emit('update:checked', targetChecked);
this.$emit('update:value', targetChecked);
this.$emit('change', event);
this.formItemContext.onFieldChange();
},
onChange2(e: RadioChangeEvent) {
this.$emit('change', e);
if (this.radioGroupContext && this.radioGroupContext.onRadioChange) {
this.radioGroupContext.onRadioChange(e);
}
},
},
const vcCheckbox = ref<HTMLElement>();
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext');
const { prefixCls } = useConfigInject('radio', props);
render() {
const { $slots, radioGroupContext: radioGroup } = this;
const props = getOptionProps(this);
const {
prefixCls: customizePrefixCls,
id = this.formItemContext.id.value,
...restProps
} = props;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const focus = () => {
vcCheckbox.value.focus();
};
const blur = () => {
vcCheckbox.value.blur();
};
expose({ focus, blur });
const handleChange = (event: RadioChangeEvent) => {
const targetChecked = event.target.checked;
emit('update:checked', targetChecked);
emit('update:value', targetChecked);
emit('change', event);
formItemContext.onFieldChange();
};
const onChange = (e: RadioChangeEvent) => {
emit('change', e);
if (radioGroupContext && radioGroupContext.onRadioChange) {
radioGroupContext.onRadioChange(e);
}
};
return () => {
const radioGroup = radioGroupContext;
const { prefixCls: customizePrefixCls, id = formItemContext.id.value, ...restProps } = props;
const rProps: RadioProps = {
prefixCls,
prefixCls: prefixCls.value,
id,
...restProps,
};
if (radioGroup) {
rProps.name = radioGroup.name;
rProps.onChange = this.onChange2;
rProps.checked = props.value === radioGroup.stateValue;
rProps.disabled = props.disabled || radioGroup.disabled;
rProps.name = radioGroup.props.name;
rProps.onChange = onChange;
rProps.checked = props.value === radioGroup.stateValue.value;
rProps.disabled = props.disabled || radioGroup.props.disabled;
} else {
rProps.onChange = this.handleChange;
rProps.onChange = handleChange;
}
const wrapperClassString = classNames({
[`${prefixCls}-wrapper`]: true,
[`${prefixCls}-wrapper-checked`]: rProps.checked,
[`${prefixCls}-wrapper-disabled`]: rProps.disabled,
[`${prefixCls.value}-wrapper`]: true,
[`${prefixCls.value}-wrapper-checked`]: rProps.checked,
[`${prefixCls.value}-wrapper-disabled`]: rProps.disabled,
});
return (
<label class={wrapperClassString}>
<VcCheckbox {...rProps} ref="vcCheckbox" />
{$slots.default && <span>{$slots.default()}</span>}
<VcCheckbox {...rProps} ref={vcCheckbox} />
{slots.default && <span>{slots.default()}</span>}
</label>
);
};
},
});

View File

@ -1,35 +1,28 @@
import { defineComponent, inject } from 'vue';
import type { RadioProps } from './Radio';
import Radio, { radioProps } from './Radio';
import { getOptionProps, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import useConfigInject from '../_util/hooks/useConfigInject';
import type { RadioGroupContext } from './interface';
export default defineComponent({
name: 'ARadioButton',
props: {
...radioProps,
},
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
radioGroupContext: inject<any>('radioGroupContext', {}),
};
},
render() {
const props = getOptionProps(this) as RadioProps;
const { prefixCls: customizePrefixCls, ...otherProps } = props;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
props: radioProps,
setup(props: RadioProps, { slots }) {
const { prefixCls } = useConfigInject('radio-button', props);
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext');
return () => {
const rProps: RadioProps = {
prefixCls,
...otherProps,
...props,
prefixCls: prefixCls.value,
};
if (this.radioGroupContext) {
rProps.onChange = this.radioGroupContext.onRadioChange;
rProps.checked = props.value === this.radioGroupContext.stateValue;
rProps.disabled = props.disabled || this.radioGroupContext.disabled;
if (radioGroupContext) {
rProps.onChange = radioGroupContext.onRadioChange;
rProps.checked = rProps.value === radioGroupContext.stateValue.value;
rProps.disabled = rProps.disabled || radioGroupContext.props.disabled;
}
return <Radio {...rProps}>{getSlot(this)}</Radio>;
return <Radio {...rProps}>{slots.default?.()}</Radio>;
};
},
});

View File

@ -41,13 +41,16 @@ exports[`renders ./components/radio/demo/radioGroup.vue correctly 1`] = `
</div>
`;
exports[`renders ./components/radio/demo/radioGroup-more.vue correctly 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="1"><span class="ant-radio-inner"></span></span><span>Option A</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="2"><span class="ant-radio-inner"></span></span><span>Option B</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="3"><span class="ant-radio-inner"></span></span><span>Option C</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="4"><span class="ant-radio-inner"></span></span><span> More... <!--v-if--></span></label></div>`;
exports[`renders ./components/radio/demo/radioGroup-more.vue correctly 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="1"><span class="ant-radio-inner"></span></span><span>Option A</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="2"><span class="ant-radio-inner"></span></span><span>Option B</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="3"><span class="ant-radio-inner"></span></span><span>Option C</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="4"><span class="ant-radio-inner"></span></span><span> More... <!--v-if--></span></label></div>`;
exports[`renders ./components/radio/demo/radioGroup-options.vue correctly 1`] = `
<div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-checked ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-checked ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-checked ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
</div>
`;

View File

@ -2,7 +2,7 @@
exports[`Radio all children should have a name property 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
exports[`Radio fire change events when value changes 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
exports[`Radio fire change events when value changes 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
exports[`Radio fire change events when value changes 2`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;

View File

@ -46,4 +46,3 @@ export default defineComponent({
},
});
</script>
```

View File

@ -32,7 +32,7 @@ export default defineComponent({
setup() {
const value = ref<number>(1);
const radioStyle = reactive({
display: 'block',
display: 'flex',
height: '30px',
lineHeight: '30px',
});

View File

@ -19,9 +19,16 @@ Render radios by configuring `options`.
<div>
<a-radio-group v-model:value="value1" :options="plainOptions" />
<br />
<a-radio-group v-model:value="value2" :options="options" />
<a-radio-group v-model:value="value2" :options="optionsWithDisabled" />
<br />
<a-radio-group v-model:value="value3" :options="plainOptions" disabled />
<br />
<a-radio-group v-model:value="value1" option-type="button" :options="plainOptions" />
<br />
<a-radio-group v-model:value="value2" option-type="button" :options="optionsWithDisabled" />
<br />
<a-radio-group v-model:value="value3" option-type="button" :options="plainOptions" disabled />
<br />
<a-radio-group v-model:value="value3" :options="optionsWithDisabled" disabled />
</div>
</template>
<script lang="ts">
@ -35,7 +42,7 @@ const options = [
const optionsWithDisabled = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: false },
{ label: 'Orange', value: 'Orange', disabled: true },
];
export default defineComponent({
data() {

View File

@ -14,7 +14,7 @@ Radio.
## API
### Radio
### Radio/Radio.Button
| Property | Description | Type | Default |
| --- | --- | --- | --- |
@ -27,15 +27,15 @@ Radio.
Radio group can wrap a group of `Radio`
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| defaultValue | Default selected value | any | - |
| disabled | Disable all radio buttons | boolean | false |
| name | The `name` property of all `input[type="radio"]` children | string | - |
| options | set children optional | string\[] \| Array&lt;{ label: string value: string disabled?: boolean }> | - |
| size | size for radio button style | `large` \| `default` \| `small` | `default` |
| value(v-model) | Used for setting the currently selected value. | any | - |
| buttonStyle | style type of radio button | `outline` \| `solid` | `outline` |
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| buttonStyle | style type of radio button | `outline` \| `solid` | `outline` | |
| disabled | Disable all radio buttons | boolean | false | |
| name | The `name` property of all `input[type="radio"]` children | string | - | |
| options | set children optional | string\[] \| Array&lt;{ label: string value: string disabled?: boolean }> | - | |
| optionType | Set Radio optionType | `default` \| `button` | `default` | 3.0.0 |
| size | size for radio button style | `large` \| `default` \| `small` | `default` | |
| value(v-model) | Used for setting the currently selected value. | any | - | |
### RadioGroup Events

View File

@ -15,27 +15,28 @@ cover: https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg
## API
### Radio
### Radio/Radio.Button
| 参数 | 说明 | 类型 | 默认值 |
| ---------------- | --------------------------------- | ------- | ------ |
| autofocus | 自动获取焦点 | boolean | false |
| checked(v-model) | 指定当前是否选中 | boolean | false |
| disabled | 禁用 Radio | boolean | false |
| value | 根据 value 进行比较,判断是否选中 | any | - |
### RadioGroup
单选框组合,用于包裹一组 `Radio`
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认选中的值 | any | - |
| disabled | 禁选所有子单选器 | boolean | false |
| name | RadioGroup 下所有 `input[type="radio"]``name` 属性 | string | - |
| options | 以配置形式设置子元素 | string\[] \| Array&lt;{ label: string value: string disabled?: boolean }> | - |
| size | 大小,只对按钮样式生效 | `large` \| `default` \| `small` | `default` |
| value(v-model) | 用于设置当前选中的值 | any | - |
| buttonStyle | RadioButton 的风格样式,目前有描边和填色两种风格 | `outline` \| `solid` | `outline` |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| buttonStyle | RadioButton 的风格样式,目前有描边和填色两种风格 | `outline` \| `solid` | `outline` | |
| disabled | 禁选所有子单选器 | boolean | false | |
| name | RadioGroup 下所有 `input[type="radio"]``name` 属性 | string | - | |
| options | 以配置形式设置子元素 | string\[] \| Array&lt;{ label: string value: string disabled?: boolean }> | - | |
| optionType | 用于设置 Radio `options` 类型 | `default` \| `button` | `default` | 3.0.0 |
| size | 大小,只对按钮样式生效 | `large` \| `default` \| `small` | `default` | |
| value(v-model) | 用于设置当前选中的值 | any | - | |
### RadioGroup 事件

View File

@ -1,5 +1,5 @@
import type { RadioProps } from './Radio';
import type { Ref } from 'vue';
export interface RadioChangeEventTarget extends RadioProps {
checked: boolean;
}
@ -10,3 +10,9 @@ export interface RadioChangeEvent {
preventDefault: () => void;
nativeEvent: MouseEvent;
}
export interface RadioGroupContext {
stateValue: Ref;
props: RadioProps;
onRadioChange: (e: RadioChangeEvent) => void;
}

View File

@ -5,34 +5,47 @@
@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';
@radio-inner-prefix-cls: ~'@{radio-prefix-cls}-inner';
@radio-duration: 0.3s;
@radio-focus-shadow: 0 0 0 3px fade(@radio-dot-color, 8%);
@radio-focus-shadow: 0 0 0 3px @primary-1;
@radio-button-focus-shadow: @radio-focus-shadow;
.@{radio-group-prefix-cls} {
.reset-component();
display: inline-block;
font-size: 0;
.@{ant-prefix}-badge-count {
z-index: 1;
}
> .@{ant-prefix}-badge:not(:first-child) > .@{radio-prefix-cls}-button-wrapper {
border-left: none;
}
}
// 一般状态
.@{radio-prefix-cls}-wrapper {
.reset-component();
position: relative;
display: inline-block;
margin-right: 8px;
white-space: nowrap;
display: inline-flex;
align-items: center;
margin-right: @radio-wrapper-margin-right;
cursor: pointer;
&::after {
display: inline-block;
width: 0;
overflow: hidden;
content: '\a0';
}
}
.@{radio-prefix-cls} {
.reset-component();
position: relative;
top: @radio-top;
display: inline-block;
line-height: 1;
white-space: nowrap;
vertical-align: sub;
outline: none;
cursor: pointer;
@ -67,12 +80,10 @@
&-inner {
&::after {
@radio-dot-size: @radio-size - 8px;
position: absolute;
top: ((@radio-size - @radio-dot-size) / 2) - @radio-border-width;
left: ((@radio-size - @radio-dot-size) / 2) - @radio-border-width;
display: table;
display: block;
width: @radio-dot-size;
height: @radio-dot-size;
background-color: @radio-dot-color;
@ -95,7 +106,7 @@
border-color: @border-color-base;
border-style: solid;
border-width: @radio-border-width;
border-radius: 100px;
border-radius: 50%;
transition: all @radio-duration;
}
@ -124,6 +135,8 @@
}
.@{radio-prefix-cls}-disabled {
cursor: not-allowed;
.@{radio-inner-prefix-cls} {
background-color: @input-disabled-bg;
border-color: @border-color-base !important;
@ -155,13 +168,14 @@ span.@{radio-prefix-cls} + * {
margin: 0;
padding: 0 @padding-md - 1px;
color: @radio-button-color;
font-size: @font-size-base;
line-height: @btn-height-base - 2px;
background: @radio-button-bg;
border: @border-width-base @border-style-base @border-color-base;
// strange align fix for chrome but works
// https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif
border-top-width: @border-width-base + 0.02px;
border-left: 0;
border-left-width: 0;
cursor: pointer;
transition: color 0.3s, background 0.3s, border-color 0.3s, box-shadow 0.3s;
@ -170,10 +184,12 @@ span.@{radio-prefix-cls} + * {
}
> .@{radio-prefix-cls}-button {
display: block;
width: 0;
height: 0;
margin-left: 0;
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
}
.@{radio-group-prefix-cls}-large & {
@ -203,6 +219,7 @@ span.@{radio-prefix-cls} + * {
content: '';
}
}
&:first-child {
border-left: @border-width-base @border-style-base @border-color-base;
border-radius: @border-radius-base 0 0 @border-radius-base;
@ -324,9 +341,4 @@ span.@{radio-prefix-cls} + * {
}
}
// Firefox hack
@supports (-moz-appearance: meterbar) and (background-blend-mode: difference, normal) {
.@{radio-prefix-cls} {
vertical-align: text-bottom;
}
}
@import './rtl';

View File

@ -0,0 +1,61 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@radio-prefix-cls: ~'@{ant-prefix}-radio';
@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';
@radio-prefix-cls-button-wrapper: ~'@{radio-prefix-cls}-button-wrapper';
.@{radio-group-prefix-cls} {
&&-rtl {
direction: rtl;
}
}
// 一般状态
.@{radio-prefix-cls}-wrapper {
&&-rtl {
margin-right: 0;
margin-left: @radio-wrapper-margin-right;
direction: rtl;
}
}
.@{radio-prefix-cls-button-wrapper} {
&&-rtl {
border-right-width: 0;
border-left-width: @border-width-base;
}
&:not(:first-child) {
&::before {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
right: -1px;
left: 0;
}
}
}
&:first-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-right: @border-width-base @border-style-base @border-color-base;
border-radius: 0 @border-radius-base @border-radius-base 0;
}
.@{radio-prefix-cls-button-wrapper}-checked:not([class*=~"' @{radio-prefix-cls}-button-wrapper-disabled'"])& {
border-right-color: @radio-button-hover-color;
}
}
&:last-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-radius: @border-radius-base 0 0 @border-radius-base;
}
}
&-disabled {
&:first-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-right-color: @border-color-base;
}
}
}
}