zoukankan      html  css  js  c++  java
  • 09:vuex组件间通信

     1.1 vuex简介

      官网:https://vuex.vuejs.org/zh/guide/

      参考博客:https://www.cnblogs.com/first-time/p/6815036.html   

      1、什么是Vuex?

          1. 官方说法:Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。
          2. 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
          3. 个人理解:Vuex是用来管理组件之间通信的一个插件

      2、vuex作用

          1. 我们知道组件之间是独立的,组件之间想要实现通信,我目前知道的就只有props选项,但这也仅限于父组件和子组件之间的通信。
          2. 如果兄弟组件之间想要实现通信呢?当做中大型项目时,面对一大堆组件之间的通信,还有一大堆的逻辑代码,会不会很抓狂??
          3. 那为何不把组件之间共享的数据给“拎”出来,在一定的规则下管理这些数据呢? 这就是Vuex的基本思想了。

          总结:使用vuex作用就是实现组件间数据共享

      3、vuex原理

          1. vue团队为了简化组件间的通信,将state抽象成一个单例模式,将其放到全局,让各个组件都能共享使用

          2. vuex数据传递是单向的:action ---> mutation ---> state ---> component ---> action

              vue component指的就是我门定义的组件
              action 交互中产生的动作
              mutations 动作产生的修改数据的行为
              state 共享数据

          3. vuex设计的时候相对修改的行为做单测(测试),开发了devtools来做测试,只能检测同步的操作

          4. 规范定义:只能在mutations中做同步操作,所以增加了action来异步处理数据

          5. 将mutations中的异步操作转移到actions中了,这样就可以测试同步的操作了

      4、vuex使用场景

          1. 如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

          2. 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。

      5、vuex流程图

          1、vue组件(Vue Components)会 发出(Dispatch)一些动作(Actions)
          2、动作会 提交(Commit)一个对数据的改变(Mutations)
          3、提交的改变数据存放在 状态(State) 中的
          4、最后 State将改变的数据再 渲染(Render)到组件(Vue Components),展示被改变后的数据

          

     1.2 vuex使用(vuex使用分为以下两步)

      1、第一步:实例化一个store

          注:vuex.store用来创建store,参数对象中,可以定义各个模块

          1. state定义状态模块(存储数据的),存放组件之间共享的数据

          2. getters定义动态的数据,类似组件中的computed动态数据

          3. mutations:定义改动states的动作行为,类似观察者模式中的订阅事件on

          4. action:定义这些交互动作(异步),类似观察者模式中的订阅事件方法on(只不过是用来处理异步的)

      2、第二步:在vue实例化对象中,注册store

          1. 将第一步的实例化对象注册进来,注册路由后,组件实例化对象有了$route属性对象

          2. 注册store,组件实例化对象有了$store属性对象,这个store对象有下面这些方法

              $.store.commit用来触发mutations订阅的消息

              $.store.dispatch用来触发action订阅的消息的

              $.store.state使用状态中的数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <h1 @click="$store.commit('reduce', 20);">vue实例化对象:点击减20</h1>
            <h2 @click="$store.dispatch('dealNum', 10, 20, 30)">更新数据:将num两秒后重置为:10</h2>
            <h1>state中的数据 {{$store.state.num}}</h1>
            <h2>双倍num {{$store.getters.doubleNum}}</h2>
            <router-view></router-view>                          <!-- 定义渲染的容器 -->
        </div>
        <template id="home">
            <div>
                <h1 @click="$store.commit('add', 10, 'hello')">home:点击加10</h1>
                <h2>home组件中 {{$store.state.num}}</h2>
                <router-view></router-view>                     <!-- 第一步 定义子路由渲染的容器 -->
            </div>
        </template>
        <script type="text/javascript" src="vue.js"></script>
        <script type="text/javascript" src="vue-router.js"></script>
        <script type="text/javascript" src="vuex.js"></script>
        <script type="text/javascript">
            // 定义组件
            var Home = {
                template: '#home'
            };
    
            // 第一步 定义路由规则
            var routes = [
                {
                    path: '/home',
                    name: 'home',
                    component: Home
                }
            ];
    
            // 定义store第一步 定义store实例化对象
            var store = new Vuex.Store({
                state: {                                       // 定义状态
                    num: 0
                },
                getters: {                                       // 定义动态绑定的数据
                    doubleNum: function(state) {
                        return state.num * 2;
                    }
                },
                mutations: {                                   // 修改的消息
                    add: function(state, num) {                    // 增加num值
                        state.num += num;
                    },
                    reduce: function(state, num) {                // 减少num值
                        state.num -= num;
                    },
                    resetNum: function(state, num) {
                        state.num = num;
                    }
                },
                actions: {                                        // 定义actions
                    dealNum: function(context, num) {
                        setTimeout(function() {                    // 我们可以异步提交
                            context.commit('resetNum', num)
                        }, 2000)
                    }
                }
            });
    
            // 第二步 实例化路由对象
            var router = new VueRouter({
                routes: routes                    // 定义路由规则
            });
    
            // 第三步 注册路由 和 store对象
            var app = new Vue({
                el: '#app',                        // 注册路由
                router: router,
                store: store                    // 使用vuex第二步 注册store
            })
        </script>
    </body>
    </html>
    vuex基本使用

         

    1.3 vuex基本用法

      1、初始化环境

          vue init webpack-simple vuex-demo

          cd vuex-demo

          npm install

          cnpm install vuex -S     # 安装vuex

          npm run dev

      2、在main.js中导入并配置store.选项(创建 sre/store.js文件,可以是一个空文件

          1. 在main.js中导入 store对象:  import store from './store'

          2. 配置store选项后,vue就会自动将store对象注入到所有子组件中,在子组件中通过this.$store 访问store对象

    import Vue from 'vue'
    import App from './App.vue'
    
    import store from './store'  // 导入store对象
    
    new Vue({
      store,  // 配置store选项后,指定为store对象,vue就会自动将store对象注入到所有子组件中
              // 在子组件中通过this.$store 访问store对象
      el: '#app',
      render: h => h(App)
    });
    main.js

      3、编辑store.js文件

          注1:Vuex的核心是Store(仓库),相当于是一个容器,一个store实例中包含以下属性的方法:

          注2:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化

          1) state 定义属性(状态、数据)

          2) getters 用来获取属性

          3) actions 定义方法(动作)

          4) commit 提交变化,修改数据的唯一方式就是显式的提交mutations

          5) mutations 定义变化

    /**
     * vuex配置:store.js
     **/
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex);
    
    //1、定义属性(数据)
    var state = {
      count:6
    };
    
    //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
    var getters={
      count(state){
        return state.count;
      }
    };
    
    //3、定义actions提交变化:其他组件中调用的方法()
    const actions = {
      increment({commit,state}){       // context包含属性(函数):commit,dispatch,state
        if(state.count<10){           // 当count数值小于10才会提交改变(大于10就不增加了)
          commit('increment');
        }
        // 1、commit提交改变(不能直接修改数据)
        // 2、commit中的参数 'increment' 是自定义的,可以认为是类型名
        // 3、commit提交的改变会给 mutations
      }
    };
    
    //4、定义mutations定义变化,处理状态(数据的改变)
    const mutations={
      increment(state){
        state.count++;
      }
    };
    
    // 创建一个store对象(对象里定义需要导出的变量)
    const store=new Vuex.Store({
      state,
      getters,
      actions,
      mutations,
    });
    
    // 导出store对象
    export default store;
    sre/store.js

      4、 编辑App.vue

        1. 在子组件中访问store对象的两种方式

            方式1:通过this.$store访问

            方式2:通过辅助函数:mapState、mapGetters、mapActions 访问,vuex提供了两个方法

                mapState        获取state

                mapGetters     获取getters(获取属性:数据)

                mapActions     获取actions(获取方法:动作)

    <template>
      <div id="app">
        <button @click="increment">增加</button>
        <button>减小</button>
        <p>当前数字为:{{count}}</p>
      </div>
    </template>
    
    <script>
      import {mapGetters,mapActions} from 'vuex'
    
    export default {
      name: 'app',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      },
    
      // 方式二:使用 辅助函数 访问 vuex 组件中数据
      computed:mapGetters([            // 这里定义一个数组,数组中指定要从vuex中获取的属性
        'count',                       // 这里的count就是 store.js中getters定义的属性
      ]),
      methods:mapActions([             // 这里定义一个数组,数组中指定要从vuex中获取的方法
        'increment'                   // 这里的increment就是 store.js中actions定义的函数
      ])
    
      // // 方式一:通过this.$store访问vuex组件中的数据
      // computed:{
      //   count(){
      //     return this.$store.state.count;
      //   }
      // }
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    
    h1, h2 {
      font-weight: normal;
    }
    
    ul {
      list-style-type: none;
      padding: 0;
    }
    
    li {
      display: inline-block;
      margin: 0 10px;
    }
    
    a {
      color: #42b983;
    }
    </style>
    App.vue

      5、效果图

          

      6、异步操作

    import Vue from 'vue'
    import App from './App.vue'
    
    import store from './store'  // 导入store对象
    
    new Vue({
      store,  // 配置store选项后,指定为store对象,vue就会自动将store对象注入到所有子组件中
              // 在子组件中通过this.$store 访问store对象
      el: '#app',
      render: h => h(App)
    });
    main.js
    /**
     * vuex配置:store.js
     **/
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex);
    
    //1、定义属性(数据)
    var state = {
      count:6
    };
    
    //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
    var getters={
      count(state){
        return state.count;
      }
    };
    
    //3、定义actions提交变化:其他组件中调用的方法()
    const actions = {
      increment({commit,state}){       // context包含属性(函数):commit,dispatch,state
        if(state.count<10){           // 当count数值小于10才会提交改变(大于10就不增加了)
          commit('increment');
        }
        // 1、commit提交改变(不能直接修改数据)
        // 2、commit中的参数 'increment' 是自定义的,可以认为是类型名
        // 3、commit提交的改变会给 mutations
      },
    
      /** 定义异步操作 **/
      incrementAsyn({commit,state}){
        var p=new Promise((resolve,reject) => {    // 异步操作
          setTimeout(() => {
            resolve()
          },3000)
        });
        p.then(() => {                             // 上面执行完成后才执行 p.then()
          commit('increment');
        }).catch(() => {                           // 异常处理
          console.log('异步操作失败')
        })
      }
    };
    
    //4、定义mutations定义变化,处理状态(数据的改变)
    const mutations={
      increment(state){
        state.count++;
      }
    };
    
    // 创建一个store对象(对象里定义需要导出的变量)
    const store=new Vuex.Store({
      state,
      getters,
      actions,
      mutations,
    });
    
    // 导出store对象
    export default store;
    store.js
    <template>
      <div id="app">
        <button @click="increment">增加</button>
        <button @click="incrementAsyn">异步增加</button>
        <p>当前数字为:{{count}}</p>
      </div>
    </template>
    
    <script>
      import {mapGetters,mapActions} from 'vuex'
    
    export default {
      name: 'app',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      },
    
      // 方式二:使用 辅助函数 访问 vuex 组件中数据
      computed:mapGetters([            // 这里定义一个数组,数组中指定要从vuex中获取的属性
        'count',                       // 这里的count就是 store.js中getters定义的属性
      ]),
      methods:mapActions([             // 这里定义一个数组,数组中指定要从vuex中获取的方法
        'increment',                   // 这里的increment就是 store.js中actions定义的函数
        'incrementAsyn'                // 异步提交
      ])
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    
    h1, h2 {
      font-weight: normal;
    }
    
    ul {
      list-style-type: none;
      padding: 0;
    }
    
    li {
      display: inline-block;
      margin: 0 10px;
    }
    
    a {
      color: #42b983;
    }
    </style>
    App.vue

        

    1.4 分模块组织Vuex

      1、初始化环境

          vue init webpack-simple vuex-demo2

          cd vuex-demo2

          npm install

          cnpm install vuex -S      # 安装vuex

          npm run dev

      2、Vuex模块化结构

    |-src
        |-main.js                       // 项目入口文件
        |-App.vue
        
        |-store
            |-index.js                  // 我们组装模块并导出 store 的地方
            |-getters.js                // 公共的 getters (用来获取公共属性)
            |-actions.js                // 根级别的 action (提交公共改变)
            |-mutations.js              // 根级别的 mutation (处理状态,数据的改变)
            |-types.js                  // 定义类型常量(commit中提交的常量)
    
            |-modules                   //分为多个模块,每个模块都可以拥有自己的state、getters、actions、mutations
                |-user.js               // 用户模块(这里仅以user模块作为事例)
    Vuex模块化结构

      3、代码事例

    import Vue from 'vue'
    import App from './App.vue'
    
    import store from './store/index.js'
    
    new Vue({
      store,
      el: '#app',
      render: h => h(App)
    });
    main.js
    <template>
      <div id="app">
        
        <button @click="increment">增加</button>
        <button @click="decrement">减小</button>
        <button @click="incrementAsync">增加</button>
        <p>当前数字为:{{count}}</p>
        <p>{{isEvenOrOdd}}</p>
    
      </div>
    </template>
    
    <script>
    import {mapState,mapGetters,mapActions} from 'vuex'
    
    export default {
      name: 'app',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      },
      computed:mapGetters([
          'count',
          'isEvenOrOdd'
      ]),
      methods:mapActions([
          'increment',
          'decrement',
          'incrementAsync'
      ])
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    
    h1, h2 {
      font-weight: normal;
    }
    
    ul {
      list-style-type: none;
      padding: 0;
    }
    
    li {
      display: inline-block;
      margin: 0 10px;
    }
    
    a {
      color: #42b983;
    }
    </style>
    App.vue
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex);
    
    import getters from './getters.js'
    import actions from './actions.js'
    import user from './modules/user.js'
    
    export default new Vuex.Store({
        getters,
        actions,
        modules:{
            user
        }
    });
    store/index.js
    const getters={
        isEvenOrOdd(state){
            return state.user.count%2==0?'偶数':'奇数';  // user模块中的count
        }
    };
    
    export default getters;
    store/getters.js
    import types from './types.js'
    
    const actions={
        incrementAsync({commit,state}){
            //异步操作
            var p=new Promise((resolve,reject) => {
                setTimeout(() => {
                    resolve();
                },3000);
            });
    
            p.then(() => {
                commit(types.INCREMENT);
            }).catch(() => {
                console.log('异步操作');
            });
        }
    };
    
    export default actions;
    store/actions.js
    /**
     * 定义类型常量
     */
    
    const INCREMENT='INCREMENT';
    const DECREMENT='DECREMENT';
    
    export default {
        INCREMENT,
        DECREMENT
    }
    store/types.js
    /**
     * 用户模块
     */
    
    import types from '../types.js'
    
     const state={
         count:6
     };
    
    var getters={
        count(state){
            return state.count;
        }
    };
    
    const actions = {
        increment({commit,state}){
            commit(types.INCREMENT); //提交一个名为increment的变化,名称可自定义,可以认为是类型名
        },
        decrement({commit,state}){
            if(state.count>10){
                commit(types.DECREMENT);
            }
        }
    };
    
    const mutations={
        [types.INCREMENT](state){   // ES6中中括号里表示 变量
            state.count++;
        },
        [types.DECREMENT](state){
            state.count--;
        }
    };
    
    export default {
        state,
        getters,
        actions,
        mutations
    }
    store/modules/user.js

      4、项目结构 

             

      5、简化版

    import Vue from 'vue'
    import App from './App.vue'
    
    import store from './store/index'
    
    new Vue({
      store,
      el: '#app',
      render: h => h(App)
    })
    main.js
    <template>
      <div id="app">
        <h1>app</h1>
        <p>数据:{{count}}</p>
        <p @click="increment">增加</p>
      </div>
    </template>
    
    <script>
      import {mapGetters, mapActions} from 'vuex'
    
    export default {
      name: 'app',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      },
      computed:mapGetters([
        'count',
      ]),
      methods:mapActions([
        'increment'
      ])
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    
    h1, h2 {
      font-weight: normal;
    }
    
    ul {
      list-style-type: none;
      padding: 0;
    }
    
    li {
      display: inline-block;
      margin: 0 10px;
    }
    
    a {
      color: #42b983;
    }
    </style>
    App.vue
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex);
    
    // import getters from './getters.js'
    // import actions from './actions.js'
    import user from './modules/user.js'
    
    export default new Vuex.Store({
      // getters,
      // actions,
      modules:{
        user
      }
    });
    srcstoreindex.js
    //1、定义属性(数据)
    var state = {
      count:6
    };
    
    //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
    var getters = {
      count(state){
        return state.count
      }
    };
    
    //3、定义actions提交变化:其他组件中调用的方法()
    var actions = {
      increment({commit,state}){
        commit('increment')
      }
    };
    
    //4、定义mutations定义变化,处理状态(数据的改变)
    var mutations = {
      increment(state){
        state.count++
      }
    };
    
    //5、导出store对象
    export default {
      state,
      getters,
      actions,
      mutations
    }
    srcstoremodulesuser.js

        

  • 相关阅读:
    配置域名服务器报错named[822]: dns_rdata_fromtext /etc/bind/db.asertest.com mail not a valid number
    Cookie/Session机制详解
    java中一个数组不能放不同数据类型的值
    javascript中 (function(){})();如何理解?
    图表实现基于SVG或Canvas
    千层饼图 年轮图
    element select下拉框绑定number类型
    Vue和JQuery相比,除了节省了开发成本,还有什么优点?
    前端领域的BEM到底是什么
    js数组操作find查找特定值结合es6特性
  • 原文地址:https://www.cnblogs.com/xiaonq/p/9697921.html
Copyright © 2011-2022 走看看