vue 项目实战 (vue全家桶之--- vuex)

2018-10-03 17:56:30来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

老规矩先安装

npm install vuex --save

在看下面内容之前 你应该大概的看了一边vuex官方的文档对vuex有个大概对了解

首先

vuex 是什么?

vuex 是属于vue中的什么,它在项目中扮演着一个什么样的角色,起到什么作用,在项目中我是否要用到vuex。

官方文档对vuex的解读是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

如果你是在开发一个大型的应用程序,组件与组件之间,兄弟组件之间,或者说多层嵌套组件之间,你是无法传递数据的。子父组件之间,也只是说通过事件保持数据的一致性,也是很繁琐的,会变得很不好管理。而vuex就是为了解决这样的问题,把组件的共享状态抽取出来,以一个全局单例模式管理。组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为,而且代码将会变得更结构化且易维护。

新建一个最简单的store

store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0,
    me: {
      name: 'huangenai',
      age: 22,
      sex: '女'
    },
      list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

main.js

import store from './store.js'

new Vue({
  el: '#app',
  router,
  store,//加这个
  components: { App },
  template: '<App/>'
})

State

驱动应用的数据源,组件之间共享的状态。

上面代码中的 count 就是一个共享的数据,me 也是一个共享的数据对象。

在组件中获得state 中的count

this.$store.state.count

newvue.vue

<template>
    <div>
        new vue page
        <p>{{count}}</p>
    </div>
</template>

<script>
export default {
  name: 'newvue',
  data () {
    return {
    }
  },
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}
</script>

<style scoped>
</style>

为什么要写在computed 里面呢,而不是写在data里面,因为当state.count 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM,如果你不理解可以先去看看computed

当一个组件要引用到多个状态的时候 ,一个个写是不是很累。不用担心,我们有mapState 辅助函数帮助我们生成计算属性。

在组件中引用

import { mapState } from 'vuex'
<template>
    <div>
        <p>{{count}}</p>
        <p>{{countPlusLocalState}}</p>
        <p>sex: {{sex}}</p>
        <p>age: {{myAge}}</p>
        <p>name: {{name}}</p>
    </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'newvue',
  data () {
    return {
      localCount: 1
    }
  },
  computed: {
    ...mapState({
      // 箭头函数可使代码更简练
      sex: state => state.me.sex,
      myAge: state => state.me.age,
      name: state => state.me.name,
      // 传字符串参数 'age' 等同于 `state => state.age`
      count: 'count',
      // 为了能够使用 `this` 获取局部状态,必须使用常规函数
      countPlusLocalState (state) {
        return state.count + this.localCount
      }
    })
  }
}
</script>

<style scoped>
</style>

假设computed 里面还有别的数据,因为mapstate返回来的是一个对象所以我们这样写可以将数据混入

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}

Mutation

你说你想修改state的值,this.$store.state.count = 1 这样可不可以 no no no....  所以就有了Mutation。

切记Mutation 必须是同步函数!!!

想要修改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

在上面代码我们新建一个store里面下的 有一个increment,就可以实现修改state里面的count

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count ++
    }
  }
})

那么如何调用increment呢??

调用 this.$store.commit(type)  类型叫increment 的 mutation。

this.$store.commit('increment')

我们还可以传入参数

// ...
mutations: {
  increment (state, n) {
    this.$state.count = n
  }
}

store.commit('increment', 10)

传入一个对象

mutations: {
  increment (state, data) {
    state.count += data.count
  }
}
store.commit('increment', {
  count: 10
})

mutations可以修改store中的状态,但是并不是说随随便便修改的,比如说??状态是对象的时候,你突然重新赋值过去一个新对象,原来的属性没了,真怎么行。

Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。

比如 上面代码的 state 内有个对象me 我可以新增删除里面的属性吗,怎么操作呢。

最好就是一开始就定义好所有的属性。

如果你非要新增属性,也提供了方法。

1.     Vue.set(me, 'height','156cm')

2.    state.me = { ...state.me, height: '156cm' }

store.js

...
mutations: {
    increment (state) {
      state.count++
    },
    setWeight (state) {
      Vue.set(state.me, 'weight', '45kg')
    },
    setHeight (state) {
      state.me = { ...state.me, height: '156cm' }
    }
 }

newvue.vue 中调用

...  
methods: { setWeight () { this.$store.commit('setWeight') alert(JSON.stringify(this.$store.state.me)) }, setHeight () { this.$store.commit('setHeight') alert(JSON.stringify(this.$store.state.me)) } }

当mutations中的类型多了起来,我们在组件中要commit 某一个类型 还要去找 再复制过来 是不是很不好管理。

所以我们可以使用常量替代 mutation 事件类型,新建一个

mutation-types.js

export const SET_WEIGHT = 'SET_WEIGHT'
export const SET_HEIGHT = 'SET_HEIGHT'

store.js

import * as types from './metations-types'
  ...
  mutations: {
    increment (state) {
      state.count++
    },
    [types.SET_WEIGHT] (state) {
      Vue.set(state.me, 'weight', '45kg')
    },
    [types.SET_HEIGHT] (state) {
      state.me = { ...state.me, height: '156cm' }
    }
  }

newvue.vue

....
  methods: {
    setWeight () {
      this.$store.commit(types.SET_WEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    setHeight () {
      this.$store.commit(types.SET_HEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    }
  }

 

state中有mapState, Mutations中也有mapMutations

使用 mapMutations 辅助函数将组件中的 methods 映射为 this.$store.commit 调用

newvue.vue

先引用

import { mapMutations } from 'vuex'
...
    setWeight () {
      this.$store.commit(types.SET_WEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    setHeight () {
      this.$store.commit(types.SET_HEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    ...mapMutations([
      'increment'
      // 将 `this.increment()` 映射为 this.$store.commit('increment')`
    ])
  }

 getter

getter 又是什么 ,在store中。什么时候用到他。

上述我们可以用 this.$store.state.count 能拿到 store的state ,而getter 则是拿store中的计算属性。

比如store 中的state 中的list 

在项目中我们有多个组件需要通过过滤拿到list中 age 大于等于22的对象,如果没有getter 我们需要在每个组件中都要定义一个函数过滤好在返回值,或者抽出来一个公共的方法哪个组件需要的时候就导入这个方法,再进行调用,也是很麻烦的一件事。

在这里我们可以用到store 里的getter,并通过属性访问获得过滤后的数据

store.js

export default new Vuex.Store({
  state: {
    ...
    list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
  },
  mutations: {
   ...
  },
  getters: {
    ageFilter: state => {
      return state.list.filter(item => item.age>=23)
    }
  }
})

newvue.vue

....
computed: {
    list () {
      return this.$store.getters.ageFilter
    }
  }

在getter中,Getter 也可以接受其他 getter 作为第二个参数。

例子

... 
getters: {
    ageFilter: state => {
      return state.list.filter(item => item.age >= 23)
    },
    listCount (state,getters){
        return getters.ageFilter.length
    }
}

newvue.vue中调用

...
computed: {
    ...
    listCount () {
      return this.$store.getters.listCount
    }
  }

通过方法访问,让getter返回一个函数,我们可以传值过去

store.js

...
getters: {
    ....
    getName: (state) => (name) => {
      return state.list.find(item => item.name === name)
    }
  }

newvue.vue

....
computed: {
.... listbyName () { return this.$store.getters.getName('cpq') } }

getter 有mapGetters 辅助函数,将 store 中的 getter 映射到局部计算属性

newvue.vue

import { mapGetters } from 'vuex'
  computed: {
   ....
    // listCount () {
    //   return this.$store.getters.listCount
    // },
    ...mapGetters([
      'listCount'
    ])
  }

在组件中,什么时候通过getter拿到store 状态,什么时候 直接拿state 想必都清楚了。

Action

其实跟上述的mutation很相似。

但是他不是直接修改state,在上面mutation说过,必须是同步函数。而Action则可以包含任意异步函数,action 是通过提交 mutation,而修改state。

store.js

export default new Vuex.Store({
  state: {
    ...
  },
  mutations: {
    ...
  },
  getters: {
    ...
  },
  actions: {
    setWeight ({commit}) {
      commit(types.SET_WEIGHT)
    }
  }

Action 通过 this.$store.dispatch 方法触发

newvue.vue

...  
methods: {
    ...
    setWeight () {
      this.$store.dispatch('setWeight')
    }
}

同样action 也支持传参数

action.js

export default new Vuex.Store({
  state: {
    count: 0,
    ...
  },
  mutations: {
    increment (state,count) {
      state.count = count
    },
    ...
  },
  getters: {
    ...
  },
  actions: {
    ...
    setCount ({commit},data) {
      commit('increment',data.count)
    }
  }
})

newvue.vue

methods: {
    ...
    setCount () {
      this.$store.dispatch('setCount', {count: 123})
} }

为什么要action 直接用mutation岂不更方便,为什么要通过action,又多了一步

因为mutation只是同步函数啊,在很多情况下我们要执行异步操作的。

action可以包含异步函数。

我们假设一个登录的功能,在action中支持异步函数,在mutation只能是同步函数,所以要用到action

import api from '../api'

... 
actions: {
  login ({commit}, payload) => {
  return new Promise((resolve, reject) => {
    api.login(payload, userToken => {
      if (userToken && userToken.accessToken) {
        commit(types.LOGIN, userToken)
        resolve(userToken)
      } else {
        reject()
      }
    })
  })
}

调用

this.$store.dispatch('login', {username, password}).then(
  (res) => {
             
}).catch()

同样action也有辅助函数 mapActions

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
  }
}

你还可以action中相互调用

actions: {
    ...
    setCountA ({commit},count) {
      commit('increment', count)
    },
    setCountB ({commit},data) {
      dispatch('setCountA',data.count)
    }
}

  

此随笔乃本人学习工作记录,如有疑问欢迎在下面评论,转载请标明出处。

如果对您有帮助请动动鼠标右下方给我来个赞,您的支持是我最大的动力。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:CSS 小结笔记之图标字体(IconFont)

下一篇:seo优化