Vuex

头像
Liane
    阅读 5 分钟
    1
    头图

    一、简介
    Vuex是服务于Vue.js应用程序的状态管理模式。
    vue状态管理分为三部分
    image.png

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

    vuex的设计思想:在多个组件共享状态时,将该共享状态抽离出来以一个全局单例模式管理。通过定义和隔离状态管理中的各种概念,并通过强制规则维持视图和状态间的独立性,让代码变得更结构化且易维护。


    二、安装
    npm安装

    npm install vuex --save

    在模块化的打包系统中,通过Vue.use()安装vuex
    (当通过全局script标签引用Vuex时,不需要使用Vue.use()安装)

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)

    三、Store与State
    每一个Vuex应用的核心就是store仓库,store是一个容器,包含应用中大部分的state。
    Vuex与单纯的全局对象的区别:
    1、Vuex状态存储是响应式的,当vue组件从store中读取state时,若state发生变化,则相应的组件也会相应地得到高效更新。
    2、不能直接改变store中的state,改变的唯一途径就是commit mutation。可以更方便跟踪每一个状态的变化。

    使用new Vuex.Store()创建store

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    /*安装Vuex*/
    Vue.use(Vuex)
    
    //创建一个store实例
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment(state) {
          state.count++
        }
      }
    })
    //创建一个组件实例,读取state,修改state
    const Counter = {
      template: `<div>
      <div class="btn" @click='add'>增加</div>
      {{count}}</div>`,
      computed: {
        //将state定义为计算属性
        count() {
          // return store.state.count
    
          //在根实例vm中注册store以后,所有子组件都能通过this.$store访问到state
          return this.$store.state.count
        }
      },
      methods: {
        add() {
          //修改state必须提交一个commit
          // store.commit('increment')
    
          //在根实例vm中注册store以后,所有子组件都能通过this.$store访问到state
          this.$store.commit('increment')
        }
      }
    }
    //创建一个vue实例,提供一个创建好的store
    let vm = new Vue({
      el: '#app',
      store, //把store对象提供给‘store’选项,可以把store的实例注入所有子组件中
      components: {
        Counter
      }
    })

    mapState获取多个状态
    当一个组件需要获取多个状态时,将这些状态都声明为计算属性会有些重复和冗余,可使用mapState辅助函数帮助我们生成计算属性。

    //引入mapState
    //import {mapState} from 'vuex'
    const mapState = Vuex.mapState
    
    const store = new Vuex.Store({
      state: {
        count: 0,
        isLogin: true,
        user: {
          username: 'Liane',
          id: '1',
          gender: 'female'
        }
      },
      mutations: {
        increment(state) {
          state.count++
        }
      }
    })
    
    const Counter = {
      template: `<div>
            <div class="btn" @click='add'>增加</div>
            <div>{{count}}</div>
            <div>{{user.username}}</div>
            <div>{{user.id}}</div>
            </div>`,
      //使用mapState()辅助函数
      computed: mapState({
        // count() {
        //   return this.$store.state.count
        // }
        //count可简化如下
        count: state => state.count,
        isLogin: state => state.isLogin,
        user: state => state.user
      }),
      methods: {
        add() {
          this.$store.commit('increment')
        }
      }
    }
    let vm = new Vue({
      el: '#app',
      store,
      components: {
        Counter
      }
    })

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

    computed: mapState([
      'count',
      'isLogin', 
      'user'
    ])

    通常我们使用扩展运算符将需要用到的state通过mapState与组件的计算属性混合

    computed:{
      ...mapState([
        'count',
        'isLogin',
        'user'
      ])
    }

    四、Getter
    当我们需要store中的某些state派生出一些状态时,可以使用Getter,getter就像是store中的计算属性一样,会根据它的依赖被缓存起来,依赖一旦发生改变,就会重新计算。

    //定义一个store存储代办事项的状态
    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: 'study', done: true },
          { id: 2, text: 'exercise', done: true },
          { id: 3, text: 'painting', done: false }
        ]
      },
      getters: {
        //得到已完成的事项
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        },
        //得到已完成的事件个数
        doneTodosCount: (state, getters) => {
          return getters.doneTodos.length
        }
      }
    })
    const Counter = {
      template: `<div>
        <span>已完成{{doneTodosCount}}件代办事项</span>
        <ul>
          <li v-for="item in doneTodos">
            {{item.text}}
          </li>
        </ul>
      </div>`,
      computed: {
        doneTodos() {
          return this.$store.getters.doneTodos
        },
        doneTodosCount() {
          return this.$store.getters.doneTodosCount
        }
      }
    }
    let vm = new Vue({
      el: '#app',
      store,
      components: {
        Counter
      }
    })

    mapGetter辅助函数

    computed: {
      ...mapGetter([
        'doneTodos',
        'doneTodosCount'
      ])
    }

    若想将getter属性另取名字,可使用对象形式

    computed:{
      ...mapGetter({
        doneCount: 'doneTodosCount'
      })
    }

    五、Mutations
    更改store中属性的唯一方法就是commit一个mutation。
    vuex中的mutation类似事件,每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)

    const mapState = Vuex.mapState
    const store = new Vuex.Store({
      state: {
        isLogin: false,
        user: {}
      },
      mutations: {
        setLogin(state, val) {
          state.isLogin = val
        },
        setUser(state, val) {
          state.user = val
        }
      }
    })
    const Counter = {
      data() {
        return {
          username: ''
        }
      },
      template:
            `<div>
              <div v-if='isLogin'>
                {{user.username}}已登录
                <a @click="signOut" href="javascript:;">退出登录</a>
              </div>
              <div v-else>
                <input v-model="username" placeholder="输入用户名">
                <div class="btn" @click="submit">登录</div>
              </div>
            </div>`,
      computed: {
        ...mapState(['isLogin', 'user'])
      },
      methods: {
        submit() {
          if (this.username) {
            this.$store.commit('setLogin', true)
            this.$store.commit('setUser', {
              id: 1,
              username: this.username
            })
          }
        },
        signOut() {
          this.$store.commit('setLogin', false)
          this.$store.commit('setUser', {})
        }
      }
    }
    let vm = new Vue({
      el: '#app',
      store,
      components: {
        Counter
      }
    })

    六、Actions
    Action类似于mutation,区别:
    1、Action提交的是mutation,而不是直接变更状态。
    2、Action可以包含任意异步操作


    Liane
    16 声望2 粉丝