質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

【Vue】vueのコンポーネントから別のコンポーネントを呼び出したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 5,002

hasshy

score 97

親子関係があるコンポーネント間の操作についてお伺いしたい事がございます。

 お聞きしたい事

2点質問があります。
1点目は解決しました。
スペルミスで、componentsとするところをcomponentとしていました。

質問内に、vue名が直接出ておりますが、その内容は、ソースの構成をご確認ください。

 1点目:vueコンポーネントの中から、別のコンポーネントを呼び出せない。 解決しました。

~~ 親子関係があるコンポーネントで、子コンポーネントを呼び出す事ができません。

ソースは後述しますが、mainvisualと言う親コンポーネントから、子コンポーネントである、opning,scene,shearという複数のvueを呼び出したいのですが、
次のようなエラーが表示されます。 ~~

Unknown custom element: <opning> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

 export defaultで、対象のコンポーネントを指定していますし、nameオプションも指定しています。 

 2点目:コンポーネントの出し分け

vueの開発手法的な話になってしまうのですが、場面ごとにコンポーネントを切り替えるにはどのように実装すれば良いのでしょうか?

例えば、opning.vueと言うコンポーネントは、youtubeの動画を流し、終わったら、scene.vueへ移行するとします。  
その場合、opning.vueのdisplayをnoneにし、代わりにscene.vueのdisplayをblockにします。

このような実装方法になると思うのですが、この方法がvueとしてベターな実装方法でしょうか?
(状況の把握ようにvuexも導入する準備はできているのですが、まだ使い方が把握でていません。)

 ソース

上記、質問にも出てきた、コンポーネント名も踏まえて説明いたします。

 構成

構成は下記です。 

component/
    mainvisual.vue
    opning.vue
    scene.vue
    share.vue
app.js
index.html

画面の切り替え的に、3部構成になっていて、それぞれ次のようなコンポーネント構成担っています。

  • opning.vue:初回読み込み時に表示させる要素
  • scene.vue:スライドショーのように次々画面が変わる
  • share.vue:scene.vueで選択した要素に紐づいた要素表示。

mainvisualコンポーネントは、それぞれのコンポーネントの出し分けをする想定です。

 index.html

<!DOCTYPE html>
<html lang="jp" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title></title>
        <!--[if IE]>
        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
    </head>
    <body>
        <h1>vueテスト</h1>
        <div id="app"></div>
        <script src="bundle.js"></script>
    </body>
</html>

 app.js

import Vue from 'vue'
import Vuex from 'vuex'

import Cookies from 'js-cookie'
import axios from 'axios'

import MainVisual from './components/mainvisual'

const URL_BASE = 'http://localhost:3000/'

var mv = new Vue({
    el: '#app',
    data: {
        scenes_list: []
    },
    components: {
        'mainvisual': MainVisual,
    },
    methods: {
        get_ajax(url, name) {
            return axios.get(URL_BASE + url)
                .then((res) => {
                    Vue.set(this, name, res.data);
                    this.$emit('GET_AJAX_COMPLETE');
                })
        },
        get_data(name) {
            return this.$data[name];
        }
    },
    template: '<mainvisual></mainvisual>'
});

// クッキーの情報を取得
Cookies.set('opning-skip', '1');

 commponent/mainvisual.vue

これが大元のvueになります。
もしかしたら、app.jsの二度手間かなと思ったのですが、分けています。

現在はtemplate内に全て出力してしまっていますが、本来は状況に応じてコンポーネントを消したり、表示したりしたいと考えています。

<template>
<div>
    <Opning></Opning>
    <Scene></Scene>
    <Share></Share>
</template>

<script>
import Opning from './opning'
import Scene from './scene'
import Share from './share'

export default {
    component: {
        'opning': Opning,
        'scene': Scene,
        'share': Share
    }
}
</script>

 component/opning.vue

オープニング用のコンポーネントです。

<template>
<div id="opning"></div>
</template>

<script>
import Cookies from 'js-cookie';

export default {
    name: 'opning'
}

 component/scene.vue

シーン用のコンポーネントです。

<template>
<div id="scene"></div>
</template>

<script>
export default {
    name: 'scene'
}

 component/share.vue

シェア用のコンポーネントです。

<template>
<div id="scene"></div>
</template>

<script>
export default {
    name: 'share'
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

質問2についてです。

Vue.jsには、親子コンポーネント間のやりとりの方法として、以下を用意しています。

  1. 親から子へプロパティの受け渡し
  2. 子から親へイベントの送出(通知)

hasshyさんのケースでは、全体の処理として以下のようにすればいいと思います。

  1. opningコンポーネントで動画が再生される
  2. 動画終了時、opningコンポーネントがvideoendedイベント(名前は任意)を送出
  3. mainvisualコンポーネントがvideoendedイベントを検知
  4. mainvisualコンポーネントで表示する子コンポーネントのフラグを変更
  5. mainvisualコンポーネントフラグに基づき、v-ifでコンポーネントの表示が切り替わる

 components/mainvisual.vue

<template>
<div>
    <Opning
        v-if="currentContents === 'opning'"
        v-on:videoended="toggleContents('scene')"
    ></Opning>
    <Scene v-else-if="currentContents === 'scene'"></Scene>
    <Share v-else-if="currentContents === 'share'"></Share>
</div> <!-- 閉じタグが抜けているので追記 -->
</template>

<script>
...
export default {
    ...
    data() {
        return {
            currentContents: 'opning' // 初期コンテンツ名
        }
    },
    methods: {
        toggleContents(name) {
            this.currentContents = name
        }
    }
}
</script>

 components/scene.vue

HTMLに動画部分がないので便宜的なものですが、
動画要素終了のイベントを監視し、親コンポーネントにイベントを送出しています。
$emit(this.$emit)は、Vueが自動生成するプロパティで、親にイベントを送出します。

<template>
    <div id="scene">
        <video v-on:ended="$emit('videoended')"></video>
    </div>
</template>

<script>
export default {
    name: 'scene',
    ...
}

sceneコンポーネントからshareコンポーネントへの切り替えも、同じように考えてやってみてください。

 補足

Vue.jsにおけるイベント処理については、このあたりを読んでみてください。
関連するAPIもチェックするといいと思います。

いくらか開発してみたタイミングで、公式サイトのガイドをあらためて通読されることをおすすめします。

 蛇足

opningが「オープニング」のことならopeningでは?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/15 16:23

    いつもありがとうございます!
    ご確認が遅れてしまい大変申し訳ございません。
    また、稚拙なエラーコードを書いてしまい失礼しました…スペルミスでした。

    コードやドキュメントもご用意いただきありがとうございます。
    参考にさせていただきます。

    キャンセル

  • 2018/11/17 00:05

    解決したようでよかったです。
    ちなみに、変数名は一文字の場合もあるので、RerefenceErrorにならない限り「間違い(エラー)」では無いですよ。

    キャンセル

+1

質問1

components とすべきところが、sが抜けて、componentになっているとか?

export default {
    // component: { // sが抜けてる
    components: {
        'opning': Opning,
        'scene': Scene,
        'share': Share

  

質問2

これはちゃんとしたVue.js使いに聞いたほうがいいと思うのですが、思いついたのでついでに回答を(※無視してくださって結構です)。

vueでない場合について考えてみてはどうでしょうか。
イメージとしては、カルーセルに近いような印象を受けます。
カルーセルでいいならカルーセルでいいでしょうが、単に要素の置き換えであれば、置き換えでよいのではないかと?
子のコンポーネントから親に動画終了の通知を出し(もしくはコールバックができればそれでも)、それを受けた親が子供を削除して、次の子供を配置する…とか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/29 19:38 編集

    度々ありがとうございます。
    1点目はその通りでした。
    質問してから、ちょっと間を置いて見直して発覚しました…

    キャンセル

  • 2018/10/29 19:46

    なるほど笑 とりあえずそれについては解決したみたいでよかったです。 私も質問2については興味がありますので、他の方の回答を楽しみにさせていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る