Vuex随笔

Vuex

  1. 本质上使用Vuex的原因其实是组件之间的数据交互过于复杂,重点在于当组件过多时,数据的传递就会不可控,所以引入 Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式。它采用集中式管理应用的所有组件的状态,并以相应 的规则保证状态以一种可预测的方式发生变化。

  2. 回顾数据传递方式:props , 自定义事件$emit(.sync) , EventBus , $parent , $root,vuex 。
    组件较少的情况下传递数据可以使用EventBus ; 组件特别多,而且对数据要求可预测改变就应该使用Vuex。开发大型单页面应用时用Vuex,简单的SPA不要使用。

  3. 代码执行流程:

    1. 创建store
    2. 创建state
    3. 创建mutations
    4. 创建actions
    5. 创建modules
  4. 操作store

    1. 读取state
      快捷方案:computed --> state getter
    2. 设置state(修改)
      快捷方案:methods -->mutations actions
  5. 表单相关
    表单操作:
    1. 使用 v-model 解决方案:get 和 set
    2. 不使用 v-model 解决方案:通过事件

  6. 边缘化操作

    1. 项目结构
    2. 插件
    3. 严格模式 =》安全的操作方式
    4. 热重载:方便开发人员调试

Vuex核心知识点

Store(仓库):一个项目只能有一个store仓库
State(状态):数据
Mutation(计算方式):只能通过此方法修改state状态
Action(动作):异步操作的核心
Getter(读取数据的方案):可选项,读取的容错方式
Module(模块):分解state,避免state过多引起臃肿

Vuex执行流程:VueComponent —dispatch—> Actions —commit—> Mutations —mutate—> state —render—> VueComponent

安装并引入

npm install --save es6-promise(Vuex依赖于es-promise)
npm install --save vuex

import 'es6-promise/auto'
import Vuex from 'vuex'
Vue.use(Vuex)

Vuex和全局对象的区别

全局对象:Vue.prototype.$api = api ; //此时给两个页面分别通过
this.$api 都使用一次,然后改变其中一个页面的$api的值,另一个组件的值不会改变。
Vuex : this.$store.state.对象名.key 如果其中一个改变则另外一个响应的也改变。

创建仓库

创建一个store文件夹,创建index.js并配置
const store = new Vuex.Store({
	      state : {
	      		obj : {
					name : "apple",
					pic : 0
	      		}
	       }
	})
然后挂载到 new Vue({     //主入口文件main.js
		     render : h => h(App),
		     store
		}).$mount('#app')

显示 :产品:{{ this.$store.state.obj.name }}
	   价格:{{ this.$store.state.obj.pic }}

分离 store文件:src下创建一个 store,里边创建 index.js引入配置导出,main.js引入使用。

State快捷读取方法

mapState辅助函数:

import { mapState } from 'vuex'
	写法1 :computed : mapState({
		     msg : state => state.obj
		})
	写法2:computed : {
		     ...mapState(["obj","...",,,]) //必须是字符串
		}

Mutation

更改 Vuex 中的 store 中的状态的唯一方法是提交 mutation。

在 index.js 中配置, 和 state 同级配置:
	mutations:{
	          increment(state){    //参数state指的就是同级的state
    	             state.obj.pic++
    	          },
        	       decrement(state){   
            		state.obj.pic --
        	        }
在组件中配置:
	<button @click="addHandle">增加</button>
    <button @click="minHandle">减少</button>
	addHandle(){
            	this.$store.commit("increment") 
       	 },
    minHandle(){
            	this.$store.commit("decrement")
       	 }

提交载荷(Payload)

在index.js中配置, 和 state 同级配置:
	mutations:{
	       //     increment(state,n){   //写法1
    	       //         state.obj.pic+=n
    	       //     },
        	       increment(state,payload){   //写法2
            		state.obj.pic += payload.num
        	       },
        	       decrement(state,{ num }){   //写法3:es6解构赋值
            		state.obj.pic -= num
      }

在组件中配置:
	<button @click="addHandle">增加</button>
        	<button @click="minHandle">减少</button>
        	<input placeholder="请输入" type="text" v-model="num">

	methods:{
        	       addHandle(){
         		// this.$store.commit("increment",parseInt(this.num))  //写法1
            		this.$store.commit("increment",{    //写法2
                		num : parseInt(this.num)
            		})
		this.$store.commit({   //写法3
                		type:"increment",
                		num : parseInt(this.num)
            		})
        	        },
        	        minHandle(){
            		// this.$store.commit("decrement",parseInt(this.num))
            		this.$store.commit("decrement",{
                		num : parseInt(this.num)
            		})
        	         }
    	}

Mutation遵循Vue的响应规则

就和数组,对象的更新检测一个意思
例如:需求要给state仓库添加一个值,同时页面也要显示

在vuex.js中配置, 和 state 同级配置:
	mutatios : {
	        xiangying(state,payload){
            		// state.obj.aa = payload.msg;//仓库加进去了但是页面不显示,和数组对象更新检测同理
            		Vue.set(state.obj,"aa",payload.msg);//成功
        	         }
	  }
在组件中配置:
	aa:{{ this.$store.state.obj.aa }}
	data(){ return{ msg : "我是新添加的产品" }}
	methods:{
	         tianjia(){
            		this.$store.commit("xiangying",{
                	            msg : this.msg
            	                })
        	          }
	  }
  1. 以新对象替换老对象
    利用对象展开运算符我们可以这样写:
    state.obj = { …state.obj, newProp: 123 }

  2. 使用常量替代 Mutation 事件类型
    在vuex文件夹下创建一个 mutation-type.js 文件,导出
    export const INCREMENT = “INCREMENT”;
    export const DECREMENT = “DECRMENT”;
    随后在vue.js和组件使用vuex的地方,引入并把字符串“increment”"decrement"替换掉
    import { INCREMENT,DECREMENT } from ‘./mutation-type’

Mutation必须是同步函数(重点)

待补充。。。

在组件中提交Mutation(快捷方案)

import { mapMutations } from 'vuex'

        methods:{
        ...mapMutations([INCREMENT,DECREMENT,"xiangying"]),//...是es6高级语法,这里的这个包 core-js 经常丢包,重装一下就行。
        addHandle(){
            
            // this.$store.commit({   //写法3
            //     type:INCREMENT,
            //     num : parseInt(this.num)
            // })

            this[INCREMENT]({ num : parseInt(this.num) })  //写法4
        },
        minHandle(){

            // this.$store.commit(DECREMENT,{
            //     num : parseInt(this.num)
            // })

            this[DECREMENT]({ num : parseInt(this.num) })
        },
        tianjia(){

            // this.$store.commit("xiangying",{
            //     msg : this.msg
            // })

            this.xiangying({ msg:this.msg })
        }
    }

Action

Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作,有异步操作时action才有意义。

index.js中配置
	const store = new Vuex.Store({
	         state : {
		banner : { }   //定义一个存储仓库
	         },
	         mutations : {
		setBanner(state,payload){
          		          //异步请求数据
          		          state.banner = payload.banner; //把参数的值赋值到仓库
        		}
	         },
	         actions : { 
		asyncBanner(context,url){      //定义一个异步请求方法,参数context固定,url地址
        		        axios.get(url).then(res=>{
          			context.commit("setBanner",res.data);//通过context.commit提交一个mutation
        		         })
      		}
	         }
	})
组件中配置:
	<button @click="asyncAction">action提交异步请求</button>
        	<ul>
            	        <li v-for="(item,index) in banner" :key="index">{{item.title}}</li>
        	</ul>
	import { mapState } from 'vuex'
	 computed:mapState({
        	         banner : state => state.banner   //将仓库中的banner存放到变量banner中
	         //...mapState([ "banner" ])   //写法2
    	}),
    	methods:{
        	         asyncAction(){   //定义一个方法
            		this.$store.dispatch("asyncBanner","http://iwenwiki.com/api/blueberrypai/getIndexBanner.php");  //通过dispatch分发action
        	         }
    	}

在组件中分发action

 组件中配置:
	import { mapState,mapActions } from 'vuex'   
	 methods:{
        	         ...mapActions(["asyncBanner"]), //写法2
        	         asyncAction(){
            		// this.$store.dispatch("asyncBanner","http://iwenwiki.com/api/blueberrypai/getIndexBanner.php");//写法1
            		this.asyncBanner("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php"); //写法2
        	         }
    	}

Getter

对store中的state的状态的验证修改

  1. 需求:假设产品价格最高不超过100,最低不低于1
index.js配置:
	const store = new Vuex.Store({
	          getters:{
      		getPic(state){
        		      if(state.obj.pic > 100 || state.obj.pic <= 0){
          			return "价格出错了"
        		         }else{
          			return state.obj.pic;
        		         }
     		 }
   	          }
  	})

在组件中读取 :{{ this.$store.getters.getPic }}
  1. 通过属性访问
index.js配置:
	const store = new Vuex.Store({
	     getters:{
	          getPic(state,getter){
        		console.log(getter);
        		if(state.obj.pic > 100 || state.obj.pic <= 0){
          			// return "价格出错了";    //方法1
          			return getter.getHello;    //方法2
        		}else{
          			return state.obj.pic;
        		}
      	           },
      	          getHello(){
        		return "价格出错了";
      	          }
	      }
  	})
  1. 通过方法访问
  2. mapGetters 辅助函数
组件读取:
	import { mapGetters  } from 'vuex'
	computed : mapState({
        	         ...mapGetters(["getPic"])
    	})
    	
	<div> 价格:{{ getPic }} </div>

项目结构

├── index.html
├── main.js
├── api
│ └── … # 抽取出API请求
├── components
│ ├── App.vue
│ └── …
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块

Module

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

// 创建Store仓库
const store = new Vuex.Store({
    state : defaultStore,
    mutations : defaultMutations,
    actions : defaultActions,
    getters : defaultGetters,
    modules:{
      //拥有完整的vuex结构
      moduleA : {
        namespaced : true,  //命名空间
        state : {
          msg : "我是moduleA的"
        },
        mutations : {

        },
        actions : {

        },
        getters : {

        }
      },
      moduleB : {
        namespaced:true,
        state : {
          msg : "我是moduleB的"
        },
       .....
      },
      // moduleC....
    }
  })
 读取moduleA 和 moduleB 的值:
	方式1直接读取 : {{ this.$store.state.moduleA.msg }}
	读取方式2{{ msg }}--{{str}}
	import { mapState } from 'vuex'
	computed:{  //计算属性
        	        ...mapState("moduleA",{   //这种读取方式必需设置命名空间 namespaced:true 才能读到
            		msg : state => state.msg
        	          }),
        	        ...mapState("moduleB",{
            		str : state => state.msg
       	          })
    	  }

Vuex动态模块

可以使用 store.registerModule 动态创建,使用 store.unregisterModule(模块名) 来动态卸载模块,使用 store.hasModule(moduleName) 方法检查该模块是否已经被注册到 store。

插件

Vuex 的 store 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数:

在index.js中配置:
	const myPlugin = store =>{
  	        //当store初始化后调用
  	         store.subscribe((mutation,state)=>{
    		console.log( mutation , state);
 	          })
	}
	
	// 在Store仓库引用
	const store = new Vuex.Store({
	         plugins : [myPlugin , ......],
	})

严格模式

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。然而在mounted生命周期函数中和标签中直接用 = 赋值,都可以改变它的值。为了解决这个问题,严格模式由此而生,仅需在创建 store 的时候传入 strict : true ,在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

const store = new Vuex.Store({
  	          strict : true
		// ...
	})

【注意】:不要在发布环境下启用严格模式!请确保在发布环境下关闭严格模式,以避免性能损失。类似于插件,我们可以让构建工具来处理这种情况 strict : process.env.NODE_ENV !== 'production’

const store = new Vuex.Store({
  		// ...
  		//直接写这种就行,自动识别
  		strict : process.env.NODE_ENV !== 'production'  
	})

表单处理

建议使用v-model模式

Vuex热重载

方便开发阶段调试

  1. 热更新:浏览器自动刷新 webpack(我们在开发阶段在浏览器控制台添加调试的都会重置)

  2. 热重载:浏览器不刷新,但是数据要更新(不会重置)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值