32.vueX

1.概念

Vuex就是一个状态管理模式,VueX包含了一套对state的操作规范,集中存储所有组件的状态。

管理各个组件共享的数据,类似session,存的过程就是管理,数据的每一次赋值就是当次状态。

session存储数据,

Vue简单模型

  • state,驱动应用的数据源;

  • view,以声明方式将 state 映射到视图;

  • actions,响应在 view 上的用户输入导致的状态变化。

2.搭建

使用的vue ui勾选了vux,实则不需要手动创建。

1.安装

npm install vuex --save

2.新建store文件夹,在文件夹下创建index.js

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

Vue.use(Vuex)

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

3.在main.js中引用并挂载这个文件

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')

3.通信功能

之前使用的是父传子通信方式,现在使用Vuex来进行组件之间的通信

例:

在store的index.js中定义公共数据counter

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

Vue.use(Vuex)

export default new Vuex.Store({
state: {
  counter:1000
},
mutations: {
},
actions: {
},
modules: {
}
})

在components文件夹下的HelloVuex.vue文件中调用这个数据

<template>
  <div>
      <h2>{{$store.state.counter}}</h2>
  </div>
</template>
<script>
export default {
  name:'HelloVuex',
  // 父子传值
  // props:{
  //     counter:Number
  // },
  data() {
    return {
    }
  },
  activated() {
  },
watch: {
},
created(){
},
mounted(){
},
methods:{
}


}
</script>
<style>
</style>

4.修改index.js中的公共数据

虽然$store.state.count++也可对公共值进行修改,但这样操作Devtools监听不到state每一次修改的状态,就是当多个组件修改同一个公共值时,追踪不到是哪个组件修改的。

当修改Mutations时有异步操作时,Devtools跟踪不到,所以异步操作(如发送网络请求)在Actions中进行操做的。

4.通过Mutations修改值

在vue 中,只有mutation 才能改变state. mutation 类似事件,每一个mutation都有一个类型和一个处理函数,因为只有mutation 才能改变state, 所以处理函数自动会获得一个默认参数 state. 所谓的类型其实就是名字,

  • 案例一

    点击click对值进行修改

store/index.js

state中定义counter值,mutations中对值进行修改

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

Vue.use(Vuex)
export default new Vuex.Store({
state: {
  counter:1000
},
mutations: {
  increment(state){
    state.counter++
  },
  decrement(state){
    state.counter--
  }
},
actions: {
},
modules: {
}
})

2.App.vue中定义点击事件

这里点击事件里是用commit而不是直接调用

<template>
<div id="app">
  <h2>--------App内容</h2>
  <h2>{{message}}</h2>
  <h2>{{$store.state.counter}}</h2>
  <button @click="addition">+</button>
  <button @click="subtraction">-</button>
  <h2>------hello vue 内容</h2>
  <hello-vuex ></hello-vuex>
</div>
</template>
<script>
import HelloVuex from './components/HelloVuex.vue'
export default{
name:'App',
components:{
  HelloVuex
},
data(){
  return{
    message:'你好',
    // counter:0
  }
},
methods:{
  addition(){
    this.$store.commit('increment')
  },
  subtraction(){
    this.$store.commit('decrement')
  }
}
}
</script>

<style>

</style>
  • 案例二:对传入的值进行click进行增加

App.vue

  <button @click="addCount(5)">+5</button>

methods中定义点击事件

  addCount(count){
    this.$store.commit('incrementCount',count)
  },

store/index.js中

定义counter

  state: {
  counter: 1000,
},

nutations对传入的值进行修改

 mutations: {
  incrementCount(state, count) {
    state.counter += count
  },
}

 

  • 案例三:添加学生信息

store/index.js中

state定义students

state: {
  students: [
    { id: 110, name: 'xx', age: 18 },
    { id: 111, name: 'xj', age: 19 },
    { id: 112, name: 'jx', age: 20 },
    { id: 113, name: 'jj', age: 21 },
  ]
},

App.vue template

    <button @click="addStudent">添加学生</button>

App.vue methods中

 addStudent(){
    const stu = {id:114,name:'aaa',age:18}
    this.$store.commit('addStudent',stu)
  }

state定义students,添加到state中

    addStudent(state,stu){
      state.students.push(stu)
  }
  • mutations提交风格

    当App.vue的methods中addcount改为如下提交格式

       <template>
      <button @click="addCount(5)">+5</button>
      </template>
     
     
    <script>
    addCount(count){
        this.$store.commit({
        type:'incrementCount',
        count
        })
      },
      </script>

    store/index.js的mutations

     incrementCount(state, count) {
        console.log(count);
        // state.counter += count
      },

    这里的count传入的实则是payload对象,count只是一个变量名字,打印一下得到的是

    {type: "incrementCount", count: 5}

    所以修改为

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

     

5.getters

获取state值,对state值进行加工计算,相当于computed钩子。

其实,这个操作也能在APP.vue的computed钩子中实现,但这只是计算单个页面,而getters是可以被所有页面去获得值的

  • 案例一:展示counter值的平方。

store/index.js

state定义counter值

 state: {
  counter: 1000,
},

getters

  getters: {
  powerCounter(state) {
    return state.counter * state.counter
    },
  }

App.vue响应展示

    <h2>{{ $store.getters.powerCounter }}</h2>
  <h2>{{ $store.getters.more20stuLength }}</h2>
  • 案例二:筛选大于二十岁的信息与length

    store/index.js定义students

     state: {
      students: [
        { id: 110, name: 'xx', age: 18 },
        { id: 111, name: 'xj', age: 19 },
        { id: 112, name: 'jx', age: 20 },
        { id: 113, name: 'jj', age: 21 },
      ]
    },

    getters筛选大于20岁

  getters: {
  more20stu(state) {
    return state.students.filter(s => s.age > 19)
  },
  //获取长度第一种写法
    more20stuLength(state, getters) {
    return getters.more20stu.length
  },
    //获取长度第二种写法
  // more20stuLength(state){
  //   return state.students.filter(s=>s.age>20).length
  // },
   
  }

App.vue响应展示

   <h2>{{ $store.getters.more20stu }}</h2>
  • 案例三:筛选大于用户输入的岁数信息

App.vue

    <h2>{{ $store.getters.moreAgestu(20) }}</h2>

strore/index.js中定义students值

  state: {
  students: [
    { id: 110, name: 'xx', age: 18 },
    { id: 111, name: 'xj', age: 19 },
    { id: 112, name: 'jx', age: 20 },
    { id: 113, name: 'jj', age: 21 },
  ]
},

getters

 moreAgestu(state) {
    // return function(age){
    //   return state.students.filter(s=>s.age>age)
    // }
    return age => {
      return state.students.filter(s => s.age > age)
    }
  }

6.VueX响应式

修改值和删除值

App.vue

  <h2>------App内容:info对象的内容是否为响应式的------</h2>
  <h2>{{ $store.state.info }}</h2>
  <button @click="updateInfo">修改信息</button>

methods

 updateInfo(){
    this.$store.commit('updataInfo')
  }

store/index.js中

定义值

 state: {
    info: [
    { name: 'xxjj', age: 20 }
  ]
},

mutations

    updataInfo(state) {
    // 1修改属性
    // console.log(state.info[0].age);
    // state.info[0].age = 22

    // 2添加属性
    // (错误做法)这种方法不行,做不到响应式
    // state.info[0].address = '洛杉矶'
    //(正确做法)
    // Vue.set(state.info[0],'address' , "洛杉矶")

    // 3删除属性
    //错误做法
    //delete state.info.age
    // 正确做法
    Vue.delete(state.info[0],'age')

  }

7.Action

使用mutation操作更新state的时候,使用异步修改数据。

当存在异步数据时,devtools工具没有跟踪到数据,所以不能在mutation中进行异步操作。

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation中,而不是直接变更状态。

  • Action 可以包含任意异步操作。

案例:1

App.vue设一个点击事件

    <button @click="updateInfo">修改信息</button>

methods定义点击事件

提交给Action中的函数时的方法是dipatch而不是commit,再通过Actions离commit提交给Mutations函数。

methods:{
updateInfo(){
    this.$store.dispatch('aUpdataInfo',()=>{
    console.log('里面已经完成了');
      })
      this.$store.dispatch("aUpdataInfo", {
        message: "我是携带的信息",
        success: () => {
        console.log("里面已经完成了");
        },
      });
}
}

store/index.js中

括号内使用的是context而不是state,

  actions: {
    aUpdataInfo(context,payload){
      console.log(context);
      setTimeout(() => {
      context.commit('updataInfo')
      console.log(payload.message);
      payload.success()
      }, 1000);
    }
}

commit提交给mutation里的updataInfo

 mutations: {
  updataInfo(state) {  
    state.info[0].age = 22
}
}

案例2:

使用promise方式

dipatch提交aUpdataInfo与'我是携带信息'到action中的aUpdataInfo函数,在promise中使用 context.commit提交到mutation中的updataInfo,成功resolve('11111')而App.vue中使用.then获取resolve信息。

App.vue

<template>
<button @click="updateInfo">修改信息</button>
</template>
methods:{
updateInfo() {
this.$store
        .dispatch('aUpdataInfo','我是携带信息')
        .then(res=>{
        console.log('里面完成的信息');
          console.log(res);
        })
  }
}

store/index.js

  
    updataInfo(state) {
    state.info[0].age = 22
}

actions: {
  aUpdataInfo(context,payload){
    console.log(context);
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
        context.commit('updataInfo');
        console.log(payload);
        resolve('11111')
      })
    })
  }
},

8.Modules

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

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

  • 案例1:modules中定义两个模块

  modules: {
  a: moduleA,
  b: moduleB
}

值得注意的是如下模块需要写在export default new Vuex.Store({})上面

要不然会报错。

使用moduleA中的name值

const moduleA = {
state: {
  name: 'cfy'
},
mutations: {
},
getters: {
},
actions: {
},

}

App.vue中

因为moduleA分支中的数据会自动添加到总的state中,所以调用时使用

$store.state.a.name

<div id="app">
  <h2>------App内容:modules中的内容------</h2>
  <h2>{{ $store.state }}</h2>
  <h2>{{ $store.state.a.name }}</h2>
</div>
  • 案例2:mutation修改名字

store/index.js

const moduleA = {
state: {
  name: 'cfy'
},
mutations: {
  updataName(state, payload) {
    console.log(payload);
    state.name = payload
  }
  },
}

App.vue

 <template>
<button @click="updataName">修改名字</button>
</template>
  methods: {
    updataName() {
    this.$store.commit("updataName", "lisi");
      },
    }
  }

store/index.js

const moduleA = {
state: {
  name: 'cfy'
},
mutations: {
  updataName(state, payload) {
    console.log(payload);
    state.name = payload
  }
},
}
  • 案例3:getter

    App.vue

     <h2>{{ $store.getters.fullName }}</h2>
      <h2>{{ $store.getters.fullName2 }}</h2>
      <h2>{{ $store.getters.fullName3 }}</h2>

    store/index.js

    这里的fullName中调用的state是ModuleA中的state, fullName2中调用的getters也是ModuleA中的不是根中的,而想要获取根中的数据

    fullName3中添加值rootState来获取根中的state数据,同理rootGetters获取根中getters,rootMutations,rootActions

     const moduleA = {
    state: {
      name: 'cfy'
    },
    getters: {
      fullName(state) {
        return state.name + '1111'
      },
      fullName2(state, getters) {
        return getters.fullName + '2222'
      },
      fullName3(state,getters,rootState){
        return getters.fullName2+rootState.counter
      }
    },
    }
    • 案例4:Action

App.vue

提交到Action中使用dispatch

 <template>
<button @click="asyncUpdataName">异步修改名字</button>
</template>
methods:{
asyncUpdataName(){
    this.$store.dispatch('aUpdataName')
  }
}

store/index.js

再从Action发送异步请求到mutations中

const moduleA = {
  mutations: {
  updataName(state, payload) {
    console.log(payload);
    state.name = payload
  }
},
actions: {
  aUpdataName(context){
    console.log(context);
    setTimeout(()=>{
    context.commit('updataName','xj')
    },20)
  }
},
}

 

posted @ 2021-07-21 17:48  ajaXJson  阅读(39)  评论(0编辑  收藏  举报