作者:小土豆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
每次递增1
;decrement
方法约定共享数据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
组件中的按钮,成功的将counter
减1
,且Index
组件中的数据也自动更新;点击Index
组件中的按钮,成功的将counter
加1
,App
组件中的数据也自动更新。
异步修改数据
假设我们前面的递增递减的需求变成:点击按钮后,过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.vue
和Index.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入门实践(下)
写在最后
如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者
笔芯❤️~