LoginSignup
10
11

More than 5 years have passed since last update.

Vue-routerでコンポーネント側のpropsの値に応じてURLを変更したい

Last updated at Posted at 2016-08-12

やりたいこと

  • Vue-routerのルーティングで使われるComponent側のpropsの変更でもURLを変更したい

課題

  • <router-view>v-bind:paramName.sync="$route.params.paramName"と渡してもURLは変更されない。値は変わっているが検知されない
    • ただし、URLを変更して$route.params.paramNameが変更された場合は検知され、コンポーネントのpropsも変更される
  • 仮に上記方法で出来たとしても、ルーティングが増えればそれだけコンポーネントも増え、渡す値も増えるので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するのとどっちが良かろうか
10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11