vuex 和 vue-router如何結合使用?

例如要實現用戶登錄後跳轉,很自然的想到將login這個非同步操作放到action,登錄成功後再觸發mutation來修改應用狀態(設置已登錄狀態),但是之後如何觸發路由跳轉呢,這點我一直想不通……哪位大神可以解說一下,無限感激~~


路由對象和路由匹配

$route.auth 處理用戶判斷用戶是否登錄,做登錄跳轉。

router.beforeEach((transition) =&> {
if (transition.to.auth) {
//判斷是否登錄,(可以通過介面,Vuex狀態 token)
//沒有登錄走下面邏輯
let redirect = encodeURIComponent(transition.to.path);
transition.redirect("/logon?redirect=" + redirect);
//redirect 作為參數,登錄之後跳轉回來
} else {
transition.next();
}
});


加一個回調 ?

//x.vue methods

Logined(){
var self = this;
store.actions.Logined(function(){
self.$route.router.go("xxx")
})
}

//actions.js

export default {
Logined(call){
LOGINED()
call()
}
}


把router對象import進來,然後調用push或go方法


OK,自問自答的回來了……
之前想到的方法是直接在組件內watch一個狀態值,然後等待登錄成功後跳轉。雖然這種方式能正常工作,但是總覺得有一絲的詭異。。。

後來想到可能更好更直觀的方法是:

// actions.js
import router from "./router.js" //首先導入路由對象

router.go({name:"index"}) //然後在登錄action的promise里調用這個方法

之所以繞進去了是因為一直想通過vm.$route.router來訪問路由對象,忘記了其實可以直接把路由對象import進來。

另外 @Awee 提到的非同步回調也是可行的,非常感謝。

update:
其實我這種寫法是有問題的。不符合vuex使用的思想。
vuex是應該只管理應用狀態的。vuex裡面的東西不應該直接操作視圖層面。如果把路由跳轉這種視圖層面的東西寫到vuex裡面就不符合分層和解耦合的思想了。

個人覺得一種比較優美的寫法是action內return一個promise。例如我寫了一個名為login的action。就可以在onLoginButtonClicked的method里這樣調用它:
vm = this
this.login(username,password).then(()=&>{
vm.$route.router.go("/")
})
相當於利用了login的action里返回的promise對象來實現非同步跳轉。

update2:

現在vue已經更新到2.0了,router的api對不上了。所以上面的代碼僅供參考。

Vuex的新文檔也給出了我說的問題的解決方法,可以看這裡:Actions · GitBook

update3:

現在出了這個大殺器:

vuejs/vuex-router-sync: Effortlessly keep vue-router and vuex store in sync.

相信vuex和vue-router如何結合使用 已經不再是個問題了吧 :)


在vue-router實例中可以拿到vuex的store,代碼類似下面:

router.beforeEach(transition =&> {
// call your actions.
router.app.checkUserIsLogin();
// 拿 store
router.app.$store.state;
// other stuff...
transition.next();
});

參考:How to call vuex function from vue-router beforeEach callback


import Vue from "vue";
import VueRouter from "vue-router";
import filters from "./filters";
import routerMap from "./routers";
import FastClick from "fastclick";

Vue.use(VueRouter);

$.ajaxSettings.crossDomain = true;

//實例化Vue的filter
Object.keys(filters).forEach(k =&> Vue.filter(k, filters[k]));

//實例化VueRouter
let router = new VueRouter({
hashbang: true,
history: false,
saveScrollPosition: true,
transitionOnLoad: true
});

//登錄中間驗證,頁面需要登錄而沒有登錄的情況直接跳轉登錄
router.beforeEach((transition) =&> {
//處理左側滾動不影響右邊
$("html, body, #page").removeClass("scroll-hide");
FastClick.attach(document.body);

if (transition.to.auth) {
if (localStorage.userId) {
transition.next();
} else {
var redirect = encodeURIComponent(transition.to.path);
transition.redirect("/login?redirect=" + redirect);
}
} else {
transition.next();
}
});

let app = Vue.extend({});
routerMap(router);

router.start(app, "#app");


loginTo儲存用戶登錄之後需要跳轉到的鏈接地址,默認登錄之後跳轉到/user

let store = new Vuex.Store({
state:{
loginTo:"/user"
},
mutations:{
setLoginToLink(state,link){
state.loginTo = link;
}
}
})

a頁面(/index)-&>登錄頁面(/login)-&>c頁面(/xxx)

a頁面:this.$store.commit("setLoginToLink","/xxx");

登錄頁面:window.location.href = "aaa.com"+this.$store.state.loginTo;

設置登錄狀態也是類似的,用vuex來管理一個state比如命名為hasLogin,然後默認為false,然後登錄成功之後commit一個修改這個hasLogin狀態的方法,這個hasLogin的狀態在所有頁面都可以獲取到。


Actions | Vuex

vuex 2.0的文檔,有講關於非同步的


推薦閱讀:

腳手架類的命令行工具用到了哪些技術?
vue.js 能否設置某個組件不被keep-alive?
vue.js 有哪些知名公司或項目用於實際生產環境了呢?
Knockout, Vue 和 AvalonJS 等 MVVM 框架實現中是否用到 eval 或 Function?
Vue.js如何優雅的進行form validation?

TAG:前端開發 | Vuejs |