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 ( {
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: {
reversedMessage: function ( ) {
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>
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>
import {
mapGetters } from "vuex" ;
export default {
computed: {
... 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
}
]
} )
const getters = {
doneTodos: state => {
return state. todos. filter ( todo => todo. done)
} ,
doneTodosCount: ( state, 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>
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>
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源创计划 ”,欢迎正在阅读的你也加入,一起分享。