vuex再入门-基础用法

前言前端

其实我已经用过vuex一段时间了,最近又有一段时间没有用,结果今天又生疏了。为此,我决定再入门下。vue

首先vuex是啥?vuex是vue的一个状态管理器。何为状态管理器?状态管理器能够理解为一个小型的前端数据库。用来实现各个页面之间的数据共享。java

那为啥不用sessionStorge和localStorage共享数据呢。由于这里涉及到状态更新。当你在a页面更新了数据后,使用vuex的话,b页面数据就会自动更新。而使用sessionStorage或者localStorage就没有这种效果。node

1.使用vuex程序员

1.1 安装vuexvuex

vuex跟vue是分开的,使用vuex还须要安装,可使用npm也可使用yarn。代码以下:vue-cli

npm install vuex -S
或者
yarn add vuex
复制代码

1.2 引用vuex数据库

通过上面一个步骤已经安装了vuex,如今就是咱们使用vuex的时候。使用很简单,vue的src目录下新建store文件夹,在store文件夹下新建index.js文件。其实在其余地方建也能够,不过这不太符合规范,若是有人改你的代码的时候就能够找不到你的store放哪里。目录结构以下:npm

|-src
  |- App.vue
  |- assets
  |  |-logo.png
  |-components
  |  |-HelloWorld.vue
  |-main.js
  |-store
  |  |-index.js
复制代码

1.3 引入vuexjson

在咱们新建的index.js中引入vue和vuex,而且使用vue调用vuex组件,这样咱们就能够在index中写vuex的程序了。

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
复制代码

写一个简单vuex程序。

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }})
  
export default store
复制代码

在这个程序中,咱们在store中定义了一个字段count,初始值为0。咱们还定义了一个方法increment,每次调用increament,count值都会加1.

1.4 使用vuex中的数据

1.4.1 注入store

为了方便咱们使用vuex中的数据,咱们将store加入vue中,这样之后不管在那里均可以经过this.$store访问vuex了。

修改main.js,在new Vue的构造函数中加入store

import Vue from 'vue'
import App from './App.vue'

// 引入store
import store from './store'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
复制代码

1,4,2 使用stroe

假设咱们要在组件helloworld中使用store(vuex)中的数据。就可使用this.$store.state.字段名来获取store中存放的数据。使用store中的数据也是有要求的——“要放vue的computed属性中”,你放在其余地方好比created也行,或者直接赋值给data对象对应的属性。可是这样谁有个问题,就是当store中的数据更新的时候,页面数据不能自动更新。

<template>
  <div class="contain">
    <div class="title">{{name}}</div>
    <p>
      动物园里单身狗的数量为:
      <span>{{count}}</span>只
    </p>
    <button @click="addCount">拆散一对情侣</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world'
    }
  },
  computed: {
    count() {
      return this.$store.state.count
    }
  },
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
</script>

<style scoped>
.title {
  font-size: 28px;
  text-align: center;
  margin: 10px;
}
</style>
复制代码

上面的程序初始的时候,页面显示“动物园里单身狗的数量为:0”。当咱们点击“拆散一对情侣”按钮时,“动物园里单身狗的数量为:”就变成了2.

若是咱们把count放在data对象中,好比把js改为下面这样子。点击“拆散一对情侣”按钮时,store中的count值变了,可是页面上“动物园里单身狗的数量”不会变。

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world',
      count: this.$store.state.count
    }
  },
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
复制代码

1.5 插播一个广告

使用vue-cli3开发的时候,有时候由于eslint的限制很严格,因此致使编译不经过。能够修改package.json中eslint的rules。

好比在我项目中,eslint限制我不能写console,这致使我开发的时候很不方便。我在package.json中把no-console改成0,就去掉了这种限制

"eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "rules": {
      "no-console": 0
    },
    "parserOptions": {
      "parser": "babel-eslint"
    }
  }
复制代码

以上就是vuex的简单入门,如下咱们将更加深刻的讲解下vuex。

2.vuex的组成

vuex其实很简单,我之前学习vuex的时候,感受好高深,如今看来仍是蛮简单的。vuex只由4部分组成,这四部分分别负责不一样的功能,就至关于游戏中的4个不一样的角色吧。4个分别为:

  • state 用来存储数据的
  • mutation 以同步的方式来修改数据
  • getters 用来对数据进行过滤和计算,返回计算后的数据
  • action 以异步的方式来修改数据

vuex是单一状态树的,就是在整个vue程序中只有一个vuex实例(store)。单一状态树可让咱们很容易的定位代码的执行状况。

2.1 state

咱们通常获取store对象中的数据都是经过this.$store.state.key获取的。好比咱们获取count属性,咱们是这样获取的。

this.$store.state.count
复制代码

2.1.1 mapState函数

咱们获取state上的值,通常都是放在computed属性中的,若是state中有不少值,那么咱们就要在computed中写不少计算属性。为了介绍代码量,vuex提供了一个mapState函数。

咱们能够把程序改为以下这样子。注意这里引入了mapState,在computed中咱们也使用了mapState

import { mapState } from 'vuex'
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world'
    }
  },
  computed: mapState([
    'count'
  ]),
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
复制代码

实现的功能跟以前是同样的。

computed: mapState([
   'count'
])
// 至关于咱们以前的
computed: {
  count() {
      return this.$store.state.count
  }
}
复制代码

使用mapState更简便的方法是使用对象展开符....

computed: {
    ...mapState([
      'count'
    ])
  },
复制代码

若是想重命名,能够把mapState的参数改为对象格式

computed: {
    ...mapState({
      count2: 'count'
    })
  },
复制代码

2.2 Getters

咱们有时候须要store中state的值进行计算,若是一个组件或者两个组件的话,咱们能够直接把属性放在computed中。可是若是多个组件都须要进行相同的计算的话。咱们代码就会很冗余。解决办法就是在store就对state的值进行计算。所以就要用到store的getters属性。

在咱们的案例中count表明单身狗的数量,初始值为0,这个世界是没有单生狗的。可是某天突然咱们要在vue里增长一个程序员组件(It.vue)。程序员这个群体,你们都懂的,单生狗特别多,假设比平均值count多10个,那么咱们能够在store中定义一个itDogs的属性,这个属性比count值多10。

修改store代码以下:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  getters: {
    itDogs: state => {
      return state.count + 10
    }
  }
})

export default store
复制代码

那么咱们该怎么获取呢?

获取getters中数据能够经过属性访问,也能够经过方法访问

2.2.1 经过属性访问

经过属性访问代码以下:this.$store.getters.健名,在这个需求中就是:

this.$store.getters.itDogs
复制代码

It.vue 中获取itDogs代码以下:

computed: {
    itDogs: function () {
      return this.$store.getters.itDogs
    }
 }
复制代码

2.2.2 经过方法访问

要想经过方法访问,那么getters中的属性,在定义的时候必须返回一个函数,而不是直接返回值

假设咱们的需求改变了,在程序员的世界里,使用不一样语言的单身狗的数量是不同的。好比使用js的就是在平均单身狗的数量上加10,使用java的就是平均的基础上加100

那么能够把getters里写itDogs写成一个函数,根据不一样的语言传入不一样的值,而后返回对应的结果。(固然也能够用其余方法)

store修改以下:

getters: {
    itDogs: state => (num) => {
        return state.count + num
    }
}
复制代码

获取方法以下:

computed: {
    itDogs: function () {
      return this.$store.getters.itDogs(100)
    }
  },
复制代码

**经过属性方法访问getters中的值,这个值会被缓存起来。下次须要时能够直接从缓存中拿。经过方法访问的话,每次都要调用函数从新计算

2.2.3 访问其余getter

getter也能够接受其余getter做为第二个参数。好比男程序员单身狗的数量在通常的程序员单身狗的数量上又加100.

getters: {
    itDogs: state => (num) => {
      return state.count
    },
    manItDogs: (state, getters) => {
      return getters.itDogs + 100
    }
  }
复制代码

2.2.4 mapGetters函数

mapGetters函数将store中getter映射到局部计算属性,好比getter是以下:

getters: {
    itDogs: state => {
      return state.count
    },
    manItDogs: (state, getters) => {
      return getters.itDogs + 100
    }
  }
复制代码

获取的代码咱们修改以下:

computed: {
    ...mapGetters([
      'itDogs',
      'manItDogs'
    ])
  },
复制代码

若是要重命名,能够把mapGetters的参数改为对象

computed: {
    ...mapGetters({
      itDogs2: 'itDogs',
      manItDogs2: 'manItDogs'
    })
  },
复制代码

2.3 Mutation

更改 Vuex 的 store 中的数据的惟一方法是提交 mutation。须要如今store中注册事件,后面才能调用。mutation中定义的函数必须是同步的。

好比咱们以前定义的

mutations: {
    increment(state) {
      state.count++
    }
  },
复制代码

咱们想要count的数量加1,咱们就调用

this.$store.commit('increment')
复制代码

2.3.1 传参

咱们以前定义了一个按钮叫“拆散一对情侣”。点击这个按钮咱们就把count的数量加2,咱们以前是这样调用的。

methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
    }
  },
复制代码

咱们调用了两次commit,这显得很奇怪,其实mutations中的函数是能够传参的。咱们修改increment函数。

mutations: {
    increment(state, num) {
      state.count += num
    }
  },
复制代码

state.count再也不是加1了,而是加上num。这样好了,不管是3p的仍是百人斩的,咱们均可以拆散了。

修改调用函数以下:

methods: {
    addCount() {
      this.$store.commit('increment', 2)
    }
  },
复制代码

2.3.2 对象参数

有时候咱们参数不少怎么办?咱们能够把第二个参数改为对象。

修改increment

mutations: {
    increment(state, obj) {
      state.count += obj.num
    }
  },
复制代码

修改调用

methods: {
    addCount() {
      this.$store.commit('increment', {
        num: 2
      })
    }
  },
复制代码

2.3.3 mapMutations

mapMutations能够将store中mutation中的方法映射为vue组件中methods的方法

methods: {
    ...mapMutations([
      'increment'
    ])
  },
复制代码

这样咱们调用组件的increment方法,就至关于调用stroe中mutation的increment方法

调用以下

<button @click="increment({num:2})">拆散一对情侣</button>
复制代码

2.4 Action

Action 相似于 mutation,不一样在于:

  • Action 提交的是 mutation,而不是直接变动状态。
  • Action 能够包含任意异步操做

一个简单的action以下

actions: {
    increment: (context, obj) => {
      setTimeout(() => {
        context.commit('increment', obj)
      }, 5000);

    }
  }
复制代码

action 函数接受一个与 store 实例具备相同方法和属性的 context 对象,所以你能够调用 context.commit 提交一个 mutation,或者经过 context.state 和 context.getters 来获取 state 和 getters

如何调用action呢?咱们可使用dispatch来调用

this.$store.dispatch('increment')
复制代码

完整代码:

methods: {
    increment: function () {
      this.$store.dispatch('increment', { num: 2 })
    }
  },
复制代码

actions函数跟mutation函数同样都是能够传参的。

2.4.1 mapActions

mapActions将action中的方法,映射到vue实例methods方法上。

methods: {
    ...mapActions([
      'increment'
    ])
  },
复制代码

调用

<button @click="increment({num:2})">5秒后拆散一对情侣</button>
复制代码

2.4.2 组合多个action

store.dispatch能够处理被触发的 action 的处理函数返回的 Promise,而且 store.dispatch 仍旧返回 Promise

假设咱们的action以下

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
复制代码

那么咱们在组件里能够这样处理:

store.dispatch('actionA').then(() => {
  // ...
})
复制代码

在另外一个action里的话,能够这样调用

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}
复制代码

总结:以上咱们vuex的基本用法都讲完了,以上知识点基本上能够解决咱们工做中面临的问题了。可是vuex还有些更加高深的用法,咱们下一节再讲

相关文章
相关标签/搜索