0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue.js: 子コンポーネントを親コンポーネントの外で使いたい

Last updated at Posted at 2020-11-17

Vue.jsで、親コンポーネントに埋め込むために作った子コンポーネントを、親コンポーネントの外側で使いたいことがあります。HTML上で離れたところに置く必要があるときです。

image.png

子コンポーネントの例:エラーメッセージ

例として、フォームの送信時に使うようなエラーメッセージのコンポーネントを作りました。

props に title と messages を指定せずに、オブジェクト errors を使っているのは、外側から操作しやすいようにするためです。

alert.vue
<template>
  <div>
    <div class="alert alert-danger" role="alert" v-if="title || messages.length">
      <div v-if="title">{{title}}</div>
      <ul v-if="messages.length" class="mb-0">
        <li v-for="(message, idx) in messages" :key="idx">{{message}}</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  props: { errors: Object },
  computed: {
    title() {
      return this.errors.title;
    },
    messages() {
      return this.errors.messages || [];
    }
  }
}
</script>

普通の使い方

まず、普通に親コンポーネントの中に子コンポーネント(エラーメッセージ)を置く使い方です。

sample1.html
<div id="sample1"></div>
app.js
import Vue from 'vue';
import Sample1 from './sample1.vue';

document.addEventListener('DOMContentLoaded', () => {
  new Vue(Sample1).$mount('#sample1');
});
sample1.vue
<template>
  <div>
    <alert :errors="errors"></alert>
    <p><input type="email" v-model="email" class="form-control" /></p>
    <p><input type="button" value="送信" @click="submit" class="btn btn-primary" /></p>
  </div>
</template>

<script>
import Alert from './alert.vue';

export default {
  components: { 'alert': Alert },
  data() {
    return {
      email: '',
      errors: {
        title: null,
        messages: []
      }
    };
  },
  methods: {
    submit() {
      this.errors.title = '保存に失敗しました。';
      this.errors.messages = ['メールアドレスが不正です。'];
    }
  }
}
</script>

外に置くときの使い方

次は、子コンポーネント(エラーメッセージ)を親コンポーネントの外に置くときの使い方です。props 用のオブジェクト errors を作って2つのコンポーネントで共有します。

キモは、Vue.observable を使ってオブジェクトをリアクティブにすることです。observable を使わないと title や messages の変化がエラーメッセージに伝わりません。

sample2.html
<div id="alert"></div>
<div id="sample2"></div>
app.js
import Vue from 'vue';
import Alert from './alert.vue';
import Sample2 from './sample2.vue';

document.addEventListener('DOMContentLoaded', () => {
  const errors = Vue.observable({ title: '', messages: [] });

  new Vue({
    render: h => h(Alert, { props: { errors: errors } })
  }).$mount('#alert');

  new Vue({
    render: h => h(Sample2, { props: { errors: errors } })
  }).$mount('#sample2');
});
sample2.vue
<template>
  <div>
    <p><input type="email" v-model="email" class="form-control" /></p>
    <p><input type="button" value="送信" @click="submit" class="btn btn-primary" /></p>
  </div>
</template>

<script>
export default {
  props: { errors: Object },
  data() {
    return {
      email: ''
    };
  },
  methods: {
    submit() {
      this.errors.title = '保存に失敗しました。';
      this.errors.messages = ['メールアドレスが不正です。'];
    }
  }
}
</script>

なお、Vueのバージョン3では、observable の代わりに reactive を使います。

app.js
import { createApp, reactive, h } from 'vue';
import Alert from './alert.vue';
import Sample2 from './sample2.vue';

document.addEventListener('DOMContentLoaded', () => {
  const errors = reactive({ title: '', messages: [] });

  createApp({
    render() { return h(Alert, { errors: errors }); }
  }).mount('#alert');

  createApp({
    render() { return h(Sample2, { errors: errors }); }
  }).mount('#sample2');
});

親コンポーネントなしで使う

observable または reactive を使うと、親コンポーネントなしでエラーメッセージを使うこともできます。次は、jQueryを使った例です。

sample3.html
<div id="alert"></div>
<div>
  <p><input type="email" v-model="email" class="form-control" /></p>
  <p><input type="button" value="送信" id="submit" class="btn btn-primary" /></p>
</div>
app.js
import Vue from 'vue';
import $ from 'jquery';
import Alert from './alert.vue';

document.addEventListener('DOMContentLoaded', () => {
  const errors = Vue.observable({ title: '', messages: [] });

  new Vue({
    render: h => h(Alert, { props: { errors: errors } })
  }).$mount('#alert');

  $('#submit').on('click', (e) => {
    errors.title = '保存に失敗しました。';
    errors.messages = ['メールアドレスが不正です。'];
  });
});
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?