Vue--vuex的使用

Vuex 概述

官方文档:https://vuex.vuejs.org/zh/

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
  • Vue 应用中的每个组件在 data() 中封装着自己数据属性,而这些 data 属性都是私有的,完全隔离的。
  • 如果我们希望多个组件都能读取到同一状态数据属性,或者不同组件的行为需要更新同一状态数据属性,
  • 这就需要一个将共享的状态数据属性进行集中式的管理。
  • 这就是 Vuex 状态管理所要解决的问题。

简单使用

使用vue-cli创建一个项目,命名为vue-demo,安装依赖和运行

# 进入工程目录
cd vuex-demo
# 安装依赖 npm install --save vuex
# 运行项目 npm run serve

访问 http://localhost:8080/,正常访问就表示配置的没有问题

每一个 Vuex 项目的核心就是 store(仓库)。 store 就是一个对象,它包含着你的项目中大部分的状态(state)。

state 是  store 对象中的一个选项,是 Vuex 管理的状态对象(共享的数据属性)

在 src 目录下创建 store 目录,store 下创建 index.js 文件, 编码如下:

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

// 引用vuex插件
Vue.use(Vuex)

const  store = new Vuex.Store({ //注意V和S都是大写
    // 存放状态(共享属性)
    state:{
        count: 1
    }
})


export default store

修改 main.js,导入和注册 store,编码如下:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";

import store from './store'

Vue.config.productionTip = false;

new Vue({
  router,
  store, // 注册
  render: h => h(App)
}).$mount("#app");

组件中读取 state 状态数据,修改 src\views\Home.vue,编码如下:

<template>
 <div>
 count: {{ $store.state.count }}
 </div>
</template>
<script>
</script>

访问 http://localhost:8080/ 页面显示如下

 改变状态值 mutation

在 store 的 mutations 选项中定义方法,才可以改变状态值。在通过 $store.commit('mutationName') 触发状态值的改变

修改 store/index.js , 在 store 中添加 mutations 选项,编码如下:

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

// 引用vuex插件
Vue.use(Vuex)

const  store = new Vuex.Store({ //注意V和S都是大写
    // 存放状态(共享属性)
    state:{
        count: 1
    },

    // 改变state状态
    mutations:{
        // 加法
        increment(state){
            state.count++
        },
        // 减法
        decrement(state){
            state.count--
        }
    }
})


export default store

修改 src\views\Home.vue ,调用 mutations 中 increment、decrement 方法

<template>
 <div>
 count: {{ $store.state.count }}
 <button @click="addCount">加法</button>
 <button @click="decrement">减法</button>
 </div>
</template>
<script>
export default{
    methods: {
  addCount() {
   // 获取状态值
   console.log(this.$store.state.count)
   // 通过commit 调用 mutations 中的 increment 改变状态值
   this.$store.commit('increment')
 },
  decrement() {
    console.log(this.$store.state.count)
   // 通过commit 调用 mutations 中的 decrement 改变状态值
   this.$store.commit('decrement')
 }
},
}
</script>

点击  加法 按钮,控制台和页面显示数字变化

载荷

你可以向  $store.commit 传入额外的参数,即 mutation 的 载荷(payload):

修改 src\store 下的 index.js

......
    // 改变state状态
    mutations:{
        increment(state, n){  // n 为载荷
            state.count+=n // state.count=state.count+n
        },
        decrement(state){
            state.count--
        }
    }
})

修改 views\Home.vue 组件

<template>
 <div>
 count: {{ $store.state.count }}
 <button @click="addCount">加法</button>
 <button @click="decrement">减法</button>
 </div>
</template>
<script>
export default{
    methods: {
  addCount() {
   // 获取状态值
   console.log(this.$store.state.count)
   // 通过commit 调用 mutations 中的 increment 改变状态值
   this.$store.commit('increment',5) // 提交载荷
 },
  decrement() {
    console.log(this.$store.state.count)
   // 通过commit 调用 mutations 中的 decrement 改变状态值
   this.$store.commit('decrement')
 }
},
}
</script>

页面上点击加法会一次加5,减法还是一个一个的减

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是在组件中直接变更状态, 通过它间接更新 state。
  • 在组件中通过 this.$store.dispatch('actionName') 触发状态值间接改变
  • Action 也支持载荷
  • Action 可以包含任意异步操作。

修改 store/index.js ,增加 actions 选项

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

// 引用vuex插件
Vue.use(Vuex)

const  store = new Vuex.Store({ //注意V和S都是大写
    // 存放状态(共享属性)
    state:{
        count: 1
    },

    // 改变state状态
    mutations:{
        increment(state, n){  // n 为载荷
            state.count+=n // state.count=state.count+n
        },
        decrement(state){
            state.count--
        }
    },
    actions: {
            add(context, n) {
              // 触发 mutations 中的 increment 改变 state
              context.commit('increment', n)
           },
            decrement({commit, state}) { // 按需传值
              commit('decrement')
           }
         }
})


export default store

修改 views\Home.vue, 触发 action 改变值

<template>
 <div>
 count: {{ $store.state.count }}
 <button @click="addCount">加法</button>
 <button @click="decrement">减法</button>
 </div>
</template>
<script>
export default{
    methods: {
  addCount() {
        // 获取状态值
       console.log(this.$store.state.count)
       // 通过commit 调用 mutations 中的 increment 改变状态值
       // this.$store.commit('increment')
       // this.$store.commit('increment', 10) // 提交载荷
       // 触发 actions 中的 add 改变状态值
       this.$store.dispatch('add', 10)
 },
  decrement() {
    console.log(this.$store.state.count)
   // 通过commit 调用 mutations 中的 decrement 改变状态值
    //    this.$store.commit('decrement')
     this.$store.dispatch('decrement')
 }
},
}
</script>

派生属性 getter

有时候我们需要从 store 中的 state 中派生出一些状态。

例如:基于上面代码,增加一个 desc 属性,当 count 值小于 50,则 desc 值为 吃饭 ; 大于等于 50 小于100,则desc 值为 睡觉 ; 大于100 , 则 desc 值为 打豆豆 。这时我们就需要用到 getter 为我们解决。

getter 其实就类似于计算属性(get)的对象

组件中读取 $store.getters.xxx

修改 store\index.js ,增加 getters 选项

getters 中接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

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

// 引用vuex插件
Vue.use(Vuex)

const  store = new Vuex.Store({ //注意V和S都是大写
    // 存放状态(共享属性)
    state:{
        count: 1
    },

    // 改变state状态
    mutations:{
        increment(state, n){  // n 为载荷
            state.count+=n // state.count=state.count+n
        },
        decrement(state){
            state.count--
        }
    },
    actions: {
            add(context, n) {
              // 触发 mutations 中的 increment 改变 state
              context.commit('increment', n)
           },
            decrement({commit, state}) { // 按需传值
              commit('decrement')
           }
         },
    //派生属性
      getters: {
            desc(state) {
              if(state.count < 50) {
                return '吃饭'
             }else if(state.count < 100) {
                return '睡觉'
             }else {
                return '打豆豆'
             }
                }
            }
})


export default store

 修改 views\Home.vue, 显示派生属性的值

<template>
 <div>
 count: {{ $store.state.count }}
 <button @click="addCount">加法</button>
 <button @click="decrement">减法</button>
    派生属性desc: {{ $store.getters.desc }}
 </div>
</template>

点击 Home 页面的  触发改变 按钮,当 count 新增到  51 , desc 是否会显示为  睡觉

 Module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,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 的状态

修改 store\index.js

import Vue from 'vue'
import Vuex from 'vuex'
// 引入 Vuex 插件
Vue.use(Vuex)

const home = {
  // 存放状态(共享属性)
  state: {
    count: 1
 },
  //派生属性
  getters: {
    desc(state) {
      if(state.count < 50) {
        return '吃饭'
     }else if(state.count < 100) {
        return '睡觉'
     }else {
        return '打豆豆'
     }
   }
 },
  // 改变 state 状态
  mutations: {
    increment(state, n) { // n 为载荷
      // state.count ++
      state.count += n
   },
    decrement(state) {
      state.count --
   }
 },
  actions: {
    add(context) {
      // 触发 mutations 中的 increment 改变 state
      context.commit('increment', 10)
   },
    decrement({commit, state}) { // 按需传值
      commit('decrement')
   }
 }
}

const store = new Vuex.Store({ // 注意V 和 S都是大写字母
  modules: {
    home // home: home
 }
})
export default store

修改 Home.vue

<template>
 <div>
   <!--修改部分-->
 count: {{ $store.state.home.count }}
  <button @click="addCount">加法</button>
  <button @click="decrement">减法</button>
 派生属性desc: {{ $store.getters.desc }}
 </div>
</template>
 
<script>
export default {
 methods: {
  addCount() {
   console.log(this.$store.state.home.count)
   this.$store.dispatch('add', 10)
 },
  decrement(){
   this.$store.dispatch('decrement')
 }
},
}
</script>

标准项目结构

如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。但是它建议你按以下代码
结构来构建项目结构:

├── index.html
├── main.js
├── api
│  └── ... # 抽取出API请求
├── components
│  ├── App.vue
│  └── ...
└── store
 ├── index.js     # 我们组装模块并导出 store 的地方
 ├── actions.js    # 根级别的 action
 ├── mutations.js   # 根级别的 mutation
 └── modules
   ├── cart.js    # 购物车模块
   └── products.js  # 产品模块

在 store下创建 modules 目录,该目录下创建 home.js

const state = {
      count: 1
    }
    const getters ={
      desc(state) {
        if(state.count < 50) {
          return '吃饭'
       }else if(state.count < 100) {
          return '睡觉'
       }else {
          return '打豆豆'
       }
     }
    }

const mutations = {
  increment(state, n) { // n 为载荷
    // state.count ++
    state.count += n
 },
  decrement(state) {
    state.count --
 }
}

const actions = {
  add(context) {
    // 触发 mutations 中的 increment 改变 state
    context.commit('increment', 10)
 },
  decrement({commit, state}) { // 按需传值
    commit('decrement')
 }
}
    
export default {
        // 存放状态(共享属性)
          state,
          //派生属性
          getters,
          // 改变 state 状态
          mutations,
          actions
}

修改 store\index.js, 导入 ./modules/home.js,删除之前的home变量

import Vue from 'vue'
import Vuex from 'vuex'
// 导入 Module
import home from './modules/home'

// 引入 Vuex 插件
Vue.use(Vuex)


const store = new Vuex.Store({ // 注意V 和 S都是大写字母
  modules: {
    home // home: home
 }
})
export default store

正常访问, 与重构前一样

猜你喜欢

转载自www.cnblogs.com/zouzou-busy/p/11826654.html