Vuex

初识Vuex

Vuex是一个专门为Vue.js应用程序开发的状态管理模式
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化

状态管理

简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面,然后将这个对象放在顶层的Vue实例中,让其他组件可以使用,那么多个组件就可以共享这个对象中的所有变量属性了

2.1 单界面的状态管理

State:状态 (姑且当作是data中的属性)
View:视图层,可以根据不同的State,显示不同的信息
Actions:主要表示用户的各种操作:点击、输入等等,会导致状态的变化

在下面这个例子中,counter就是状态管理对象
1.counter需要某种方式被记录下来,也就是State
2.counter的值需要被显示在界面中,也就是View
3.界面发生某些操作时,需要去更新状态,也就是Actions

App.vue

<template>
  <div id="app">
    <h2>---------app内容-------</h2>
    <button @click="$store.state.counter++">+</button>
    <button @click="$store.state.counter--">-</button>
    <h2>---------hello-vuex内容-------</h2>
    <hello-vuex :counter = 'counter'></hello-vuex>
  </div>
</template>

<script>
// 把HelloVuex用起来
import HelloVuex from './components/HelloVuex'
export default {
  name: 'App',
  // 注册组件
  components: {
    HelloVuex
  },
  data() {
    return {
      message: '我是App组件',
      counter: 0
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

HelloVue.vue

<template>
  <div>
    <h2>{{$store.state.counter}}</h2>
  </div>
</template>
<script>
export default {
  name: 'HelloVuex',
  props: {
    counter: Number
  }
}
</script>

main.js

import Vue from 'vue'
import App from './App'
import Vuex from 'vuex'
import store from './store'

Vue.config.productionTip = false

Vue.prototype.$store = store

new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

index.js

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

// 1.安装插件
Vue.use(Vuex) 

// 2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 0
  },
  mutations:{

  },
  actions: {

  },
  getters: {

  },
  modules: {
    
  }
})

// 3.导出store共享

2.2 多界面的状态管理

当多个视图都依赖于同一个状态
这时候就需要一个大管家来统一帮助我们管理这个状态
Vuex就是位我们提供这个大管家的工具

全局单例模式(大管家)
将共享的状态抽离出来,交给大管家,统一进行管理
之后的每个视图,都要按照规定,进行访问个修改等操作

在这里插入图片描述

Devtools

Vue 开发的一个浏览器插件
https://www.crxdl.com

在这里插入图片描述

2.3 案例

1.新建文件夹store,并且在其中创建index.js文件
2.让所有的Vue组件都可以使用这个store对象
到main.js文件,导入store对象,并且放在new Vue中
这样,在其他Vue组件中,就可以通过this.$store的方式,获取到这个store了

index.js

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

// 1.安装插件
Vue.use(Vuex) 

// 2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 0
  },
  mutations:{
    // 定义方法
    increment(state) {
      state.counter++
    },
    decrement(state) {
      state.counter--
    }
  },
  actions: {

  },
  getters: {

  },
  modules: {
    
  }
})

// 3.导出store共享
export default store

main.js

import Vue from 'vue'
import App from './App'
import Vuex from 'vuex'
import store from './store'

Vue.config.productionTip = false

Vue.prototype.$store = store

new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

App.vue

<template>
  <div id="app">
    <h2>---------app内容-------</h2>
    <h2>{{$store.state.counter}}</h2>
    <button @click="addition">+</button>
    <button @click="subtraction">-</button>
    <h2>---------hello-vuex内容-------</h2>
    <hello-vuex :counter = 'counter'></hello-vuex>
  </div>
</template>

<script>
// 把HelloVuex用起来
import HelloVuex from './components/HelloVuex'
export default {
  name: 'App',
  // 注册组件
  components: {
    HelloVuex
  },
  data() {
    return {
      message: '我是App组件',
      counter: 0
    }
  },
  methods: {
    addition() {
      this.$store.commit('increment')
    },
    subtraction() {
      this.$store.commit('decrement')
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

HelloVuex.vue

<template>
  <div>
    <h2>{{$store.state.counter}}</h2>
  </div>
</template>
<script>
export default {
  name: 'HelloVuex',
  props: {
    counter: Number
  }
}
</script>

在这里插入图片描述

Vuex核心概念

3.1 State

保存共享状态相关信息

单一状态树

即单一数据源
只创建一个store对象,使用单一状态树来管理应用层级的全部状态
单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护
只有一个store


// 2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 0
  },
  mutations:{
    // 定义方法
    increment(state) {
      state.counter++
    },
    decrement(state) {
      state.counter--
    }
  },
  actions: {

  },
  getters: {

  },
  modules: {
    
  }
})

3.2 Getters

功能是将state里面的内容进行处理之后传递
Getters作为参数和传递参数
使用方式一:
index.js中定义

getters: {
    powerCounter(state) {
      return state.counter * state.counter
    },
    more15(state) {
      return state.student.filter(s => s.age > 15)
    }
  },

App.vue中使用

    <h2>{{$store.getters.more15}}</h2>
    <h2>{{$store.getters.powerCounter}}</h2>

使用方式二:
index.js中定义

    more15Length(state, getters) {
      return getters.more15.length
    },
    moreAge(state) {
      return age => {
        return state.student.filter(s => s.age > age)
      }
    }

App.vue中使用

    <h2>{{$store.getters.more15Length}}</h2>
    <h2>{{$store.getters.moreAge(12)}}</h2>

3.3 Mutation

Mutation同步函数
Vuex要求Mutation中的方法必须是同步方法
如果是异步方法,那么dextools将不能很好的追踪这个操作何时完成
Vuex的store状态更新的唯一方式: 提交Mutation
Mutation包括两部分:
字符串的事件类型(type)
一个回调函数,该回调函数的第一个参数就是state
index.js

 mutations: {
    // 定义方法
    increment(state) {
      state.counter++
    },
    decrement(state) {
      state.counter--
    },
    incrementCount(state) {
      state.counter += count
    },
    addStudent(state, stu) {
      state.student.push(stu)
    }
  },

App.vue

    addCount(count) {
      // count专业名词叫playload  负载 (参数不止一个时)
      this.$store.commit("incrementCount", count);
    },
    addStudent() {
      const stu = { id: 114, name: "z", age: 15 };
      this.$store.commit("addStudent");
    }

mutation实现的两种风格

普通风格
通过commit提交的是普通风格

    addCount(count) {
      // count专业名词叫playload  负载
       this.$store.commit("incrementCount", count);
      })
    },
    incrementCount(state,count) {
      state.counter += count
    },

另一种风格
Vue还提交了另一种风格,他是一个包含type对象的属性

    addCount(count) {
      // count专业名词叫playload  负载
      this.$store.commit({
        type: "incrementCount",
        count,
        age: 18
      })
    },

Mutation的出路方式是将整个commit的对象作为payload使用,所以代码没有改变

    incrementCount(state,payload) {
      state.counter += payload.counter
    },

mutation的响应式原理

    info: {
      name: 'kobe',
      age: 40,
      height: 1.98
    }

这些属性会加入响应式系统中,二响应式系统会见厅属性的变化,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生改变

让属性加入响应式系统必须遵守一些Vuex对应的规则
1.提前在store中初始化好所需的属性
2.当给state中的对象添加新属性时,用以下两种方式

  Vue.set(state.info,address,'北京')
  Vue.delete(state.info, 'age')

mutation的类型常量

新建Mutation-type.js存放常量

export const INCREMENT = "increment"

index.js中导入和定义方法相应改变

import { INCREMENT } from './mutation-types'
  mutations: {
    // 定义方法
    [INCREMENT](state) {
      state.counter++
    },
   }

App.vue

    addition() {
      this.$store.commit(INCREMENT);
    }

3.4 Action

当有异步操作时,一定在actions中完成

  actions: {
    // context: 上下文
    // aUpdateInfo(context, payload) {
    //   setTimeout(() => {
    //     context.commit('updateInfo'),
    //     console.log(payload.message);
    //     payload.success()
    //   },1000)
    // }
    aUpdateInfo(context,payload) {
      return new Promise((resolve,reject) => {
        setTimeout(() => {
          context.commit('updateInfo'),
          console.log(payload);
          resolve('1111')
        },1000)
      })
    }
  },

action本身可以返回一个Promise
App.vue 中可以通过dispatch拿到Promise,.then继续使用Promise

    updateInfo() {
      // this.$store.dispatch('aUpdateInfo',{
      //   message: '我是payload,携带信息哦',
      //   success: () => {
      //     console.log('里面已经完成了');
      //   }
      // })
      this.$store
      .dispatch('aUpdateInfo','我是payload携带信息哦')
      .then(res => {
        console.log('里面完成了提交');
        console.log(res);
      })
    }

3.5 Module

Module是模块:
① Vue使用单一状态树,就意味着很多状态都交给Vuex来管理
② 当应用变得复杂时,store对象就有可能变得相当臃肿
③ 为解决这个问题,可以在modules中定义多个模块,每个模块都有一个state、getters、mutations、actions
(●’◡’●)

index.js

  modules: {
    // 可以在modules中定义多个模块,每个模块都有一个state
    a: moduleA
  }
const moduleA = {
  state: {
    name: 'zzy'
  },
  getters: {
    fullname(state) {
      return state.name + '111'
    },
    fullname2(state, getters) {
      return getters.fullname + '222'
    },
    fullname3(state, getters, rootState) {
      return getters.fullname2 + rootState.counter
    }
  },
  mutations: {
    updateName(state, payload) {
      state.name = payload
    }
  },
  actions: {
    // 一般进行异步操作
    aUpdateName(context) {
      // 提交同一对象内的mutations
      setTimeout(() => {
        context.commit('updateName','ying') 
      },1000)
    }
  }
}

App.vue

    updateName() {
      // 只要是提交就是commit
      this.$store.commit('updateName','lv')
    },
    asyncUpdateName() {
      this.$store.dispatch('aUpdateName')
    }

在这里插入图片描述

点击修改名字
在这里插入图片描述
点击异步修改名字
在这里插入图片描述

项目目录组织

在这里插入图片描述
index.js

import Vue from 'vue'
import Vuex from 'vuex'
import { INCREMENT } from './mutation-types'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'

// 1.安装插件
Vue.use(Vuex)


const state =  {
  counter: 0,
  student: [
    { id: 100, name: 'a', age: 18 },
    { id: 101, name: 'b', age: 19 },
    { id: 102, name: 'c', age: 11 },
    { id: 103, name: 'd', age: 12 },
  ],
  info: {
    name: 'kobe',
    age: 40,
    height: 1.98
  }
}
// 2.创建对象
const store = new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules: {
    // 可以在modules中定义多个模块,每个模块都有一个state
    a: moduleA
  }
})

// 3.导出store共享
export default store

getters示例

export default {
  powerCounter(state) {
    return state.counter * state.counter
  },
  more15(state) {
    return state.student.filter(s => s.age > 15)
  },
  more15Length(state, getters) {
    return getters.more15.length
  },
  moreAge(state) {
    return age => {
      return state.student.filter(s => s.age > age)
    }
  }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值