zoukankan      html  css  js  c++  java
  • 深入浅出的webpack4构建工具--webpack4+vue+route+vuex项目构建(十七)

    阅读目录

    一:vue传值方式有哪些?

    二:理解使用Vuex

    三:webpack4+vue+route+vuex 项目架构

    一:vue传值方式有哪些?

    在vue项目开发过程中,经常会使用组件来进行项目开发,那么在组件中会调用另一个组件来作为自己的子组件,那么我们如何进行给子组件进行传值呢?或者说,子组件如何给父组件传值呢?父子组件数据是如何通信的呢?
    因此vue常用的传值方式有如下几种:
    1. 父传子
    2. 子传父
    3. 非父子传值

    父子组件传递数据可以看如下图所示

    总结是:父组件向子组件传递数据,可以通过prop属性向下传递数据,子组件向父组件传递数据是通过事件给父组件发送消息。

    下面我们看如下父子组件的demo。在看demo之前,我们看下项目目录的结构如下:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- parent.vue                    # 父组件
    |   | | | |-- child.vue                     # 子组件
    |   | | | |-- index.vue
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- js                              # 存放js文件的
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件

    1. 父组件向子组件传值demo如下:

    app/index/views/parent.vue 代码如下:

    <template>
      <div>
        <div>
          <label>父组件:</label>
          <input type='text' v-model = 'name' />
          <br />
          <!-- 引入子组件 -->
          <child :inputName="name"></child>
        </div>
      </div>
    </template>
    
    <script type="text/javascript">
      import child from './child';
      export default {
        data() {
          return {
            name: ''
          }
        },
        components: {
          child: child
        }
      }
    </script>

    app/index/views/child.vue 代码如下:

    <template>
      <div>
        <label>子组件:</label>
        <span>{{inputName}}</span>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        // 接收父组件的值
        props: {
          inputName: String,
          required: true
        }
      }
    </script>

    app/index/views/index.vue 代码如下:

    <style lang="stylus">
      
    </style>
    
    <template>
      <div id="app">
        <header>
          <router-link to="/parent" tag='li'>parent</router-link>
        </header>
        <!-- 对应组件的内容渲染到router-view中 -->
        <router-view></router-view>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            
          }
        }
      }
    </script>

    app/index/router.js 代码如下:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    // 告诉 vue 使用 vueRouter
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/parent',
        name: 'parent',
        component: resolve => require(['./views/parent'], resolve)
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/parent'
      }
    ]
    
    var router = new VueRouter({
      base: '/app/index', // 配置单页应用的基路径
      routes: routes
    });
    
    export default router;

    因此页面运行效果如下图所示:

    2. 子组件向父组件传值方式demo如下:

    app/index/views/parent.vue 代码改成如下:

    <template>
      <div>
        <div>
          <label>父组件:</label>
          <span style="color:red;">{{name}}</span>
          <br />
          <!-- 引入子组件 定义一个方法来监听子组件的状态值 -->
          <child @childChange="childChangeFunc"></child>
        </div>
      </div>
    </template>
    
    <script type="text/javascript">
      import child from './child';
      export default {
        data() {
          return {
            name: ''
          }
        },
        methods: {
          childChangeFunc(value) {
            // value 就是子组件传递过来的值
            this.name = value;
          }
        },
        components: {
          child: child
        }
      }
    </script>

    app/index/views/child.vue 代码改成如下:

    <template>
      <div>
        <label>子组件:</label>
        <span>{{childValue}}</span>
        <!-- 子组件事件传值 -->
        <input type='button' value='点击触发' @click="childClick" />
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            childValue: '我是子组件的数据'
          }
        },
        methods: {
          childClick() {
            // 子组件触发事件
            this.$emit('childChange', this.childValue);
          }
        }
      }
    </script>

    运行如下:

    么有触发点击之前的效果图如下:

    点击触发按钮后,效果图如下:

    3. 非父子组件进行传值

    非父子组件之间传值,需要定义个公共的实列文件来作为中间仓库来传值的。比如定义一个叫 bus.js 文件。
    所谓中间仓库就是创建一个事件中心,相当于中转站,可以使用它来传递事件和接收事件的。

    在app/index 下新建一个js文件夹,在文件夹内新建一个bus.js文件,代码如下:

    import Vue from 'vue';
    
    export default new Vue();

    在app/index/views/a.vue, 代码如下:

    <template>
      <div>
        <label>A组件:</label>
        <span>{{value}}</span>
        <input type="button" value="点击触发" @click="clickFunc" />
      </div>
    </template>
    
    <script type="text/javascript">
      // 引入公共的bus
      import Bus from '../js/bus.js';
      export default {
        data() {
          return {
            value: 1
          }
        },
        methods: {
          clickFunc() {
            Bus.$emit('val', this.value);
          }
        }
      }
    </script>

    在app/index/views/b.vue, 代码如下:

    <template>
      <div>
        <label>B组件:</label>
        <input type='button' value='点击触发' @click="getDataFunc" />
        <span>{{name}}</span>
      </div>
    </template>
    
    <script type="text/javascript">
      import Bus from '../js/bus.js';
      export default {
        data() {
          return {
            name: 0
          }
        },
        mounted() {
          const vm = this;
          // 使用$on事件来接收参数
          Bus.$on('val', (data) => {
            console.log(data);
            vm.name = data;
          });
        },
        methods: {
          getDataFunc() {
            this.name++;
          }
        }
      }
    </script>

    app/index/views/index.vue 代码改成如下:

    <style lang="stylus">
      
    </style>
    
    <template>
      <div id="app">
        <A></A>
        <B></B>
      </div>
    </template>
    
    <script type="text/javascript">
      import A from './a';
      import B from './b';
      export default {
        data() {
          return {
            
          }
        },
        components: {
          A: A,
          B: B
        }
      }
    </script>

    页面进来的时候,页面渲染成如下图所示

    当点击 A 组件后的点击触发后,B组件的值变成了4,如下图所示:

    二:理解使用Vuex

    1. 什么是vuex?

    Vuex官网的解释:Vuex是一个专为vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    官网的解释很模糊。其实在vue组件开发中,经常会需要将当前的组件的数据传递给其他的组件,父子组件通信的话,我们可以采用props+emit 这种方式,如上面的demo方式来传递数据,但是当通信双方不是父子组件甚至根本不存在任何关系的时候,或者说一个状态需要共享给多个组件的时候,那么就会非常麻烦,数据维护也相当的不好维护,因此就出现了vuex。它能帮助我们把公用的状态抽出来放在vuex的容器中,然后根据一定的规则进行管理。vuex采用了集中式存储管理所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    2. 怎么使用vuex?

    如下demo使用:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script type="text/javascript" src='https://unpkg.com/vue/dist/vue.js'></script>
      <script type="text/javascript" src='https://unpkg.com/vuex@3.0.1/dist/vuex.js'></script>
    </head>
    <body>
      <div id='app'></div>
      <script type="text/javascript">
        Vue.use(Vuex); // 使用vuex
        var myStore = new Vuex.Store({
          // state是存储状态 定义应用状态全局的数据结构
          state: {
            name: 'kongzhi',
            todoLists: []
          },
          /*
            mutations是提交状态修改,也就是set、get中的set,这是vuex中唯一修改state的方式,但是不支持异步操作。
            每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)
            第一个参数默认是state,外部调用方式为:store.commit('SET_AGE', 30).
          */
          mutations: {
            // 新增list
            ADDLIST(state, item) {
              state.todoLists.push(item);
            },
            // 删除list中的项
            DELLIST(state, index) {
              state.todoLists.splice(index, 1);
            },
            // 设置 错误提示信息
            SETERROR(state, msg) {
              state.message = msg;
            }
          },
          /*
            getters是从state中派生出状态的。也就是set、get中的get,它有两个可选的参数,state和getters,
            分别可以获取state中的变量和其他的getters。外部调用的方式:store.getters.todoCount()
          */
          getters: {
            todoCount(state) {
              return state.todoLists.length;
            }
          },
          /*
           和上面的mutations类似,但是actions支持异步操作的,外部调用方式为:store.dispatch('nameAction')
           常见的使用是:从服务器端获取数据,在数据获取完成后会调用 store.commit()来更改Store中的状态。
           Action函数接收一个与store实列具有相同方法和属性的context对象,因此我们可以使用 context.commit 提交一个
           mutation,或者通过 context.state 和 context.getters来获取state和getters
          */
          actions: {
            addList(context, item) {
              if (item) {
                context.commit('ADDLIST', item);
                context.commit('SETERROR', '');
              } else {
                context.commit('SETERROR', '添加失败');
              }
            },
            delList(context, index) {
              context.commit('DELLIST', index);
              context.commit('SETERROR', '删除成功');
            }
          },
          /*
           modules 对象允许将单一的Store拆分为多个Store的同时保存在单一的状态树中。
          */
          modules: {
    
          }
        });
        new Vue({
          el: '#app',
          data: {
            name: 'init name'
          },
          store: myStore,
          mounted: function() {
            console.log(this);
          }
        })
      </script>
    </body>
    </html>

    如上代码,new Vuex.store({}) 含义是创建一个Vuex实列。store是vuex的一个核心方法,字面含义为 '仓库'的意思。实列化完成后,需要注入到vue实列中,它有五个核心的选项,state、mutations、getters、actions和modules。如下图所示:

    查看demo1.html

    3. vuex中如何获取state的数据呢?
    下面我们来注册一个组件,那么在组件内部中的computed来获取state的数据(computed是实时响应的)。如下代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script type="text/javascript" src='https://unpkg.com/vue/dist/vue.js'></script>
      <script type="text/javascript" src='https://unpkg.com/vuex@3.0.1/dist/vuex.js'></script>
    </head>
    <body>
      <div id='app'>
        <xxx></xxx>
      </div>
      <script type="text/javascript">
        Vue.use(Vuex); // 使用vuex
        var myStore = new Vuex.Store({
          // state是存储状态 定义应用状态全局的数据结构
          state: {
            name: 'kongzhi',
            todoLists: []
          },
          /*
            mutations是提交状态修改,也就是set、get中的set,这是vuex中唯一修改state的方式,但是不支持异步操作。
            每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)
            第一个参数默认是state,外部调用方式为:store.commit('SET_AGE', 30).
          */
          mutations: {
            // 新增list
            ADDLIST(state, item) {
              state.todoLists.push(item);
            },
            // 删除list中的项
            DELLIST(state, index) {
              state.todoLists.splice(index, 1);
            },
            // 设置 错误提示信息
            SETERROR(state, msg) {
              state.message = msg;
            }
          },
          /*
            getters是从state中派生出状态的。也就是set、get中的get,它有两个可选的参数,state和getters,
            分别可以获取state中的变量和其他的getters。外部调用的方式:store.getters.todoCount()
          */
          getters: {
            todoCount(state) {
              return state.todoLists.length;
            }
          },
          /*
           和上面的mutations类似,但是actions支持异步操作的,外部调用方式为:store.dispatch('nameAction')
           常见的使用是:从服务器端获取数据,在数据获取完成后会调用 store.commit()来更改Store中的状态。
           Action函数接收一个与store实列具有相同方法和属性的context对象,因此我们可以使用 context.commit 提交一个
           mutation,或者通过 context.state 和 context.getters来获取state和getters
          */
          actions: {
            addList(context, item) {
              if (item) {
                context.commit('ADDLIST', item);
                context.commit('SETERROR', '');
              } else {
                context.commit('SETERROR', '添加失败');
              }
            },
            delList(context, index) {
              context.commit('DELLIST', index);
              context.commit('SETERROR', '删除成功');
            }
          },
          /*
           modules 对象允许将单一的Store拆分为多个Store的同时保存在单一的状态树中。
          */
          modules: {
    
          }
        });
        // 注册vue组件 xxx
        Vue.component('xxx', {
          template: "<div>{{name}}</div>",
          computed: {
            name: function() {
              console.log(this.$store.state);
              return this.$store.state.name;
            }
          },
          mounted: function() {
            console.log(this);
          }
        });
        new Vue({
          el: '#app',
          data: {
            name: 'init name'
          },
          store: myStore,
          mounted: function() {
            console.log(this);
          }
        })
      </script>
    </body>
    </html>

    运行效果如下图所示:

    查看demo2.html

    4. 如何对state的数据进行筛选和过滤。
    有时候,我们需要对state的数据进行刷选和过滤操作,比如后台请求回来的数据,我们需要进行数据过滤操作,getters就可以了。具体代码可以看如下demo:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script type="text/javascript" src='https://unpkg.com/vue/dist/vue.js'></script>
      <script type="text/javascript" src='https://unpkg.com/vuex@3.0.1/dist/vuex.js'></script>
    </head>
    <body>
      <div id='app'>
        <xxx></xxx>
      </div>
      <script type="text/javascript">
        Vue.use(Vuex); // 使用vuex
        var myStore = new Vuex.Store({
          // state是存储状态 定义应用状态全局的数据结构
          state: {
            name: 'kongzhi',
            todoLists: []
          },
          /*
            mutations是提交状态修改,也就是set、get中的set,这是vuex中唯一修改state的方式,但是不支持异步操作。
            每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)
            第一个参数默认是state,外部调用方式为:store.commit('SET_AGE', 30).
          */
          mutations: {
            // 新增list
            ADDLIST(state, item) {
              state.todoLists.push(item);
            },
            // 删除list中的项
            DELLIST(state, index) {
              state.todoLists.splice(index, 1);
            },
            // 设置 错误提示信息
            SETERROR(state, msg) {
              state.message = msg;
            }
          },
          /*
            getters是从state中派生出状态的。也就是set、get中的get,它有两个可选的参数,state和getters,
            分别可以获取state中的变量和其他的getters。外部调用的方式:store.getters.todoCount()
          */
          getters: {
            todoCount(state) {
              return state.todoLists.length;
            }
          },
          /*
           和上面的mutations类似,但是actions支持异步操作的,外部调用方式为:store.dispatch('nameAction')
           常见的使用是:从服务器端获取数据,在数据获取完成后会调用 store.commit()来更改Store中的状态。
           Action函数接收一个与store实列具有相同方法和属性的context对象,因此我们可以使用 context.commit 提交一个
           mutation,或者通过 context.state 和 context.getters来获取state和getters
          */
          actions: {
            addList(context, item) {
              if (item) {
                context.commit('ADDLIST', item);
                context.commit('SETERROR', '');
              } else {
                context.commit('SETERROR', '添加失败');
              }
            },
            delList(context, index) {
              context.commit('DELLIST', index);
              context.commit('SETERROR', '删除成功');
            }
          },
          /*
           modules 对象允许将单一的Store拆分为多个Store的同时保存在单一的状态树中。
          */
          modules: {
    
          }
        });
        // 注册vue组件 xxx
        Vue.component('xxx', {
          template: "<div>{{name}}, 总数:{{todoCount}}</div>",
          computed: {
            name: function() {
              console.log(this.$store.state);
              return this.$store.state.name;
            },
            todoCount: function() {
              return this.$store.getters.todoCount;
            }
          },
          mounted: function() {
            console.log(this);
          },
    
        });
        new Vue({
          el: '#app',
          data: {
            name: 'init name'
          },
          store: myStore,
          mounted: function() {
            console.log(this);
          }
        })
      </script>
    </body>
    </html>

    运行效果 如下图所示

    查看demo3.html

    5. mutations操作来改变state数据
    如上是如何获取state的数据了,那么现在我们使用mutations来改变state的数据了,在Vuex中,改变状态state的唯一方式是通过提交commit的一个mutations,mutations下的对应函数接收第一个参数state,第二个参数为payload(载荷),payload一般是一个对象,用来记录开发时使用该函数的一些信息。mutations是处理同步的请求。不能处理异步请求的。看如下demo

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script type="text/javascript" src='https://unpkg.com/vue/dist/vue.js'></script>
      <script type="text/javascript" src='https://unpkg.com/vuex@3.0.1/dist/vuex.js'></script>
    </head>
    <body>
      <div id='app'>
        <xxx></xxx>
      </div>
      <script type="text/javascript">
        Vue.use(Vuex); // 使用vuex
        var myStore = new Vuex.Store({
          // state是存储状态 定义应用状态全局的数据结构
          state: {
            name: 'kongzhi',
            todoLists: []
          },
          /*
            mutations是提交状态修改,也就是set、get中的set,这是vuex中唯一修改state的方式,但是不支持异步操作。
            每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)
            第一个参数默认是state,外部调用方式为:store.commit('SET_AGE', 30).
          */
          mutations: {
            // 新增list
            ADDLIST(state, item) {
              console.log(state.todoLists);
              state.todoLists.push(item);
            },
            // 删除list中的项
            DELLIST(state, index) {
              state.todoLists.splice(index, 1);
            },
            // 设置 错误提示信息
            SETERROR(state, msg) {
              state.message = msg;
            }
          },
          /*
            getters是从state中派生出状态的。也就是set、get中的get,它有两个可选的参数,state和getters,
            分别可以获取state中的变量和其他的getters。外部调用的方式:store.getters.todoCount()
          */
          getters: {
            todoCount(state) {
              return state.todoLists.length;
            }
          },
          /*
           和上面的mutations类似,但是actions支持异步操作的,外部调用方式为:store.dispatch('nameAction')
           常见的使用是:从服务器端获取数据,在数据获取完成后会调用 store.commit()来更改Store中的状态。
           Action函数接收一个与store实列具有相同方法和属性的context对象,因此我们可以使用 context.commit 提交一个
           mutation,或者通过 context.state 和 context.getters来获取state和getters
          */
          actions: {
            addList(context, item) {
              if (item) {
                context.commit('ADDLIST', item);
                context.commit('SETERROR', '');
              } else {
                context.commit('SETERROR', '添加失败');
              }
            },
            delList(context, index) {
              context.commit('DELLIST', index);
              context.commit('SETERROR', '删除成功');
            }
          },
          /*
           modules 对象允许将单一的Store拆分为多个Store的同时保存在单一的状态树中。
          */
          modules: {
    
          }
        });
        // 注册vue组件 xxx
        Vue.component('xxx', {
          template: "<div>{{name}}, 总数:{{todoCount}} <span @click='addList'>点击改变总数</span></div>",
          computed: {
            name: function() {
              return this.$store.state.name;
            },
            todoCount: function() {
              return this.$store.getters.todoCount;
            }
          },
          mounted: function() {
            console.log(this);
          },
          data: function() {
            return {
              count: 0
            }
          },
          methods: {
            addList: function() {
              var count = this.count++;
              this.$store.commit('ADDLIST', count);
            }
          }
        });
        new Vue({
          el: '#app',
          data: {
            name: 'init name'
          },
          store: myStore,
          mounted: function() {
            console.log(this);
          }
        })
      </script>
    </body>
    </html>

    如上代码,在组件xxx中的template添加代码 <span @click='addList'>点击改变总数</span>,每次点击的时候,会调用自身内部的addList的函数,然后count自增1,然后会继续调用 this.$store.commit('ADDLIST', count); 来提交 commit的一个mutations,因此state.todoLists.push(item);会增加一项数据后,在组件xxx内部通过 todoCount 可以实时获取到数据的改变状态。

    查看demo4.html

    6. actions操作mutations异步来改变state数据
    actions可以异步操作,actions提交mutations,通过mutations来提交数据的变更。它是异步修改state的状态的。
    外部调用方式是 this.$store.dispatch('nameAsyn');

    下面我们看如下demo

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <script type="text/javascript" src='https://unpkg.com/vue/dist/vue.js'></script>
      <script type="text/javascript" src='https://unpkg.com/vuex@3.0.1/dist/vuex.js'></script>
    </head>
    <body>
      <div id='app'>
        <xxx></xxx>
      </div>
      <script type="text/javascript">
        Vue.use(Vuex); // 使用vuex
        var myStore = new Vuex.Store({
          // state是存储状态 定义应用状态全局的数据结构
          state: {
            name: 'kongzhi',
            todoLists: [],
            // 添加count字段
            count: 1
          },
          /*
            mutations是提交状态修改,也就是set、get中的set,这是vuex中唯一修改state的方式,但是不支持异步操作。
            每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)
            第一个参数默认是state,外部调用方式为:store.commit('SET_AGE', 30).
          */
          mutations: {
            // 新增list
            ADDLIST(state, item) {
              console.log(state.todoLists);
              state.todoLists.push(item);
            },
            // 删除list中的项
            DELLIST(state, index) {
              state.todoLists.splice(index, 1);
            },
            // 设置 错误提示信息
            SETERROR(state, msg) {
              state.message = msg;
            },
            // 异步操作count
            COUNTASYNC(state, param) {
              console.log(state.count += param);
            }
          },
          /*
            getters是从state中派生出状态的。也就是set、get中的get,它有两个可选的参数,state和getters,
            分别可以获取state中的变量和其他的getters。外部调用的方式:store.getters.todoCount()
          */
          getters: {
            todoCount(state) {
              return state.todoLists.length;
            }
          },
          /*
           和上面的mutations类似,但是actions支持异步操作的,外部调用方式为:store.dispatch('nameAction')
           常见的使用是:从服务器端获取数据,在数据获取完成后会调用 store.commit()来更改Store中的状态。
           Action函数接收一个与store实列具有相同方法和属性的context对象,因此我们可以使用 context.commit 提交一个
           mutation,或者通过 context.state 和 context.getters来获取state和getters
          */
          actions: {
            addList(context, item) {
              if (item) {
                context.commit('ADDLIST', item);
                context.commit('SETERROR', '');
              } else {
                context.commit('SETERROR', '添加失败');
              }
            },
            delList(context, index) {
              context.commit('DELLIST', index);
              context.commit('SETERROR', '删除成功');
            },
            // 设置延时来演示一下异步提交
            addFunc(context, value) {
              console.log(context);
              setTimeout(function(){
                // 异步提交 actions操作Mutations
                context.commit('COUNTASYNC', value);
              }, 100);
            }
          },
          /*
           modules 对象允许将单一的Store拆分为多个Store的同时保存在单一的状态树中。
          */
          modules: {
    
          }
        });
        // 注册vue组件 xxx
        Vue.component('xxx', {
          template: 
            `<div>
              {{name}}, 总数:{{todoCount}} 
              <span @click='addList'>点击改变总数</span>
              <button @click='addFuncAnsyc'>点击我actions改变数据</button>
            </div>`,
          computed: {
            name: function() {
              return this.$store.state.name;
            },
            todoCount: function() {
              return this.$store.getters.todoCount;
            }
          },
          mounted: function() {
            console.log(this);
          },
          data: function() {
            return {
              count: 0
            }
          },
          methods: {
            addList: function() {
              var count = this.count++;
              this.$store.commit('ADDLIST', count);
            },
            addFuncAnsyc: function() {
              this.$store.dispatch('addFunc', 1);
            }
          }
        });
        new Vue({
          el: '#app',
          data: {
            name: 'init name'
          },
          store: myStore,
          mounted: function() {
            console.log(this);
          }
        })
      </script>
    </body>
    </html>

    如上代码,template中新增代码 <button @click='addFuncAnsyc'>点击我actions改变数据</button>,点击后,触发内部函数 addFuncAnsyc后,会调用 this.$store.dispatch('addFunc', 1);调用来操作actions中的方法,第一个参数对应actions中的方法名,第二个是参数值,在actions中的函数 addFunc 打印出 context, 如下图所示:


    addFunc函数会调用 context.commit('COUNTASYNC', value); 代码,会找到 mutations中对应的COUNTASYNC,然后会对state数据进行更改。

    理解context:  context是和 this.$store 具有相同的方法和属性的对象。我们可以通过 context.state 和 context.getters来获取state和getters。

    理解dispatch: 它含有异步操作,含义可以理解为 '派发',比如向后台提交数据,可以为 this.$store.dispatch('actions方法名', 值);

    查看demo5.html

    三:webpack4+vue+route+vuex 项目架构

     如上代码是基本的demo,但是在项目中,我们是如何配置的呢?下面再来看看使用store来重构项目,整个目录架构如下:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- parent.vue                    # 父组件
    |   | | | |-- child.vue                     # 子组件
    |   | | | |-- index.vue
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- js                              # 存放js文件的
    |   | | |-- store                           # store仓库
    |   | | | |--- actions.js
    |   | | | |--- mutations.js
    |   | | | |--- state.js
    |   | | | |--- mutations-types.js
    |   | | | |--- index.js
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件

    在app/index/views 下新建 testvue.vue, 代码如下:

    <template>
      <div>
        {{name}}, 总数:{{todoCount}} 
        <span @click='addList'>点击改变总数</span>
        <button @click='addFuncAnsyc'>点击我actions改变数据</button>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            name: '我是空智',
            count: 1,
            todoLists: []
          }
        },
        created() {
          
        },
        computed: {
          todoCount: function() {
            return this.$store.state.add;
          }
        },
        methods: {
          addList() {
            var count = this.count++;
            this.$store.commit('ADD', count);
          },
          addFuncAnsyc() {
            const obj = {
              
            };
            Promise.all([this.$store.dispatch('commonActionGet', ['getPower:COUNTASYNC', obj])]).then((res) => {
    
            });
          }
        }
      }
    </script>

    模板代码中 <span @click='addList'>点击改变总数</span> 点击一下 触发 addList 函数,该函数会调用 this.$store.commit('ADD', count); 该方法,commit方法是同步的,它会寻找mutations.js对应的 'ADD'函数.
    因此,app/index/store/mutations-types.js 代码可以改成如下:

    // 新增list
    export const ADD = 'ADD'; 
    
    // 设置错误提示
    export const SETERROR = 'SETERROR';
    
    // 异步操作count
    export const COUNTASYNC = 'COUNTASYNC';

    app/index/store/mutations.js 代码改造成如下:

    import * as types from './mutations-types';
    
    export default {
      [types.ADD] (state, payload) {
        state.add = payload;
      },
      [types.SETERROR] (state, payload) {
        state.errors = payload;
      },
    
      [types.COUNTASYNC] (state, payload) {
        state.counts = payload;
      }
    }

    app/index/store/state.js 改造代码如下:

    export default {
      add: 0,
      errors: '',
      counts: 0
    };

    app/index/store/actions.js 改造代码如下, 封装了常见的ajax中的get和POST方法:

    import * as types from './mutations-types';
    import Vue from 'vue';
    const ajaxHandle = () => {
      const buildUrl = (url, params, childParams) => {
        let str = '?'
        for (const key in params) {
          url += str + key + '=' + params[key];
          str = '&';
        }
        if (childParams) {
          return url + '/' + childParams;
        }
        return url;
      };
      const ajaxGet = (url, fn) => {
        let results = null;
        Vue.http.get(url, { emulateJSON: true, credentials: true }).then((response) => {
          if (response.ok) {
            results = response.body;
            fn && fn(1, results);
          } else {
            fn && fn(0, results);
          }
        }, (error) => {
          if (error) {
            fn && fn(0, results);
          }
        });
      };
      const ajaxGetJSON = (url, fn) => {
        let results = null;
        Vue.http.get(url, { credentials: true }).then((response) => {
          if (response.ok) {
            results = response.body;
            fn && fn(1, results);
          } else {
            fn && fn(0, results);
          }
        }, (error) => {
          if (error) {
            fn && fn(0, results);
          }
        });
      };
      const ajaxPost = (url, params, options, fn) => {
        let results = null;
        if (typeof options === 'function' && arguments.length <= 3) {
          fn = options;
          options = {};
        }
        Vue.http.interceptors.push((request, next) => {
          request.credentials = true;
          next();
        });
        Vue.http.post(url, params, { emulateJSON: true }).then((response) => {
          if (response.ok) {
            results = response.body;
            fn && fn(1, results);
          } else {
            fn && fn(0, results);
          }
        }, (error) => {
          if (error) {
            fn && fn(0, results);
          }
        })
      };
      const ajaxPostJSON = (url, params, options, fn) => {
        let results = null;
        if (typeof options === 'function' && arguments.length <= 3) {
          fn = options;
          options = {};
        }
        Vue.http.interceptors.push((request, next) => {
          request.credentials = true;
          next();
        });
        Vue.http.post(url, params).then((response) => {
          if (response.ok) {
            results = response.body;
            fn && fn(1, results);
          } else {
            fn && fn(0, results);
          }
        }, (error) => {
          if (error) {
            fn && fn(0, results);
          }
        })
      };
      return {
        buildUrl: buildUrl,
        ajaxGet: ajaxGet,
        ajaxGetJSON: ajaxGetJSON,
        ajaxPost: ajaxPost,
        ajaxPostJSON: ajaxPostJSON
      }
    };
    
    const ah = ajaxHandle();
    const prefix = '//xxx.abc.com';
    
    const apiObj = {
      API_GET_POWER: prefix + '/xxxx/yyy', // 获取用户信息
    };
    
    const apiFuncObj = {
      getPower: 'API_GET_POWER', // 获取用户信息
    };
    
    export default {
      commonActionPost ({ commit }, payload) {
        let url = apiObj[apiFuncObj[payload[0].split(':')[0]]];
        const mutationsName = payload[0].split(':')[1];
    
        const params = payload[1] ? payload[1] : {};
        return new Promise((reslove, reject) => {
          ah.ajaxPost(url, params, (state, results) => {
            if (state) {
              reslove(results);
            } else {
              reject();
            }
            if (mutationsName) {
              commit(mutationsName, results);
            }
          });
        });
      },
      commonActionPostJSON({ commit }, payload) {
        let url = apiObj[apiFuncObj[payload[0].split(':')[0]]];
        const mutationsName = payload[0].split(':')[1];
    
        const params = payload[1] ? payload[1] : {};
        return new Promise((reslove, reject) => {
          ah.ajaxPostJSON(url, params, (state, results) => {
            if (state) {
              reslove(results);
            } else {
              reject();
            }
            if (mutationsName) {
              commit(mutationsName, results);
            }
          });
        });
      },
      commonActionGet ({ commit }, payload) {
        let url = apiObj[apiFuncObj[payload[0].split(':')[0]]];
        const mutationsName = payload[0].split(':')[1];
    
        const params = payload[1] ? payload[1] : {};
        const childParams = payload[2] ? payload[2] : '';
        url = ah.buildUrl(url, params, childParams);
        return new Promise((reslove, reject) => {
          ah.ajaxGet(url, (state, results) => {
            if (state) {
              reslove(results);
            } else {
              reject();
            }
            if (mutationsName) {
              commit(mutationsName, results);
            }
          });
        });
      },
      commonActionGetJSON ({ commit }, payload) {
        let url = apiObj[apiFuncObj[payload[0].split(':')[0]]];
        const mutationsName = payload[0].split(':')[1];
    
        const params = payload[1] ? payload[1] : {};
        url = ah.buildUrl(url, params);
        return new Promise((reslove, reject) => {
          ah.ajaxGetJSON(url, (state, results) => {
            if (state) {
              reslove(results);
            } else {
              reject();
            }
            if (mutationsName) {
              commit(mutationsName, results);
            }
          });
        });
      }
    }

    app/index/store/index.js 改造代码如下

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    import state from './state';
    import mutations from './mutations';
    import actions from './actions';
    
    Vue.use(Vuex);
    
    Vue.config.devtools = true;
    
    export default new Vuex.Store({
      state,
      mutations,
      actions
    });

    然后在我们入口文件 app/index/app.js 引入store即可,如下代码:

    import Vue from 'vue';
    
    // 添加store
    import store from './store/index';
    
    // 暂时先用 vue-resource 演示
    import VueResource from 'vue-resource';
    
    import Index from './views/index';
    
    // 引入路由
    import router from './router';
    
    // Resource
    Vue.use(VueResource);
    
    new Vue({
      el: '#app',
      router: router,
      // vue实列添加store
      store: store,
      render: h => h(Index)
    });

    查看github源码

  • 相关阅读:
    编写登陆认证程序
    Ubuntu18.04安装MySQL
    python输出的高亮显示
    河北省赛
    dp
    迷宫问题
    牛客-幸运数字Ⅱ
    [管理运筹学]线性规划&单纯形法的各种姿势(题目:[NOI2008]志愿者招募)
    [管理运筹学]指派问题的匈牙利算法及其c++实现 (例:「网络流 24 题」分配问题 )
    打算在CSDN写了,虽然博客园也很好
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/9763177.html
Copyright © 2011-2022 走看看