使用 Vue.js 和 Vuex 实现购物车场景

2016年6月23日 248点热度 0人点赞 0条评论

本文是上篇文章的序章,一直想有机会再次实践下 Vuex。写下这篇总结,需要 Demo 请后台私信一下小编。

什么是 Vuex?

Flux-inspired Application Architecture for Vue.js

Vuex 实际上是类Flux的数据管理架构。它主要帮我们更好的组织代码,更好的让 Vue 中的状态更好的通过状态管理维护起来。在实际项目运用中我们需要对组件的 组件本地状态(component local state)应用层级状态(application level state) 进行区分。

Vuex 的作用就是汇集应用层级的状态到一处,方便管理。

说状态其实有些同学可能不太理解,那么在刚上手Vue的时候做过的例子中,一个 Vue 实例中都会有 data,那么这个 data 中保存的属性其实就是可以理解为状态。

试想这样的场景,比如一个 Vue 根实例下面有一个根组件名为App.vue,它下面有两个子组件A.vueB.vue,父组件和子组件之间使用 Props 通讯是没问题的,通过绑定 Props 轻松的实现。

但是如果我们需要 A.vue 组件和 B.vue 组件之间通讯呢?因为组件实例的作用域是孤立的,它们之间是不能直接通讯的。那么只能借助共有的父组件通过自定义事件实现。

A 组件想要和 B 组件通讯往往是这样的:

  • A 小弟说:“报告老大,能否帮我捎个信给你的小弟B组件?”,它需要dispatch一个事件给 App

  • App 老大说:“包在我身上”,它需要监听 A 组件dispatch的事件,同时需要broadcast一个事件给 B 组件。

  • B 小弟说:“信息已收到。”,它需要on监听 App 组件分发的事件。
    图片

这只是一条通讯路径,那么如果父组件下有多个子组件,子组件之间通讯的路径就会变的很繁琐,父组件需要监听大量的事件,还需要负责分发给不同的子组件。很显然这并不是我们想要的组件化开发体验。

Vuex 就是为了解决这一问题出现的。

Vuex 是如何工作的?

下面这张图很好的诠释了 Vuex 和组件之间的通讯关系。

图片

这张图描述的很棒,完整的数据流闭环,整个应用的数据流是单向的。对我们理解 Vuex 和 Vue 的组件间的通讯关系很有帮助。

需要掌握的:

  • 用户在组件中的输入操作触发 action 调用;

  • Actions 通过分发 mutations 来修改 store 实例的状态;

  • Store 实例的状态变化反过来又通过 getters 被组件获知。

使用 Vuex

进入正题。一个购物车我们都需要完成哪些功能?先看看 Demo 的样子(需要 Demo 请继续后台找小编= =

图片

需求分析

  • 显示商品的文字描述、图片描述、类型、价格信息;

  • 改变商品颜色的时候图片切换;

  • 改变商品类型的时候价格变化;

  • 加入/移除购物车;

  • 购物车中商品数量统计以及总价的统计;

目录结构

我参考了中型到大型项目的目录结构说明构建的购物车,把 Vuex 相关的代码分割到多个模块(module),我认为这样更清晰明了。

图片

配置 vuex

每一个 Vuex 应用的核心就是 store(仓库)。”store” 基本上就是一个容器,它包含着你应用里大部分的 状态(即 state),我们创建store.js导入各个模块的初始状态和 mutations。

store.js

// vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import index from './modules/index'

Vue.use(Vuex)

export default new Vuex.Store({
// 组合各个模块  modules: {    index  } })

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中。

App.vue

import Nav from './components/Nav.vue'
import store from './vuex/store'

export default {
 name: 'App',  store,  data() {
   return {
     // note: changing this line won't causes changes      // with hot-reload because the reloaded component      // preserves its current state and we are modifying      // its initial state.    }  },  components: {    'cart-nav': Nav  } }

组件中通过 getters 读取状态

配合 ES6 的箭头函数真的很简洁的。

vuex: {
  getters: {
    iPhone6S: ({ index }) => index.iPhone6S
  }
}

理解数据流闭环

比如我们需要根据更改外观来改变商品的图片这样的需求。我们该怎样完成一个数据流闭环呢?

从组件开始:

一(Vue components)、首先子组件Index.vue需要一个点击事件来触发action:

Index.vue

<li v-for="styleUrl in iPhone6S.style"
   @click="changeStyle($key, styleUrl)"
   :class="{active: iPhone6S.activeStyleUrl == styleUrl}">
<span v-text="$key"></span></li>

二(Actions)、声明一个名为changeStyle的action

actions.js

export const changeStyle = makeAction('CHANGE_STYLE')

并分发 mutations,用统一的函数处理。

function makeAction (type) {
 return ({ dispatch }, ...args) => dispatch(type, ...args) }

三(Mutations)、我们用常量声明mutation,并把它放到单独的地方。mutation常量习惯性大写的,区分于actions。

mutation-types.js

export const CHANGE_STYLE = 'CHANGE_STYLE'

四(State)、在模块中导入mutation改变状态:

index.js

[CHANGE_STYLE] (state, styleName, styleUrl) {
  state.iPhone6S.activeStyle = styleName
  state.iPhone6S.activeStyleUrl = styleUrl
}

由于 Vuex store 内部的 state 对象被 Vue 改造成了响应式对象,当我们对 state 进行修改时,任何观测着 state 的 Vue 组件都会自动地进行相应地更新。

使用 Vuex 管理状态并不是需要把所有的状态都放在 Vuex 里。如上所述,组件本地状态是不需要写在 Vuex 里的。

组件不允许直接修改 store 实例的状态

在使用vuex的过程中你有可能会对从vuex.getters获取的数据进行再次操作。这是不允许的。改变 store 中的状态的唯一途径就是显式地分发 状态变更事件

组件永远都不应该直接改变 Vuex store 的状态。因为我们想要让状态的每次改变都很明确且可追踪,Vuex 状态的所有改变都必须在 store 的 mutation handler (变更句柄)中管理。

使用 Vue Tools 调试 vuex

使用 Vue Tools 调试 vuex 是一个非常愉快的体验,可以在Components中清楚的看到哪些数据是从 vuex.getters 中获取来的。

图片

它记录了每次 mutation 的状态变化,保存了状态变化后的快照,我们可以定位到你想检查的快照观察数据的变化。

图片



-EOF-

【活动推荐】由运维派、码客帮主办,SegmentFault 联合主办的运维派 Ops-Day 将于本周六在厦门举行,活动以「运维与网络安全」为主题,感兴趣的小伙伴可通过【阅读原文】报名活动。

图片

8790使用 Vue.js 和 Vuex 实现购物车场景

root

这个人很懒,什么都没留下

文章评论