環境
nuxt 3.11.2
vue 3.4.27
自作するRadioGroupの要件は以下です。
- 複数の選択肢から一つを選択状態にできる
- スタイルは呼び出し元で指定する
ファイル作成
nuxt環境でコードを書きます。
RadioGroupの一つ一つのボタンをradio.vue
, ボタンをまとめるコンポーネントをradioGroup.vue
として定義します。
src/components/atoms/radio.vue
<template>
<div>
<slot />
</div>
</template>
src/components/atoms/radioGroup.vue
<template>
<div flex="~ col" gap="12px">
<slot />
</div>
</template>
RadioGroupで選択中の値を管理できるようにする
value
という変数名で選択中の値を管理します。
src/components/atoms/radioGroup.vue
<template>
<div flex="~ col" gap="12px">
<slot />
</div>
</template>
<script setup lang="ts">
export interface RadioGroupHelper {
vale: Ref<string | undefined>;
handleSelect: (value?: string) => void;
}
interface Props {
value?: string
}
interface Emits {
(event: 'update:value', value?: string): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const value = useVModel(props, 'value', emit)
</script>
radioをクリックしたときにradioGroupで管理している値を更新する
provide
を使い、radioをクリックしたときに実行する関数を定義します。
src/components/atoms/radioGroup.vue
<template>
<div flex="~ col" gap="12px">
<slot />
</div>
</template>
<script lang="ts">
export const radioGroupHelperKey: InjectionKey<RadioGroupHelper> =
Symbol("radioGroupHelper");
</script>
<script setup lang="ts">
import type { InjectionKey } from "vue";
export interface RadioGroupHelper {
value: Ref<string | undefined>;
handleSelect: (value: string) => void;
}
interface Props {
value?: string;
}
interface Emits {
(event: "update:value", value?: string): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const value = useVModel(props, "value", emit);
provide(radioGroupHelperKey, {
value,
handleSelect: (itemValue: string) => {
value.value = itemValue;
},
});
</script>
src/components/atoms/radio.vue
<template>
<div @click="updateSelected">
<slot />
</div>
</template>
<script setup lang="ts">
import { radioGroupHelperKey, type RadioGroupHelper } from "./radioGroup.vue";
interface Props {
value: string;
}
const props = defineProps<Props>();
const radioGroupHelper = inject<RadioGroupHelper | undefined>(
radioGroupHelperKey,
undefined
);
const selected = ref<boolean>(false);
const updateSelected = () => {
selected.value = !selected.value;
if (selected.value) {
radioGroupHelper?.handleSelect(props.value)
}
};
</script>