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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

1049閲覧

Vue.jsで親コンポーネントのdataに定義された配列の値を監視して、その変更に応じて子コンポーネントから処理を行いたい

take-t.t.

総合スコア360

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2019/07/10 16:35

編集2019/07/11 12:03

少し長くなってしまい申し訳ないのですが、宜しければお付き合いください。

現在Vue.jsを使って、以下のコードで複数あるアコーディオンの開閉を一度に行う「toggleAll」メソッドを定義しています。
アコーディオンはこのコンポーネントからpropsでdataを渡し、子コンポーネントである<AccordionComponent>内でv-forを使いレンダリングしているものです。

html

1<section> 2 <div class="skills-box"> 3 <h3>My Skills</h3> 4 <div class="show-box"> 5 <p>Click the item <span>or</span></p> 6 <a class="show-all" v-on:click="change(); toggleAll()"> <!-- この部分です --> 7 {{ toggleMessage }} 8 <i class="fas fa-sort"></i> 9 </a> 10 </div> 11 <AccordionComponent v-bind:skills="skills"></AccordionComponent> <!-- 子コンポーネント --> 12 </div> 13 <router-link to="/" class="move"><i class="fas fa-angle-left"></i> BACK</router-link> 14</section>

JavaScript

1import AccordionComponent from '../components/Accordion.vue' 2export default { 3 name: 'Skills', 4 data() { 5 return { 6 skills: [ 7 {id: 1, name: 'HTML・CSS', bgColor: 'orangered', show: false, description: `text`}, 8 {id: 2, name: 'Sass', bgColor: 'hotpink', show: false, description: `text`}, 9 {id: 3, name: 'JavaScript', bgColor: 'gold', show: false, description: `text`}, 10 {id: 4, name: 'Vue.js', bgColor: 'mediumseagreen', show: false, description: `text`}, 11 {id: 5, name: 'Firebase', bgColor: 'orange', show: false, description: `text`}, 12 {id: 6, name: 'PHP', bgColor: 'steelblue', show: false, description: `text`}, 13 {id: 7, name: 'Git・Github', bgColor: 'black', show: false, description: `text`}, 14 {id: 8, name: 'webpack', bgColor: 'skyblue', show: false, description: `text`}, 15 ], //skills 16 toggleMessage: 'Show all' 17 } 18 }, 19 methods: { 20 change: function() { 21 if(this.toggleMessage === 'Show all') { 22 this.toggleMessage = 'Close all' 23 } else { 24 this.toggleMessage = 'Show all' 25 } 26 }, 27 toggleAll: function() { 28 for(let skill of this.skills) { 29 if(this.toggleOpen === 'Show all') { 30 skill.show = true 31 } else { 32 skill.show = false 33 } 34 } // for of 35 }, 36 }, 37 components: { 38 AccordionComponent 39 } 40}

各アコーディオンの開閉は上記の配列「skills」内のオブジェクトが各々持っている「show」の真偽値によって管理しているのですが、「toggleAll」はその「show」全ての真偽値を一斉に切り替えるメソッドです。
しかしこのコードですと、下記のgifのように、仮に全て手動でアコーディオンを開けた場合、一度意味のないtogglleAllを実行しなければなりません。(勝手にClose allには切り替わってくれないため)

→imigurに飛びます

そのため、配列skills内のshowの真偽値を監視して、全ての「show」がtrueまたはfalseになった時に「toggleMessage」の値を変更したいと考えております。

とりあえず真偽値が全てtrueまたはfalseだった時に「toggleMessage」を変更する、という処理を行うコードは下記のように考えたのですが、これをどう正しく動く形でVueの算出プロパティ等に反映してよいか分からずに困っています。
公式のリファレンスにも中にこのように複数の関数を入れ込む方法が載っておらず、エラーになってしまい私のスキルでは解決できないため手詰まりになってしまっています。

JavaScript

1let toggleMessage = 'Show all'; 2 3const skills = [ 4 {id: 1, name: 'item1', show: true}, 5 {id: 2, name: 'item2', show: true}, 6 {id: 3, name: 'item3', show: true} 7]; 8 9const checkTrue = skills.every(value => value.show === true ); 10const checkFalse = skills.every(value => value.show === false ); 11 12if(checkTrue === true) { 13 toggleMessage = 'Close all'; 14} else if(checkFalse === true) { 15 toggleMessage= 'Show all'; 16}

そして何より、この一連の単純な動作のために3つに分けてここまでグチャグチャと書かなければいけないのか、ということも我ながら疑問に思っています。
もし、もっと効率の良い方法があれば教えていただけると幸いです。

JavaScriptの基礎が少し怪しいため、分かりづらいコード・質問になってしまい本当に申し訳ありませんが、何卒お力添えをよろしくお願いいたします。

※追記です
下記のコードをコンポーネント内に追加いたしました。

JavaScript

1updated: function() { 2 alert('updated') 3 const checkTrue = this.skills.every(value => value.show === true ) 4 const checkFalse = this.skills.every(value => value.show === false ) 5 if(checkTrue === true) { 6 this.toggleMessage = 'Close all' 7 } else if(checkFalse === true) { 8 this.toggleMessage = 'Show all' 9 } 10},

しかし思い通りの挙動にはなっておらず、どうやらアコーディオンの開閉ではアラートが表示されなかったので、そのタイミングでは処理は行われていないようです。
試しに「toggleAll」メッソドを実行してみると、アラートが表示されました。
公式で「仮想DOMが再描画されたタイミング」とあったので、「v-show」で行っていたアコーディオンの開閉を「v-if」に変えてみたりもしたのですが、処理は実行されませんでした。

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

これはライフサイクルメソッドを使うとうまくいくかも知れません。
Vue公式ライフサイクルメソッド

export default { updated: { alert('updated') // 動作確認用 const checkTrue = this.skills.every(value => value.boolean === true ); const checkFalse = this.skills.every(value => value.boolean === false ); if(checkTrue === true) { this.sampleText = 'Close all'; } else if(checkFalse === true) { this.sampleText = 'Show all'; } } }

こちらのupdatedメソッドは、仮想DOMが変更される度に実行されます。
この場合だとアコーディオンが動く度に実行されるはずです。
動作確認をしていないのですが、参考になれば幸いです。

投稿2019/07/10 16:58

編集2019/07/10 16:59
ttakatech

総合スコア118

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

take-t.t.

2019/07/11 06:59 編集

ご回答ありがとうございます。 ライフサイクルメソッドに関しては思いつきもしていなかったので、とても勉強になりました。 ただ残念ながら思ったようには動作しませんでした。 変更した箇所は質問文に追記させていただいたので、もしよろしければもう少しお力添えをいただければ幸いです。
ttakatech

2019/07/11 06:33 編集

細かい仕様は確認していないので分かりかねますが、もしかしたらコンポーネントごとで稼働するのかも知れません。 AccordionComponent内でupdatedメソッドとalert()を実装してみて頂けないでしょうか。
take-t.t.

2019/07/11 07:20 編集

ご返信ありがとうございます。 AccordionComponent内にupdatedを追加してみたのですが、何故かalertは実行されてもtoggleMessageの変更は実行されませんでした。 そこで試しに子コンポーネントの内容を丸ごと親コンポーネントに移してみたところ、updatedが正しく実行されました。 詳しい仕様はわからないのですが、同じ配列を参照している「toggleAll」メソッドのボタンとアコーディオンはファイルを分けないほうが良いようでした。 改めまして、複数回に渡りご回答していただきありがとうございました。
ttakatech

2019/07/11 09:18 編集

説明不足だったようです。 今回の場合は、子コンポーネント側から親コンポーネントの``toggleMessage: 'Show all'``を操作する必要があります。これを行うためには、``$emit``などを使い、親コンポーネントの``methods: {}``内にあるchange関数を呼び出す必要があります。詳しくは公式を御覧ください。 https://jp.vuejs.org/v2/guide/components.html#%E5%AD%90%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%82%92%E8%B3%BC%E8%AA%AD%E3%81%99%E3%82%8B コンポーネントでコードを分割するのは、全体のわかりやすさのために不可欠の要素です。 これを省いてはVue.jsの利点をほとんど活かせません。 理解に苦労されるかも知れませんが、是非学習してみてください。 また少し先の話になりますが、これらのデータ管理やメソッド管理に習熟し、同時に苦労を感じるようになりましたらVuexもご検討ください。 各コンポーネントの``data: {}``を一律に管理するようなことができます。 がんばってください。
take-t.t.

2019/07/11 11:44

解決済みにしてしまったにも関わらず、更にご説明いただき本当にありがとうございました。 あれから格闘いたしまして、なんとか実装までこぎつけました。 以前のコードでも配列skillsの中のshowの真偽値が子コンポーネントからも変更できてしまっていたので考えもしなかったのですが、オブジェクトと普通の文字列では扱いが違う事や、なんとなくで使っていたpropsについて等、色々と詳しく知る機会になりました。 本当にありがとうございました。
guest

0

なんとかttakatechさんに教えて頂いた事を元に実装できました。

親コンポーネントを以下のように変更しました

html

1<template> 2 <section> 3 <div class="skills-box"> 4 <h3>My Skills</h3> 5 <div class="show-box"> 6 <p class="subheading">Click the item <span>or</span></p> 7 <a class="show-all" v-on:click="toggleAll(); change()"> 8 {{ toggleMessage }} 9 <i class="fas fa-sort"></i> 10 </a> 11 </div> 12 <accordion-component v-bind:inheritSkills="skills" v-bind:inheritMessage.sync="toggleMessage"></accordion-component> <!-- 変更しました --> 13 </div> <!-- skills-box --> 14 <router-link to="/" class="move"><i class="fas fa-angle-left"></i> BACK</router-link> 15 </section> 16</template>

子コンポーネントを以下のようにしました。

JavaScript

1export default { 2 name: 'AccordionComponent', 3 props: ['inheritSkills', 'inheritMessage'], //親コンポーネント内のskillsとtoggleMessageを受け取る 4 data() { 5 return { 6 inherit_message: this.inheritMessage //受け取った値を更に子コンポーネントのdataに格納 7 } 8 }, 9 methods: { 10 toggleAccordion: function(skill) { 11 this.inheritSkills.find(inheritSkills => inheritSkills.id === skill.id).show 12 = 13 !this.inheritSkills.find(inheritSkills => inheritSkills.id === skill.id).show 14 } //アコーディオンの開閉を行う関数 15 }, 16 updated: function() { 17 alert('updated') 18 const checkTrue = this.inheritSkills.every(value => value.show === true ) 19 const checkFalse = this.inheritSkills.every(value => value.show === false ) 20 if(checkTrue === true) { 21 this.inherit_message = 'Close all' 22 } else if(checkFalse === true) { 23 this.inherit_message = 'Show all' //子コンポーネント内のdataを変更する 24 } 25 this.$emit('update:inheritMessage', this.inherit_message) //子コンポーネントに定義したinherit_messageを$emitを使い親コンポーネントに反映 26 }, 27}

投稿2019/07/11 11:45

編集2019/07/11 12:02
take-t.t.

総合スコア360

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問