diff --git a/packages/uni-components/src/components/radio-group.ts b/packages/uni-components/src/components/radio-group.ts index 17e143a7d9d2df79108ae87fad902793e1f92cbc..8e7e51a8291ad2cdd8e0c1928cf9fe679c7a4faa 100644 --- a/packages/uni-components/src/components/radio-group.ts +++ b/packages/uni-components/src/components/radio-group.ts @@ -1,3 +1,24 @@ +import { WritableComputedRef, ExtractPropTypes } from 'vue' import { PolySymbol } from '@dcloudio/uni-core' export const uniRadioGroupKey = PolySymbol(__DEV__ ? 'uniRadioGroup' : 'ucg') + +export type UniRadioGroupFieldCtx = WritableComputedRef<{ + radioChecked: boolean + value: string +}> + +export interface UniRadioGroupCtx { + addField: (field: UniRadioGroupFieldCtx) => void + removeField: (field: UniRadioGroupFieldCtx) => void + radioChange: ($event: Event, field: UniRadioGroupFieldCtx) => void +} + +export const radioGroupProps = { + name: { + type: String, + default: '', + }, +} + +export type RadioGroupProps = ExtractPropTypes diff --git a/packages/uni-components/src/nvue/radio-group/index.tsx b/packages/uni-components/src/nvue/radio-group/index.tsx index dd1b649705837ab51dd921dacf4f1f415a95bbdd..5f2d36d60461b1c17dfd0d87c8c427beef84798f 100644 --- a/packages/uni-components/src/nvue/radio-group/index.tsx +++ b/packages/uni-components/src/nvue/radio-group/index.tsx @@ -2,41 +2,27 @@ import { defineComponent, inject, provide, - ComputedRef, ref, - ExtractPropTypes, + onBeforeUnmount, + onMounted, } from 'vue' -import { uniRadioGroupKey } from '../../components/radio-group' +import { + uniRadioGroupKey, + UniRadioGroupFieldCtx, + UniRadioGroupCtx, + RadioGroupProps, + radioGroupProps, +} from '../../components/radio-group' import { UniFormCtx, uniFormKey } from '../../components/form' import { CustomEventTrigger, useCustomEvent, EmitEvent, -} from '../../helpers/useEvent' - -type UniRadioGroupFieldCtx = ComputedRef<{ - radioChecked: boolean - value: string -}> - -const props = { - name: { - type: String, - default: '', - }, -} - -type RadioGroupProps = ExtractPropTypes - -export interface UniRadioGroupCtx { - addField: (field: UniRadioGroupFieldCtx) => void - removeField: (field: UniRadioGroupFieldCtx) => void - radioChange: ($event: Event) => void -} +} from '../../helpers/useNVueEvent' export default defineComponent({ name: 'RadioGroup', - props, + props: radioGroupProps, emits: ['change'], setup(props, { slots, emit }) { const rootRef = ref(null) @@ -56,13 +42,12 @@ function useProvideRadioGroup( ) { const fields: UniRadioGroupFieldCtx[] = [] + onMounted(() => { + _resetRadioGroupValue(fields.length - 1) + }) + const getFieldsValue = () => - fields.reduce((res, field) => { - if (field.value.radioChecked) { - res.push(field.value.value) - } - return res - }, new Array()) + fields.find((field) => field.value.radioChecked)?.value.value provide(uniRadioGroupKey, { addField(field: UniRadioGroupFieldCtx) { @@ -71,26 +56,53 @@ function useProvideRadioGroup( removeField(field: UniRadioGroupFieldCtx) { fields.splice(fields.indexOf(field), 1) }, - radioChange($event) { - trigger('change', $event, { + radioChange($event: Event, field: UniRadioGroupFieldCtx) { + const index = fields.indexOf(field) + _resetRadioGroupValue(index, true) + trigger('change', { value: getFieldsValue(), }) }, }) const uniForm = inject(uniFormKey, false as unknown as UniFormCtx) + const formField = { + submit: () => { + let data: [string, any] = ['', null] + if (props.name !== '') { + data[0] = props.name + data[1] = getFieldsValue() + } + return data + }, + } if (uniForm) { - uniForm.addField({ - submit: () => { - let data: [string, any] = ['', null] - if (props.name !== '') { - data[0] = props.name - data[1] = getFieldsValue() - } - return data - }, + uniForm.addField(formField) + onBeforeUnmount(() => { + uniForm.removeField(formField) + }) + } + + function setFieldChecked( + field: UniRadioGroupFieldCtx, + radioChecked: boolean + ) { + field.value = { + radioChecked, + value: field.value.value, + } + } + + function _resetRadioGroupValue(key: number, change?: boolean) { + fields.forEach((value, index) => { + if (index === key) { + return + } + if (change) { + setFieldChecked(fields[index], false) + } }) } - return getFieldsValue + return fields } diff --git a/packages/uni-components/src/nvue/radio/index.tsx b/packages/uni-components/src/nvue/radio/index.tsx index a07ff802ad25ec49703030dd25cacf839d36ea95..57ac6426d7b4d7fdaef038c324c76a26938404f3 100644 --- a/packages/uni-components/src/nvue/radio/index.tsx +++ b/packages/uni-components/src/nvue/radio/index.tsx @@ -2,16 +2,20 @@ import { defineComponent, inject, onBeforeUnmount, + Ref, ref, computed, watch, - reactive, - ExtractPropTypes, } from 'vue' import { uniLabelKey, UniLabelCtx } from '../label' import { useListeners } from '../../helpers/useListeners' import { NVueComponentStyles, createNVueTextVNode } from '../utils' import { radioProps } from '../../components/radio' +import { + uniRadioGroupKey, + UniRadioGroupCtx, +} from '../../components/radio-group' +import { UniFormCtx, uniFormKey } from '../../components/form' const radioStyles: NVueComponentStyles = [ { @@ -59,8 +63,6 @@ const radioStyles: NVueComponentStyles = [ }, ] -type RadioProps = ExtractPropTypes - export default defineComponent({ name: 'Radio', props: radioProps, @@ -68,47 +70,56 @@ export default defineComponent({ emits: ['change'], setup(props, { slots }) { const rootRef = ref(null) + const radioChecked = ref(props.checked) + const radioValue = ref(props.value) + + const radioStyle = computed(() => { + const color = props.disabled ? '#adadad' : props.color + if (radioChecked.value) { + return { + backgroundColor: color, + borderColor: color, + } + } + return { + borderColor: '#d1d1d1', + } + }) + + const reset = () => { + radioChecked.value = false + } - const state = useRadioState(props) + const { uniCheckGroup, uniLabel, field } = useRadioInject( + radioChecked, + radioValue, + reset + ) - const onClick = (e: Event, isLabelClick?: boolean) => { + const _onClick = ($event: Event, isLabelClick?: boolean) => { if (props.disabled) { return } if (isLabelClick) { rootRef.value!.click() } - state.radioChecked = !state.radioChecked - /* const formType = props.formType - if (formType) { - if (!uniForm) { - return - } - if (formType === 'submit') { - uniForm.submit(e) - } else if (formType === 'reset') { - uniForm.reset(e) - } - } */ + radioChecked.value = !radioChecked.value + uniCheckGroup && uniCheckGroup.radioChange($event, field) } - const uniLabel = inject( - uniLabelKey, - false as unknown as UniLabelCtx - ) if (uniLabel) { - uniLabel.addHandler(onClick) + uniLabel.addHandler(_onClick) onBeforeUnmount(() => { - uniLabel.removeHandler(onClick) + uniLabel.removeHandler(_onClick) }) } - useListeners(props, { 'label-click': onClick }) + useListeners(props, { 'label-click': _onClick }) watch( [() => props.checked, () => props.value], ([newChecked, newModelValue]) => { - state.radioChecked = newChecked - state.radioValue = newModelValue + radioChecked.value = newChecked + radioValue.value = newModelValue } ) @@ -127,21 +138,20 @@ export default defineComponent({ return () => { const { disabled } = props - const { radioChecked, radioStyle } = state return (
- {radioChecked + {radioChecked.value ? createNVueTextVNode('\uEA08', { class: 'uni-radio-input-icon', }) @@ -154,29 +164,49 @@ export default defineComponent({ }, }) -function useRadioState(props: RadioProps) { - const radioChecked = ref(props.checked) - const radioValue = ref(props.value) - - const radioStyle = computed(() => { - if (radioChecked.value) { - return { - backgroundColor: props.color, - borderColor: props.color, - } - } - return { - borderColor: '#d1d1d1', - } +function useRadioInject( + radioChecked: Ref, + radioValue: Ref, + reset: () => void +) { + const field = computed({ + get: () => ({ + radioChecked: Boolean(radioChecked.value), + value: radioValue.value, + }), + set: ({ radioChecked: checked }) => { + radioChecked.value = checked + }, }) + const formField = { reset } + + const uniCheckGroup = inject( + uniRadioGroupKey, + false as unknown as UniRadioGroupCtx + ) + if (!!uniCheckGroup) { + uniCheckGroup.addField(field) + } - const radioColor = computed(() => (props.disabled ? '#adadad' : props.color)) + const uniForm = inject(uniFormKey, false as unknown as UniFormCtx) + if (!!uniForm) { + uniForm.addField(formField) + } - const state = reactive({ - radioStyle, - radioColor, - radioChecked, - radioValue, + const uniLabel = inject( + uniLabelKey, + false as unknown as UniLabelCtx + ) + + onBeforeUnmount(() => { + uniCheckGroup && uniCheckGroup.removeField(field) + uniForm && uniForm.removeField(formField) }) - return state + + return { + uniCheckGroup, + uniForm, + uniLabel, + field, + } }