【Vue2】Vuex 基础使用

作者: 睡神疯子 | 来源:发表于2021-03-24 03:55 被阅读0次

    本文仅为 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

    相关文章

      网友评论

        本文标题:【Vue2】Vuex 基础使用

        本文链接:https://www.haomeiwen.com/subject/srpacltx.html