Vue - 用小白的学习方式去掌握 Vuex 使用

Vuex 是什么

Vuex是什么

  • 一个专为 Vue.js 应用程序开发的响应式状态管理模式.

状态管理是什么?

从我个人角度来看,状态可以指代数据。而状态管理也就可以看作数据管理,主要是用于分层解耦。

Vuex中状态管理可以看作是全局变量,这个变量可以通过state取出变量映射到view中,也可以根据用户的输入actions改变该变量

响应式是什么?

从我个人角度来看,响应式就是自适应。

Vuex中响应式是指数据(状态)的改变能够及时的所有数据变更为最新的数据。

不用 Vuex 也是可以的

  • 从父组件一层一层将数据传递给子组件(麻烦)
  • 通过 EventBus 的订阅/发布模式实现数据数据传递

可看这篇文章介绍:什么情况下我应该使用 Vuex

使用

安装

npm 安装

npm install vuex --save

知识储备

全局 store

参考:shoppint-cart 示例
store 目录下创建index.js

import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/products'
import createLogger from '../../../src/plugins/logger'

Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
   
   
  // 注入其它模块的 store
  modules: {
   
   
    cart,
    products
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})

app.js中注入store,如:

import Vue from 'vue'
import App from './components/App.vue'
import store from './store'
import {
   
    currency } from './currency'

Vue.filter('currency', currency)

new Vue({
   
   
  el: '#app',
  store, // 全局注入
  render: h => h(App)
})

如在counter组件中通过this.$store去使用

this.$store.commit('increment')

State

用于声明数据。

computed 计算属性

对于任何复杂逻辑,你都应当使用计算属性。

例如下面的示例中,第二个 message ,如果我们要在 view 中写也是可以,但是会比较复杂,如下:

<p>Computed reversed message: "{
  
  { message.split('').reverse().join('') }}"</p>

那么我们可以将该复杂写法通过计算属性封装成一个方法,直接调用该方法对象即可。
示例:

<div id="example">
  <p>Original message: "{
   
   { message }}"</p>
  <p>Computed reversed message: "{
   
   { reversedMessage }}"</p>

  <!-- 在 Vuex 中如果不用计算属性,我们需要这么写 -->
  <p>Computed reversed message: "{
   
   { this.$store.state.counter.message.split('').reverse().join('') }}"</p>

</div>

var vm = new Vue({
   
   
  el: '#example',
  data: {
   
   
    message: 'Hello'
  },
  computed: {
   
   
    // 计算属性的 getter
    reversedMessage: function () {
   
   
      // `this` 指向 vm 实例
      // 使用 vuex 则可通过 $store 取到数据之后再转换,如下
      // return this.$store.state.counter.message.split('').reverse().join('')
      return this.message.split('').reverse().join('')
    }
  }
})

输出结果:

Original message: "Hello"

Computed reversed message: "olleH"

mapState 辅助函数

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

辅助函数,用于简化this.$store.state,示例如下:

<template>
  <div>
    <!-- 直接使用 -->
    Clicked: {
   
   {
   
    $store.state.counter.count }} times.
    <br>
    <!-- 使用 Vuex mapState -->
    mapState使用: {
   
   {
   
    count }} times.
  </div>
</template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import {
   
    mapState } from 'vuex'

export default {
   
   

  computed:{
   
   
    ...mapState({
   
   
      count: state => state.counter.count
    }),
  },

  methods: {
   
   
  }
}
</script>

有时候我们需要从 store 中的 state 中派生出一些状态。
如上面的字符串反转功能就是派生出来的,我们可以使用Getters去实现。

Getters

可以认为是 store 的计算属性。getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

通过一个示例来看一下getters如何使用。
Counter.vue文件如下:

<template>
  <div>
    <p>hello 字符串反转:{
   
   {
   
    reverseStr }}</p>
    <p>getter 获取 todo done: {
   
   {
   
    doneTodosCount }}</p>
    <p>传入 getters 做参数:{
   
   {
   
    doneTodosCount }}</p>
    <p>直接访问:{
   
   {
   
    doneTodos }}</p>
  </div>
</template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapGetters
import {
   
     mapGetters } from "vuex";

export default {
   
   
  computed: {
   
   
    // 由于使用了命名空间,因此需要加上,否则获取反转的字符串如: reverseStr:'counter/reverseStr'
    ...mapGetters('counter',{
   
   
      reverseStr: "reverseStr",
      doneTodosCount: "doneTodosCount",
      doneTodos: "doneTodos",
    }),
  },

};
</script>

counter.js文件如下:

const state = () => ({
   
   
    message: 'hello',
    todos: [{
   
   
            id: 1,
            text: '写日报',
            done: true
        },
        {
   
   
            id: 2,
            text: '看一篇英文文章',
            done: false
        }
    ]
})

// getters
const getters = {
   
   
    doneTodos: state => {
   
    
        return state.todos.filter(todo => todo.done)
    },
    doneTodosCount: (state, getters) => {
   
    // 传入 getters 做参数
        return getters.doneTodos.length
    },
    reverseStr: state => {
   
   
        return state.message.split('').reverse().join('')
    }
}

export default {
   
   
    namespaced: true,
    state,
    getters,
}

Mutations

通过提交 mutation 的方式,而非直接改变 store.state.count
其实也就是通过方法的方式去操作数据。而且Mutation 必须是同步函数,如果是异步函数请使用下一节的Action

看个示例:每次点击increment文本+2,每次点击decrement文本-2
Counter.vue文件如下

<template>
  <div>
     <p @click="mIncrement">mutations 获取 increment: {
   
   {
   
    mutationsCount }}</p>
     <p @click="mDecrement">mutations 获取 decrement: {
   
   {
   
    mutationsCount }}</p>
  </div>
</template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import {
   
    mapState } from "vuex";

export default {
   
   
  computed: {
   
   
    ...mapState({
   
   
      count: (state) => state.counter.count,
      mutationsCount: (state) => state.counter.mutationsCount,
    }),
  },

  methods: {
   
   
    mIncrement() {
   
   
      this.$store.commit("counter/mIncrement",2);
    },
    mDecrement() {
   
   
      this.$store.commit("counter/mDecrement",{
   
   
        amount:2
      });
    },

  },
};
</script>

counter.js如下:

const state = () => ({
   
   
    mutationsCount:0,
})
const mutations = {
   
   

    mIncrement(state, n) {
   
   
        state.mutationsCount += n
    },
    // 通过对象传递
    mDecrement(state,payload) {
   
   
        state.mutationsCount -= payload.amount
    },
}

export default {
   
   
    namespaced: true,
    state,
    mutations
}

Actions

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

counter计数器示例:
Counter.vue文件如下:

<template>
  <div>
    Clicked: {
   
   {
   
    $store.state.counter.count }} times.
    <br />
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
   
  </div>
</template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import {
   
    mapState, mapGetters } from "vuex";

export default {
   
   
  computed: {
   
   
    ...mapState({
   
   
      count: (state) => state.counter.count,
    }),
  },

  methods: {
   
   

    increment() {
   
   
      this.$store.dispatch("counter/increment");
    },
    decrement() {
   
   
      this.$store.dispatch("counter/decrement");
    },
  },
};
</script>

counter.js文件如下:

const state = () => ({
   
   
    count: 0,
})
const mutations = {
   
   
    increment(state) {
   
   
        state.count++
    },
    decrement(state) {
   
   
        state.count--
    },
}

const actions = {
   
   
    increment: ({
   
   
        commit
    }) => commit('increment'),
    decrement: ({
   
   
        commit
    }) => commit('decrement'),
}

export default {
   
   
    namespaced: true,
    state,
    actions,
    mutations
}

Modules

也就是分模块。
例如Counter组件,在 store/modules下创建counter.js用于处理store相关的数据,而Counter.vue组件页面就正常写即可。
接着在store/目录下的 index.js添加 module的注入。具体可看上文的store全局注入。

购物车示例

对照上面的分析,你可以很容易看懂Vuex examples 中的 shoppint-cart示例了
shoppint-cart 示例地址

该示例是通过shop.js模拟数据,然后将products 和 cart组件注入全局 store
然后ProductList.vue展示shop.js中的商品列表,而ShoppingCart.vue展示购物车数据。

END~

本文同步分享在 博客“_龙衣”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/u/4483532/blog/4844594

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。