zoukankan      html  css  js  c++  java
  • vue中vuex的使用练习

    Vuex 是什么?

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

    每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

    1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

    2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

    vuex中,有默认的五种基本的对象:

    • state:存储状态(变量)

    • getters:对数据获取之前的再次编译,可以理解为state的计算属性。我们在组件中使用 $sotre.getters.fun()

    • mutations:修改状态,并且是同步的。在组件中使用$store.commit('',params)。这个和我们组件中的自定义事件类似。

    • actions:异步操作。在组件中使用是$store.dispath('')

    • modules:store的子模块,为了开发大型项目,方便状态管理而使用的。这里我们就不解释了,用起来和上面的一样。

    0、在 main.js里面,引入vuex相关的js文件

    import store from './store'
    // store.js
    
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    import user from './module/user'
    import app from './module/app'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        //
        number: 0
      },
      mutations: {
      
      },
      getters: {
       
      },
      actions: {
        
      },
      modules: {
    
      }
    })

    1、在 Vue 组件中获得 Vuex 状态(state)

    (1)直接在组件father.vue中调用:

    <div style="border: 2px solid #007606;padding: 5px;">
          VUEX的数据【number】:
          <span style="font-size: 30px;font-weight: bolder;">
            {{this.$store.state.number}}
          </span>
    </div>

     (2)或者在计算属性中处理后使用

    <div style="border: 2px solid #007606;padding: 5px;">
      VUEX的数据【number】:
      <span style="font-size: 30px;font-weight: bolder;">
        {{count}}
      </span>
    </div>
    computed: {
      count () {
        return '==这是VUEX中定义的Number==:'+this.$store.state.number
      }
    },

    2、Getter

    有时候我们需要从 store 中的 state 中派生出一些状态,

    如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。

    Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

    (1)实例:孙子级组件F中,处理【number】的值,*2

    <div style="border: 2px solid #2700ff;padding: 5px;">
      Vuex的数值【number*2】:
      <span style="font-size: 30px;font-weight: bolder;">
      {{$store.getters.doneTodosCount}}
      </span>
    </div>

    (2)store.js代码:

    getters: {
      doneTodosCount: (state, getters) => {
        return state.number * 2
      }
    },

    3、Mutation(Mutation 必须是同步函数)

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

    (1)实例:祖父级组件parent,点击按钮,对number进行++或者--的操作

    <div style="border: 2px solid #007606;padding: 5px;">
      VUEX的数据【number】:
      <span style="font-size: 30px;font-weight: bolder;">
        {{count}}
      </span>
    
      <br>
      <el-button @click="vuexClick1">点击++</el-button>
      <el-button @click="vuexClick2">点击--</el-button>
    </div>
    methods: {
      vuexClick1 () {
        this.$store.commit('vuexClick1')
      },
      vuexClick2 () {
        this.$store.commit('vuexClick2')
      }
    },

    (2)store.js代码:

    mutations: {
      //
      vuexClick1 (state) {
        return state.number++
      },
      vuexClick2 (state) {
        return state.number--
      }
    },

    4、Ation

    Action 类似于 mutation,不同在于:

    • Action 提交的是 mutation,而不是直接变更状态。

    • Action 可以包含任意异步操作。

    (1)实例:祖父级组件parent,点击按钮"number延时3s加10",对number进行延时3s加10的操作

    <el-button @click="vuexClick3">number延时3s加10</el-button>
    vuexClick3 () {
      this.$store.dispatch('vuexClick3')
    }

    (2)store.js代码:

    actions: {
      //
      vuexClick3 (state) {
        setTimeout(() => {
          return state.commit('NumberChange3')
        }, 3000)
      }
    },
    NumberChange3 (state) {
      return state.number += 10
    }

    5、Module

    官方文档

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

    image.png

    modules: {
      user,
      app
    }

    命名空间

    默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

    如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

    const store = new Vuex.Store({
      modules: {
        account: {
          namespaced: true,
    
          // 模块内容(module assets)
          state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
          getters: {
            isAdmin () { ... } // -> getters['account/isAdmin']
          },
          actions: {
            login () { ... } // -> dispatch('account/login')
          },
          mutations: {
            login () { ... } // -> commit('account/login')
          },
    
          // 嵌套模块
          modules: {
            // 继承父模块的命名空间
            myPage: {
              state: { ... },
              getters: {
                profile () { ... } // -> getters['account/profile']
              }
            },
    
            // 进一步嵌套命名空间
            posts: {
              namespaced: true,
    
              state: { ... },
              getters: {
                popular () { ... } // -> getters['account/posts/popular']
              }
            }
          }
        }
      }})

    【官网实例】

    完整代码:

    1.store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    import user from './module/user'
    import app from './module/app'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        //
        number: 0
      },
      mutations: {
        //
        vuexClick1 (state) {
          return state.number++
        },
        vuexClick2 (state) {
          return state.number--
        },
        NumberChange3 (state) {
          return state.number += 10
        }
      },
      getters: {
        doneTodosCount: (state, getters) => {
          return state.number * 2
        }
      },
      actions: {
        //
        vuexClick3 (state) {
          setTimeout(() => {
            return state.commit('NumberChange3')
          }, 3000)
        }
      },
      modules: {
        user,
        app
      }
    })

    2.father.vue

    <!--
      文件描述:祖父级组件
      创建时间:2019/12/28 15:30
    -->
    <template>
      <div class="" style=" 900px;height: 700px;background-color: #d6e7ff;padding: 20px;">
        <span style="font-size: 20px;font-weight: bold;">祖父级组件:father</span>
        <div style="border: 2px solid #007606;padding: 5px;">
          VUEX的数据【number】:
          <span style="font-size: 30px;font-weight: bolder;">
            {{count}}
          </span>
    
          <br>
          <el-button @click="vuexClick1">点击++</el-button>
          <el-button @click="vuexClick2">点击--</el-button>
          <el-button @click="vuexClick3">number延时3s加10</el-button>
        </div>
        <br>
    
        <div>
          <childrenA></childrenA>
          <childrenB></childrenB>
          <childrenC></childrenC>
        </div>
      </div>
    </template>
    
    <script>
    // 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
    // 例如:import 《组件名称》 from '《组件路径》';
    import childrenA from './childrenA'
    import childrenB from './childrenB'
    import childrenC from './childrenC'
    
    export default {
      name: 'father',
      // import引入的组件需要注入到对象中才能使用
      components: {
        childrenA,
        childrenB,
        childrenC
      },
      computed: {
        count () {
          return this.$store.state.number
        }
      },
      methods: {
        vuexClick1 () {
          this.$store.commit('vuexClick1')
        },
        vuexClick2 () {
          this.$store.commit('vuexClick2')
        },
        vuexClick3 () {
          this.$store.dispatch('vuexClick3')
        }
      },
      data () {
        // 这里存放数据
        return {
        }
      }
    }
    </script>

    3.childrenG.vue

    <!--文件描述:孙子级组件G
      创建时间:2019/12/28 15:37-->
    <template>
      <div class="" style="float: left;margin: 10px; 200px;height: 200px;background-color: #ff00de;padding: 20px;color:#fff;">
        <span style="font-size: 14px;font-weight: bold;color:#fff;">孙子级组件G:childrenG</span>
        <div style="border: 2px solid #00ff09;padding: 5px;">
          VUEX的数据【number】:
          <span style="font-size: 30px;font-weight: bolder;">
            {{this.$store.state.number}}
          </span>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'childrenA',
      // import引入的组件需要注入到对象中才能使用
      components: {},
      data () {
        // 这里存放数据
        return {
        }
      }
    }
    </script>

    4.childrenF.vue

    <!--
      文件描述:孙子级组件F
      创建时间:2019/12/28 15:37
      创建人:
    -->
    <template>
      <div class="" style="float: left;margin: 10px; 200px;height: 200px;background-color: #aaff1a;padding: 20px;">
        <span style="font-size: 14px;font-weight: bold;color:#000000;">孙子级组件F:childrenF</span>
        <div style="border: 2px solid #2700ff;padding: 5px;">
          Vuex的数值【number*2】:
          <span style="font-size: 30px;font-weight: bolder;">
          {{$store.getters.doneTodosCount}}
          </span>
        </div>
      </div>
    </template>
    
    <script>
    // 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
    // 例如:import 《组件名称》 from '《组件路径》';
    // 例如:import uploadFile from '@/components/uploadFile/uploadFile'
    
    export default {
      name: 'childrenA',
      // import引入的组件需要注入到对象中才能使用
      components: {},
      data () {
        // 这里存放数据
        return {
    
        }
      },
      // 监听属性 类似于data概念
      computed: {},
      // 方法集合
      methods: {},
      // 监控data中的数据变化
      watch: {},
      // 生命周期 - 创建完成(可以访问当前this实例)
      created () {
    
      },
      // 生命周期 - 挂载完成(可以访问DOM元素)
      mounted () {
    
      },
      beforeCreate () {
      }, // 生命周期 - 创建之前
      beforeMount () {
      }, // 生命周期 - 挂载之前
      beforeUpdate () {
      }, // 生命周期 - 更新之前
      updated () {
      }, // 生命周期 - 更新之后
      beforeDestroy () {
      }, // 生命周期 - 销毁之前
      destroyed () {
      }, // 生命周期 - 销毁完成
      activated () {
      } // 如果页面有keep-alive缓存功能,这个函数会触发
    }
    </script>
    
    <style scoped  lang="scss">
      //@import url(); 引入公共css类
    </style>

     5.user.js

    import {
      login,
      logout,
      getUserInfo,
      getMessage,
      getContentByMsgId,
      hasRead,
      removeReaded,
      restoreTrash,
      getUnreadCount
    } from '@/api/user'
    import { setToken, getToken } from '@/libs/util'
    
    export default {
      state: {
        userName: '',
        userId: '',
        avatorImgPath: '',
        token: getToken(),
        access: '',
        hasGetInfo: false,
        unreadCount: 0,
        messageUnreadList: [],
        messageReadedList: [],
        messageTrashList: [],
        messageContentStore: {}
      },
      mutations: {
        setAvator (state, avatorPath) {
          state.avatorImgPath = avatorPath
        },
        setUserId (state, id) {
          state.userId = id
        },
        setUserName (state, name) {
          state.userName = name
        },
        setAccess (state, access) {
          state.access = access
        },
        setToken (state, token) {
          state.token = token
          setToken(token)
        },
        setHasGetInfo (state, status) {
          state.hasGetInfo = status
        },
        setMessageCount (state, count) {
          state.unreadCount = count
        },
        setMessageUnreadList (state, list) {
          state.messageUnreadList = list
        },
        setMessageReadedList (state, list) {
          state.messageReadedList = list
        },
        setMessageTrashList (state, list) {
          state.messageTrashList = list
        },
        updateMessageContentStore (state, { msg_id, content }) {
          state.messageContentStore[msg_id] = content
        },
        moveMsg (state, { from, to, msg_id }) {
          const index = state[from].findIndex(_ => _.msg_id === msg_id)
          const msgItem = state[from].splice(index, 1)[0]
          msgItem.loading = false
          state[to].unshift(msgItem)
        }
      },
      getters: {
        messageUnreadCount: state => state.messageUnreadList.length,
        messageReadedCount: state => state.messageReadedList.length,
        messageTrashCount: state => state.messageTrashList.length
      },
      actions: {
        // 登录
        handleLogin ({ commit }, { userName, password }) {
          userName = userName.trim()
          return new Promise((resolve, reject) => {
            login({
              userName,
              password
            }).then(res => {
              const data = res.data
              commit('setToken', data.token)
              resolve()
            }).catch(err => {
              reject(err)
            })
          })
        },
        // 退出登录
        handleLogOut ({ state, commit }) {
          return new Promise((resolve, reject) => {
            logout(state.token).then(() => {
              commit('setToken', '')
              commit('setAccess', [])
              resolve()
            }).catch(err => {
              reject(err)
            })
            // 如果你的退出登录无需请求接口,则可以直接使用下面三行代码而无需使用logout调用接口
            // commit('setToken', '')
            // commit('setAccess', [])
            // resolve()
          })
        },
        // 获取用户相关信息
        getUserInfo ({ state, commit }) {
          return new Promise((resolve, reject) => {
            try {
              getUserInfo(state.token).then(res => {
                const data = res.data
                commit('setAvator', data.avator)
                commit('setUserName', data.name)
                commit('setUserId', data.user_id)
                commit('setAccess', data.access)
                commit('setHasGetInfo', true)
                resolve(data)
              }).catch(err => {
                reject(err)
              })
            } catch (error) {
              reject(error)
            }
          })
        },
        // 此方法用来获取未读消息条数,接口只返回数值,不返回消息列表
        getUnreadMessageCount ({ state, commit }) {
          getUnreadCount().then(res => {
            const { data } = res
            commit('setMessageCount', data)
          })
        },
        // 获取消息列表,其中包含未读、已读、回收站三个列表
        getMessageList ({ state, commit }) {
          return new Promise((resolve, reject) => {
            getMessage().then(res => {
              const { unread, readed, trash } = res.data
              commit('setMessageUnreadList', unread.sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
              commit('setMessageReadedList', readed.map(_ => {
                _.loading = false
                return _
              }).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
              commit('setMessageTrashList', trash.map(_ => {
                _.loading = false
                return _
              }).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
              resolve()
            }).catch(error => {
              reject(error)
            })
          })
        },
        // 根据当前点击的消息的id获取内容
        getContentByMsgId ({ state, commit }, { msg_id }) {
          return new Promise((resolve, reject) => {
            let contentItem = state.messageContentStore[msg_id]
            if (contentItem) {
              resolve(contentItem)
            } else {
              getContentByMsgId(msg_id).then(res => {
                const content = res.data
                commit('updateMessageContentStore', { msg_id, content })
                resolve(content)
              })
            }
          })
        },
        // 把一个未读消息标记为已读
        hasRead ({ state, commit }, { msg_id }) {
          return new Promise((resolve, reject) => {
            hasRead(msg_id).then(() => {
              commit('moveMsg', {
                from: 'messageUnreadList',
                to: 'messageReadedList',
                msg_id
              })
              commit('setMessageCount', state.unreadCount - 1)
              resolve()
            }).catch(error => {
              reject(error)
            })
          })
        },
        // 删除一个已读消息到回收站
        removeReaded ({ commit }, { msg_id }) {
          return new Promise((resolve, reject) => {
            removeReaded(msg_id).then(() => {
              commit('moveMsg', {
                from: 'messageReadedList',
                to: 'messageTrashList',
                msg_id
              })
              resolve()
            }).catch(error => {
              reject(error)
            })
          })
        },
        // 还原一个已删除消息到已读消息
        restoreTrash ({ commit }, { msg_id }) {
          return new Promise((resolve, reject) => {
            restoreTrash(msg_id).then(() => {
              commit('moveMsg', {
                from: 'messageTrashList',
                to: 'messageReadedList',
                msg_id
              })
              resolve()
            }).catch(error => {
              reject(error)
            })
          })
        }
      }
    }
  • 相关阅读:
    HTB-靶机-Charon
    第一篇Active Directory疑难解答概述(1)
    Outlook Web App 客户端超时设置
    【Troubleshooting Case】Exchange Server 组件状态应用排错?
    【Troubleshooting Case】Unable to delete Exchange database?
    Exchange Server 2007的即将生命周期,您的计划是?
    "the hypervisor is not running" 故障
    Exchange 2016 体系结构
    USB PE
    10 months then free? 10个月,然后自由
  • 原文地址:https://www.cnblogs.com/pangchunlei/p/12118391.html
Copyright © 2011-2022 走看看