Web前端之vuex基础

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

什么是Vuex

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

什么是状态管理模式

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源
  • view,以声明方式将 state 映射到视图
  • actions,响应在 view 上的用户输入导致的状态变化

单向数据流:

当遇到多个组件共享时,单向数据流的简洁性很容易被破坏

  • 多个视图依赖于同一状态
  • 来自不同视图的行为需要变更同一状态

使用Vuex管理数据的好处:

  • 能够在 vuex 中集中管理共享的数据,便于开发和后期进行维护
  • 能够高效的实现组件之间的数据共享,提高开发效率
  • 存储在 vuex 中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新

Vuex使用

安装或引入

可以通过CDN节点引入(不推荐)

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>

也可以使用npm命令进行安装(推荐)

npm install vuex -S

当然,如果在用Vue CLI 脚手架进行创建项目时,如果引用了Vuex咋不在需要上面的操作了

使用

使用时需要在新建js文件中引用,当然我们还需要在main.js中引入使用

当我们使用Vue CLI 脚手架创建项目后

我们在src目录下的views下面新建文件夹Store

在此文件夹内创建index.js文件

在index中编写如下编码

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {

  },
  mutations: {

  }
})
export default store

然后在main.js中引入调用并且创建实例

父传子

  • count 变量定义在父组件 App.vue 中
  • 两个子组件中都一个一个 prop,名为 count
  • 父组件通过 :count 为子组件中的 prop count 传值
  • 子组件单击按钮时,通过 $emit,向外广播,告诉父组件应该为 count 变量+1或者 -1

Add.vue

<template>
  <div id="app">
     <my-add :count="count" @handle-add="add"></my-add>  <my-sub
      :count="count"
      @handle-sub="del"
    ></my-sub>
  </div>
</template>
<script>
import c1 from './views/children'
import c2 from './views/children1'
export default {
  data() {
    return {
      count: 0
    }
  },
  components: {
    'my-add': c1,
    'my-sub': c2
  },
  methods: {
    add() {
      this.count++
    },
    del() {
      this.count--
    }
  }
}
</script>

children.vue

<template>
  <div class="main">
     
    <h3>变量 count 的值为:{{ count }}</h3>
     <button @click="add">+1</button>
  </div>
</template>
<script>
export default {
  props: ['count'],
  methods: {
    add() {
      this.$emit('add')
    }
  }
}
</script>

children1.vue

<template>
  <div class="main">
    <h3>变量 count 的值为:{{ count }}</h3>
    <button @click="sub">-1</button>
  </div>
</template>
<script>
export default {
  props: ['count'],
  methods: {
    sub() {
      this.$emit('del')
    }
  }
}
</script>

加加减减的写法

index.js文件

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state) {
      state.count++
    },
    del(state) {
      state.count--
    }
  }
})
export default store

修改组件

<template>
  <div class="main">
    <h3>变量 count 的值为:{{ $store.state.count }}</h3>
    <button @click="add">+1</button>
    <button @click="del">-1</button>
  </div>
</template>
<script>
export default {
  methods: {
    add() {
      this.$store.commit('add')
    },
    del() {
      this.$store.commit('del')
    }
  }
}
</script>

效果:

核心

states

单一状态树

State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
vuex 中的 state 相当于组件中的 data
State中的数据与组件 data 中的数据一样,也是响应式的

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    name: '张三',
    age: 20,
    sex: '男'
  }
})
export default store

组件使用state中的值

<template>
  <div class="home">{{ $store.state }}</div>
</template>
<script>
export default {

}
</script>

计算属性

上面原样使用不方便使用所以使用计算属性来便于使用

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
export default {
  computed: {
    name() {
      return this.$store.state.name
    },
    age() {
      return this.$store.state.age
    },
    sex() {
      return this.$store.state.sex
    }
  }
}
</script>

但上面那样使用代码量太多

我们可以使用辅助函数:mapState

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState } from 'vuex'
export default {
  computed: mapState({
    name: state => state.name,
    age: state => state.age,
    sex: state => state.sex
  })
}
</script>

  • computed 的值是一个对象,所以 mapState 函数的返回值一定是个对象
  • name,age,sex都是计算属性的名称
  • 使用箭头函数时,可以省略 this.$store,而是直接使用 state

再次简洁一步

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState } from 'vuex'
export default {
  computed: mapState({
    name: 'name',
    age: 'age',
    sex: 'sex'
  })
}
</script>

最简洁方法:

映射的计算属性的名称与 state 的子节点名称相同时,我们可以给 mapState 传一个字符串数组

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState } from 'vuex'
export default {
  computed: mapState(['name', 'age', 'sex'])
}
</script>

  • 这时候我们的计算属性就不能叫 name、age、sex了,而是与 state 中的属性同名
  • mapState 中不是一个对象了,而是一个数组,数组的元素名称就是你想要使用的 state 中的属性名称

展开运算符

使用辅助函数后,mapState 函数的返回值是一个对象

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState } from 'vuex'
export default {
  computed: mapState(['name', 'age', 'sex']),
  created() {
    const res = mapState(['name', 'age', 'sex'])
    console.log(res)
  }
}
</script>

输出结果

所以利用展开运算符可以更改上面的编码

<template>
  <div class="home">
    <p>{{ name }}</p>
    <p>{{ age }}</p>
    <p>{{ sex }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState } from 'vuex'
export default {
  computed: { ...mapState(['name', 'age', 'sex']) }
}
</script>

但是我感觉用在这里,那简直的画蛇添足、多此一举

不过展开运算符用在其他地方还是很有必要的

Getter数据获取器

在Store文件夹下index.js添加

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    teacher: [
      {
        name: '张三',
        age: 20,
        sex: '男'
      },
      {
        name: '李四',
        age: 25,
        sex: '女'
      }
    ]
  },
  getters: {
    // 定义gettter,统计所有完成的事项
    doneTodos: state => {
      return state.teacher.filter(t => t.sex)
    }
  }
})
export default store

组件中

<template>
  <div class="home">
    {{ $store.getters.doneTodos }}
  </div>
</template>
<script>

export default {

}
</script>

也可使用 mapGetters 和 mapState 辅助函数

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState, mapGetters } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  }
}
</script>

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)

这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

任何时候想添加新值,且不能直接添加,只有通过mutation才可

Store 下的 index.js

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    teacher: [
      {
        name: '张三',
        age: 20,
        sex: '男'
      },
      {
        name: '李四',
        age: 25,
        sex: '女'
      }
    ]
  },
  getters: {
    // 定义gettter,统计所有完成的事项
    doneTodos: state => {
      return state.teacher.filter(t => t.sex)
    }
  },
  mutations: {
    add(state) {
      state.teacher.push({
        name: '王五',
        age: 19,
        sex: '女'
      })
    }
  }
})
export default store

组件

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="add">添加</button>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState, mapGetters } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    add() {
      this.$store.commit('add')
    }
  }
}
</script>

提交载荷

传入额外的参数,即 mutation 的 载荷(payload)

index.js

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    teacher: [
      {
        name: '张三',
        age: 20,
        sex: '男'
      },
      {
        name: '李四',
        age: 25,
        sex: '女'
      }
    ]
  },
  getters: {
    // 定义gettter,统计所有完成的事项
    doneTodos: state => {
      return state.teacher.filter(t => t.sex)
    }
  },
  mutations: {
    add(state, teacher) {
      state.teacher.push(teacher)
    }
  }
})
export default store

组件中使用

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="add">添加</button>
  </div>
</template>
<script>
// 在vuex中引出mapState辅助函数
import { mapState, mapGetters } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    add() {
      this.$store.commit('add', {
        name: '王五',
        age: 19,
        sex: '女'
      })
    }
  }
}
</script>

大多数情况下,载荷应该是一个对象,可以包含多个字段并且记录的 mutation 会更易读Mutation 必须是同步函数:不要在其中执行ajax 等异步操作

mapMutations辅助函数减少代码

组件中作如下修改

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="addI">添加</button>
  </div>
</template>
<script>
// 在vuex中引出辅助函数
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    ...mapMutations(['add']),
    addI() {
      this.add({ name: '王五', age: 19, sex: '女' })
    }
  }
}
</script>

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态
  • Action 可以包含任意异步操作

js文件中

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

Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    teacher: [
      {
        name: '张三',
        age: 20,
        sex: '男'
      },
      {
        name: '李四',
        age: 25,
        sex: '女'
      }
    ]
  },
  getters: {
    // 定义gettter,统计所有完成的事项
    doneTodos: state => {
      return state.teacher.filter(t => t.sex)
    }
  },
  mutations: {
    add(state, teacher) {
      state.teacher.push(teacher)
    }
  },
  actions: {
    addS(state, teacher) {
      setTimeout(() => {
        state.commit('add', teacher)
      }, 2000)
    }
  }
})
export default store

组件中

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="addI">添加</button>
  </div>
</template>
<script>
// 在vuex中引出辅助函数
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    ...mapMutations(['add']),
    addI() {
      // this.add({ name: '王五', age: 19, sex: '女' })
      this.$store.dispatch('addS', { name: '王五', age: 19, sex: '女' })
    }
  }
}
</script>

mapActions 辅助函数映射使用

组件中

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="addI">添加</button>
  </div>
</template>
<script>
// 在vuex中引出辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    ...mapMutations(['add']),
    ...mapActions(['addS']),
    addI() {
      // this.add({ name: '王五', age: 19, sex: '女' })
      this.addS({ name: '王五', age: 19, sex: '女' })
    }
  }
}
</script>

  methods: {
    ...mapMutations(['add']),
    addI() {
      // this.add({ name: '王五', age: 19, sex: '女' })
      this.$store.dispatch('addS', { name: '王五', age: 19, sex: '女' })
    }
  }
}
</script>

mapActions 辅助函数映射使用

组件中

<template>
  <div class="home">
    <p>{{ doneTodos }}</p>
    <p>{{ teacher }}</p>
    <button @click="addI">添加</button>
  </div>
</template>
<script>
// 在vuex中引出辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState(['teacher']),
    ...mapGetters(['doneTodos'])
  },
  methods: {
    ...mapMutations(['add']),
    ...mapActions(['addS']),
    addI() {
      // this.add({ name: '王五', age: 19, sex: '女' })
      this.addS({ name: '王五', age: 19, sex: '女' })
    }
  }
}
</script>

本文标题为:Web前端之vuex基础

基础教程推荐