【Vue.js】単一ファイルコンポーネントを使わないVue.jsで、画面間のデータ受け渡し。【ネストルート】
前提
単一ファイルコンポーネントを使わないVue.jsでの実装。
vue-routerを使ってルーティング。
vue.jsとvue-routerはそれぞれcdnを使用。
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
やりたいこと
あるルーティングにネストされたルーティングが複数あったとして、その画面間でデータのやり取りをしたい。
例えば、ルートパス「/money」に「/」(/money/)と「/future」(/money/future)というパスがネストされているとする。
お金ルート画面
お金画面
未来画面
①お金画面で、「aaa」と入力する。
②未来画面に遷移
③未来画面で、「bbb」と入力する。
④未来画面でボタンをクリックすると「aaa / bbb」と表示される。
つまり、お金画面で入力した値を未来画面でも使いたい。
ディレクトリ構成
こんな感じ。(cssなどは省略)
index.html
js
component
moneyComponent.js
router
router.js
ネストルーティングの定義
■route.js
// コンポーネント const TopRoot = { template: '<toproot></toproot>' } const MoneyRoot = { template: '<moneyroot></moneyroot>' } const Money = { template: '<money></money>' } const Future = { template: '<future></future>' } const routes = [ { path: '/', component: TopRoot}, { path: '/money', component: MoneyRoot, children:[ {path: '', component: Money}, {path: 'future', component: Future}, ] } ] const router = new VueRouter({ routes })
childrenオプションを使ってネスト。
ネストルートがない場合は以下のように書く。
{ path: '/money', component: MoneyRoot}
注意することはchildrenのpathには'/'が不要であるということ。
今回の例で言えば、「/money」もしくは「/money/」にアクセスしたときMoneyコンポーネントの中身が表示される。
{path: '', component: Money},
「/money/future」にアクセスしたときFutureコンポーネントの中身が表示される。
{path: 'future', component: Future},
index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> </head> <body> <div id="app"> <div class="container"> <div class="construct"> <div class="main"> <!-- routerで定義したコンポーネントを表示 --> <router-view></router-view> </div> </div><!-- .construct --> </div><!-- .container --> </div> </body> </html> <script src="js/components/moneyComponent.js"></script> <script src="js/route/router.js"></script> <script> // Vueインスタンス作成して、router注入 var app = new Vue({ el : "#app", router }) </script>
route.jsで定義したコンポーネントの中身が
ただし、ここに表示されるのはpathが「/」か「/money」の場合のみ。
「/money/」と「/money/future」についてはMoneyRootコンポーネントに定義するもう一つの
これは後ほど。
コンポーネント定義
/********************************* main *********************************/ var store = { debug : true, state : { money : '', test : '' }, setMoneyAction (newValue) { if (this.debug) console.log('setMoneyAction triggered with', newValue) this.state.money = newValue }, clearMoneyAction () { if (this.debug) console.log('clearMoneyAction triggered') this.state.money = '' }, setTestAction (newValue) { if (this.debug) console.log('setTestAction triggered with', newValue) this.state.test = newValue }, clearTestAction () { if (this.debug) console.log('clearTestAction triggered') this.state.test = '' } } // moneyRootComponent Vue.component('moneyroot', { template : '<div class="contents">'+ '<div class="money-root-parent">'+ '<div class="money-root-">'+ '<p>お金</p>'+ '<router-view></router-view>'+ '</div><!-- .money-root- -->'+ '</div><!-- .money-root--parent -->'+ '</div><!-- .contents -->', }) /********************************* sub *********************************/ // moneyComponent Vue.component('money', { template : '<div class="contents">'+ '<div class="money-parent">'+ '<div class="money">'+ '<p>お金</p>'+ '<input type="text" v-model="moneytest">'+ '</div><!-- .money -->'+ '</div><!-- .money-parent -->'+ '</div><!-- .contents -->', data: function () { return { moneytest : '' } }, updated : function(){ store.setMoneyAction(this.moneytest) } }) // futureComponent Vue.component('future', { template : '<div class="contents">'+ '<div class="future-parent">'+ '<div class="future">'+ '<p>未来</p>'+ '<input type="text" v-model="moneytest2">'+ '<button @click="output()">ボタン</button>'+ '<p v-model="result"></p>'+ '</div><!-- .future -->'+ '</div><!-- .future-parent -->'+ '</div><!-- .contents -->', data: function () { return { moneytest2 : '', result: '' } }, methods: { output : function(){ this.result = store.state.money + ' / ' + store.state.test; } }, updated : function(){ store.setTestAction(this.moneytest2) } })
storeが今回の問題の救世主。
https://jp.vuejs.org/v2/guide/state-management.html
ここに記載がある。
var store = { debug : true, state : { money : '', test : '' }, setMoneyAction (newValue) { if (this.debug) console.log('setMoneyAction triggered with', newValue) this.state.money = newValue }, clearMoneyAction () { if (this.debug) console.log('clearMoneyAction triggered') this.state.money = '' }, setTestAction (newValue) { if (this.debug) console.log('setTestAction triggered with', newValue) this.state.test = newValue }, clearTestAction () { if (this.debug) console.log('clearTestAction triggered') this.state.test = '' } }
これを最初に定義しておいて、入力した値をここに詰めて持ち回す感じ。
使い方は以下参照。
moneyroot
/moneyのときにアクセスするコンポーネント。
// moneyRootComponent Vue.component('moneyroot', { template : '<div class="contents">'+ '<div class="money-root-parent">'+ '<div class="money-root-">'+ '<p>お金ルート</p>'+ '<!-- ここに未来画面、今画面が表示される -->'+ '<router-view></router-view>'+ '</div><!-- .money-root- -->'+ '</div><!-- .money-root--parent -->'+ '</div><!-- .contents -->', })
ここにはさっき記載した、2つ目の
デフォルト状態では「/money/」なので、 Moneyコンポーネントが表示される。
moneyComponent
/money/のときにアクセスするコンポーネント。
// moneyComponent Vue.component('money', { template : '<div class="contents">'+ '<div class="money-parent">'+ '<div class="money">'+ '<p>デフォルト</p>'+ '<input type="text" v-model="moneytest">'+ '</div><!-- .money -->'+ '</div><!-- .money-parent -->'+ '</div><!-- .contents -->', data: function () { return { moneytest : '' } }, updated : function(){ store.setMoneyAction(this.moneytest) } })
「v-model="moneytest"」を用意して、その値が変化したらstoreに入力値を設定する。
updated : function(){ store.setMoneyAction(this.moneytest) }
futureComponent
/money/futureのときにアクセスするコンポーネント。
// futureComponent Vue.component('future', { template : '<div class="contents">'+ '<div class="future-parent">'+ '<div class="future">'+ '<p>未来</p>'+ '<input type="text" v-model="moneytest2">'+ '<button @click="output()">ボタン</button>'+ '<p v-model="result"></p>'+ '</div><!-- .future -->'+ '</div><!-- .future-parent -->'+ '</div><!-- .contents -->', data: function () { return { moneytest2 : '', result: '' } }, methods: { output : function(){ this.result = store.state.money + ' / ' + store.state.test; } }, updated : function(){ store.setTestAction(this.moneytest2) } })
「v-model="moneytest2"」を用意して、その値が変化したらstoreに入力値を設定する。
updated : function(){ store.setTestAction(this.moneytest2) }
ボタンを押したときに、storeに詰めた「」と「」の入力値を取得して、結果に詰めて表示するメソッド。
<button @click="output()">ボタン</button>
methods: { output : function(){ this.result = store.state.money + ' / ' + store.state.test; } }
これでできる。
https://jp.vuejs.org/v2/guide/state-management.htmlを読み進めていくと、「vuex」を使ってみるともっといいよ!
って書いてあるので、これがベストアンサーではないかも?