• vuex简单示例


    一.vuex是什么,解决了什么问题?

    官方解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
    个人理解是因为vue各个组件是相对独立的,要共享数据,就变的很麻烦.vuex就是为了解决各个组件传递数据与共享数据.

    二.vuex的核心概念

    vuex的核心概念是store,store中包括了state,mutation,action,getter

    1.state:需要用到的状态变量
    2.mutation:同步修改state
    3.action:异步方法和commit mutation
    4.getter:相当于computed,主要用作对state进行计算后,生成新的数据状态

    一般流程是组件dispatch一个action,action再commit一个mutation,mutation对state做更改;需要计算后的state,则使用getter.

    三.一个简单的示例

    1.需求:
    根据id来获取用户信息

    2.安装vuex,安装axios(ajax需求)

    3.在src下新建目录store,建立store.js文件,代码如下所示

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    import qs from 'qs'
    
    Vue.use(Vuex)
    axios.defaults.baseURL = '/api'
    
    const store = new Vuex.Store({
      state: {
        username: '暂无用户名,请获取数据'
      },
      // Vue 建议我们mutation 类型用大写常量表示
      mutations: {
        SET_USER_NAME (state, user) {
          state.username = user.name
        }
      },
      actions: {
        getData (context, id) {
          axios.post(
            'http://127.0.0.1:9000/mobile/info',
            qs.stringify({id: id})
          ).then(function (res) {
            context.commit('SET_USER_NAME', res.data)
          }).catch(function (error) {
            console.info(error)
          })
        }
      },
      getters: {
        username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
      }
    })
    
    export default store
    

      

    ps:
    a.getters中的username方法并无实际作用,只是演示计算生成新的一个状态数据
    b.username用了es6的箭头函数;等价于:
    username(state){
    return username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
    }

    4.main.js中注入store;关键代码

    import store from '@/store/store'
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      store,
      template: '<App/>',
      components: { App }
    })
    

      

    5.在components中新建query.vue;代码如下:

    <template>
      <div>
        <span>{{ this.$store.getters.username }}</span>
        <input type="text" v-model="id" />
        <button @click="$store.dispatch('getData', id)">获取数据</button>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {id: 0}
      }
    }
    </script>
    

      

    6.在App.vue中:

    <template>
      <div id="app">
        <img src="./assets/logo.png">
        <span>{{ $store.getters.username }}</span>
        <query></query>
      </div>
    </template>
    
    <script>
    import query from '@/components/query'
    export default {
      methods: {
    
      },
      components: {
        query
      }
    }
    </script>
    

      

    至此完成了一个简单的示例

    输入id,点击获取数据后

    四.继续改进(引入mapState)

    以上就是基本的用法,但还有些瑕疵,我们继续改进:

    1.上面的示例中,在query.vue中我们常见的应该是用computed属性去访问state,因为它是依赖缓存的;代码改进如下:

    <template>
      <div>
        <span>比较好看的username:{{ humanUserName }}</span>
        <br>
        <span>普通的username:{{ username }}</span>
        <br>
        <input type="text" v-model="id" />
        <button @click="$store.dispatch('getData', id)">获取数据</button>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {id: 0}
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        username () {
          return this.$store.state.username
        }
      }
    }
    </script>
    

      

    ps:可以看到我们定义了两个computed属性,humanUserName和username;前者从store的getters取数据,后者直接从state取数据.

    2.我们在store.js中再增加一些状态:

    const store = new Vuex.Store({
      state: {
        username: '暂无用户名,请获取数据',
        sex: '未知',
        age: '0'
      },
      ...........................
    })
    

      

    3.在query.vue中我们仍然打印这些状态:

    <template>
      <div>
        <span>比较好看的username:{{ humanUserName }}</span>
        <br>
        <span>普通的username:{{ username }}</span>
        <br>
        <span>性别: {{ sex }}</span>
        <br>
        <span>年龄: {{ age }}</span>
        <input type="text" v-model="id" />
        <button @click="$store.dispatch('getData', id)">获取数据</button>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {id: 0}
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        username () {
          return this.$store.state.username
        },
        age () {
          return this.$store.state.age
        },
        sex () {
          return this.$store.state.sex
        }
      }
    }
    </script>
    

      

    你会发现现在的代码变的冗长了,原因在于我们在computed挨个获取state;改进这一点

    4.使用Vuex的mapState来改进,改进部分代码如下

    <script>
    import {mapState} from 'vuex'
    export default {
      data () {
        return {id: 0}
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        ...mapState({
          username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
          age: 'age',
          sex: 'sex'
        })
      }
    }
    </script>
    

      

    ps:
    在...mapState前面的...叫做扩展运算符

    五.继续改进

    当然<button @click="$store.dispatch('getData', id)">获取数据</button>这个也不是很好,应该将他放入组件的methods中

    1.改进代码如下:

    <template>
      <div>
        <span>比较好看的username:{{ humanUserName }}</span>
        <br>
        <span>普通的username:{{ username }}</span>
        <br>
        <span>性别: {{ sex }}</span>
        <br>
        <span>年龄: {{ age }}</span>
        <input type="text" v-model="id" />
        <button @click="getRemoteData()">获取数据</button>
      </div>
    </template>
    
    <script>
    import {mapState} from 'vuex'
    export default {
      data () {
        return {id: 0}
      },
      methods: {
        getRemoteData () {
          this.$store.dispatch('getData', this.id)
        }
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        ...mapState({
          username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
          age: 'age',
          sex: 'sex'
        })
      }
    }
    </script>
    

      

    2.如果有十个dispatch,this.$store.dispatch('XXX', XXX)这样的代码势必要写十遍;可以使用...mapActions,改进部分代码如下:

    <template>
      <div>
        <span>比较好看的username:{{ humanUserName }}</span>
        <br>
        <span>普通的username:{{ username }}</span>
        <br>
        <span>性别: {{ sex }}</span>
        <br>
        <span>年龄: {{ age }}</span>
        <input type="text" v-model="id" />
        <button @click="getRemoteData(id)">获取数据</button>
      </div>
    </template>
    
    <script>
    import {mapState, mapActions} from 'vuex'
    export default {
      data () {
        return {id: 0}
      },
      methods: {
        ...mapActions({getRemoteData: 'getData'})
        /*
        如果名称相同,可以直接写成,...mapActions(['getData'])
        */
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        ...mapState({
          username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
          age: 'age',
          sex: 'sex'
        })
      }
    }
    </script>
    

      

    然还有个...mapGetters,用法和mapState,mapActions是一样的,在此不做介绍了.

    五.增加一个loading提示

    现在似乎是完善了,但忽略了一点是,我们的数据是从服务器获取的,所以为了好的用户体验,应该加个loading.在获取数据的时候显示,获取完了隐藏.

    1.store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    import qs from 'qs'
    
    Vue.use(Vuex)
    axios.defaults.baseURL = '/api'
    
    const store = new Vuex.Store({
      state: {
        username: '暂无用户名,请获取数据',
        sex: '未知',
        age: '0',
        waiting: false // loading状态
      },
      mutations: {
        SET_USER_NAME (state, user) {
          state.username = user.name
        },
        // 显示和隐藏waiting
        SHOW_WAITING_MESSAGE (state) {
          state.waiting = true
        },
        HIDE_WAITING_MESSAGE (state) {
          state.waiting = false
        }
      },
      actions: {
        getData ({commit}, id) {
          commit('SHOW_WAITING_MESSAGE')
          axios.post(
            'http://127.0.0.1:9000/mobile/info',
            qs.stringify({id: id})
          ).then(function (res) {
            commit('HIDE_WAITING_MESSAGE')
            commit('SET_USER_NAME', res.data)
          }).catch(function (error) {
            console.info(error)
          })
        }
      },
      getters: {
        username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
      }
    })
    
    export default store
    

      

    2.query.vue

    <template>
      <div>
        <span v-if="show">正在加载....</span>
        <br>
        <span>比较好看的username:{{ humanUserName }}</span>
        <br>
        <span>普通的username:{{ username }}</span>
        <br>
        <span>性别: {{ sex }}</span>
        <br>
        <span>年龄: {{ age }}</span>
        <input type="text" v-model="id" />
        <button @click="getRemoteData(id)">获取数据</button>
      </div>
    </template>
    
    <script>
    import {mapState, mapActions} from 'vuex'
    export default {
      data () {
        return {id: 0}
      },
      methods: {
        ...mapActions({getRemoteData: 'getData'})
        /*
        如果名称相同,可以直接写成,...mapActions(['getData'])
        */
      },
      computed: {
        humanUserName () {
          return this.$store.getters.username
        },
        ...mapState({
          username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
          age: 'age',
          sex: 'sex',
          show: 'waiting'
        })
      }
    }
    </script>
    

      

    ps:对于store中的actions中的方法

    getData (context, id) {
    ......
    }
    

      

    会自动获得一个默认参数context,它是一个store 实例,通过它可以获取到store 实例的属性和方法,如 context.state 就会获取到 state 属性, context.commit 就会执行commit命令.其实actions 还可以简写一下, 因为函数的参数是一个对象,函数中用的是对象中一个方法,我们可以通过对象的解构赋值直接获取到该方法。可以修改如下

    getData ({commit}, id) {
    ......
    }
    

      

    本文参考了:

    http://www.cnblogs.com/SamWeb/p/6527240.html

    https://segmentfault.com/a/1190000009404727

  • 相关阅读:
    layui + mvc + ajax 导出Excel功能
    PL/SQL Developer工具包和InstantClient连接Oracle 11g数据库
    .NET中JSON的序列化和反序列化的几种方式
    C# 编程中的堆栈(Stack)和队列(Queue)
    Oracle 数据库常用操作语句大全
    C#方法中参数ref和out的解析
    JS实现限行
    ajax+ashx 完美实现input file上传文件
    HTML5 学习
    Linux文件和目录操作管理命令
  • 原文地址:https://www.cnblogs.com/itfenqing/p/7401857.html
Copyright © 2020-2023  润新知