• Vue2.0 实战项目(六) Vuex


    vuex

    最近进入了一个新项目组,前端框架选择vue进行开发,数据的状态管理选择用vuex。本篇随笔中的代码采用vuex官网提供的购物车案例

    项目结构

    ├── index.html
    ├── main.js
    ├── api
    │   └── shop.js # 抽取出API请求
    ├── components
    │   ├── App.vue # 根级别的页面
    │   ├── Cart.vue # 购物车组件
    │   └── ProductList.vue # 产品组件
    │  
    └── store
        ├── index.js          # 我们组装模块并导出 store 的地方
        ├── actions.js        # 根级别的 action
        ├── mutations.js      # 根级别的 mutation
        ├── mutation-types.js # mutation事件类型
        └── modules
            ├── cart.js       # 购物车模块
            └── products.js   # 产品模块
    

    核心概念

    Vuex有五个核心概念,分别是:State、Getter、Mutation、Action和Module

    State

    由于Vuex的状态存储是响应式的,所以从store实例中读取状态最简单的方式是在计算属性中返回某个状态

    //product.js
    const state = {
      all: [{
        'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01
      },{
        'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99
      }]
    }
    
    export default {
      state
    }
    
    //productList.vue
    import store from '../store/index'
    
    <template>
      <ul>
        <li v-for="p in products">
          {{ p.title }} - {{ p.price | currency }}
        </li>
      </ul>
    </template>
    
    <script>
    export default {
      computed: {
        products() {
          return store.state.all
        }
      })
    }
    </script>
    

    当一个组件需要获取多个状态时,可以通过mapState辅助函数帮助我们生成计算属性

    //改造productList.vue
    import { mapState } from 'vuex'
    
    export default {
      computed: mapState({
        // 箭头函数可使代码更简练
        products: state => state.all,
    
        // 传字符串参数 'all' 等同于 `state => state.all`
        //products: 'all',
    
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        /* products (state) {
          return state.all + this.localCount
        } */
      })
    }
    

    如果计算属性名和state子节点名字相同,也可以传递一个字符串数组

    computed: mapState([
      // 映射 this.all 为 store.state.all
      'all'
    ])
    

    如果想要与局部计算属性混合使用,则可以通过对象展开运算符做到这一点

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

    Getter

    Getter相当于store实例的计算属性,Getter的返回值会根据它的依赖被缓存起来,只有依赖发生改变,才会重新计算。
    Getter接受State作为第一个参数,其他的getter作为第二个参数,同时也会暴露为store.getters对象

    //products.js
    const getters = {
        allProducts: (state, getter) => state.all
    }
    
    export default {
        state,
        getters
    }
    
    //productList.vue
    computed: {
        allProducts() {
            return this.$store.getters.allProducts
        }
    }
    

    同样,Getter也有辅助函数mapGetters,它的作用是将store中的getter映射到局部计算属性,使用方法与mapState一样。

    Mutation

    更改 Vuex 的 store 中的状态的唯一方法是提交 Mutation。

    每个 Mutation 都有一个字符串的 事件类型 (type) 和 一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,通过store.commit可以传递第二个参数,也就是载荷(Payload)

    // project.js
    // 可以使用常量代替Mutation事件类型
    const mutations = {
      [types.RECEIVE_PRODUCTS] (state, { products }) {
        state.all = products
      },
    
      [types.ADD_TO_CART] (state, { id }) {
        state.all.find(p => p.id === id).inventory--
      }
    }
    
    // actions
    const actions = {
      getAllProducts ({ commit }) {
        shop.getProducts(products => {
          commit(types.RECEIVE_PRODUCTS, { products })
        })
      }
    }
    
    // mutation-types.js
    export const ADD_TO_CART = 'ADD_TO_CART'
    export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS'
    

    Mutation也有辅助函数mapMutations

    import { mapMutations } from 'vuex'
    
    export default {
      methods: {
        ...mapMutations([
          'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
          
          // `mapMutations` 也支持载荷:
          'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
        ]),
        ...mapMutations({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
        })
      }
    }
    

    Mutation必须是同步函数,如果想包含异步操作,那么必须要使用Action

    Action

    Action和Mutation有两点不同:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。
    actions: {
      getAllProducts ({ commit }) {
        commit('types.types.RECEIVE_PRODUCTS')
      }
    }
    

    Action通过store.dispatch方法触发
    store.dispatch('getAllProducts')

    在组件中分发Action,我们可以使用mapActions辅助函数将组件的methods映射为store.dispatch调用,使用方法同mapMutations

    Module

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

    const moduleA = {
      state: { ... },
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    }
    
    const moduleB = {
      state: { ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })
    
    store.state.a // -> moduleA 的状态
    store.state.b // -> moduleB 的状态
    

    默认情况下,模块内部的action、mutation、getter是注册在全局命名空间的,如果需要模块被更好的封装,那么可以通过添加namespaced: true的方式使其成为命名空间模块

    启用了命名空间的 getter 和 action 会收到局部化的 getterdispatchcommit

  • 相关阅读:
    Html-浅谈如何正确给table加边框
    如何在移动设备上调试html5开发的网页
    swiper嵌套小demo(移动端触摸滑动插件)
    移动端如何用swiper实现导航栏效果
    background-color:transparent
    点击按钮 发送短信验证码后60秒倒计时
    placeholder的样式设置
    linux 定时任务crontab
    laravel学习一
    centos 7安装jdk
  • 原文地址:https://www.cnblogs.com/hello-wuhan/p/7750159.html
Copyright © 2020-2023  润新知