Vuex使用详解,附加项目遇到的问题(简单明了)

 

Vuex的定义、个人理解和结构解析

 

vuex定义:vuex是一个专门为vue.js设计的集中式状态管理架构。

vuex的个人理解:

是存储公有状态数据state的一个仓库(store);解决了大型应用时组件传参的繁杂和不易维护性;vuex的状态储存是响应的,store中状态发生改变后相应组件会得到更新;不能直接修改store中的状态,唯一途径是显示的提交(commit)mutation, 可以通过getter获取state的派生值;

 

Vuex结构组成:

Store(仓库):

State(状态):负责存储应用的状态数据,可以理解为数据容器;组件中获取vuex中的数据时使用this.$store.state.stateName来获取;

Mutations(变化):利用它来更改状态state数据,本质是处理数据的函数,其接收唯一参数值state。我们可以在methods方法中使用this.$store.commit(‘mutationName’);来触发一个mutation的方法;必须是同步函数,否则devtool中的数据将会出现问题;

Actions:通过触发mutation来修改state状态,重要的是可以异步改变state状态,在methods方法中使用this.$store.dispatch(actionName);直接触发

Getters:有些状态需要进行二次处理就可以使用getters,可以在方法中使用this.$store.getters.valueName对派生出来的状态数据进行访问;当依赖发生改变时会改变

 

mapActions、mapMutations、mapGetters、mapState:是利用辅助函数将actions、mutations、getters、state映射到本地计算属性或methods方法中去;使用前需引入映射如:    import {mapGetters} from ‘vuex’

 

vuex的demo实践:

第一步:创建项目

    基于vue-cli脚手架生成一个vue项目;

    常用命令:

        npm i vue-cli --g                     来安装vue-cli

         vue --vesion  或  vue -V        来检查vue安装是否成功

         vue init webpack 项目名       来创建vue-cli 脚手架项目

 

注意:运行 npm i vue-cli --g 安装vue-cli“ WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen) ” 错误时可以尝试 使用   cnpm i vue-cli --g  安装

 

第二步:检查项目是否创建成功,安装vuex

          npm run dev                        来运行vue项目

          npm i vuex --save               来安装vuex

 

第三步:代码实现父子组件通过vuex传递参数Demo

效果:

 

1、项目文件结构如下: 创建父子组件文件和store.js文件

 

2、Store.js文件引用vuex如下:

import Vue from 'vue';
import Vuex from 'vuex';

//vue引用vuex
Vue.use(Vuex);

//state状态数据容器
const state={
   testMsg:"state中的一行测试文本",
   parentMsg:"父组件原始文本",
   childMsg:"子组件原始文本",
   count:99,
}

//修改satate的方法,就是state状态数据的处理函数
const mutations= {
   changeParentMsg:function(state,str){
      state.parentMsg=str;
   },
   changeChildMsg:function(state,str){
      state.childMsg=str;
   },
}

//异步,通过commit触发mutations中的方法来修改state
const actions={
   changeParentTxt({commit},data){
      commit('changeParentMsg',data);
   },
   changeChildTxt:function(context,data){
      context.commit('changeChildMsg',data);
   },
   //上述两个方法中的参数使用{commit}和context均有效,context代表store本身
}

//对获取到的state数据进行过滤修改
const getters={
   countNum:function(state){
      if(state.count>100){
         return state.count+100;
      }else {
         return state.count-50;
      }
   }
}

//创建store实例,将在main.js文件中将它加入到vue实例对象中
export default new Vuex.Store({   //export default 是封装代码,使外部可用
   state,  //依此加入到store对象中
   mutations,
   actions,
   getters,
});

3、Main.js文件在vue实例中引用store对象:

将store实例从根组件中‘注入’到子组件中,子组件通过‘this.$store’调用

 

4、组件文件:

     HelloWorld.vue

<template>
  <div class="hello">
    <h3>测试文本如下:</h3>
    <p>在组件模板中直接输出获取值:{{$store.state.testMsg}}</p>
    <hr>
    <Parent></Parent>
    <hr>
    <h4>getters获取state的值修改后如下:</h4>
    <p>{{$store.getters.countNum}}</p>
  </div>
</template>

<script>
import Parent from './Parent'
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  components:{
    Parent
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}

</style>

     Parent.vue

<template>
   <div>
      <div class="parentContainer">
         <div>
            <h3>父组件的内容:</h3>
            <p class="txt">{{oldtxt}}</p>
         </div>
         <button class="btn" @click="changeParentTxt()">点击更改父组件内容</button>
         <button class="btn" @click="changeChildTxt()">点击更改子组件内容</button>
      </div>
      <Child></Child>
   </div>
</template>
<style>
   .parentContainer {
      height:150px;
      width:350px;
      background-color: lightblue;
      color:#fff;
      margin:10px auto;
   }
   .txt {
      border:1px solid red;
      padding:10px;
   }
   .btn {
      background-color: #fff;
      color: #000;
   }
</style>
<script>
   import Child from './Child'
   export default {
      name:"Parent",
      data(){
         return {

         }
      },
      components:{
         Child,
      },
      computed:{
         oldtxt:function(){
            return this.$store.state.parentMsg;
         }
      },
      methods:{
         changeParentTxt:function(){
            let newParentTxt="更改后的父组件内容变长的很多!!!";
            this.$store.dispatch('changeParentTxt',newParentTxt);
         },
         changeChildTxt:function(){
            let newChildTxt="这里是父组件点击修改后的文本内容....";
            this.$store.dispatch('changeChildTxt',newChildTxt);
         },
      },
   }
</script>

 

     Child.vue

<template>
   <div class="childContainer">
      <div>
         <h3>子组件的内容:</h3>
         <p class="txt">{{oldtxt}}</p>
      </div>
      <button class="btn" @click="changeChildTxt2()">点击更改子组件内容</button>
      <button class="btn" @click="changeParentTxt2()">点击更改父组件内容</button>
   </div>
</template>
<style>
   .childContainer {
      height:150px;
      width:350px;
      background-color: lightcoral;
      color:#fff;
      margin:10px auto;
   }
   .txt {
      border:1px solid red;
      padding:10px;
   }
   .btn {
      background-color: #fff;
      color: #000;
   }
</style>
<script>
   export default {
      name:"Child",
      data(){
         return {

         }
      },
      computed:{
         oldtxt:function(){
            return this.$store.state.childMsg;
         }
      },
      methods:{
         changeParentTxt2:function(){
            let newParentTxt="我这是通过子组件修改父组件state后获取到的文字!!!";
            this.$store.dispatch('changeParentTxt',newParentTxt);
         },
         changeChildTxt2:function(){
            let newChildTxt="点击子组件按钮后内容变成了这样!!!";
            this.$store.dispatch('changeChildTxt',newChildTxt);
         },
      },
   }
</script>

 

Vuex在项目中代码使用详解

1、组件模板获取state状态数据:将状态对象赋值给内部对象,也就是将stroe.js中的值赋值给模板中的data中的值,有三种赋值方式:

      ①使用computed计算属性直接赋值;

      ②使用mapState辅助函数来赋值(将state值映射到局部计算属性);

      ③使用mapState的数组来赋值;

    <div>computed计算属性获取的值:{{count01}}</div>
    <div>使用mapState辅助函数来赋值:{{count02}} </div>
    <div>使用mapState的数组来赋值:{{count}} </div>
  computed:{ //多个computed时,后面的会覆盖前面的
    count01(){  //普通计算属性
      return this.$store.state.count;
    },
    ...mapState({  //mapState(obj)对象辅助函数赋值
      count02:(state)=>{return state.count}  //ES6的箭头函数
    }),
    ...mapState(['count'])  //mapState(arr)数组来赋值
  }

 

2、getters获取的是经过加工过滤后的state状态数据。

//store.js中getters定义
//对获取到的state数据进行过滤修改
const getters={
  changeCount:function(state){
    if(state.count>100){
      return state.count*2;
    }else {
      return state.count-1;
    }
  }
}

const mutations= {
   addCount:function(state,num){
    return state.count+=num;
   },
}
// 组件模板中使用mapGetters
<template>
   <div class="childContainer">
      <h3>原值:{{count}}</h3>
      <h3>getter加工过滤后的值:{{changeCount}}</h3>
      <button @click="$store.commit('addCount',20)">点击数字加20</button>
   </div>
</template>
<script>
import {mapState,mapMutations, mapGetters} from 'vuex'
   export default {
      name:"Child",
      data(){
         return {
         }
      },
      computed:{
        ...mapState(['count']),
        ...mapGetters(['changeCount']),
      },
      methods:{
        ...mapMutations(['reduceCount']),
      },
   }
</script>

同理在组件模板可以通过this.$store.getters.changeCount来获取store中过滤更改后的count值;

mapGetters辅助函数和mapState辅助函数类似是将store中的getter 映射到局部计算属性computed中,mapGetters使用前先import引入;

 

3、组件模板更改store中的state值通过mutations中的方法:mutations同步更改状态($store.commit('mutationName'))的方式:

     ①使用this.$store.commit('mutationName');

//store.js
//mutations中更改satate的方法,就是state状态数据的处理函数
const mutations= {
   addCount:function(state,num){
    return state.count+=num;
   },
   reduceCount:function(state,num){
    return state.count-=num;
   },
}
 <button class="btn" @click="$store.commit('addCount',50)">点击使用commit直接触发mutations中的方法</button>

   

②使用mapMutations辅助函数将mutations中的方法映射到methods中; 

a、组件中首先需要使用import 引入mapMutations和mapState(依赖性),如

import {mapState,mapMutations} from 'vuex'

b、将mutations中的方法映射到methods中; 

methods:{
    ...mapMutations(['reduceCount']),
},

c、组件模板中直接使用映射的方法如:

<button class="btn" @click="reduceCount(20)">通过mapMutations触发mutations中的方法</button>

 

4、actions异步更改状态state,actions方法通过mutations中方法来更改state,actions中的方法有两种写法如下:

//异步,通过commit触发mutations中的方法来修改state
const actions={
   changeParentTxt({commit},data){
      commit('changeParentMsg',data);
   },
   changeChildTxt:function(context,data){
      context.commit('changeChildMsg',data);
   },
   //上述两个方法中的参数使用{commit}和context均有效,context代表store本身
}

mapActions的使用类似mapMutations将方法映射到methods中,组件模板使用前先 import 引用mapActions、mapMutations、mapState;

methods:{
    changeCountNum:function(){
       this.$store.dispatch("countNum_action",99);  //$store.dispatch("actionName");直接触发actions中的方法
    },
},

 

5、module模块组:为解决state状态对象过多而杂的问题,我们将一个store划分为多个module模块,每个模块拥有自己的state、mutations、actions、getters使用如下

①store.js中是声明modules

//声明模块组module
const moduleA={
  state:{
    name:'zhangsan',
    age:27
  },
  mutations:{},
  actions:{},
  getters:{}
};

const moduleB={
  state:{
    name:'wangwu',
    age:26
  },
  mutations:{},
  actions:{},
  getters:{}
};

export default new Vuex.Store({
  modules:{a:moduleA,b:moduleB}  //使用a做为moduleA的别名,b同理
});

②模板组件中获取指定module中的state数据有以下两种方式

<div>模块A的name值是:{{$store.state.b.name}}</div>
computed:{
    moduleAname:function(){
       return this.$store.state.a.name;
    }
},

 

PS附加:

1、如果store文件太大,也可以将 action、mutation 和 getter 分割到单独的文件。分割的文件需要export  default 导出,并在store.js文件中的import 导入,如下

//mymutations.js 文件
const mutations= {
   changeParentMsg:function(state,str){
      state.parentMsg=str;
   },
   changeChildMsg:function(state,str){
      state.childMsg=str;
   },
}
export default mutations
import state from './mystate'
import mutations from './mymutation'
import actions from './myactions'

export default new Vuex.Store({
   state,  
   mutations,
   actions,
   getters,
});

2、在vue 的构造器里边只能有一个computed属性,如果你写多个,只有最后一个computed属性可用;

 

3、vuex数据在页面刷新时数据会丢失问题,解决思路是vuex更改state数据时同时存储到sessionStorage,当getters获取state数据时判断state为空时对应sessionStorage是否存在,为true则获取sessionStorage赋值给丢失了数据的stateName,如下:

//store.js中定义getters获取时为空会判断从sessionStorage获取值或初始值
const getters={
   countNum:function(state){
      if(!state.count){
        state.count=10; //首次num数值为空初始值赋值为10
        let sessionVal=sessionStorage.getItem("count_num");
        if(sessionVal){
          state.count=parseInt(sessionVal);
        }
      }
      return state.count
   }
}

//store.js中定义mutations更改state后存储到sessionStorage
const mutations= {
   change_numCount:function(state,data){
    state.count=data;
    sessionStorage.setItem('count_num',data);
  },
}
//组件模板中触发更改state状态数据的action方法
methods:{
   changeCountNum:function(){  
      this.$store.dispatch("countNum_action",99);
   },
},

 

参考网址:https://blog.csdn.net/H5_QueenStyle12/article/details/75386359

https://blog.csdn.net/mjzhang1993/article/details/78321903

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值