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

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

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

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

JavaScript

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

Onsen UI

HTML5で記述されたモバイルアプリの高速化、およびネイティブアプリライクなUIが作れるフレームワーク。 様々なJavaScriptフレームワークと併せて使用することができます。スマートフォン向けアプリ、Webサイトに必要なアニメーション、UI/UXを実装することが可能になります。

Monaca

「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

Q&A

解決済

4回答

4488閲覧

Vue.js+OnsenUIのnavigatorの扱うページで値を共有したい

tyama_jp

総合スコア17

Vue.js

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

JavaScript

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

Onsen UI

HTML5で記述されたモバイルアプリの高速化、およびネイティブアプリライクなUIが作れるフレームワーク。 様々なJavaScriptフレームワークと併せて使用することができます。スマートフォン向けアプリ、Webサイトに必要なアニメーション、UI/UXを実装することが可能になります。

Monaca

「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

0グッド

1クリップ

投稿2018/11/13 15:22

編集2018/11/14 14:58

前提・実現したいこと

Vueを学習しており、現在はMonacaでアプリの画面遷移について勉強中です。
v-ons-navigatorで管理されたコンポーネント間で共有できる変数を用意したいと考えています。

コンポーネントは
・App.vue (v-ons-navigator所持)
・Page1.vue (最初に表示されるページ)
・Page2.vue (途中でpush、popされるページ)
の三つです。

App.vueに作ったtodos配列を、push時に子に渡し、
子からは、emitで値を親に渡して、親のコンポーネントで配列の追加を行っております。

下記は、そのソースコードとなっております。
page1、page2それぞれ配列を追加できる形になっておりますが、
描画の更新が行われません。またこのほかに方法があればご教授願いたいです。

ソースコード (試したこと①の内容)

vue.js

1//App.vue 2 3<template> 4 <v-ons-navigator 5 :page-stack="pageStack" 6 @push-page="pushPage" 7 @pop-page="popPage" 8 @add-todo="addTodo" 9 ></v-ons-navigator> 10</template> 11 12<script> 13import page1 from './Page1' 14import page2 from './Page2' 15 16export default { 17 data() { 18 return { 19 pageStack: [], 20 todos: [ 21 { 22 text: 'todo one', 23 }, 24 { 25 text: 'todo two', 26 }, 27 { 28 text: 'todo three', 29 } 30 ] 31 } 32 }, 33 methods: { 34 pushPage(page) { 35 this.pageStack.push({ 36 extends: page, 37 data : ()=> { 38 return { 39 todos: this.todos 40 } 41 } 42 }) 43 }, 44 popPage() { 45 this.pageStack.pop(); 46 }, 47 addTodo(val) { 48 this.todos.push({text: val}) 49 } 50 }, 51 created: function(){ 52 this.pushPage(page1); 53 } 54} 55</script>

vue.js

1// Page1.vue 2 3<template> 4 <v-ons-page> 5 <custom-toolbar>Page 1</custom-toolbar> 6 <v-ons-list-item v-for="(todo) in todos"> 7 <label> 8 {{ todo.text }} 9 </label> 10 </v-ons-list-item> 11 12 <ons-button @click="nextPage"> 13 Page2に遷移する 14 </ons-button> 15 <ons-button @click="change"> 16 todoを追加する 17 </ons-button> 18 </v-ons-page> 19</template> 20 21<script> 22import page2 from './Page2' 23export default { 24 methods: { 25 nextPage() { 26 this.$emit('push-page', page2) 27 }, 28 change() { 29 this.$emit('add-todo', 'page1の値です') 30 } 31 }, 32 props: ['pageStack'] 33} 34</script>

vue.js

1//Page2.vue 2 3<template> 4 <v-ons-page> 5 <custom-toolbar>Page 2</custom-toolbar> 6 <ons-button @click="pop"> 7 Page1に戻る 8 </ons-button> 9 <ons-button @click="change"> 10 todoを追加する 11 </ons-button> 12 </v-ons-page> 13</template> 14 15<script> 16export default { 17 methods: { 18 pop() { 19 this.$emit('pop-page') 20 }, 21 change() { 22 this.$emit('add-todo', 'page2の値です') 23 } 24 }, 25 props: ['pageStack'] 26} 27</script>

試したこと

①pushの第二引数でextendを使用し、data型で直接渡す方法を試しました。
結果:参照で渡せないことと、親に返すだけではPage1とPage2の同期がとれないことが問題となりました。
追記:子の間でも値を共有していることはconsole.logにて確認できましたが、再描画のみが行われていない状態でした。

②vueの解説でよくあるpropsで行うやりかたも、ons-navigatorが絡むと形がイメージできず、
取り入れることができませんでした。
追記:ons-navigatorでpropsは利用できないとのことでした。代わりのextends。

③Vue.prototype.$hoge というグローバルに近いものも試しましたが、思ったように値変更ができないようで断念しました。

補足情報

vue : 2.5.16
vue-onsenui : 2.6.1
onsenui : 2.10.3

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

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

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

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

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

guest

回答4

0

状態管理方法について

  1. 単なるオブジェクトへのアクセス
  2. storeパターン
  3. Vuex

私の知る限りVueでの状態管理方法は上記3つ存在します。

3つの特徴を理解して好きなもの(適切なもの)を選べば良いかと思います。

小さなアプリケーションであれば1か2で問題ありません。
大規模アプリケーションの場合は3をおすすめします。

1. 単なるオブジェクトへのアクセス

以下プログラムの通りです。
一番シンプルですが、オブジェクトの値を直接変更できてしまう為デバッグが困難になる場合があります。

余談ですが、私は個人的なアプリケーションを時間をかけずに開発する場合この方法を利用しています。

公式サイトより引用

this.$root.$data を通じてアクセスすることもできます。
ただ1つの情報源を持つことにはなりましたが、このままだとデバッグは悪夢になるでしょう。
どんなデータでも、アプリケーションのどこからでも痕跡を残すことなく変えることができてしまいます。

** ファイル構成例 **

** app.js **

js

1const app = new Vue({ 2 router, 3 el: '#app', 4 components: { App }, 5 template: '<App/>', 6 data () { 7 return { 8 hoge: 'hello world' 9 } 10 } 11}) 12 13app.$mount('#app')

** Index.vue **

js

1export default { 2 data () { 3 return { 4 } 5 }, 6 async mounted () { 7 console.log(this.$root.hoge) 8 } 9}

参考
https://jp.vuejs.org/v2/guide/state-management.html#%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AA%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86%E3%82%92%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8B

2. storeパターン

1の弱点を補う為に考えられたパターンです。
オブジェクトへ直接アクセスを行わず、メソッドを経由して値を書き換えるという考え方です。
メソッドを経由するためデバッグをログを吐かせればデバッグが簡単になります。

var store = { debug: true, state: { message: 'Hello!' }, setMessageAction (newValue) { if (this.debug) console.log('setMessageAction triggered with', newValue) this.state.message = newValue }, clearMessageAction () { if (this.debug) console.log('clearMessageAction triggered') this.state.message = '' } }

参考
https://jp.vuejs.org/v2/guide/state-management.html#%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AA%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86%E3%82%92%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8B

3. Vuex

規模が大きくなることが見込まれている場合はVuexを使うべきです。
Vuexを使うと適切な管理ができます。

しかし、小さなアプリケーション開発の場合は非常に冗長だと感じるはずです。

公式サイトより引用

Vuex は、共有状態の管理に役立ちますが、さらに概念やボイラープレートのコストがかかります。これは、短期的生産性と長期的生産性のトレードオフです。
もし、あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で恐ろしいと感じるかもしれません。
そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。単純な ストアパターン が必要なだけかもしれません。

参考
https://vuex.vuejs.org/ja/

投稿2018/11/20 00:24

aglkjggg

総合スコア769

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

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

tyama_jp

2018/11/20 13:59

回答ありがとうございます。 全ての状態管理方法を出していただき大変参考になっております。 現在はVuexにて、③を使っているものと思いましたが、形だけで見ると非常に②と似ており、 それ以上でも以下でもないので、実際はVuexの機能を全く引き出せていないようです。 また、わたしが今作っているアプリに関しては、そこまで大規模になる予定はないので、 aglkjggg様の教えていただいた、①と同じ方法でアプリを再構築しました。 非常に管理しやすく重宝しております。デバッグが困難らしいですが、またその際に、 VuexやStoreでの管理方法への移行を検討したいとおもいます。 為になる情報助かりました。ありがとうございます。
guest

0

ベストアンサー

VueのコアライブラリのVuex使うのも手です
https://vuex.vuejs.org/ja/

monacaなのでターミナルで
npm install --save vuex
でインストールして

main.js

js

1import Vue from 'vue'; 2import VueOnsen from 'vue-onsenui'; 3import Vuex from 'vuex'; 4 5import 'onsenui'; 6// Onsen UI Styling and Icons 7require('onsenui/css-components-src/src/onsen-css-components.css'); 8require('onsenui/css/onsenui.css'); 9 10import App from './App'; 11 12Vue.use(VueOnsen); 13Vue.use(Vuex); 14 15const store = new Vuex.Store({ 16 state: { 17 todos: [ 18 { id: 1, text: 'aaaa', done: true }, 19 { id: 2, text: 'bbbb', done: false } 20 ] 21 }, 22 getters: { 23 doneTodos: state => { 24 return state.todos.filter(todo => todo.done) 25 } 26 }, 27 mutations: { 28 addTodos (state, data) { 29 state.todos.push(data) 30 console.log(state.todos) 31 } 32 }, 33 actions: { 34 addTodos (context, data) { 35 context.commit('addTodos', data) 36 } 37 } 38}) 39 40new Vue({ 41 el: '#app', 42 template: '<app></app>', 43 components:{App}, 44 store 45});

App.vue

vue

1<template> 2 <v-ons-navigator 3 :page-stack="pageStack" 4 @push-page="pushPage" 5 @pop-page="popPage" 6 ></v-ons-navigator> 7</template> 8 9<script> 10import page1 from './Page1' 11 12export default { 13 data() { 14 return { 15 pageStack: [], 16 } 17 }, 18 methods: { 19 pushPage(page) { 20 this.pageStack.push(page) 21 }, 22 popPage() { 23 this.pageStack.pop(); 24 } 25 }, 26 created: function(){ 27 this.pushPage(page1); 28 } 29} 30</script>

Page1.vue

vue

1<template> 2 <v-ons-page> 3 <custom-toolbar>Page 1</custom-toolbar> 4 <ons-button @click="nextPage"> 5 Page2に遷移する 6 </ons-button> 7 <div> 8 <div v-for="data in todos"> 9 {{ data.text }} 10 </div> 11 </div> 12 </v-ons-page> 13</template> 14 15<script> 16import { mapState } from 'vuex' 17import page2 from './Page2' 18export default { 19 methods: { 20 nextPage() { 21 this.$emit('push-page', page2) 22 }, 23 }, 24 computed: mapState({ 25 todos: state => state.todos, 26 }), 27 props: ['pageStack'] 28} 29</script>

Page2.vue

<template> <v-ons-page> <custom-toolbar>Page 2</custom-toolbar> <ons-button @click="pop"> Page1に戻る </ons-button> </v-ons-page> </template> <script> import page2 from './Page2' export default { data() { return { } }, methods: { pop() { this.$store.dispatch('addTodos', { id: 3, text: 'cccc', done: true }) this.$emit('pop-page') }, }, props: ['pageStack'] } </script>

投稿2018/11/14 15:00

rururu3

総合スコア5545

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

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

tyama_jp

2018/11/14 15:03

回答ありがとうございます。 質問の本文編集とタイミングが被ってしまいすみません。 vuexについては触れたことがなかったので、少し調べてみます。
tyama_jp

2018/11/14 15:50

vuexの解説を読むと私が期待していた内容がそこにありました。 頂いたコードをひとつひとつ実行させていただきましたが、無事動作を確認できました。 ありがとうございます。vuexの機能を最大限に引きだすにはまだまだ勉強が必要ですが、 今後の展開としてもvuexは貴重な知識となりました。 また、現在本文に記載している不具合として、頂いたソースコードから気付きがありました。 その点については、本文で記述させていただきます。ありがとうございました。
guest

0

◆◆◆◆◆
◆方法①:push時の参照渡し方法
再描画がされない件については、
対象の値が<v-ons-page>直下に書いてあることが原因?だった。

<div> <v-ons-list-item v-for="(todo) in todos"> <label> {{ todo.text }} </label> </v-ons-list-item> </div>

このように<div>で囲むことで無事に更新を確認できた。
rururu3様の、コードを自分で書いてある途中、値が更新されない件に気付き、
そのまま流用した際に、再描画されたことから発見につながった。
詳細についてはまた詳しくリファレンスを読んでいきたいと思います。

◆◆◆◆◆
◆方法②:vuexでの管理
rururu3様のコードを参照

投稿2018/11/14 15:58

tyama_jp

総合スコア17

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

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

0

###専門外言語ですが

アルゴリズムの話だと思うので、参加できるかと思っています。

###私の考え

まず、vueを親オブジェクトになっているので、ページ間の内容をかんりする親オブジェクトを作成し、
vueをその親オブジェクトから子オブジェクトとして呼び出し、
ページ出力の際に管理しているデータをページ内に含めるように大改造する。

ページ間移動を管理する親オブジェクトは常に子オブジェクトの帰り値を保持するようにコーディングする。

子オブジェクトが値を返さなかったらページ間移動をキャンセルする。

こんな考え方で実装可能になるのではないでしょうか?

投稿2018/11/13 20:30

phpsyoshinsya

総合スコア156

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

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

tyama_jp

2018/11/14 00:34

回答ありがとうございます。 >ページ間の内容をかんりする親オブジェクト おそらくこれは現在App.vueがその役割を担っています。 ons-navigatorの作りでは、ページを都度pushして移動しておらず、 Page1の上にPage2が乗っかる形なので、pushの度に値を渡すという実装に代えられません。 >子オブジェクトが値を返さなかったらページ間移動をキャンセルする。 Page2をpopし、親に値を渡しても、すでにPage1は表示されているので、 Page1に値を渡し直す方法がわからない次第となっております。 on,emitなどを使って対象コンポーネントを指定する方法を無理やりとれなくはないかと 少しは考えたのですが、実装としてあまりに遠回りな処理なのではと少し感じております。 理解が浅く、phpsyoshinsya様の方法で実装できるのやもしれませんが、 私の実力では現在そこに至りません。回答ありがとうございました!
phpsyoshinsya

2018/11/14 07:27

なるほどです。ただ、もしこれでやればというのがあるなら、遠回りでも実装に成功するか試してみるのは必要ではないでしょうか。 私もコードを見てみましたが、帰り値が戻ってきていたとしても、それを管理していそうなコードが見当たりません。 親オブジェクトとなる新しいオブジェクトがVUEの帰り値をチェックしなければ、今後アプリが大きくなってくれば、どこかの条件で結果セットがプッシュされないということも起こりえるのではないかと。もちろん、単なる練習であればそこまでかんが見る必要はないでしょうが、そういう意識を持っでコーディングに望まれる方が特にコンパイル言語では大切なのではないかと。また、一つ確認を忘れていましたが、なぜページ移動でVUEの帰り値を共有したいと思われたのかが明治されていませんでしたね。私の見落としならすみませんが。
tyama_jp

2018/11/14 07:55

たしかに、、おっしゃる通りです。 冗長なコードを実装するより先に、効率的な実装法を求めて逆に遠回りになっていたようです。 >私もコードを見てみましたが、帰り値が戻ってきていたとしても、それを管理していそうなコードが見当たりません。 回答の妨げになってしまうかと思い、私が試行錯誤したコードは省いていました。 本来は親のappVueに値を渡す関数を用意していました。 本日近しい実装を行い次第、コードを改めてあげさせていただきます。 >なぜページ移動でVUEの帰り値を共有したいと思われたのかが明治されていません 本文中になぜ実装したいかを追記しました。 親身に考えてくださり、ありがとうございます。
phpsyoshinsya

2018/11/14 08:25

何かしらヒントになれば、いいのかとは思いますが。 ただ、新たなコードが提示されるとのこと、楽しみにしています。 環境が許すなら、ゆっくり頑張ってください。
phpsyoshinsya

2018/11/14 08:37

なるほどです。いま質問内容を再度確認しなおしました。ページ2で作成したToDoリストが戻ってこないということですね。 それなら、根本的にコードが足りませんね。 書き方として、ページ1から2に移動する際、 VUEの子オブジェクトであるページ1を開放しないとページが重なる結果となり、もしこのままで実装に成功してもメモリを圧迫するアプリとなってしまう恐れについて考慮したことはありますでしょうか? VUEと最後にプッシュしたページは親子関係にありますが、 今のならページ1を親オブジェクトとし、 ページ2を子オブジェクトとし、 VUEを読み込み必須のクラスに設定 するのがもっともスマートではないかと。 いかがでしょうか?
tyama_jp

2018/11/14 08:56

>メモリを圧迫するアプリとなってしまう恐れについて考慮したことはありますでしょうか? OnsenUIのNavigatorを使っているのでその恐れはありません。 Page1の複数回pushは行っていないので、詳しくは下記を確認してください。 https://qiita.com/coboco/items/5c33e201907623de5270 https://ja.onsen.io/v1/reference/ons-navigator.html >今のならページ1を親オブジェクトとし、 OnsenUIのNavigatorでのアニメーションが今回の実装の大前提となりますので、 その方法は選択できない形となります。
phpsyoshinsya

2018/11/14 09:16

そういう大前提があるのですね。 私もQiitaさんのサイト読んでみます。
phpsyoshinsya

2018/11/14 09:24

私はQiitaさんのご紹介いただいたページから答えを既に導き出しました。 まずは質問者さんのコード再提示をお待ちしています。
tyama_jp

2018/11/14 14:59

ありがとうございます。 ソースコードの編集と、問題点の簡略化を行いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問