やりたいこと
- Vue-routerのルーティングで使われるComponent側のpropsの変更でもURLを変更したい
課題
-
<router-view>
にv-bind:paramName.sync="$route.params.paramName"
と渡してもURLは変更されない。値は変わっているが検知されない- ただし、URLを変更して
$route.params.paramName
が変更された場合は検知され、コンポーネントのpropsも変更される
- ただし、URLを変更して
- 仮に上記方法で出来たとしても、ルーティングが増えればそれだけコンポーネントも増え、渡す値も増えるので
v-bind
でやると破綻が見えている
てきとうなSPAアプリ
var News = Vue.extend({
props:{
newsId:{
type:Number,
default:1
}
}
});
var Mail = Vue.extend({
props:{
mailId:{
type:Number,
default:1
}
}
});
var Todo = Vue.extend({
props:{
todoId:{
type:Number,
default:1
}
}
});
var router = new VueRouter();
router.map({
'/News/:news_id':News,
'/Mail/:mail_id':Mail,
'/Todo/:todo_id':Todo
});
/*
この時v-bindでpropsと結びつけようとすると、View側の<router-view>に
<router-view :news_id="$route.params.news_id" :mail_id="$route.params.mail_id" :todo_id="$route.params.todo_id"></router-view>
とかやらなきゃならず、コンポーネントが増えれば増えるほど、各々のコンポーネントから見れば要らないものを結びつけようとする
*/
- と言ってComponent内で
$route.params
を使うと密結合になってしまう
とりあえずの方法
- router.mapでルーティングにコンポーネントを割り当てる際に予め定義したコンポーネントをextendしてwatchとcreatedで値をsyncさせる
サンプル
// URLパラメータはStringなので数値型に変換
Vue.filter('int',function(val){return parseInt(val);});
var App = Vue.extend();
var router = new VueRouter();
var Component = Vue.extend({
template:"<p>Current route params: {{$route.params | json}}</p><p>pageNum: <input v-model='pageNum' type='number' number></p>",
props:{
pageNum:{ // 1. この値に応じてURLを変えたい
type:Number,
default:1,
twoWay:false // trueにしても意味がない。$route.paramsはdefinePropertyでプロパティを設定していないから見張れない
}
}
});
// 2. 疎結合ならrouterの存在はComponentは知らない筈なので・・・
router.map({
'/page/:pagenumber': {
component: Component.extend({ // 3. routerの中でComponentを割り当てる時にwatchでpageNumを見張るよう設定する
watch:{
'pageNum': function (val, oldVal) {
router.go('/page/'+val);
},
'$route.params.pagenumber':function(val,oldVal){
this.pageNum = parseInt(val);
}
},
created:function(){ // 4. 初期値はv-bindでなくこっちで入れないとrouter-viewタグに全部書く羽目になる
this.pageNum = parseInt(this.$route.params.pagenumber);
}
}),
// 5. 例えばこう書ければいいのに
/*
bind:{'pagenumber':{
name:'pageNum',
sync:true // changing pageNum invokes router.go
}
}
*/
}
});
router.start(App, '#app',function(){
router.go('/page/5');
});
疑問点
- もっとシンプルに書けないものか
- イベントドリブンにしてComponentから
$dispatch
してAppでrouter.goするのとどっちが良かろうか