【Vue2】Vuex 基础使用

本文仅为 vuex 使用方法,如有不对的地方,欢迎指正。
项目使用可以直接拉到后面 vuex 实际项目中使用部分。

首先为啥要用 vuex,用它有什么好处。

  • 数据跨组件共享。
  • 防止数据意外修改。程序过于庞大或多人开发时,容易不知道是哪改数据, vuex 可以记录哪个组件修改的修改的。
  • 调试、测试方便,同上。

vuex 基本描述

文档地址:https://vuex.vuejs.org/zh/
核心思想(流程):

vuex 流程

  • state 存储、数据;包含了所有变量也只有变量。
  • mutations 修改数据、追踪;操作 state;vue-devtools 上监控到的就是这一属性,只能有同步操作。
    mutation 都有一个字符串的 事件类型 (type)和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
mutations: {
  add (state) {
    // 变更状态
    state.count++
  }
}

store.commit('add') 调用 mutations 中函数的方法,可以传入参数。

mutations: {
  add (state, args) {
    state.count += args.n
  }
}
// 调用
store.commit('add', {n: 10})
  • actions 封装、组合;操作 mutations,可以有异步和同步操作,数据请求一般放这。
    Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 stategetters
actions: {
  add (context) {
   context.commit('add')
  }
}

store.dispatch('add') 调用 actions 中函数的方法,可以传入参数。

actions: {
  add ({commit}, args) {
   commit('add', args)
  }
}
// 以载荷形式分发
store.dispatch('add', {
  n: 10
})

// 以对象形式分发
store.dispatch({
  type: 'add',
  n: 10
})
  • vue components 可以从 state 读数据,state更新了 vue components 也会更新,vue components只能通过调用 actions 操作数据。

vuex 目录结构

这只是个示例,这目录官网扒的,嘿嘿嘿

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

vuex 使用前置

vuex 可以直接在 main.js 中直接引入,也可以独立出一个文件,再引入到 main.js 中。
先安装 vuex:npm install vuex

直接在 main.js 中直接引入

main.js 文件:

import Vue from 'vue'
// 第一步 引入
// 在主 js 文件 main.js 中引入
import Vuex from 'vuex';

// 第二步 添加到vue身上
// 把 vuex 的操作方法挂到 vue 上
Vue.use(Vuex);

// 第三步 声明 store 对象
// 必须先 use 才能进行操作,然后把 store 对象挂到 vue 上
const store=new Vuex.Store({
  strict: process.env.NODE_ENV!='production',   //严格模式:防止直接修改state,打开时会影响性能,只在开发模式打开;process.env.NODE_ENV 是 webpack 配置取的变量
  state: {a: 12, b: 5},                         //核心:数据
  mutations: {
    add(state, n){
      state.a+=n;
    }
  },
  actions: {
    add({commit}, n){
      commit('add', n); // 调用 mutations 中的 add
    }
  },
  getters: {},
  modules: {}
});
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

vue 文件:

<template>
    <div>
      a: {{$store.state.a}}<br/>
      <input type="button" value="+5" @click="fn()">
    </div>
  </template>
  
  <script>
  export default {
    data () {
      return {
      }
    },
    methods: {
      fn(){
        //this.$store.state.a+=5;// 直接改也可以改,但会报错
        //this.$store.commit('add', 5);// 使用 mutations 也可以改,但是一般不会用
        this.$store.dispatch('add', 5);
      }
    }
  }
  </script>

把 vuex 独立到 store 文件夹中

store/index.js 文件:

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

Vue.use(Vuex);
const store=new Vuex.Store({
  strict: process.env.NODE_ENV!='production', 
  state: {a: 12, b: 5},
  mutations: {
    add(state, n){
      state.a+=n;
    }
  },
  actions: {
    add({commit}, n){
      commit('add', n);
    }
  },
  getters: {},
  modules: {}
});
export default store

main.js 文件:

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

vue 文件无需改动。

vuex 实际项目中使用

项目中使用时就要用到 getters 函数,可以把它看成 store 的计算属性。

vuex 有几个辅助函数,把 vuex 的函数映射成 vue 组件中对应的函数,简化操作

  • mapState state -> computed
  • mapActions actions -> methods
  • mapGetters getters -> computed

store/index.js 文件:

import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex);
const store=new Vuex.Store({
  strict: process.env.NODE_ENV!='production',
  state: {a: 12, b: 5},
  mutations: {
    add(state, n){
      state.a+=n;
    },
    addA(state, n){
      state.a+=n;
    },
    addB(state, n){
      state.b+=n;
    },
    setOnline(state, id){
      state.users.forEach(user=>{
        if(user.id==id){
          user.online=true;
        }
      });
    },
    setUsers(state, users){
      state.users=users;
    }
  },
  actions: {
    add({commit}, n){
      commit('add', n);
    },
    addA({commit}, n){
      commit('addA', n);
    },
    addB({commit}, n){
      commit('addB', n);
    },
    setOnline({commit}, id){
      commit('setOnline', id);
    },
    async readUsers({commit}){
      let res=await fetch('http://localhost:2021/static/user.txt');
      // [{"id":3,"name":"blue","age":18,"online":true},{"id":5,"name":"zhangsan","age":22,"online":false},{"id":11,"name":"lisi","age":25,"online":true}]
      let users=await res.json();

      commit('setUsers', users);
    }
  },
  getters: {
    count(state){
      return state.a+state.b;
    },
    onlineUsers(state){
      return state.users.filter(user=>user.online);
    }
  },
  modules: {}
});
export default store

vue 文件:

<template>
  <div>
    <div>a: {{a}}</div>
    <div>b: {{b}}</div>
    <div>count: {{count}}</div>
    <input type="button" value="a+5" @click="addA(5)" />
    <input type="button" value="b+3" @click="addB(3)" />
    <br>
    <br>
    <input type="button" value="法外狂徒出现" @click="setOnline(5)" />
    <ul>
      <li v-for="user in onlineUsers" :key="user.name">
        名字:{{user.name}}
        年龄:{{user.age}}
      </li>
    </ul>
  </div>
</template>

<script>
import {mapState, mapActions, mapGetters} from 'vuex';

export default {
  async created(){
    await this.readUsers();
  },
  methods: {
    ...mapActions(['addA', 'addB', 'setOnline', 'readUsers']),
  },
  computed: {
    ...mapState(['a', 'b']),
    ...mapGetters(['count', 'onlineUsers'])
  }
}
</script>

vuex 模块化

首先需要在 store/index.js引入对应子模块,注意子模块的 mutationsactions 重名会多次执行。
store/index.js:

import Vue from 'vue'
import Vuex from 'vuex';
import boy from './boy';
import girl from './girl';
Vue.use(Vuex);

const store=new Vuex.Store({
  strict: process.env.NODE_ENV!='production',
  state: {str: 'liangzai'},
  getters: {
    couples(state) {
      return `${state.boy.str} && ${state.girl.str}`;
    }
  },
  modules: {
    boy,
    girl
  }
});
export default store

store/boy.js:

export default {
  state: {
    str: 'boy'
  },
  mutations: {
    'boySetStr': function (state, s){
      console.log('boy 的 setStr');
      state.str=s;
    }
  },
  actions: {
    'boySetStr': function ({commit}, s){
      commit('boySetStr', s);
    }
  }
}

store/girl.js:

export default {
  state: {
    str: 'girl'
  },
  mutations: {
    'girlSetStr': function (state, s){
      console.log('girl 的 setStr');
      state.str=s;
    }
  },
  actions: {
    'girlSetStr': function ({commit}, s){
      commit('girlSetStr', s);
    }
  }
}

vue 文件:

<template>
  <div>
    str: {{str}}<br>
    couples: {{couples}}<br>
    a_str: {{str_boy}}<br>
    b_str: {{str_girl}}<br>
    <input type="button" value="设置 boy" @click="set_boy('aaa')">
    <input type="button" value="设置 girl" @click="set_girl('bbb')">
    <br>
  </div>
</template>
<script>
import {mapState, mapActions, mapGetters} from 'vuex';

export default {
  // created(){console.log(this.$store)},
  methods: {
    ...mapActions({
      set_boy: 'boySetStr',
      set_girl: 'girlSetStr'
    })
  },
  computed: {
    ...mapState(['str']),
    ...mapState({
      str_boy: state=>state.boy.str,
      str_girl: state=>state.girl.str,
    }),
    ...mapGetters(['couples'])
  }
}
</script>

参考代码下载:https://github.com/windliang/simpleJS/tree/master/vue/vuexDemo

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

推荐阅读更多精彩内容