0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Vue】Provide, Injectを使ってRadioGroupを自作する

Posted at

環境

nuxt 3.11.2
vue 3.4.27

自作するRadioGroupの要件は以下です。

  1. 複数の選択肢から一つを選択状態にできる
  2. スタイルは呼び出し元で指定する

ファイル作成

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>

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?