Vuex概述
vuex是一个vue的状态管理工具,状态就是数据(多组件共享数据)。
优势:
- 共同维护一份数据,数据集中化管理
- 响应式变化
- 操作简洁(vuex提供了一些辅助函数)
vuex的使用
安装vuex插件
yarn add vuex@3
创建vuex模块文件
新建store/index.js专门存放vuex
创建仓库
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store()
export default store
main.js导入挂载
html
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')
state状态
1.提供数据
state提供唯一的公共数据源,所有共享的数据都要统一放到Store中的stare中储存。
在state对象中可以添加我们要共享的数据。
html
const store = new Vuex.Store({
state: {
title: '大标题',
count: 100
}
})
2.使用数据
- 通过store直接访问
- 通过辅助函数(简化)
获取store:
- this.$store
- import 导入 stroe
直接访问
html
<template>
<div>
<p>数据:{{ $store.state.count }}</p>
<Son1Component></Son1Component>
<Son2Component></Son2Component>
</div>
</template>
辅助函数mapstate
mapstate是辅助函数,帮助我们把store中的数据自动映射到组件的计算机属性中。
导入mapState
html
import { mapState } from 'vuex'
通过对象的方式映射
html
computed: {
...mapState(['count', 'title'])
}
在模板中使用
html
<template>
<div>
<p>数据:{{ count }}</p>
<Son1Component></Son1Component>
<Son2Component></Son2Component>
</div>
</template>
mutations
1.定义mutations对象,对象中存放修改state的方法
html
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
title: '大标题',
count: 100
},
mutations: {
addcount (state) {
state.count += 1
},
subcount (state) {
state.count -= 1
}
}
})
export default store
2.组件中提交调用mutations
html
<template>
<div>
<p>数据:{{ this.$store.state.count }}</p>
<button @click="handleAdd">+1</button>
</div>
</template>
<script>
export default {
name: 'Son1Component',
methods: {
handleAdd () {
this.$store.commit('addcount')
}
}
}
</script>
mutations传参语法
提交mutations是可以传递参数的'this.$store,commit('xxx',参数)'
1.提供mutation函数(带参数---提交载荷payload)
html
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
title: '大标题',
count: 100
},
mutations: {
addcount (state, n) {
state.count += n
},
subcount (state, n) {
state.count -= n
}
}
})
export default store
html
<template>
<div>
<p>数据:{{ this.$store.state.count }}</p>
<button @click="handleAdd(1)">+1</button>
<button @click="handleAdd(5)">+5</button>
</div>
</template>
<script>
export default {
name: 'Son1Component',
methods: {
handleAdd (n) {
this.$store.commit('addcount', n)
}
}
}
</script>
传递多个参数时,可以包装成一个对象传递
html
handleAdd (n) {
this.$store.commit('addcount', {
count: n,
msg: 'haha'
})
}
html
addcount (state, obj) {
state.count += obj.count
console.log(obj.msg)
}
input的实时输入更新
输入框渲染
html
<input :value="count" @input="handInput" type="text" >
监听输入获取内容
html
methods: {
handInput (e) {
this.$store.commit('changecount', e.target.value)
}
封装mutation处理函数
html
changecount (state, newcount) {
state.count = newcount
}
辅助函数mapMutations
mapMutations和mapState很像,它是把位于mutations中的方法提取了出来,映射到组件methods中
html
<template>
<div>
<p>数据:{{ this.$store.state.count }}</p>
<button @click="subcount(1)">-1</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
name: 'Son1Component',
methods: {
...mapMutations(['subcount'])
}
}
</script>
actions
处理异步处理,mutations必须是同步的(便于监测数据变化,记录调试)
1.提供action方法
html
actions: {
changecountactions (context, num) {
setTimeout(() => {
context.commit('changecount', num)
}, 1000)
}
}
在页面中dispath调用
html
handchange (n) {
this.$store.dispatch('changecountactions', n)
}
辅助函数mapActions
mapActions是把位于actions中的方法提供了出来,映射到组件methods中
html
<template>
<div>
<p>数据:{{ this.$store.state.count }}</p>
<button @click="subcount(1)">-1</button>
<button @click="changecountactions(888)">一秒改成888</button>
</div>
</template>
<script>
import { mapMutations, mapActions } from 'vuex'
export default {
name: 'Son1Component',
methods: {
...mapMutations(['subcount']),
...mapActions(['changecountactions'])
}
}
</script>
getters
类似于计算属性
除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters。
定义getters
- getters函数的第一个参数是state
- getters函数必须要有返回值
html
getters: {
filterList (state) {
return state.list.filter(item => item > 5)
}
}
访问getters
- 通过store访问getters
- 通过辅助函数mapGetters映射
html
<div>{{ $store.getters.filterList }}</div>
html
<template>
<div>
<p>数据:{{ this.$store.state.count }}</p>
<button @click="subcount(1)">-1</button>
<button @click="changecountactions(888)">一秒改成888</button>
<hr>
<div>{{ filterList }}</div>
</div>
</template>
<script>
import { mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son1Component',
methods: {
...mapMutations(['subcount']),
...mapActions(['changecountactions'])
},
computed: {
...mapGetters(['filterList'])
}
}
</script>
Pinia
Pinia是vue的专属的最新状态管理库,是Vuex状态管理工具的代替品
优点:
- 提供更简单的API(去掉了mutation)
- 提供符合,组合式风格的API(和Vue3新语法统一)
- 去掉了modules的概念,每一个store都是一个对立的模块
- 配合TypeScript更加友好,提供可靠的类型推断
手动添加Pinia到Vue项目
在实际开发项目时,关于Pinia的配置,可以在创建项目时自动添加
1.使用Vite创建一个空的Vue3项目
2.按照官方文档安装pinia项目中
html
yarn add pinia
# 或者使用 npm
npm install pinia
javascript
import './assets/main.css'
import { createApp } from 'vue'
import {createPinia} from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia).mount('#app')
Pinia基础使用
1.定义store
javascript
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const usecounterstore = defineStore('counter',()=>{
const count = ref(100)
return {
count
}
})
2.组件使用store
javascript
<script setup>
import son1 from "@/components/son1.vue"
import son2 from "@/components/son2.vue"
import {usecounterstore} from "@/store/counter"
const counterstore = usecounterstore()
</script>
<template>
<div>
<h3>数据:{{ counterstore.count }}</h3>
<son1></son1>
<son2></son2>
</div>
</template>
javascript
import { defineStore } from 'pinia'
import { ref,computed } from 'vue'
export const usecounterstore = defineStore('counter',()=>{
// 声明数据state
const count = ref(100)
// 声明操作数据的方法active(普通函数)
const addcount = ()=>count.value++
const subcount = ()=>count.value--
//声明基于数据派生的计算属性getters(computed)
const double = computed(() => count.value*2)
return {
count,
addcount,
subcount,
double
}
})
active异步实现
javascript
import { defineStore } from 'pinia'
import { ref,computed } from 'vue'
export const usecounterstore = defineStore('counter',()=>{
// 声明数据state
const count = ref(100)
// 声明操作数据的方法active(普通函数)
const addcount = ()=>count.value++
const subcount = ()=>count.value--
//声明基于数据派生的计算属性getters(computed)
const double = computed(() => count.value*2)
return {
count,
addcount,
subcount,
double
}
})
javascript
<script setup>
import son1 from "@/components/son1.vue"
import son2 from "@/components/son2.vue"
import {usecounterstore} from "@/store/counter"
import {usechannelstore} from "@/store/channel"
const counterstore = usecounterstore()
const usestore = usechannelstore()
</script>
<template>
<div>
<h3>数据:{{ counterstore.count }}</h3>
<son1></son1>
<son2></son2>
<hr>
<button @click="usestore.getlist">获取数据</button>
<ul>
<li v-for="item in usestore.channellist" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
storeToRefs
用于将 Pinia store 实例中的状态属性转换为 ref 对象。
javascript
import { defineStore } from 'pinia';
const useMyStore = defineStore({
id: 'myStore',
state: () => ({
count: 0,
text: 'Hello, Pinia!',
}),
});
// 在组件中使用 storeToRefs 将状态转换为 ref 对象
const myStore = useMyStore();
const { count, text } = pinia.storeToRefs(myStore);
Pinia持久化
1.安装插件 pinia-plugin-persistedstate
javascript
npm i pinia-plugin-persistedstate
2.main.js使用
import persist from 'pinia-plugin-persistedstate'
...
app.use(createPinia().use(persist))
javascript
import './assets/main.css'
import persist from 'pinia-plugin-persistedstate'
import { createApp } from 'vue'
import {createPinia} from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia.use(persist))
app.mount('#app')
3.store仓库中,persist:true开启
javascript
import { defineStore } from 'pinia'
import { ref,computed } from 'vue'
export const usecounterstore = defineStore('counter',()=>{
// 声明数据state
const count = ref(100)
// 声明操作数据的方法active(普通函数)
const addcount = ()=>count.value++
const subcount = ()=>count.value--
//声明基于数据派生的计算属性getters(computed)
const double = computed(() => count.value*2)
return {
count,
addcount,
subcount,
double
}
},{
persist:true
})