[手把手式教程,适合新手入门Vuex]-Vuex入门实践(上)

1,579 阅读4分钟

作者:小土豆biubiubiu
博客园:www.cnblogs.com/HouJiao/
掘金:juejin.im/user/243617…
码字不易,点赞鼓励哟~

前言

Vuex被称为是专为Vue应用程序开发的的状态管理模式。它的作用使用一句话描述就是:让组件之间可以共享数据

话不多少,先抛开概念,我们写一个简单的示例感受一波。

Vuex入门实践将分为三篇,本篇是第一篇。

项目环境搭建

项目开发环境搭建请移步作者的另外一篇文章 新手入门vue-教你使用vue-cli搭建项目开发环境

本次的项目目录如下:

安装Vuex

使用Vuex前需要先进行安装,安装命令:npm install vuex --save--dev

创建和访问共享数据

使用Vuex创建全局共享数据

首先我们先需要在E:\MyStudy\test\VueDemo\src\目录下新建一个目录vuex和文件store.js

接着在store.js中使用Vuex创建一个全局的共享数据。

// E:\MyStudy\test\VueDemo\src\vuex\store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中创建一个全局共享的数据 counter
    state: {
        counter: 0
    }
})

可以看到使用Vuex创建一个共享数据的语法也比较简单,即在new Vuex.Store中定义state对象,在state对象中就可以创建全局的共享数据,本次我们创建了一个counter数据。

入口文件中配置Vuex

共享数据前面我们已经创建好了,接着需要在入口文件main.js中配置Vuex,配置的步骤如下:

1.引入我们编写的关于Vuex的代码模块store.js

2.在根实例上配置Vuex
//  E:\MyStudy\test\VueDemo\src\main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router/router'
//1.引入vuex
import store from './vuex/store'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>',
  router: router,
  // 2.根实例上配置vuex
  store: store
})

组件中获取共享数据

前面我们已经完成了两件事:使用Vuex创建共享数据counter和配置Vuex

接着我们就需要在组件中访问这个共享数据counter

我们先新建一个Index.vue组件,在该组件中编写访问counter的代码。

<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h1>Index组件获取共享数据:{{ $store.state.counter }}</h1>
    </div>
</template>
<script>
export default {
    name: 'Index'
}
</script>

访问共享数据counter的代码为:

<h1>Index组件获取共享数据:{{ $store.state.counter }}</h1>

接着在App.vue中编写同样的代码访问这个counter,并且在App.vue组件中将Index.vue组件引入并展示。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h1> App组件获取共享数据 : {{ $store.state.counter }} </h1>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
export default {
  name: 'App',
  components: { Index }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

浏览器查看结果

我们分别在App.vue组件和Index.vue组件中访问了共享数据counter,现在我们启动项目在浏览器中看下结果。

可以看到, App组件和Index组件均可以访问到counter的值。

到此,我们简单的创建一个共享数据并且在组件中成功的访问到了这个共享数据,这里我们对Vuex的使用步骤做一个小总结:

1.安装vuex:npm install vuex
2.全局配置vuex:创建vuex实例,调用store方法配置在state中创建共享数据。
3.组件中使用$store.state.counter可以访问到共享数据

修改共享数据

定义修改共享数据的状态

Vuex中,假如需要改变共享数据,必须在Vuex实例对象的Store方法中约定这个变化。

我们在store.js中对counter做两个约束:递增递减

// E:\MyStudy\test\VueDemo\src\vuex\store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中创建一个全局共享的数据 counter
    state: {
        counter: 0
    },
    mutations: {
        // 递增
        increase(state) {
            state.counter++ 
        },
        // 递减
        decrement(state) {
            state.counter--
        }
    }
})

mutations中的increase方法就是约定共享数据counter每次递增1decrement方法约定共享数据counter每次递减1

组件中触发状态变化

约束共享数据的变化已经完成了,接着就开始触发这个变化从而使共享数据发生变化。

我们在App.vue组件中触发counter递减,在Index.vue中触发counter递增

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h1> App组件获取共享数据 : {{ $store.state.counter }} </h1>
    <button v-on:click="$store.commit('decrement')">点击触发共享数据counter递减1</button>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
export default {
  name: 'App',
  components: { Index }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue  -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h1>Index组件获取共享数据:{{ $store.state.counter }}</h1>
        <button v-on:click="$store.commit('increase')">点击该组件触发共享数据counter递增1</button>
    </div>
</template>
<script>
export default {
    name: 'Index'
}
</script>

可以看到在组件中触发共享数据counter递增和递减的逻辑分别为:$store.commit('increase')$store.commit('decrement')

即使用$store.commit方法并传递对应的函数名称

浏览器查看结果

可以看到,点击App组件中的按钮,成功的将counter1,且Index组件中的数据也自动更新;点击Index组件中的按钮,成功的将counter1App组件中的数据也自动更新。

异步修改数据

假设我们前面的递增递减的需求变成:点击按钮后,过3秒再去修改counter的值。那么这个时候应该怎么实现呢?

我们直接上代码。

// E:\MyStudy\test\VueDemo\src\vuex\store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中创建一个全局共享的数据 counter
    state: {
        counter: 0
    },
    mutations: {
        // 递增
        increase(state) {
           state.counter++    
        },
        // 递减
        decrement(state) {
           state.counter--   
        }
    },
    actions: {
        increaseAction(context){
            setTimeout(function(){
                context.commit('increase')
            }, 3000); 
        },
        decrementAction(context){
            setTimeout(function(){
                context.commit('decrement')
            }, 3000); 
        }
    }
})

store.js中,我们把异步修改数据的逻辑定义在actions中,并且通过提交mutations改变共享数据的状态。

那在组件中需要使用$store.dispatch对应去触发共享数据的改变。

下面我们看一下组件中如何使用$store.dispatch

<!-- E:\MyStudy\test\VueDemo\src\App.vue  -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h1> App组件获取共享数据 : {{ $store.state.counter }} </h1>
    <button v-on:click="$store.dispatch('decrement')">点击等待3秒触发共享数据counter递减1</button>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
export default {
  name: 'App',
  components: { Index }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h1>Index组件获取共享数据:{{ $store.state.counter }}</h1>
              <button v-on:click="$store.dispatch('increase')">点击等待3秒触发共享数据counter递增1</button>
    </div>
</template>
<script>
export default {
    name: 'Index'
}
</script>

最后,我们在浏览器看下效果。

可以看到,setTimeout这个异步逻辑成功执行。

这里有点不一样的

关于上面想要实现的异步递增和递减,我们的第一反应可能就是在mutations中的递增递减函数添setTimeout延迟执行函数,我们来实践一下。

App.vueIndex.vue不做任何修改,还是前面的内容,只修改store.js

// E:\MyStudy\test\VueDemo\src\vuex\store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中创建一个全局共享的数据 counter
    state: {
        counter: 0
    },
    mutations: {
        // 递增
        increase(state) {
            // 添加定时器执行
            setTimeout(function(){
                state.counter++
            },3000);
             
        },
        // 递减
        decrement(state) {
            //添加定时器
            setTimeout(function(){
                state.counter--
            },3000);
            
        }
    }
})

浏览器看下结果:

可以看到效果和actions一样!!!

没办法,我这人就是想多造作造作给大家看点不一样的东西。

那对于mutations官网确实有明确的说明,mutations必须是同步函数。

当我仔细读了红色框里面的内容后,我大概理解了官方文档的为什么说mutations必须是同步函数了。

原因一:如果是异步函数,在触发mutations的时候,浏览器的调试功能看不到数据的变化;

原因二:mutations中异步函数中的数据变化无法追踪。

到这里呢,我们就不继续往下探究了,因为基础的还没有总结完,基础总结完后在探究这个问题。

共享数据的计算属性

vue组件中的计算属性想必大家都知道,那么Vuex中共享数据的计算属性的用途和原理也是同vue组件中的计算属性。

我们假设vue组件中需要对共享数据做一些其他的转换:将某个字符串进行翻转,并且转为大写。(这个场景项目中几乎不会用到,仅仅为了演示而编造的)。当多个组件都需要对某个共享数据做这样的转化时,想必写起来也会比较繁琐,因此Vuex共享数据的计算属性就帮了我们解决这个问题。下面我们使用Vuex的共享数据的计算属性来实现这个需求。

// E:\MyStudy\test\VueDemo\src\vuex\store.js
// 在该文件中已经将前面定义的counter删除,重新定义了一个共享数据str
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    // 在state中创建一个全局共享的数据 str
    state: {
        str: 'hello'
    },
    getters: {
        reverseAndToUpper(state){
            return state.str.split("").reverse().join("");
        }
    }
})

关于共享数据的计算属性的访问,我们只在App组件中添加访问代码。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<!-- 在App组件中,将Index组件的引入代码已经删除 -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h1> App组件获取共享数据 : {{ $store.getters.reverseAndToUpper }} </h1>
  </div>
</template>

<script>
import Index  from './components/Index'
export default {
  name: 'App',
  components: { Index }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

浏览器查看一下结果:

可以看到,在App组件中已经成功的访问到了str的计算属性。

总结

前面我们一共实践了Vuex的这些内容:

1.在state中定义共享属性,在组件中可使用$store.state.属性名访问共享属性。

2.在mutations可中定义修改共享数据的方法,在组件中可使用$store.commit('方法名')同步修改共享属性。

3.在actions中可定义异步修改共享数据的方法,在组件中可使用$store.dispatch('方法名')异步修改共享属性。

4.在getters中可定义共享数据的计算属性,在组件中可使用$store.getters.计算属性名访问共享数据的计算属性。

那最后我在将文章最开始的图拿过来。

根据我们前面实践的内容,大家能看懂这个状态变化吗?

Vuex入门实践系列文章

[手把手式教程,适合新手入门Vuex]-Vuex入门实践 这整个系列的总结已经完结,都是一些关于Vuex基础的用法,比较适合新手刚开始学习和实践Vuex

最后呢,将这个系列的所有文章链接整理到这里,方便大家观看。

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(上)

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(中)

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(下)

写在最后

如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者

笔芯❤️~