LoginSignup
7
3

More than 3 years have passed since last update.

【Vue.js】 子コンポーネントのプロパティやイベントをそのまま全て親コンポーネントから使用する方法

Last updated at Posted at 2020-09-07

はじめに

input や button などの基本的な自作コンポーネントをさらにラップしたコンポーネントを使うときなどに、子コンポーネントのプロパティやイベントをすべて使いたい時がしばしばあります。そのようなときにどうすればいいのかをまとめました。

ルートの HTML 要素の属性は親から付与可能

そもそもの前提として、コンポーネントのルートの HTML 要素の属性は親から付与可能です。
下記のようなルート要素に input だけを配置した基本的なコンポーネントを作ったとします。

BaseInput.vue
<template>
  <input type="text">
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component({})
export default class BaseInput extends Vue {}
</script>

<style scoped lang="scss"></style>

親コンポーネントから子コンポーネントのルート HTML 要素に属性を付与することができます。

CustomInput.vue
<template>
  <base-input
    class="base-input-class"
  />
</template>

image.png

子要素のプロパティを親からすべて利用可能にする

v-bind="$attrs" を使うことで、ルート HTML 要素の属性以外の prop も親から利用可能になります。

BaseLabelInput.vue
<template>
  <div>
    <p>{{ label }}</p>
    <input
      type="text"
      v-bind="$attrs"
    >
  </div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component({})
export default class BaseLabelInput extends Vue {
  @Prop({ default: '' })
  label!: string
}
</script>
CustomLabelInput.vue
<template>
  <base-label-input
    label="label name"
    :value="test"
  />
</template>

image.png

ルート HTML 要素の属性を親から使用させたくないとき

ルート要素のプロパティを親に継承させたくないときは inheritAttrs: false を使います。
下記の例では input をルート要素に持つ BaseInput コンポーネントに inheritAttrs: false を適用した上で placeholder プロパティを付与しています。

BaseInput.vue
<template>
  <input
    type="text"
    :placeholder="placeholder"
  >
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component({ inheritAttrs: false })
export default class BaseInput extends Vue {
  @Prop()
  placeholder?: string
}
</script>

親コンポーネント側では value 属性を付与することはできません。
placeholder prop は通常通り使用できます。

CustomInput.vue
<template>
  <!-- value は無効、placeholder は有効 -->
  <base-input
    value="sample text"
    placeholder="placeholder"
    @input="onInput"
  />
</template>
...

image.png

すべてのイベントを親から使用したい時

プロパティと異なり、ルート要素であったとしても、子のイベントは受け取ることができません。
そこで、v-on=$listeners を子要素に記述し、すべてのイベントを親コンポーネントで受け取れるようにします。

BaseInput.vue
<template>
  <input
    type="text"
    v-on="$listeners"
  >
</template>
...
CustomInput.vue
<template>
  <base-input
    @input="onInput"
    @click="onClick"
    @focus="onFocus"
  >
</template>
...

参考

7
3
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
7
3