使用Vuex实现数据共享

在我们的程序中,City.vue和Home.vue是没有公用的父级组件的,因此没办法使用父级组件作为中转站的方式进行数据的传递。在这样的情况下我们可以使用数据框架Vuex辅助进行数据传递。


Vuex

Vuex的设计理念是把数据放在公共的存储空间进行存储,当某个组件改变了数据,其他组件也可以感知到。

state:存放公用数据。

  • 组件改变数据先使用dispatch调用Actions做异步处理或批量同步操作,再使用commit调用Mutations改变公用数据的值。
  • 有时也可以直接从State到Mutations,跳过Actions。

一、安装Vuex

npm install vuex --save

二、使用Vuex

①组件调用actions来调用mutations,以此改变state值

在src目录下创建store文件夹,创建index.js文件,引入Vuex,并创建store。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state:{},
    mutations:{},
})

在main.js中引入store,并在引入根vue实例时把store传入进去。

import store from "./store/index.js"

new Vue({
  el: '#app',
  // 键和值一样,写一个即可
  router,
  store,
  components: { App },
  template: '<App/>'
})

如下图,在首页的header区域,我们希望第一次访问网站的人默认显示城市为北京。


Home.header

我们在store/index.js内对state数据进行定义。这样在其他组件中要使用时可以使用{{this.$store.state.city}}来表示

let defaultCity = "北京"
// 使用localstorage最好加入try catch,这是为了防止出现异常,因为用户可能关闭本地存储的功能导致出错
try{
    if (localStorage.city){
        defaultCity = localStorage.city
    }
} catch(e) {}

export default new Vuex.Store({
    state:{
        city:defaultCity
    },
})

在点击其他城市时,我们希望实现当前位置也发送改变的功能。


因此我们在list.vue中为列表绑定一个click,同时在methods中定义handleCityClick事件。

@click="handleCityClick(item.name)
handleCityClick(city){
            // 可以省略action步骤,直接由commit调用mutation
            this.$store.dispatch("changeCity",city)
}

仅仅在list.vue中的methods里定义了handleCityClick是无法起作用的,因为触发的changeCity事件还未定义,我们需要在store中定义changeCity函数。

export default new Vuex.Store({
    actions:{
        changeCity(ctx,city){
            // 借助ctx拿到commit,用mutation的changeCity来改变city的值。
            ctx.commit('changeCity',city)
        }
    },
})

这样Actions就接收到了传递来的数据(城市),需要调用Mutations来改变state的值。因此我们还需要在store中定义Mutations。

export default new Vuex.Store({
    mutations:{
        changeCity(state,city){
            // 让state的city等于传入的city
            state.city = city
            try {
                localStorage.city=city
            } catch (e) {}
        }
    }
})

②组件直接调用mutations来改变state值

在list.vue中handleCityClick函数可以不用dispatch调用Actions,而直接由commit调用Mutations。

handleCityClick(city){
            // 可以省略action步骤,直接由commit调用mutation
            this.$store.commit("changeCity",city)
}

因此,store定义可以删去Actions部分。

export default new Vuex.Store({
    state:{
        city:defaultCity
    },
    //actions:{
    //  changeCity(ctx,city){
    //      // 借助ctx拿到commit,用mutation的changeCity来改变city的值。
    //      ctx.commit('changeCity',city)
    //  }
    //},
    mutations:{
        changeCity(state,city){
            // 让state的city等于传入的city
            state.city = city
            try {
                localStorage.city=city
            } catch (e) {}
        }
    }
})

③当index.js内的内容越来越多时,我们可以把state和mutations拿出来单独写成代码文件。

state.js

let defaultCity = "北京"
// 使用localstorage最好加入try catch,这是为了防止出现异常,因为用户可能关闭本地存储的功能导致出错
try{
    if (localStorage.city){
        defaultCity = localStorage.city
    }
} catch(e) {}

export default {
    city: defaultCity
}

mutations.js

export default{
    changeCity(state,city){
        // 让state的city等于传入的city
        state.city = city
        try {
            localStorage.city=city
        } catch (e) {}
    }
    
}

在index.js内导入以上两个文件

import state from "./state"
import mutations from "./mutations"

④mapState, mapMutations, mapGetters

- 在其他组件中通过{{this.$store.state.city}}使用数据书写麻烦,利用mapState简写

在使用数据的组件<script>部分加入以下代码,把state的数据映射到名为city的计算属性中。那么在使用数据时,可以不写{{this.$store.state.city}},直接写作{{this.city}}

import mapState from 'vuex'
export default{
    name:'HomeHeader',
    computed: {
        // 把city的数据映射到名字叫做city的计算属性中
        ...mapState(['city']),
        ...mapGetters(['doubleCity'])
    }
}

也可以写作以下形式,使用{{this.currentCity}}使用数据

import mapState from 'vuex'
export default{
    name:'CityList',
    computed:{
        // 以下两种写法均可,可以是数组也可以是对象
        // ...mapState(['city'])
        ...mapState({
            currentCity:'city'
        }),
    },
}

- 点击城市时,通过 this.$store.commit 派发mutation,书写复杂,可以利用mapMutations简写

methods:{
    handleCityClick(city){
        // 可以省略action步骤,直接由commit调用mutation
         this.$store.commit("changeCity",city)
    },
}

首先在需要派发mutation的组件中<script>部分需要引入mapMutations

import { mapState, mapMutations} from 'vuex'

然后在methods里应用mapMutations,原methods中handleCityClick函数如下:

methods:{
        handleCityClick(city){
            this.$store.commit("changeCity",city)
            this.$router.push("./")
        },

应用mapMutation之后handleCityClick函数:
(mapMutation把mutation映射到组件中名为changeCity的方法里)

methods:{
        ...mapMutations(['changeCity']),
        handleCityClick(city){
            // 引入mapMutations之后可以简写
            this.changeCity(city)
            this.$router.push("./")
        },

- 当需要利用state里的数据进行计算出新的数据时可以使用mapGetters,避免数据冗余

export default new Vuex.Store({
    state,
    mutations,
    // gettters的作用和computed作用类似
    // 当需要利用state里的数据进行计算出新的数据时可以使用getters
    getters:{
        doubleCity (state) {
            return state.city+' ' +state.city
        }
     }
})

在需要使用数据的组件<script>中引入mapGetters,并在computed部分进行映射

import mapGetters from 'vuex'
export default{
    name:'HomeHeader',
    computed: {
        // 把city的数据映射到名字叫做city的计算属性中
        ...mapState(['city']),
        ...mapGetters(['doubleCity'])
    }
}

在组件中可以通过{{this.doubleCity}}使用数据

⑤模块化的Vuex(Modules)

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

https://vuex.vuejs.org/zh/guide/modules.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1、Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以...
    秋玄语道阅读 6,568评论 0 3
  • 安装 npm npm install vuex --save 在一个模块化的打包系统中,您必须显式地通过Vue.u...
    萧玄辞阅读 8,040评论 0 7
  • vuex 场景重现:一个用户在注册页面注册了手机号码,跳转到登录页面也想拿到这个手机号码,你可以通过vue的组件化...
    sunny519111阅读 12,461评论 4 111
  • Vuex是什么? Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件...
    萧玄辞阅读 8,322评论 0 6
  • 目录 - 1.什么是vuex? - 2.为什么要使用Vuex? - 3.vuex的核心概念?||如何在组件中去使用...
    我跟你蒋阅读 9,590评论 4 51

友情链接更多精彩内容