vuex

vuex 基本使用

1. 安装 vuex

npm i vuex 

2. 在vue项目下的src目录下创建一个 store 目录,并在里面创建一个 index.js 文件

image-20200530220930581.png

3. 在 index.js 中 书写关于仓库的代码

// index.js

// 引入 vue
import Vue from 'vue';
//引入 vuex
import Vuex from 'vuex'

// 1. 安装插件 在 vue 中使用Vue
Vue.use(Vuex);

// 2. 创建对象
const store = new Vuex.Store({
  state: {
    myname: '',
    count: 100,
    list: [{
        name: "ming",
        score: 40
      },
      {
        name: "gang",
        score: 50
      },
      {
        name: "lan",
        score: 60
      },
      {
        name: "mei",
        score: 70
      },
      {
        name: "tian",
        score: 80
      },
      {
        name: "bai",
        score: 90
      },
    ],      

  },
  mutations: {
    // 方法
    // 这里通过是通过 action 里面的 asyncSaveName 方法触发的次方法
    // 因为 action 里面的方法不能修改 state 里面的数据,只能通过 mutations 里面的方
    // 法来修改.
    saveName(state,n){
      // console.log('从action 传过来的数据', n, state);
      // 通过
      state.myname = n.username;
    },
    increment() {
      // console.log(arguments);
      this.state.count++;
    },
    decrement() {
      this.state.count--;
    },
    add(state,n){
      state.stus.push(n);
    },
  },
  //相当于vue的 computed 计算属性
  getters: {
    // 这里是吧上面的 list 数组当中成绩小于60分的数据过滤出来
    faileNum(state){
      return (function(){
        // console.log(arguments);
        return state.list.filter(item => item.score < 60)
      })();
    }
  },
  actions: {
    //在组件当中调用登录接口,如果登录成功那么触发这个方法,把用户名保存到state当中
    // 的 myname 
    asyncSaveName(context,n){
    // console.log('登录成功action被调用', context,n);
    //这里面不能直接修改 state 中的数据 需要提交 mutations 在 mutations 当中的方法
    // 修改 saveName 为 mutations 里面的方法
    context.commit('saveName',n)
      
    }
  },
  modules: {},
})

// 3. 导出store对象
export default store;

// index.js

// store 里面包含 5个模块 
const store = new Vuex.Store({
    // state 存放数据的地方
    state:{},
    //相当于vue的 computed 计算属性
    getters:{},
    // 如果要修改仓库里面的数据 也就是修改 state 里面的数据需要提交 mutations 来修改
    // 并且 mutations 里面不能有异步操作
    mutations:{],
    //actions 是做异步操作的地方 发送请求之类的异步操作都要在 actions 里面做
    // 并且在 actions 里面 也必须提交 mutations  
    actions:{},
    // 如果项目非常大,所有组件数据放到一起管理,非常不方便,并且容易混淆
    // 通过 modules 把仓库分成 多个模块 不同组件的值,保证到不同模块当中
    // 在把模块注入到根仓库中 方便管理
    modules:{}
})

4. 在页面中展示 vuex 里面的数据

  • 目前仓库有以下数据
 state: {
    myname: '',
    count: 100,
    list: [{
        name: "ming",
  • 现在把 state 里面的 count 展示到页面上
  • vue 官网提供两种方式展示
    1. 直接在模板写 $store.state.***
    2. 先引入 mapState 并在计算属性当中写上 ...mapState([ 'count', 'myname’ ])
    3. 单引号里面写的是 你要展示的数据 可以通过 逗号隔开 写上多个
    4. 之后可以在模板当中直接 写 count 就能展示数据了
// store.vue 

<template>
  <div>
    <h1>{{name}}</h1>
    <div>
      <!-- <button @click="add" >+</button> -->
      <p> 使用 $store.state.count 展示数据 {{$store.state.count}}</p> <!--100-->
      <p> 使用...mapState(['count'])展示数据 {{count}}</p> <!--100-->
        
      <!-- <button @click="sub" >+</button> -->
    </div>
  </div>
</template>
 
<script>
import {mapState} from 'vuex'
export default {
  data() {
    return {
      name:'Store'
    }
  },
  computed: {
    ...mapState(['count'])
  },
  methods: {
    add(){
      this.$store.commit('increment');
    }
  },
}
</script>

5. 下面介绍 state, getters, mutations, actions 在页面中的一些用法

5.1 state 上面已经说过就不记录了

5.2 getters

  • getters相当于vue 里面的计算属性 computed.

  • 比如我们往仓库中存放了一个 学生成绩对象数据如:

  • const store = new Vuex.Store({
      ......
      state:{
      ......
      list: [{name:'小米',score:50 },
               {name:'小明 ',score:70 },
               {name:'小王 ',score:60 },
               {name:'小李 ',score:90 } 
              ]
      ......
    })
    
  • 现在 页面上要展示 仓库数据中 学生成绩小于60分的数据 我们可以这样写

  • const store = new Vuex.Store({
      ......
      getters: {//返回成绩低于60的数据
          filterScore(state){
              return state.list.filter( item => item.score < 60 )
          }
      },
      ......
    })
    
  • 在页面当中展示

  • 引入 mapGetters 可以使我们少写代码 import {mapState ,mapGetters} from 'vuex';

  • 在计算属性中写 ...mapGetters(['filterScore']) 中括号写 要展示到 模板上的 数据

  • // store.vue
    
    <template>
      <div>
        <h1>{{name}}</h1>
        <div>
          <!-- <button @click="add" >+</button> -->
          <p> 使用 $store.state.count 展示数据 {{$store.state.count}}</p>
          <p> 使用...mapState(['count'])展示数据 {{count}}</p>
            <!--  -->
          <!-- <button @click="sub" >+</button> -->
          <hr>
          <p> getters: </p>
          <p>在计算属性中使用...mapGetters(['filterScore'])展示:</p>
          <p>  {{filterScore}} </p>
          <p> 直接通过$store.getters.getters展示:  </p>
          <p>{{$store.getters.filterScore}}</p>
        </div>
      </div>
    </template>
     
    <script>
    import {mapState ,mapGetters} from 'vuex';
    import { log } from 'util'
    export default {
      data() {
        return {
          name:'Store'
        }
      },
      created(){
        console.log(this.$store);
        
      },
      computed: {
        ...mapState(['count']),
        ...mapGetters(['filterScore'])
      },
      methods: {
        add(){
          this.$store.commit('increment');
        }
      },
    }
    </script>
    

5.3 mutations 不能做异步操作

  • mutations 是修改仓库数据的地方 在里面定义方法 通过触发里面的方法来修改仓库数据

  • 仓库里面有 count:100 的数据,现在我们做一个简单的计数器

  • 首先在 mutations 里面写好要操作的方法

  • const store = new Vuex.Store({
      ......
      state:{
      ......
      count:100,
      ......
      },
      mutations:{
          // 定义加法方法 方法里面可以接受2个参数(state,options)
        // options 通常作为一个对象传入进此方法 
        // state 为当前仓库数据 
        // { num } 是es6结构写法 传过来的对象中包含 num ,那么可以用此方法结构出来
        increment(state,{num}) {
          state.count += num;
        },
        decrement(state, {num}) {
          state.count += num;
        },
      }
      ......
    })
    
  • 在模板中使用出来

  • 定义两个 方法 sub(), add(),

  • 改变仓库中的数据就是提交 mutations

  • 触发 mutations 里面的方法 有两种方式

    1. this.$store.commit('increment',{num:1});// 提交到仓库中的 increment 里面进行数据修改, {num:1} 作为参数传入进去

    2. 第二种通过 mapMutations 不同与 mapState 和 mapGetters 这两种是在计算属性中书写出来, mapMutations 必须写在方法当中 也就是 methods 里面比如

    3. ...... 
      methods: {
          // 这样写好之后可以直接在 模板中使用
          //比如 @cliick='increment({num:1})'
          /*
           <button @click="sub" >-</button>
              {{count}}
            <button @click="increment({num:1})" >+</button>
          */
          // 也可以在方法当中使用 
          /*
          add(){
            // this.increment({num:123})
          },
          */
          ...mapMutations(['increment']),
          add(){
            // this.increment({num:123})
          },
      ......
      
  • //store.vue
    
    <template>
      <div>
        <h1>{{name}}</h1>
        <div>
          <!-- <button @click="add" >+</button> -->
          <p> 使用 $store.state.count 展示数据 {{$store.state.count}}</p>
          <p> 使用...mapState(['count'])展示数据 {{count}}</p>
            <!--  -->
          <!-- <button @click="sub" >+</button> -->
          <hr>
          <p> getters: </p>
          <p>在计算属性中使用...mapGetters(['filterScore'])展示:</p>
          <p>  {{filterScore}} </p>
          <p> 直接通过$store.getters.getters展示:  </p>
          <p>{{$store.getters.filterScore}}</p>
          <hr>
          <p>mutations </p>
          <button @click="sub" >-</button>
            {{count}}
          <button @click="add" >+</button>
          <!-- <button @click="increment({num:1})" >+</button> -->
    
        </div>
      </div>
    </template>
     
    <script>
    import {mapState ,mapGetters,mapMutations} from 'vuex';
    import { log } from 'util'
    export default {
      data() {
        return {
          name:'Store'
        }
      },
      created(){
        console.log(this.$store);
        
      },
      computed: {
        ...mapState(['count']),
        ...mapGetters(['filterScore'])
      },
      methods: {
        ...mapMutations(['increment']),
        add(){
          // this.increment({num:123})
          this.$store.commit('increment',{num:1});
        },
        sub(){
          this.$store.commit('decrement',{num:-1});
        }
      },
    }
    </script>
    
    

5.4 action 可以做异步

  • 在仓库中书写 action 代码

  • 我们通过 发送一个登录请求来改变 testname 的名字

  • // index.js   
    ......
    //  因为要发送请求,所以仓库中引入 axios
    import axios from '../utils/axios'
    
    const store = new Vuex.Store({
      ......
      state:{
      ......
      testname:'测试名字',
      ......
      },
      mutations:{
        // actions 里面提交并触发此方法 修改仓库数据
        changeName(state, {user}) {
          state.testname = user;
        }
      },
      actions:{
          async handleLogin({commit},{user,pwd}){
          let url = '/login';
          let a1 = await axios.post(url,{username:user,password:pwd});
          // a1.status === 'ok' 表示登录成功 可以修改用户名
          if (a1.status === 'ok'){
            // 我们把仓库中的 testname 改成用户登录的用户名
            // actin 里面可以做异步操作,但是不能直接修改仓库数据
            // 必须提交到 mutations 里面去修改
            commit('changeName',{user});
          }
        }
      }
      ......
    })
      
    
    
  • 触发 action 里面的方法 有两种方式

    1. this.$store.dispatch('handleLogin')
      
    2. 也可以通过 引入 mapActions

    3. import {mapActions} from 'vuex';
      ...... 
      methods: {
          ...mapActions(['handleLogin']),
          // 这样写好之后可以直接在 模板中使用
          //比如  @click="handleLogin({user,pwd})"
          /*
        <button @click="handleLogin({user,pwd})" > 登录 </button>
          */
          // 也可以在方法当中使用 
          /*
          <!-- <button @click="login" > 登录 </button> -->
          login(){
            this.$store.dispatch('handleLogin',
            {user:this.user,pwd:this.pwd});
            console.log('登录');
          }
          */
      
      ......
      
  1. // store.vue 
    
    <template>
      <div>
        <h1>{{name}}</h1>
        <div>
          <!-- <button @click="add" >+</button> -->
          <p> 使用 $store.state.count 展示数据 {{$store.state.count}}</p>
          <p> 使用...mapState(['count'])展示数据 {{count}}</p>
            <!--  -->
          <!-- <button @click="sub" >+</button> -->
          <hr>
          <p> getters: </p>
          <p>在计算属性中使用...mapGetters(['filterScore'])展示:</p>
          <p>  {{filterScore}} </p>
          <p> 直接通过$store.getters.getters展示:  </p>
          <p>{{$store.getters.filterScore}}</p>
          <hr>
          <p>mutations </p>
          <button @click="sub" >-</button>
            {{count}}
          <button @click="add" >+</button>
          <!-- <button @click="increment({num:1})" >+</button> -->
          <hr>
          <p>mapActions</p>
          <p> 名字:{{testname}} </p>
          <input type="text"     v-model="user" placeholder="输入用户名" > <br><br>
          <input type="password" v-model="pwd"  placeholder="输入密码" > <br><br>
          <button @click="handleLogin({user,pwd})" > 登录 </button>
          <!-- <button @click="login" > 登录 </button> -->
        </div>
      </div>
    </template>
     
    <script> 
    
    import {mapState ,mapGetters,mapMutations,mapActions} from 'vuex';
    import { log } from 'util'
    export default {
      data() {
        return {
          name:'Store',
          user:'',
          pwd:''
        }
      },
      created(){
        // console.log(this.$store);
        
      },
      computed: {
        ...mapState(['count','testname']),
        ...mapGetters(['filterScore'])
      },
      methods: {
        ...mapMutations(['increment']),
        ...mapActions(['handleLogin']),
        add(){
          // this.increment({num:123})
          this.$store.commit('increment',{num:1});
        },
        sub(){
          this.$store.commit('decrement',{num:-1});
        },
        login(){
          this.$store.dispatch('handleLogin',{user:this.user,pwd:this.pwd})
          console.log('登录');
        }
      },
    }
    </script>
    
  • 官网说明

  • import { mapActions } from 'vuex'
    
    export default {
      // ...
      methods: {
        ...mapActions([
          'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
    
          // `mapActions` 也支持载荷:
          'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
        ]),
        ...mapActions({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
        })
      }
    }
    

gitee 项目地址 : git clone https://gitee.com/lil-kz/vuecli4.git

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339