vuex的简介

一. 认识vuex

1. 什么是vuex

vuex是一个vue的状态管理工具,状态就是数据

大白话:vuex是一个插件,可以帮我们管理vue通用的数据(多组件共享的数据)

2. vuex的应用场景

1. 某个状态在很多组件都要用(个人信息)

2. 多个组件共同维护一份数据(购物车)

3. vuex的优势

1. 共同维护一份数据,数据集中化管理

2. 响应式变化

3. 操作简洁(vuex提供了一些辅助函数)

4. 构建vuex环境

基于脚手架创建项目,构建vuex多组件数据共享环境

效果:

1. 三个组件,共享一份数据

2. 任意一个组件都可以修改数据

3. 三个组件的数据是同步的

安装vuex插件,初始化一个空仓库

//1. 安装vuex 
yarn add vuex@3

//2. 新建vuex模块文件
store/index.js专门存放vuex

//3. 创建仓库
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库
const store = new Vuex.Store()
// 导出给main.js使用
export default store

//4. main.js导入挂载
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
  store
}).$mount('#app')

二. 使用vuex管理数据 

1. 核心概念-state状态

如何给仓库提供数据

state提供唯一的公共数据源,所有共享的数据都要统一放到Store中的state中存储。

在state对象中可以添加我们要共享的数据。

const store = new Vuex.Store({
  //state状态,即数据,类似于vue组件中的data
  //区别:data是组件自己的数据,state是所有组件共享的数据
  state: {
    count: 101
  }
})

如何使用仓库的数据

1. 通过store直接访问

获取store:
1. this.$store
2. import 导入 store

模板中:{{ $store.state.xxx }}
组件逻辑中:this.$store.state.xxx
JS模块中:store.state.xxx

2. 通过辅助函数mapState

辅助函数mapState,映射状态

mapState是辅助函数,帮助我们把store中的数据,自动映射到组件的计算属性中 

{{ count }}

//把state中的数据,定义在组件内的计算属性中
computed: {
    count () {
        return this.$store.state.count
    }
}
// 上面的方法简化了以前的代码,但如果每次都要去写computed的话还是很麻烦,所有有了mapState

//1. 导入mapState
import { mapState } from 'vuex'

//2. 数组方式引入state
// 注意这样得到的结果是对象
mapState(['count', 'title'])

//3. 展开运算符映射
computed: {
    ...mapState(['count', 'title'])
}

// 此时页面中就可以直接写
{{ title }}
{{ count }}

2. mutations修改数据 

state数据的修改只能通过mutations

vuex同样遵循单向数据流,组件中不能直接修改仓库的数据

// 通过strict: true可以开启严格模式
const store = new Vuex.Store({
  // 开启严格模式(有利于初学者,检测不规范的代码=>上线时需要移除)
  strict: true,
  state: {
    title: '仓库大标题',
    count: 101
  }
})

handleAdd (n) {
    // 错误代码(vue默认不会监测,监测需要成本)
    // this.$store.state.count++
    // console.log(this.$store.state.count)
},

如何用mutation修改数据

mutations: {
    // 所有mutation函数,第一个参数,都是state
    addCount (state) {
        // 修改数据
        state.count += 1
    }
}

//在页面中就可以提交调用mutation
handleAdd () {
    // 应该通过 mutation 核心概念,进行修改数据
    // 需要提交调用mutation
    this.$store.commit('addCount')
}

mutations传参语法 this.$store,commit( 'xxx',参数 )

// 提供mutation函数(带参数-提交载荷payload)
mutations: {
    ...
    addCount (state, n) {
        // 修改数据
        state.count += n
    },
    changeTitle (state, newTitle) {
        state.title = newTitle
    }
}

// 在页面中提交调用mutation
handleAdd (n) {
    // 调用带参数的mutation函数
    this.$store.commit('addCount', n)
},
changeFn () {
    this.$store.commit('changeTitle', '传智教育')
}

辅助函数mapMutations,映射方法

把位于mutations中的方法提取出来,映射到组件methods中

// 这里是index.js文件
mutations:{
    subCount(state,n) {
        state.count -= n
    },
}


//这里是别的.vue组件
import { mapMutions } from 'vuex'
methods: {
    ...mapMutations([ 'subCount' ])
}
// 等价于
methods: {
    subCount (n) {
        this.$store.commit( 'subCount',n )
    }
}
// 调用
handleSub(n) {
    this.subCount(n)
}

3. actions处理异步 

actions,处理异步操作

说明:mutations必须是同步的(便于检测数据变化,记录调试),如果有异步,就得走actions

// 需求:一秒钟之后,修改state的count成666

// 这里是index.js文件中
// 1. 提供action方法
actions: {
    setAsyncCount (context, num) {
        // 这里是setTimeout模拟异步,以后大部分场景是发请求
        //一秒后,给一个数,去修改num
        setTimeout(()=>{
            context.commit('changeCount',num)
        },1000)
    }
}


// 这里是其他的.vue文件中
//2. 页面中dispatch调用
this.$store.dispatch('setAsyncCount', 666 )

辅助函数mapActions,映射方法

 把位于actions中的方法提取出来,映射到组件methods中。

// 这里是index.js文件中
actions: {
    setAsyncCount (context, num) {
        // 这里是setTimeout模拟异步,以后大部分场景是发请求
        //一秒后,给一个数,去修改num
        setTimeout(()=>{
            context.commit('changeCount',num)
        },1000)
    }
}


// 这里是其他的.vue文件中
import { mapActions } from 'vuex'
methods: {
    ...mapActions(['changeCountAction'])
}
//等价于
methods: {
    changeCountAction (n) {
        this.$store.dispatch('changeCountAction',n )
    }
}
//调用
this.changeCountAction(666)

4. getters修改数据 

 getters,类似于计算属性

除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters。

// 这里是index.js文件
//1. 定义getters
getters: {
    // 注意点:
    // 1. 形参第一个参数,就是state
    // 2. 必须有返回值,返回值就是getters的值
    filterList (state) {
      return state.list.filter(item => item > 5)
    }
}

//这里是别的.vue组件
//2. 访问getters
//1. 通过store访问getters
{{ $store.getters.filterList }}

辅助函数mapGetters,映射属性

//2. 通过辅助函数mapGetters映射
computed: {
    ...mapGetters(['filterList'])
}
{{ filterList }}

5. module模块化 

模块module,进阶语法

由于vuex使用单一状态数,应用的所有状态会集中到一个比较大的对象。

当应用变得非常复杂时,store对象就有可能变得相当臃肿。(当项目变得越来越大的时候,Vuex会变得越来越难以维护)。

每一个.js文件就是一个模块

user模块:store/modules/user.js
setting模块:store/modules/setting.js

// user模块
const state = {
  userInfo: {
    name: 'zs',
    age: 18
  },
  score: 80
}
const mutations = {
  setUser (state, newUserInfo) {
    state.userInfo = newUserInfo
  }
}
const actions = {
  setUserSecond (context, newUserInfo) {
    // 将异步在action中进行封装
    setTimeout(() => {
      // 调用mutation   context上下文,默认提交的就是自己模块的action和mutation
      context.commit('setUser', newUserInfo)
    }, 1000)
  }
}
const getters = {
  // 分模块后,state指代子模块的state
  UpperCaseName (state) {
    return state.userInfo.name.toUpperCase()
  }
}

export default {
  //开启命名空间
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

// setting模块
const state = {
  theme: 'light', // 主题色
  desc: '测试demo'
}
const mutations = {
  setTheme (state, newTheme) {
    state.theme = newTheme
  }
}
const actions = {}
const getters = {}

export default {
  //开启命名空间
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

在store下面的index.js里面进行导入和挂载 

// 然后在index.js文件中,导入模块
import user from './modules/user'
import setting from './modules/setting'

const store = new Vuex.Store({
    modules:{
        user,
        setting
    }
})

//在vue调试工具中看到,说明挂载成功了
Root
  user
  setting

如何访问子模块中的state

 尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名。

1. 直接通过模块名访问$store.state.模块名.xxx

<!-- 测试访问模块中的state - 原生 -->
<div>{{ $store.state.user.userInfo.name }}</div>
<div>{{ $store.state.setting.theme }}</div>

2. 通过mapState映射

默认根级别的映射mapState(['xxx])

...mapState(['user', 'setting'])

子模块的映射mapState('模块名', ['xxx'] ) -需要开启命名空间

...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),

如何访问子模块中的getters

1. 直接通过模块名访问$store.getters['模块名/xxx']

<!-- 测试访问模块中的getters - 原生 -->
<div>{{ $store.getters['user/UpperCaseName'] }}</div>

2. 通过mapGetters映射

默认根级别的映射mapGetters(['xxx'])

...mapGetters(['user']),

子模块的映射mapGetters('模块名',['xxx'])-需要开启命名空间

...mapGetters('user', ['UpperCaseName'])

如何调用子模块的mutation

1. 直接通过store调用$store.commit('模块名/xxx',额外参数)

// 2. 定义两个click事件
<button @click="updateUser">更新个人信息</button>
<button @click="updateTheme">更新主题色</button>

//3. 在methods中调用方法
updateUser () {
    // $store.commit('模块名/mutation名', 额外传参)
    this.$store.commit('user/setUser', {
        name: 'xiaowang',
        age: 25
    })
},
updateTheme () {
    this.$store.commit('setting/setTheme', 'pink')
},


//1. 先在user.js和setting.js的mutations中定义mutation
const mutations = {
  setUser (state, newUserInfo) {
    state.userInfo = newUserInfo
  }
}
const mutations = {
  setTheme (state, newTheme) {
    state.theme = newTheme
  }
}

2. 通过mapMutations映射

默认根级别的映射mapMutations(['xxx'])

子模块的映射mapMutations('模块名',['xxx'])-需要开启命名空间

...mapMutations('setting', ['setTheme']),
...mapMutations('user', ['setUser']),

// 这时候就可以直接用了
<button @click="setUser({ name: 'xiaoli', age: 80 })">更新个人信息</button>
<button @click="setTheme('skyblue')">更新主题</button>

如何调用子模块的action

1. 直接通过store调用$store.dispatch('模块名/xxx',额外参数)

// 2. 定义点击事件处理函数
<button @click="updateUser2">一秒后更新信息</button>

//3. 在methods中方法
updateUser2 () {
    // 调用action dispatch
    this.$store.dispatch('user/setUserSecond', {
        name: 'xiaohong',
        age: 28
    })
},

//1. 先在子模块user.js中提供一个action
const actions = {
  setUserSecond (context, newUserInfo) {
    // 将异步在action中进行封装
    setTimeout(() => {
      // 调用mutation   context上下文,默认提交的就是自己模块的action和mutation
      context.commit('setUser', newUserInfo)
    }, 1000)
  }
}

2. 通过mapActions映射

默认根级别的映射mapActions(['xxx'])

子模块的映射mapActions('模块名',['xxx'])-需要开启命名空间

...mapActions('user', ['setUserSecond'])

// 这个时候,页面中就可以直接调用了
<button @click="setUserSecond({ name: 'xiaoli', age: 80 })">一秒后更新信息</button>

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值