Vue-Vuex 小白学习笔记
什么是Vuex ?
我的理解就是在多个组件想公用一些数据或者是状态;因为组件们是通过一种组件树的形式互相关系所以一个组件想要获得另一个组件的数据就显得特别麻烦,除了父子组件之间的传递。
你可以看看我画的图:
画得有点扯了,勉强用吧:)
如果这里 我的4 组件想要获取1组件的东西怎么办呢,如果先到获取到3再获取到2再获取1组件,这样太麻烦
于是Vue引入了一个Vuex的概念
可以把所有的组件所需要的数据存放到一个对象里
然后这个对象放在顶层的Vue实例里面,然后所有组件都能用
在项目里实例:头像,登陆状态,名称、地址等
但是在多个组件同时控制一个数据时,不知道到底是谁先后改变了数据,显得很乱
状态管理是怎么进行的呢?
我们先看一个组件的状态管理过程:
通过这个图分析开来:
首先有数据状态State展现在view里然后view里又有一些行为actions 改变了这个State ,然后又重新渲染这个view
案例
<template> <div id="app"> <h2>{{message}}</h2> <h2>{{counter}}</h2> <button @click="counter++">+</button> <button @click="cunter--">-</button> </div> </template> <script> export default { name: 'App', data() { return { message: '我是首页', counter: 0 } } } </script> <style> </style>
结果图:
这是单个页面两个按钮控制这个数字的增长减少;
然后新创一个HelloVuex组件怎么来也控制这个counter?
这个时候就要请出我们的vuex了
先安装
npm install vuex --save
然后src下创一个叫store,推荐取这个名字,企业,官方都取的这个,意思就是仓库的意思
index.js配置
import Vue from 'vue' import Vuex from 'vuex' //1.安装插件 Vue.use(Vuex) //2.创建对象 const store = new Vuex.Store({ //状态 state: { counter:1000 }, // 改变 mutations: { }, // 行为 异步操作 actions: { }, // 吸,除 getters: { // 模块 }, modules: { } }) export default store
怎么拿到这个状态counter?
直接$store.state.counter
在使用和修改等操作都需要依照vue的规定来,就要看下面这个图了。
我们就不能想上面第一张过程图一样修改了数据了而是
通过三大关
首先
发布(diapath)一个行为(actions),
然后提交(commit)到 mutate然后通过它修改,再传到state
这里vue官方有个插件可以监听跟踪状态和谁改的状态,非常的方便········>devtools
图解释完了就是几个
核心
state
就是把需要共享控制的状态放在这里 eg:counter
这里Vuex提出了一个单一状态树,就使用一个Store 来管理我们的状态,因为有人可能创建多个Store 来分类管理,其实这样很难维护,所以提出了单一状态树
getters
相当于就是一个计算属性
当我们要拿state中的counter的平方
平时是这样的:
<h2>{{$store.state.counter*$store.state.counter}}</h2>
通过getters:
先定义
getters: { powerCounter(state) { return state.counter * state.counter } },
后使用
<h2>---------------------Getters内容------------</h2> <h2>{{$store.getters.powerCounter}}</h2>
显示的结果是一样的
注意getter中的函数可以传两个参数(state,getter)
想在里面实在传参数的话就要在里面写一个return function(参数)
mutation
是Vuex唯一的修改状态的方法提交Mutation类似于方法(methods)
怎么使用?
先在Store中的mutation中定义事件类型:
// 改变 mutations: { increment(state) { //increment就是事件类型 state.counter++ }, decrement(state) { state.counter-- } },
然后在组件里面添加方法:
<button @click="addcounter">+</button> <button @click="subcounter">-</button> 方法: methods: { addcounter() { //方法中提交到store的方法事件中 this.$store.commit('increment') }, subcounter() { //方法中提交到store的方法事件中
this.$store.commit('decrement')
}
},
添加参数:
//未添加参数
<button @click="addcounter">+</button> <button @click="subcounter">-</button> -------------------------------------------------
//添加参数
<button @click="addCount(5)">+5</button> <button @click="addCount(-5)">-5</button>
方法: methods: {
//未添加参数 addcounter() { this.$store.commit('increment') }, subcounter() { this.$store.commit('decrement') }, --------------------------------------------
添加参数
addCount(count) { this.$store.commit('addnum', count) } }, 改变事件mutations: mutations: {
未添加参数 increment(state) { state.counter++ }, decrement(state) { state.counter-- }, ----------------------------------------------
添加参数
addnum(state, count) { state.counter += count } },
其实mutation参数官网称为载荷Payload
封装提交
以下是我们的普通提交:
this.$store.commit('addnum', count)
其实还有可以封装提交:
addCount(count) { this.$store.commit({ type: 'addnum', count })
但是在store中mutation处理就要改变一下
如果还是和以前一样
addnum(state, count) { state.counter += count }
这里的count就不是原来的count了而是一个对象就是前面我们说的Payload载体,只是名字换成了count,所以使用的话就没法正常使用。
于是:
addnum(state, payload) { state.counter += payload.count }
载体paload这个对象包含了这个count。
Vuex数据的响应式原理
原理:
store中的state数据都会加入到响应式数据里
而响应式系统会监听属性的变化
当属性发生变化
系统会通知所有用到这些属性的界面发生刷新
注意:
这些属性必须是先在store中定义好的,如果是后面通过方法push、pop的属性添加是不会响应式的
但是我们可以用splic、set方法来添加这个是响应式的;
删除的直接delete state.xxxx.xx也不是响应式的
需要Vue.delete(state.xxxx.xx)则是响应式的
Vuex.mutation 的类型常量
为什么?
以为mutation的事件类型会多处使用,所以,
为了避免mutation的事件类型名称写错,我们专门创个mutation-type.js文件
const INCREMENT = 'increment', const DECREMENT = 'decrement' export { INCREMENT, DECREMENT }
然后组件引入使用我们定义的名字
import { INCREMENT, DECREMENT } from './store/mutation-type' addcounter() { this.$store.commit(INCREMENT) }, subcounter() { this.$store.commit(DECREMENT) },
store中muatations加[ ]使用
import { INCREMENT, DECREMENT } from './mutation-type' mutations: { [INCREMENT](state) { state.counter++ }, [DECREMENT](state) { state.counter-- }, }
这样即使我们在mutation-type中写错了,也可以正常使用。
简直妙不可言:)
actions:
作用:
在mutation加一个延时函数settimeout进行我们的数据修改的话,
页面发生变化,但是在mutation devtool工具中的状态还是没有变化,于是Vuex提出不能再mutation中执行异步任务;
但是我们有的时候要使用到异步任务,eg:网络请求
于是就要用active:就是来做异步任务
当有异步任务时:
我们其实是先在组件中 dispatch到actions再commit到mutations
就是比以前多了一个dispatch
dispacth:
modfiytext() { this.$store.dispatch('aUPdataInfo', { message: 'active-dispatch携带的信息', success: () => { console.log('任务完成'); } }) }
actives:
// 行为 actions: { // context 上下文 默认属性 aUPdataInfo(context, payload) { setTimeout(() => { context.commit('modifytext', payload) console.log(payload.message); payload.success() }, 1000); } },
还有一种写法:
//index.js aUPdataInfo(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('modifytext', payload) console.log(payload.message) resolve(111111) }, 1000); }) } //App.vue
直接返回一个Promise
modules
因为vuex全都把状态放到一个state里 会显得很臃肿,这时就有了模块化;
这个非常的简单,
// 模块 modules: { a: moduleA } const moduleA = { state: { name: '李四' }, mutations: { updataname(state, payload) { state.name = payload } },
getters:{},
actives:{},
}
就是一样的 只是分出去了,但是调用的时候是在一起的
注意:
在使用模块的state时要加定义的名字,其他的不用,和一起一样使用
<h2>{{$store.state.a.name}}</h2>
还有actives只能调用模块内的mutations
大概了解了后,页面就是太乱了,所以我们通过对象结构给抽出来就可以了
然后导出引用到index.js,就很简洁了,要修改响应的东西时就可以到响应的文件中修改