Vuex的使用

Vuex是用来对vue项目中,多个组件的共享状态进行集中的管理(读和写)。通过action行为触发定义好的修改方式来修改全局变量,以及getters获取全局变量,能够让我们方便地管理这些全局变量。

本文将介绍:

一、什么是Vuex

1.1  单项数据流

1.2  为什么会出现Vuex

         1.3 Vuex的实现思路

二、Vuex的使用

2.1 文件基本模式

2.2 核心模块

三、实战:移动端上,使用Vuex控制统一弹窗界面的显示


一、什么是Vuex

在学习如何使用Vuex之前,我们要先学习到 Vue 中单项数据流的概念。

1.1  单项数据流

一个单项数据流中包含三个元素:

State:  驱动应用的数据源;

View:   以声明方式将 State 映射到视图

Actions: 响应在 view 上的用户输入导致的状态变化

在使用时,通过 Actions 修改变量的状态,变量状态修改后,变量通过映射的方式引起视图变化

在Vue文件中,上述三种元素提现为:

<template>
  <div class="Item">
    {{myData}} // view: 通过双夸号声明的方式,将myData数据显示到视图层上
  </div>
</template>

<script>

export default {
  name: 'Test',
  data () {
    return {
      myData: 'this is my test' // state:数据源,用来承载数据
    }
  },
  methods: {
    changeMyData: function() {  // action: 动作行为。用来修改数据状态(内容)
        this.myData = 'myData is changed'
    }
  }
}

</script>

 

1.2  为什么会出现Vuex

由于Vue中单项数据流的变量管理模式,当出现多个组件同时依赖同一个数据,同时会修改这个数据,并响应到页面上的情况时,单向数据流模型就会遭到破坏,变得复杂。最直接的就是数据难以传输和管理。而 Vue 提供的组件间传值方式,在多个共享变量,多组件共享的情况下,无疑太多复杂。

如下图:

当出现多个组件共享数据AData,并都会去修改这个共享数据AData的状态时,若只是在子组件(如组件B、组件C)中做修改,无法做到在子组件中修改了数据内容,自动重新渲染其他组件的内容。

 

1.3 Vuex的实现思路

基于上面的共享变量需要被多个组件同时使用和修改状态,Vue将这些共享变量都提取出来,统一存储,并提供一个Action修改方法,提供一个Getter方法获取这个共享变量。这样就形成了一个全局单例模式管理,在这种模式下,所有的组件树都能够自由获取状态或者触发行为,但这种行为只能根据设定好的规则触发和获取,有利于未来代码的维护和变更。

从Vue官网提供的这张图就可以看出Vuex的实现模式,即将Vuex作为一个全局的单例单向流结构,提供给所有组件使用。

vuex

二、Vuex的使用

2.1 文件基本模式

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    userName: 'xiaowang'
  },
  getters: {
    getName () {
        return state.userName
    }
  },
  mutations: {
    setUName(state:any, name:string) {
      state.userName = name
    }
  },
  actions: {
    setUserName({ commit, state }, name:number) {
      commit('setUName', name)
    }
  },
  modules: {
  }
})

2.2 核心模块

2.2.1  State  单一状态树

每一个Vue项目都只有一个单一状态树,其作为唯一数据源存在,让我们能直接定位到特定的数据片段。

state: {
   loadingProcess: 0,
   popPage: 'loading'
},

 

2.2.2  Mutation 状态修改事件

当要修改 Vuex 中存储的状态,唯一方法就是是提交 mutation,通过传值的方式修改 State 中存储的特定变量。

mutation事件中提供state参数和payload载荷,state参数可以看作是单一状态树具体化的一个对象,可以获取到单一状态树内的数据,payload载荷其实是一个json形式对象,也可以直接传变量。

// 定义
export default new Vuex.Store({
  state: {
    userName: 'xiaowang',
    age: 18
  },
  mutations: {
    serUser(state:any, payload:any) {
      state.userName = payload.name
      state.age = payload.age
    },
    setUName(state:any, name:string) {
      state.userName = name
    }
  }
})

// 使用载荷
store.commit('serUser', {
  userName: 'lisi',
  age: 22
})
// 直接传值
store.commit('setUName', userName: 'lisi')

但由于Mutation只能是同步,如果在Mutation中混合了异步操作,如http请求,则会导致线程卡住,且难以调试。Mutation应该更注重于State的变化,而不是修改State的值的来源逻辑。这应该放在Action中使用

 

2.2.3  Action 修改动作

Action和 Mutation很像,都是通过外部调用来修改state,但实际Action也是通过调用Mutation来间接修改State值的。

他们的具体区别在于:

  • Action是通过提交Mutation来修改状态的,而Mutation才是直接改变状态
  • Action中可以包含任意异步操作,可以在Action中使用http等任意异步操作,并在回调函数中通过 commit 触发Mutation来修改状态值。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    userName: 'xiaowang'
  },
  getters: {
    getName () {
        return state.userName
    }
  },
  mutations: {
    setUName(state:any, name:string) {
      state.userName = name
    }
  },
  actions: {
    setUserName({ commit, state }, name:number) {
      axios.post(Api.getName).then{
        (res) => {
            commit('setUName', res) // 获取到异步请求的数据后,提交mutations修改state值
        }
      } 
    }
  },
  modules: {
  }
})

三、实战:移动端上,使用Vuex控制统一弹窗界面的显示

在移动端中,弹窗界面一般只会显示一个,如果用传统的方式来控制弹窗之间的切换时,需要用js代码主动遍历一遍所有的弹窗,确定他们都被关闭了。或是在按键控制时,频繁的操控弹窗的打开和关闭。

Vue中提供了v-if来控制界面是否显示,我们可以将Vuex和v-if结合起来,在Vuex中存储一个唯一的弹窗变量,来表明当前是哪一个弹窗。同时由于Vuex的实时渲染,其他打开的弹窗就会自动隐藏起来。以下是项目代码:

 store.js ///

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    popPage: 'loading'
  },
  getters: {
    // 获取当前弹窗
    getPopPageName: (state) => {
      return state.popPage
    }
  },
  mutations: {
    setPopPages (state:any, pageName:string) {
      state.popPage = pageName
    }
  },
  actions: {
    switchPopPages ({ commit, state }, pageName:string) {
      commit('setPopPages', pageName)
    }
  },
  modules: {
  }
})
<!-- tom 首页 -->
<template>
  <div class='Home'>
      <div class="AgentCenter" @click="jumpToPage('/agentCenter')">
        <div class="AgentImg"></div>
      </div>

      <!-- tom 用户中心-->
      <ComDialog ref="userCenter" v-if="state.getters.getPopPageName === 'userCenter'">
        <div slot="dialog-title">用户中心</div>
        <div slot="dialog-content">用户名称</div>
      </ComDialog>

      <!-- tom 设置-->
      <ComDialog ref="setting" v-if="state.getters.getPopPageName === 'setting'">
        <div slot="dialog-title">设置中心</div>
        <div slot="dialog-content">音量</div>
      </ComDialog>

      <!-- tom 消息-->
      <ComDialog ref="message" v-if="state.getters.getPopPageName === 'message'">
        <div slot="dialog-title">消息中心</div>
        <div slot="dialog-content">消息</div>
      </ComDialog>
  </div>
</template>
<script>

export default {
  name: 'Home',
  data () {
    return {
    }
  },
  methods: {
    // 可以调用这个方法,来打开某个弹窗,其他弹窗会自动隐藏
    openPop: function (url) {
      this.$state.switchPopPages(url)
    }
  },
  created () {
  },
  mounted () {
  }
}
</script>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值