Vuex —— The core of Vue application

系列文章:

  1. Vue 2.0 升(cai)級(jí)(keng)之旅
  2. Vuex — The core of Vue application (本文)

當(dāng)今,談到狀態(tài)管理首先想到的肯定是 Redux,而隨著 Vue 2.0 的發(fā)布,Vuex 也伴隨著推出了最新版夕膀,本文就帶你對(duì)照 Redux 來(lái)看看剛剛出爐的 Vuex 2.0喧锦。

有關(guān) Redux 的基礎(chǔ)概念在本文中會(huì)簡(jiǎn)要略過,如再一一贅述篇幅就太長(zhǎng)了,不了解的可以看一下本人之前寫的有關(guān) Redux 的兩篇文章:

  1. Redux 入門
  2. Redux 進(jìn)階

為什么說(shuō) Vuex 是 Vue 應(yīng)用的核心绢掰?

眾所周知霉翔,一個(gè)應(yīng)用的外觀可以千變?nèi)f化,但無(wú)論如何變化,它都需要一樣?xùn)|西去支撐,那就是——數(shù)據(jù)离唬。這個(gè)數(shù)據(jù)是廣義上的,可以是數(shù)據(jù)庫(kù)中的數(shù)據(jù)划鸽,也可以是當(dāng)前應(yīng)用所處的狀態(tài)输莺,甚至可以是 WebRTC, Web Bluetooth 等一系列實(shí)時(shí)數(shù)據(jù)。

在 vue 應(yīng)用中裸诽,vuex 就充當(dāng)了數(shù)據(jù)提供者的角色嫂用,vue 則只需要關(guān)注頁(yè)面的展示與交互。

既然丈冬,明確了以 vuex 為核心尸折,那么就來(lái)看看如何在 vue 應(yīng)用中使用 vuex?

隨著 Vue 2.0 的發(fā)布殷蛇,Vuex 在近期也隨之推出 2.0 版。在上一篇文章中有提到作者的博客是用 vue 2.0 搭建的橄浓,但之前并沒有添加 vuex粒梦,現(xiàn)在正可以借此機(jī)會(huì)將 vuex 添加到項(xiàng)目中。

本文將介紹 Vuex 2.0 的同時(shí)荸实,分享一些本人在這個(gè)過程中的一些心得匀们。

首先,當(dāng)然是核心的核心 Store准给。

Store

Store 用來(lái)存放整個(gè)應(yīng)用的 state泄朴。

那怎么建立 store 哪?由于露氮,Vuex 2.0 剛剛推出祖灰,最新的 API 還得看 Release Note

創(chuàng)建一個(gè) Store 非常簡(jiǎn)單只需 new Vuex.Store({ ...options })畔规,其中局扶,options 可以是一下幾種:

  • state Object:存放應(yīng)用狀態(tài)
  • actions Object:注冊(cè) action
  • mutations Object:注冊(cè) mutation
  • getters Object:注冊(cè) getter
  • modules Object:注冊(cè) module
  • plugins Array<Function>:注冊(cè)中間件
  • strict Boolean:是否開啟嚴(yán)格模式,嚴(yán)格模式下所有對(duì) state 的變化必須通過 mutation 來(lái)修改叁扫,反之拋出異常三妈,默認(rèn)不開啟。

或許你不了解這些屬性的含義莫绣,沒關(guān)系畴蒲,之后每個(gè)還會(huì)分別解釋。

明白了屬性的含義对室,那么創(chuàng)建一個(gè) store 的代碼就可能會(huì)是這樣

// store.js
import Vue from 'vue';
import Vuex from 'vuex';
import createLogger from 'vuex/logger';

import blog from './module/blog';

// 在 Vue 中模燥,注冊(cè) Vuex
Vue.use(Vuex);

export default new Vuex.Store({
    state: {},
    plugins: process.env.NODE_ENV !== 'production' ? [createLogger()] : [],
    modules: {
        blog
    }
});

store 創(chuàng)建完成之后咖祭,就可以在根組件中使用了。

import Vue from 'vue';
import store from '../vuex';
import router from './router';
import './blog';

new Vue({
    store,
    router,
    template: '<blog></blog>'
}).$mount('#app');

個(gè)人看來(lái)涧窒,一個(gè)狀態(tài)管理的應(yīng)用心肪,無(wú)論是使用 vuex,還是 redux纠吴,最困難的部分是在 store 的設(shè)計(jì)硬鞍。

究竟該如何設(shè)計(jì)一個(gè) store,是根據(jù)組件的結(jié)構(gòu)層次設(shè)計(jì)對(duì)應(yīng)的 store戴已,還是根據(jù)應(yīng)用數(shù)據(jù)來(lái)設(shè)計(jì) store固该?

由于,store 是存放整個(gè)應(yīng)用狀態(tài)的地方糖儡,所以伐坏,起初我認(rèn)為應(yīng)該是前者按組件的層次結(jié)構(gòu)去設(shè)計(jì)。這樣 store 中分別保存著每個(gè)組件的狀態(tài)握联,這對(duì)大型項(xiàng)目來(lái)說(shuō)或許會(huì)造成大量的冗余數(shù)據(jù)存儲(chǔ)在 store 中桦沉,以及一些重復(fù)的工作,但這也提供了簡(jiǎn)潔鮮明的層次結(jié)構(gòu)金闽,增強(qiáng)了項(xiàng)目的可維護(hù)性纯露,這對(duì)大型項(xiàng)目來(lái)說(shuō)更至關(guān)重要。

但伴隨著寫項(xiàng)目時(shí)的思考代芜,我漸漸推翻了之前的想法埠褪。

假設(shè)這樣一個(gè)場(chǎng)景,項(xiàng)目中有兩個(gè)互不相關(guān)的組件挤庇,但它們倆卻依賴同一份數(shù)據(jù)源钞速。如果,這時(shí)采用之前的設(shè)計(jì)方法嫡秕,那么這同一份數(shù)據(jù)源會(huì)被存放在 store 的兩個(gè)不同的位置渴语。那么此時(shí),如果一個(gè)組件需要對(duì)數(shù)據(jù)源進(jìn)行操作的話昆咽,它不但需要修改自己組件對(duì)應(yīng)的 state遵班,同時(shí)還要發(fā)起 action 來(lái)修改另一個(gè)組件的 state,這恰恰違背了組件的單一性潮改。

然而狭郑,使用應(yīng)用數(shù)據(jù)來(lái)設(shè)計(jì) store 就不會(huì)有這樣的問題。鑒于這個(gè)原因汇在,我現(xiàn)在更傾向于第二個(gè)理念來(lái)設(shè)計(jì)整個(gè)應(yīng)用的 store翰萨。

所以,當(dāng)項(xiàng)目開始時(shí)糕殉,要考慮到整個(gè)應(yīng)用的數(shù)據(jù)模型來(lái)設(shè)計(jì) store 真是相當(dāng)麻煩啊亩鬼。

談完了 store殖告,就再一個(gè)個(gè)來(lái)看剛剛創(chuàng)建 store 時(shí)所提到的屬性,state 就是用來(lái)保存狀態(tài)的雳锋,沒啥好說(shuō)的黄绩,直接來(lái)看看第二個(gè) actions

Actions

actions 是一個(gè)對(duì)象玷过,key 就是 action 的名字爽丹,value 就是對(duì)應(yīng)的 action。此處的 action辛蚊,無(wú)論從名字粤蝎,還是作用都和 redux 中的 action 相同,用于激發(fā) state 的變更袋马。但是初澎,它們的用法卻不相同。

Redux 中的 action 需要返回一個(gè) JS 對(duì)象虑凛,即使加了 thunk 中間件之后碑宴,能夠返回一個(gè)函數(shù),但這個(gè)函數(shù)最終返回的還是一個(gè) JS 對(duì)象桑谍,最后通過墓懂,store.dispatch 該對(duì)象來(lái)觸發(fā) state 的變更。

然而霉囚,Vuex 中的 action 它本身就是一個(gè)方法,并且這個(gè)方法并不需要任何的返回匕积,而是盈罐,通過 store.commit 來(lái)觸發(fā) mutation

Vuex 2.0 中闪唆,已將原先的 store.dispatch 改名為了 store.commit 來(lái)觸發(fā) mutation盅粪。
Vuex 2.0 中,并沒有移除 store.dispatch悄蕾,而是改為用于觸發(fā) action票顾。

所有 action 方法接受當(dāng)前 store 的實(shí)例作為第一個(gè)參數(shù),調(diào)用傳遞的參數(shù)會(huì)作為第二個(gè)參數(shù)傳入(暫不支持多參數(shù))帆调。

Mutations

mutations 也是一個(gè)對(duì)象奠骄,同 actions 類似,key 就是 mutation 的名字番刊,value 就是對(duì)應(yīng)的 mutation含鳞。

mutation 用于更新應(yīng)用的 state。Redux 中雖然沒有 mutation 這個(gè)詞芹务,但從上面的解釋就明白蝉绷,這同 redux 中的 reduce 起著相同的作用鸭廷。

但兩者在寫法上又有著不同,由于 vuex 中的 mutations 是一個(gè)對(duì)象熔吗,并借用 ES6 對(duì)象方法可以使用變量省略的特點(diǎn)辆床,調(diào)用 mutation 可以直接通過命名找到相應(yīng)的處理方法,這使得它比 redux 的一系列 switch/case 語(yǔ)句要更簡(jiǎn)單桅狠、更優(yōu)雅讼载。

更大的不同之處在于 redux 的 reduce 是要求返回一個(gè)新的 state,而 vuex 就如它的命名 mutations(變異)是對(duì)當(dāng)前 state 進(jìn)行操作垂攘,而不能返回一個(gè)新的 state维雇,這里就和 FP 的理念有所沖突了。

// mutations.js
export default {
    // work
    [LOAD_SOCIAL_LINK](state = {}, mutation = {}) {
        state.socialLinkList = mutation.payload
            .filter(item => !!item.link)
            .map(item => ({
                ...item,
                svgPath: svgPath + '#' + item.name
            }));
    }
    
    // not work
    [LOAD_SOCIAL_LINK](state = {}, mutation = {}) {
        state = {
            ...state,
            socialLinkList: mutation.payload
                .filter(item => !!item.link)
                .map(item => ({
                    ...item,
                    svgPath: svgPath + '#' + item.name
                }))
        };
    }
};

單就這點(diǎn)來(lái)看晒他,redux 略勝一籌吱型。

Getters

Getters 也是一個(gè)對(duì)象,用于注冊(cè) getter陨仅,每個(gè) getter 都是一個(gè) function 用于返回一部分的 state津滞。

getter 方法接受 state 作為第一個(gè)參數(shù),一個(gè)簡(jiǎn)單的 getters 就可能是這樣:

export default {
    // 省略...
    getters: {
        socialLinkList: state => state.socialLinkList
    }
};

掌握了 Store, Actions, Mutations 以及 Getters 這幾個(gè)概念灼伤,那你就掌握了 vuex 的核心触徐,已經(jīng)完全可以創(chuàng)建一個(gè)完整的 store,并可以使用了狐赡。

但隨著項(xiàng)目的增長(zhǎng)撞鹉,你會(huì)發(fā)現(xiàn)將 Actions, Mutations, Getters 全都寫在一起非常難以維護(hù),這時(shí)你會(huì)想念 Redux 中將 state 劃分處理的 combineReducers颖侄。

Wake up!

醒醒鸟雏!別想 Redux 啦,Vuex 也可以劃分處理 state 樹览祖,它就是接著就要提到的 modules孝鹊。

Modules

Modules 的作用就如它的名字,劃分模塊展蒂。

它的屬性也是一個(gè)對(duì)象又活,key 是對(duì)應(yīng)的 module 名,在 state 中會(huì)創(chuàng)建相應(yīng)的 key锰悼,而 value 是一個(gè)用于配置如何創(chuàng)建 module 的對(duì)象柳骄,該對(duì)象的屬性基本同創(chuàng)建 store 時(shí)的 options 對(duì)象一樣,只少了最后 2 個(gè)還沒有講到的屬性 pluginsstrict箕般。這兩者是不是有什么關(guān)系哪夹界?

class Store {
  constructor (options = {}) {
    // 省略...
    
    // init root module.
    // this also recursively registers all sub-modules
    // and collects all module getters inside this._wrappedGetters
    installModule(this, state, [], options)
    
    // 省略...
  }

從 vuex 創(chuàng)建的源碼中可以看到,其實(shí),store 它本身就是一個(gè) module可柿。

既然鸠踪,modules 中能配置 modules 那就意味著:模塊是可以嵌套的。那么复斥,使用 modules 就可以將 state 劃分為各個(gè)模塊营密,同 combineReducers 一樣可以化繁為簡(jiǎn),這對(duì)中大型項(xiàng)目來(lái)說(shuō)必不可少目锭。

一個(gè) module 的定義就可以是這樣评汰。

// nav module
import mutations from './mutations';
import actions from './actions';

export default {
    state: {},
    getters: {
        navList: state => state.navList
    },
    actions,
    mutations
};

警報(bào)!前方第 6 行有坑痢虹,請(qǐng)速速繞行被去。

第 6 行?

state: {}, 初始化 state 能有什么問題敖蔽ā惨缆?

當(dāng)你運(yùn)行你的應(yīng)用的時(shí)候,你會(huì)發(fā)現(xiàn)丰捷,如果 navList 的變化是由一個(gè)同步的方法返回的就沒有問題坯墨,但如果,它是通過異步方法返回的病往,你會(huì)發(fā)現(xiàn)雖然控制臺(tái)上的 mutation log 輸出正確捣染,但你的組件中并沒有得到正確的值。

What happened?

因?yàn)橥O铮?dāng) action 調(diào)用之后會(huì)計(jì)算一次 getter耍攘,如果是同步的,那么此時(shí) getter 的 state 中已經(jīng)保存著最新的數(shù)據(jù)畔勤。

但如果是異步的蕾各,那么此時(shí) getter 中的 state 是一個(gè)空對(duì)象,那么上例中的 state.navList 就會(huì)返回一個(gè) undefined硼被。然而,undefined 就不會(huì)進(jìn)入 vue 的 watch 系統(tǒng)渗磅,所以當(dāng)異步請(qǐng)求結(jié)束后嚷硫,即使 state 中對(duì)應(yīng)字段變?yōu)榱四繕?biāo)值,但也不會(huì)再調(diào)用 getter 了始鱼,組件中的值自然也不會(huì)更新了仔掸。

那怎么解決哪?那就是給 state 中的每個(gè)屬性設(shè)初始值医清,這樣在第一次計(jì)算 getter 的值時(shí)就會(huì)返回對(duì)應(yīng)的初始值起暮,而這個(gè)初始值是在 vue 的系統(tǒng)中的,所以當(dāng)異步請(qǐng)求結(jié)束后調(diào)用 mutation 改變 state 中對(duì)應(yīng)的值后会烙,getter 會(huì)自動(dòng)觸發(fā)更新负懦,此時(shí)筒捺,組件中對(duì)應(yīng)的值也就被修改了。

所以纸厉,一定要記得:

為每個(gè)屬性設(shè)置初始化 state O悼浴!颗品!

為每個(gè)屬性設(shè)置初始化 state ?铣摺!躯枢!

為每個(gè)屬性設(shè)置初始化 state T蛞鳌!锄蹂!

重要的話氓仲,說(shuō)三遍!0芷ァ寨昙!

最后,在使用 modules 還需要注意掀亩,在不同 modules 下舔哪,注冊(cè)的 action 或 mutation 的名字重復(fù)并不會(huì)報(bào)錯(cuò),但都會(huì)被調(diào)用槽棍,所以要注意命名捉蚤。

好,modules 講完了炼七,繼續(xù)看下一個(gè)屬性 plugins缆巧。

Plugins

vuex 自 1.0 版開始就將原先的 middlewares 替換成了 plugins。也就是說(shuō)豌拙,現(xiàn)在使用的 plugins 就是中間件陕悬。

plugins 的參數(shù)終于同之前的有所不同了,是一個(gè)數(shù)組按傅,數(shù)組中的每一項(xiàng)都是一個(gè)方法捉超,方法接受一個(gè)參數(shù)就是當(dāng)前 store 的實(shí)例。

    // vuex source code: apply plugins
    plugins.concat(devtoolPlugin).forEach(plugin => plugin(this))

vuex 中間件的編寫理解起來(lái)也十分容易唯绍,就是通過 store.subscribe 來(lái)訂閱 mutation 的變化拼岳,這比 redux 中間件的工作原理更容易理解。

最后的 strict 屬性之前已經(jīng)提到了况芒,就是用來(lái)設(shè)置時(shí)候開啟嚴(yán)格模式的惜纸,嚴(yán)格模式下,state 只能通過 mutation 來(lái)修改。

至此耐版,創(chuàng)建 vuex store 的所有屬性都講完了祠够,store 也就完成了,那么椭更,vue 的組件該如何和 vuex 的 store 鏈接起來(lái)哪哪审?

連接到組件

vuex 1.0 之前如何將 vuex 連接到組件在這里就不說(shuō)了,有興趣可以上官網(wǎng)上看看虑瀑。

主要來(lái)看看如何使用 vue 2.0 新增的 4 個(gè) helper 方法優(yōu)雅地將 vuex 連接到組件湿滓。

這 4 個(gè) helper 方法,分別是:

  • mapState
  • mapMutations
  • mapGetters
  • mapActions

常言道:口說(shuō)無(wú)憑舌狗。

我們就來(lái)看一個(gè)博客升級(jí)中的簡(jiǎn)單例子叽奥,沒有加入 vuex 前,本人博客的首頁(yè)是這樣設(shè)定的:

// home.js
import Vue from 'vue';

import PostService from '../../../common/service/PostService';

import img from '../../../assets/img/home-bg.jpg';
import template from './home.html';

const Home = Vue.extend({
    template,
    data: () => {
        return {
            header: {
                img,
                title: 'D.D Blog',
                subtitle: 'Share More, Gain More.'
            },
            postList: []
        };
    },
    created() {
        const postService = new PostService();
        postService.queryPostList().then(({postList}) => (this.postList = postList));
    }
});

這里我們回顧一下之前的所講痛侍,為 home 組件創(chuàng)建對(duì)應(yīng)的 store module朝氓。

// index.js
// mutation types
const INIT_HOME_PAGE = 'INIT_HOME_PAGE';
const LOAD_POST_LIST = 'LOAD_POST_LIST';

// actions
const initHomePage = ({dispatch, commit}) => {
    commit(createAction(INIT_HOME_PAGE, {
        header: {
            image,
            title: 'D.D Blog',
            subtitle: 'Share More, Gain More.'
        }
    }));
    dispatch('loadPostList');
};

const loadPostList = ({commit}) => {
    new PostService().queryPostList()
        .then((result = {}) => {
            commit(createAction(LOAD_POST_LIST, {
                postsList: result.postsList
            }));
        });
};

const actions = {initHomePage, loadPostList};

// mutations
const mutations = {
    [INIT_HOME_PAGE](state = {}, mutation = {}) {
        state.header = mutation.payload.header;
    },

    [LOAD_POST_LIST](state = {}, mutation = {}) {
        state.postsList = mutation.payload.postsList;
    }
};

export default {
    state: {
        header: {},
        postsList: []
    },
    getters: {
        postsList: state => state.postsList
    },
    actions,
    mutations
};
const createAction = (typeName = '', data = '') => ({ type: typeName, payload: data });

這里的 createAction 是自己創(chuàng)建的一個(gè)簡(jiǎn)單函數(shù),用于格式化 mutation 獲得的參數(shù)主届,這并不是必須的赵哲,vuex 的 commit 方法是接受參數(shù)為 (type, data) 的。

OK君丁。對(duì)應(yīng)的 store module 也創(chuàng)建好了枫夺,就來(lái)改組件吧。

首先绘闷,應(yīng)用的狀態(tài)都來(lái)自于 store橡庞,那么組件中的 data 屬性自然就不用了,直接刪除印蔗。爽~

const Home = Vue.extend({
    template,
    created() {
        const postService = new PostService();
        postService.queryPostList().then(({postList}) => (this.postList = postList));
    }
});

其次扒最,原先在 created hooks 里直接去查數(shù)據(jù),現(xiàn)在用了 vuex 自然要通過調(diào)用 action 來(lái)獲取數(shù)據(jù)华嘹,這里就要用到 4 大金剛之一——mapActions 來(lái)獲取 vuex 中設(shè)定好的 action吧趣。

mapActions 接受一個(gè)數(shù)組或?qū)ο螅鶕?jù)相應(yīng)的值將對(duì)應(yīng)的 action 綁定到組件上耙厚。

import {mapActions} from 'vuex';

const Home = Vue.extend({
    template,
    methods: mapActions(['initHomePage']),
    created() {
        this.initHomePage();
    }
});

數(shù)據(jù)拿到了强挫,怎么綁定到組件上哪?這就可以用到另兩個(gè) helper:mapStatemapGetters颜曾。

mapStatemapGetters 同樣接受一個(gè)數(shù)組或?qū)ο缶腊危⒏鶕?jù)相應(yīng)的值將 store 中的 state 或 getter 綁定到組件上秉剑。

import vue from 'vue';
import { mapState, mapGetters, mapActions } from 'vuex';

import template from './home.html';

const Home = vue.extend({
    template,
    computed: {
        ...mapState({
            header: state => state.home.header
        }),
        ...mapGetters(['postsList'])
    },
    methods: mapActions(['initHomePage']),
    created() {
        this.initHomePage();
    }
});

哈哈泛豪,這樣模板不用改變一分一毫,升級(jí)就完成啦~

是不是很簡(jiǎn)潔,很優(yōu)雅~

容器組件和展示組件

容器組件和展示組件這個(gè)概念在 Redux 入門一文中已有提到诡曙。然而臀叙,這個(gè)概念并不只服務(wù)于 react,在 vue 中也可以用到价卤。

簡(jiǎn)單來(lái)說(shuō)劝萤,容器組件就是用于包裹展示組件的組件,它和界面展示無(wú)關(guān)慎璧,它負(fù)責(zé)數(shù)據(jù)的獲取和傳遞床嫌,之前的 home 組件就是一個(gè)容器組件,再來(lái)看看它的 template胸私,你會(huì)發(fā)現(xiàn)它除了根元素以外厌处,不包含其他任何的 html 標(biāo)簽。

<section>
    <!-- Content Header -->
    <content-header :board-img="header.image" :title="header.title" :subtitle="header.subtitle"></content-header>

    <!-- Main Content -->
    <main-content>
        <post-list :post-list="postsList"></post-list>
    </main-content>
</section>

與此相反的是岁疼,展示組件單單用于展示阔涉,自己不獲取任何數(shù)據(jù),數(shù)據(jù)都通過 props 傳遞捷绒,比如 content-header瑰排。

const template = `<header class="intro-header" :style="{ backgroundImage: 'url(' + boardImg + ')' }">
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="site-heading">
                    <h1>{{ title }}</h1>
                    <hr class="small">
                    <span class="subheading">{{ subtitle }}</span>
                </div>
            </div>
        </div>
    </div>
</header>`;

export default Vue.component('contentHeader', {
    template,
    props: {
        boardImg: {
            type: String,
            default: _defaultImg
        },
        title: {
            type: String,
            required: true
        },
        subtitle: {
            type: String
        }
    }
});

這樣明確地區(qū)分容器組件和展示組件會(huì)使得項(xiàng)目結(jié)構(gòu)變得更清晰,追蹤 bug 暖侨,以及維護(hù)也變得輕而易舉椭住。

管理路由

是不是覺得這樣就完了?

No, No, No. 路由系統(tǒng)還沒處理它碎,那么如何將 vue-router 納入到 vuex 的管理中哪函荣?

這里又得感謝尤大大為我們?cè)旌昧艘粋€(gè)小工具 vuex-router-sync

首先扳肛,安裝

npm install vuex-router-sync@next --save

然后傻挂,在項(xiàng)目初始化的時(shí)候?qū)?router 同 store 聯(lián)系起來(lái)就行,簡(jiǎn)單到都不知道說(shuō)啥好挖息。

不知道說(shuō)啥金拒,就說(shuō)說(shuō)原理,看看源碼吧套腹。

這個(gè)工具的原理也非常好理解绪抛,主要是 2 點(diǎn):

一是,給 vuex 的 store 注冊(cè)一個(gè) router 的 module电禀。

function patchStore (store) {
  // 略...
  var routeModule = {
    mutations: {
      'router/ROUTE_CHANGED': function (state, to) {
        store.state.route = to
      }
    }
  }

  // add module
  if (store.registerModule) {
    store.registerModule('route', routeModule)
  } else if (store.module) {
    store.module('route', routeModule)
  } else {
    store.hotUpdate({
      modules: {
        route: routeModule
      }
    })
  }
}

另一個(gè)幢码,就是使用 vue-router 的 afterEach hooks 來(lái)觸發(fā) mutation。

exports.sync = function (store, router) {
  patchStore(store)
  store.router = router

  var commit = store.commit || store.dispatch
  // 略...
  
  // sync store on router navigation
  router.afterEach(function (transition) {
    if (isTimeTraveling) {
      isTimeTraveling = false
      return
    }
    var to = transition.to
    currentPath = to.path
    commit('router/ROUTE_CHANGED', to)
  })
}

項(xiàng)目中使用:

import { sync } from 'vuex-router-sync';
import store from '../vuex';
import router from './router';

sync(store, router);

new Vue({
    store,
    router,
    template: '<blog></blog>'
}).$mount('#app');

OK尖飞,這樣就大功告成了症副。

寫在最后

加入了 vuex 后店雅,我的博客終于讓 vue 它們一家子(vue + vuex + vue-router)團(tuán)圓了。

總的來(lái)看贞铣,vuex 同 vue 一樣使用起來(lái)相當(dāng)方便闹啦,集成了許多方法,但似乎缺少了 redux 的那份優(yōu)雅辕坝,而我喜歡比較優(yōu)雅的...(看在全篇我都在安利 vue 的情面上窍奋,尤大大請(qǐng)不要打我~)

逃~

PS: 一下把 vuex 有關(guān)的一股腦都過了,可能過得太快酱畅,如有不明白的就留言吧琳袄。

最后的最后,當(dāng)然是繼續(xù)安利下自己的 Blog纺酸,以及 Source Code挚歧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市吁峻,隨后出現(xiàn)的幾起案子滑负,更是在濱河造成了極大的恐慌,老刑警劉巖用含,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矮慕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡啄骇,警方通過查閱死者的電腦和手機(jī)痴鳄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缸夹,“玉大人痪寻,你說(shuō)我怎么就攤上這事∷洳眩” “怎么了橡类?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芽唇。 經(jīng)常有香客問我顾画,道長(zhǎng),這世上最難降的妖魔是什么匆笤? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任研侣,我火速辦了婚禮,結(jié)果婚禮上炮捧,老公的妹妹穿的比我還像新娘庶诡。我一直安慰自己,他們只是感情好咆课,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布末誓。 她就那樣靜靜地躺著璧函,像睡著了一般。 火紅的嫁衣襯著肌膚如雪基显。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天善炫,我揣著相機(jī)與錄音撩幽,去河邊找鬼。 笑死箩艺,一個(gè)胖子當(dāng)著我的面吹牛窜醉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播艺谆,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼榨惰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了静汤?” 一聲冷哼從身側(cè)響起琅催,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虫给,沒想到半個(gè)月后藤抡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抹估,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年缠黍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片药蜻。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓷式,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出语泽,到底是詐尸還是另有隱情贸典,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布踱卵,位于F島的核電站瓤漏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颊埃。R本人自食惡果不足惜蔬充,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望班利。 院中可真熱鬧饥漫,春花似錦、人聲如沸罗标。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至彻消,卻和暖如春竿拆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宾尚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工丙笋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人煌贴。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓御板,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親牛郑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子怠肋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)淹朋,并以相應(yīng)...
    白水螺絲閱讀 4,652評(píng)論 7 61
  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中笙各,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,926評(píng)論 0 7
  • Vuex是什么? Vuex 是一個(gè)專為 Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式础芍。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,106評(píng)論 0 6
  • Vuex 的學(xué)習(xí)記錄 資料參考網(wǎng)址Vuex中文官網(wǎng)Vuex項(xiàng)目結(jié)構(gòu)示例 -- 購(gòu)物車Vuex 通俗版教程N(yùn)uxt....
    流云012閱讀 1,451評(píng)論 0 7
  • vuex 場(chǎng)景重現(xiàn):一個(gè)用戶在注冊(cè)頁(yè)面注冊(cè)了手機(jī)號(hào)碼酪惭,跳轉(zhuǎn)到登錄頁(yè)面也想拿到這個(gè)手機(jī)號(hào)碼,你可以通過vue的組件化...
    sunny519111閱讀 8,008評(píng)論 4 111