index.tsx 3.2 KB
Newer Older
D
DCloud_LXH 已提交
1
import { inject, provide, ref, onMounted, onBeforeUnmount } from 'vue'
2 3 4
import type { Ref, ExtractPropTypes, WritableComputedRef } from 'vue'
import { PolySymbol } from '@dcloudio/uni-core'
import { UniFormCtx, uniFormKey } from '../form'
5
import { defineBuiltInComponent } from '../../helpers/component'
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
import { CustomEventTrigger, useCustomEvent } from '../../helpers/useEvent'

export const uniRadioGroupKey = PolySymbol(__DEV__ ? 'uniCheckGroup' : 'ucg')

type UniRadioGroupFieldCtx = WritableComputedRef<{
  radioChecked: boolean
  value: string
}>

export interface UniRadioGroupCtx {
  addField: (field: UniRadioGroupFieldCtx) => void
  removeField: (field: UniRadioGroupFieldCtx) => void
  radioChange: ($event: Event, field: UniRadioGroupFieldCtx) => void
}

const props = {
  name: {
    type: String,
    default: '',
  },
}

type RadioGroupProps = ExtractPropTypes<typeof props>

30
export default /*#__PURE__*/ defineBuiltInComponent({
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
  name: 'RadioGroup',
  props,
  // emits: ['change'],
  setup(props, { emit, slots }) {
    const rootRef: Ref<HTMLElement | null> = ref(null)
    const trigger = useCustomEvent(rootRef, emit)

    useProvideRadioGroup(props, trigger)

    return () => {
      return (
        <uni-radio-group ref={rootRef}>
          {slots.default && slots.default()}
        </uni-radio-group>
      )
    }
  },
})

function useProvideRadioGroup(
  props: RadioGroupProps,
  trigger: CustomEventTrigger
) {
  const fields: UniRadioGroupFieldCtx[] = []

  onMounted(() => {
    _resetRadioGroupValue(fields.length - 1)
  })

  const getFieldsValue = () =>
    fields.find((field) => field.value.radioChecked)?.value.value

  provide<UniRadioGroupCtx>(uniRadioGroupKey, {
    addField(field: UniRadioGroupFieldCtx) {
      fields.push(field)
    },
    removeField(field: UniRadioGroupFieldCtx) {
      fields.splice(fields.indexOf(field), 1)
    },
    radioChange($event: Event, field: UniRadioGroupFieldCtx) {
      const index = fields.indexOf(field)
      _resetRadioGroupValue(index, true)
      trigger('change', $event, {
        value: getFieldsValue(),
      })
    },
  })

79
  const uniForm = inject<UniFormCtx>(uniFormKey, false as unknown as UniFormCtx)
D
DCloud_LXH 已提交
80 81 82 83 84 85 86 87 88 89
  const formField = {
    submit: () => {
      let data: [string, any] = ['', null]
      if (props.name !== '') {
        data[0] = props.name
        data[1] = getFieldsValue()
      }
      return data
    },
  }
90
  if (uniForm) {
D
DCloud_LXH 已提交
91 92 93
    uniForm.addField(formField)
    onBeforeUnmount(() => {
      uniForm.removeField(formField)
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    })
  }

  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)
      } else {
        // 这里逻辑有点奇怪,但我决定保留
        fields.forEach((v, i) => {
          if (index >= i) {
            return
          }
          if (fields[i].value.radioChecked) {
            setFieldChecked(fields[index], false)
          }
        })
      }
    })
  }

  return fields
}