Web前端之vuex基础

什么是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>

来源:https://www.icode9.com/content-4-906651.html

(0)

相关推荐