前端框架Vue(4)——vuex 状态管理
1、Vuex 是什么?
在使用 Vue 框架做单页面应用时,我们时常会遇到传值,组件公用状态的问题。(子父间传值文章传送门) ,如果是简单的应用,兄弟组件之间通信还能使用 eventBus 来作为中介。但是一旦应用比较庞大,那状态将会变得难以维持管理。
Vue 为我们提供了进行大型状态管理的 Vuex,类似 Flux 。Vuex 采用了集中式存储管理所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
直接用官方文档提供的关系图来讲:
一个 store 中包含了: Actions( 行为 ) 、Mutations( 突变 )、State( 状态 ),完整的 Vuex 动作是这样的 Components( 组件 )中 methods 里面一个方法 dispatch (调用)Actions,Actions 然后 commit 对应的Mutations, 只有 Mutations 可以操作 State 中的状态数据,状态一改变,组件中就重新渲染。路线:C——>A——>M——>S——>C。
2、Vuex 安装
(1)引入式
<script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script>
(2)npm 安装
npm install vuex --save
3、Vuex 使用,结合小实例
一、这边提供两中目录结构共使用:
1、适合简单的项目,所有模块放到 store.js 中管理
import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const store = new Vuex.Store({ state:{ count: 10, }, mutations:{ //格式:类型(名字)+处理函数 //加1 INCREMENT(state) { //console.log(state)//state对象 state.count++; } }, actions:{ increment({commit}){ commit("INCREMENT") } } }) export default store
2、将各个 js 单文件分开,便于管理
==store =index.js =mutations.js =actions.js =getters.js
index.js 主文件入口:
/** *主要入口文件,引入其他四个js */ import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) //引入actions、mutations、getters import actions from "./actions.js" import mutations from "./mutations.js" import getters from "./getters.js" // 定义状态state const state = { } // 设置暴露接口 export default new Vuex.Store({ state, mutations, actions, getters })
mutations.js 、actions.js 、getters.js 文件类似:
export default { //方法 对state数据进行统一操作 }
main.js 进行全局注册:
import store from './store/index' /* eslint-disable no-new */ new Vue({ el: '#app', store, router, template: '<App/>', components: { App } })
二、结合简易‘’不符合逻辑‘’计算器讲解 Vuex
1、先上简陋图:
2、逻辑: 输入框中进行数字输入,加减乘除按钮点击使用,点击确认输出结果。
3、目录结构:
*一 一对应
XTGL : 计算器
showBox : 最上方显示区
input : 输入区
calc : 四则运算区
output : 结果输出区
4、代码实现:
components 部分
inputBox.vue 负责初始值的输入,dispatch actions 中的 inputevent ,为了将输入的值显示到 showBox 中。
<template> <div class="inputBox"> <div class="layui-form-item"> <label class="layui-form-label">输入:</label> <div class="layui-input-block"> <input class="layui-input" v-model="inputNum" @blur="inputEvent"> </div> </div> </div> </template> <script> export default { data () { return { inputNum: '', } }, methods:{ inputEvent:function(){ //调用dispatch this.$store.dispatch('inputevent',this.inputNum) } } } </script>
showBox.vue 只需要将 store.js 中 state 里的初始值拿到并显示,这边 this.$store.state.inputNum
需要写在 computed 中。
<template> <div class="showBox"> <div class="layui-form-item"> <div class="layui-input-block"> <input class="layui-input" v-model="inputNum"> </div> </div> </div> </template> <script> export default { data () { return { } }, computed:{ //拿inputNum inputNum () { return this.$store.state.inputNum } } } </script> <style scoped> .layui-input-block{ margin-left: 0!important; } .layui-input{ width: 100%!important; } </style>
calc.vue
<template> <div class="clacBox"> <div> <button class="btn layui-btn" @click="increment">加1</button> <button class="btn layui-btn" @click="decrement">减1</button> <button class="btn layui-btn" @click="increment">乘2</button> <button class="btn layui-btn" @click="increment">除2</button> </div> </div> </template> <script> export default { data () { return { } }, methods:{ increment () { //dispatch调用 this.$store.dispatch('increment') }, decrement () { this.$store.dispatch('decrement') } } } </script> <style scoped> </style>
outputBox.vue 点击确认按钮,操作 store.js 中 actions 中 resultevent, 并且拿到结果值 resultNum。
<template> <div class="inputBox"> <div class="layui-form-item"> <label class="layui-form-label">结果:</label> <div class="layui-input-inline"> <input class="layui-input" v-model="resultNum"> </div> </div> <button class="btn layui-btn layui-btn-danger" @click="resultEvent">确认</button> </div> </template> <script> import {mapState} from "vuex" export default { data () { return { } }, computed:{ resultNum () { return this.$store.state.resultNum } }, methods:{ resultEvent () { this.$store.dispatch('resultevent') } } } </script> <style scoped> .inputBox{ overflow: hidden; } .layui-form-item{ float: right; margin-top: 15px; } button{ float: right; margin-top: 15px; } </style>
XTGL.vue 父组件
<template> <div id="XTGLPage" class="XTGLPage"> <showBox></showBox> <inputBox></inputBox> <calcBox></calcBox> <outputBox></outputBox> </div> </template> <script> import showBox from "./chlidComponents/showBox.vue" import inputBox from "./chlidComponents/inputBox.vue" import calcBox from "./chlidComponents/calc.vue" import outputBox from "./chlidComponents/outputBox.vue" export default { name:'', data () { return { } }, components:{ inputBox, showBox, calcBox, outputBox } } </script> <style scoped> .XTGLPage{ width: 500px; height: 400px; padding: 30px 20px 0; border: 2px solid #ccc; box-shadow: 10 10 0 0 #333; background-color: #ccc; } </style>
store 中 store.js 部分 完整操作是 '自下往上'
import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const store = new Vuex.Store({ state:{ inputNum:'', outputNum:'', resultNum:'' }, mutations:{ //格式:类型(名字)+处理函数 //大写 //inputNum赋值 INPUTEVENT(state,value) { state.inputNum += value state.outputNum = value }, //加 INCREMENT(state,value) { state.inputNum += '+1' state.outputNum++ }, //减 DECREMENT(state,value) { state.inputNum += '-1' state.outputNum-- }, //结果 RESULTEVENT(state){ state.resultNum = state.outputNum console.log(state.resultNum) } }, actions:{ //小写 inputevent({commit},value){ commit("INPUTEVENT",value) }, increment({commit},value){ commit("INCREMENT",value) }, decrement({commit},value){ commit("DECREMENT",value) }, resultevent({commit}){ commit("RESULTEVENT") } } }) export default store
代码比较多,文字解释待加入,先看效果图:
操作复杂度,逻辑复杂度为0,自己都尴尬的设计,希望对于学习、理解 Vuex 有些许帮助!