1.安装
// 安装vuex
npm install vuex --save
2.创建store
import { createStore } from 'vuex'
const store = createStore({
state:{
counter:100,
name:'zql',
age: 45,
height:180,
book:[
{name:'深入vue',price:200,count:30},
{name:'深入react',price:150,count:20},
{name:'深入webpack',price:100,count:60}
]
},
mutations: { // 方法 修改state唯一途径 同步操作
increment(state) { // 默认就有个state参数,不用通过this.state
state.counter++
},
decrement(state) {
state.counter--
}
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
},
modules: {
}
})
export default store
3.挂载使用store --> main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
4.组件中使用store中的数据
第一种方法($store.state.xx和this.$store.commit('xx')):
<template>
<div class="dome">
<span>{{$store.state.counter}}</span>
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
</div>
</template>
<script>
export default {
data() {
},
created(){
},
methods:{
increment(){
this.$store.commit('increment')
},
decrement(){
this.$store.commit('decrement')
}
}
}
</script>
<style scoped>
</style>
第二种方法 options API(3种)中 computed 和 映射mapState(1.数组写法,2.对象写法)
<template>
<div class="dome">
<span>{{sCounter}}</span>
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
// <div>{{ sName }}</div>
// <div>{{ sAge }}</div>
<div>{{ name }}</div>
<div>{{ age }}</div>
<div>{{ height }}</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
},
created(){
},
computed:{
//第一种写法
sCounter(){
return this.$store.state.counter
},
//第二种写法
...mapState(['name','age','height'])//数组写法
//第三种写法
// ...mapState({ //对象写法
// sName: state => state.name,
// sAge: state => state.age
// })
},
methods:{
increment(){
this.$store.commit('increment')
},
decrement(){
this.$store.commit('decrement')
}
}
}
</script>
<style scoped>
</style>
第三种方法composition api (2种) setup()与mapState,computed
<template>
<div class="dome">
<span>{{sCounter}}</span>
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
{{ name }}
{{ age }}
{{ height }}
</div>
</template>
<script>
import { mapState, useStore } from 'vuex'
import { computed } from 'vue'
export default {
setup(){
const store = useStore()
// 第一种写法
const sCounter = computed(()=> store.state.counter)
// 第二种写法
const storeStateFns = mapState(['name','age','height'])
//{name:function,age:function,height:function}
//{name:ref,age:ref,height:ref}
const storeState ={}
Object.keys(storeStateFns).forEach(fnkey =>{
const fn = storeStateFns[fnkey].bind({$store:store});
storeState[fnkey] = computed(fn)
})
return {
sCounter,
...storeState
}
},
methods:{
increment(){
this.$store.commit('increment')
},
decrement(){
this.$store.commit('decrement')
}
}
}
</script>
<style scoped>
</style>
封装mapState与computed混用
import { mapState, useStore } from 'vuex'
import { computed } from 'vue'
function useState(item){
// 拿到store对象
const store = useStore()
// 获取到对应的对象:{name:function,age:function,height:function}
const storeStateFns = mapState(item)
//对数据转化{name:ref,age:ref,height:ref}
const storeState ={}
Object.keys(storeStateFns).forEach(fnkey =>{
const fn = storeStateFns[fnkey].bind({$store:store});
storeState[fnkey] = computed(fn)
})
return storeState
}
export default useState
页面使用(数组,对象两种)
<template>
<div class="dome">
<span>{{counter}}</span>
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
{{ name }}
{{ age }}
{{ height }}
{{ sCounter }}
{{ sName }}
</div>
</template>
<script>
import useState from './hook/useState'
export default {
setup(){
const storeState = useState(['counter','name','age','height'])//数组
const storeState2 = useState({//对象
sCounter: state=> state.counter,
sName: state=> state.name,
})
return {
...storeState,
...storeState2
}
},
methods:{
increment(){
this.$store.commit('increment')
},
decrement(){
this.$store.commit('decrement')
}
}
}
</script>
<style scoped>
</style>
5.getters的创建以及使用
第一种基本使用
gatters ==》store
import { createStore } from 'vuex'
const store = createStore({
state:{
book:[
{name:'深入vue',price:200,count:30},
{name:'深入react',price:150,count:20},
{name:'深入webpack',price:100,count:60}
]
},
mutations: { // 方法 修改state唯一途径 同步操作
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
bookPrice(state){
let bookPrice= 0
for(const item of state.book){
bookPrice += item.price * item.count
}
return bookPrice
}
},
modules: {
}
})
export default store
页面展示
<template>
<div class="dome">
书本总数{{$store.getters.bookPrice}}
</div>
</template>
<script>
export default {
setup(){
},
methods:{
}
}
</script>
第二种使用其他getters
import { createStore } from 'vuex'
const store = createStore({
state:{
book:[
{name:'深入vue',price:200,count:30},
{name:'深入react',price:150,count:20},
{name:'深入webpack',price:100,count:60}
],
discount:0.6
},
mutations: { // 方法 修改state唯一途径 同步操作
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
bookPrice(state, getters){
let bookPrice= 0
for(const item of state.book){
bookPrice += item.price * item.count
}
return bookPrice * getters.bookDiscount
},
bookDiscount(state){
return state.discount * 0.9
}
},
modules: {
}
})
export default store
<template>
<div class="dome">
书本总数{{$store.getters.bookPrice}}
</div>
</template>
<script>
export default {
setup(){
},
methods:{
}
}
</script>
第三种返回函数
import { createStore } from 'vuex'
const store = createStore({
state:{
book:[
{name:'深入vue',price:200,count:30},
{name:'深入react',price:150,count:20},
{name:'深入webpack',price:100,count:1}
],
discount:0.6
},
mutations: { // 方法 修改state唯一途径 同步操作
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
bookPrice(state, getters){
let bookPrice= 0
for(const item of state.book){
bookPrice += item.price * item.count
}
return bookPrice * getters.bookDiscount
},
bookDiscount(state){
return state.discount * 0.9
},
bookDiscountN(state, getters){
return function(N){
let bookPrice= 0
for(const item of state.book){
if(item.count > N){
bookPrice += item.price * item.count
}
}
return bookPrice * getters.bookDiscount
}
}
},
modules: {
}
})
export default store
<template>
<div class="dome">
书本总数{{$store.getters.bookPrice}}
筛选{{ $store.getters.bookDiscountN(6) }}
</div>
</template>
<script>
export default {
setup(){
},
methods:{
}
}
</script>
第四种 options API(3种)中 computed 和 映射mapGetters(1.数组写法,2.对象写法)
import { createStore } from 'vuex'
const store = createStore({
state:{
counter:100,
name:'zql',
age: 45,
height:180,
book:[
{name:'深入vue',price:200,count:30},
{name:'深入react',price:150,count:20},
{name:'深入webpack',price:100,count:1}
],
discount:0.6
},
mutations: { // 方法 修改state唯一途径 同步操作
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
nameInfo(state){
return `name:${state.name}`
},
ageInfo(state){
return `age:${state.age}`
},
heightInfo(state){
return `height:${state.height}`
},
counterInfo(state){
return `counter:${state.counter}`
},
},
modules: {
}
})
export default store
<template>
<div class="dome">
{{ $store.getters.nameInfo }}
{{ ageInfo }}
{{ heightInfo }}
{{ counterInfo }}
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed:{
// 第一种
ageInfo(){
return this.$store.getters.ageInfo
},
// 第二种数组
...mapGetters(['heightInfo']),
// 第三种对象
...mapGetters({
counterInfo:'counterInfo'
})
},
setup(){
},
methods:{
}
}
</script>
<style scoped>
</style>
第五种方法composition api (2种) setup()与mapGetters,computed
页面展示
<template>
<div class="dome">
{{ nameInfo }}
{{ ageInfo }}
{{ heightInfo }}
{{ counterInfo }}
</div>
</template>
<script>
import {computed} from 'vue'
import { useStore } from 'vuex'
import { mapGetters } from 'vuex';
import useMapper from './hook/useMapper'
export default {
setup(){
const store = useStore()
const nameInfo = computed(()=>store.getters.nameInfo)//第一种
const storeGettersFns = useMapper(['ageInfo','heightInfo','counterInfo'],mapGetters)//第二种函数封装
return {
nameInfo,
...storeGettersFns
}
},
methods:{
}
}
</script>
<style scoped>
</style>
封装
import { useStore } from 'vuex'
import { computed } from 'vue'
function useMapper(item,mapFn){
// 拿到store对象
const store = useStore()
// 获取到对应的对象:{name:function,age:function,height:function}
const storeStateFns = mapFn(item)
//对数据转化{name:ref,age:ref,height:ref}
const storeState ={}
Object.keys(storeStateFns).forEach(fnkey =>{
const fn = storeStateFns[fnkey].bind({$store:store});
storeState[fnkey] = computed(fn)
})
return storeState
}
export default useMapper
6.mutations的创建以及使用
mutations必须是同步函数,devtool会记录mutation的状态。
第一种基础写法(三种)
import { createStore } from 'vuex'
const store = createStore({
state:{
counter:100,
},
mutations: { // 方法 修改state唯一途径 同步操作
increment(state) { // 默认就有个state参数,不用通过this.state
state.counter++
},
decrement(state) {
state.counter--
},
incrementN(state,payload) { // 默认就有个state参数,不用通过this.state
state.counter += payload.n
},
},
actions: { // 如果有异步操作在这里写 比如网络请求
},
getters: {
},
modules: {
}
})
export default store
展示
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="$store.commit('increment')">加1</button>
//第一种
<button @click="$store.commit('decrement')">减1</button>
<button @click="addincrementN">加10</button>
</div>
</template>
<script>
export default {
methods:{
addincrementN(){
//第二种
//this.$store.commit('incrementN',{n:10,name:'你好'})
//第三种
this.$store.commit({
type:'incrementN',
n:10,
name:'你好'
})
}
}
}
</script>
<style scoped>
</style>
第二种 options API辅助函数mapMutations
vuex使用上方
页面展示
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
<button @click="incrementN({n:10})">加10</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
methods:{
//第一种数组
...mapMutations(['increment','decrement','incrementN'])
//第二种对象
//...mapMutations({
// add:'increment'
// })
}
}
</script>
<style scoped>
</style>
第三种方法composition api (1种) setup()与mapMutations
vuex使用上上方
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="increment">加1</button>
<button @click="decrement">减1</button>
<button @click="incrementN({n:10})">加10</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
setup(){
const mutation = mapMutations(['increment','decrement','incrementN'])
return {
...mutation
}
},
methods:{
}
}
</script>
<style scoped>
</style>
7.actions的使用
Action类似与mutation不用在于:
1.Action提交的是mutation,而不是直接修改状态,
2.Action可以包含任意异步操作。
Action还有一个context参数。context是一个和store实例均有相同方法和属性的context对象;
所以可以从其中获取到commit方法来提交一个mutation,或者通过context.state和context.getters来获取state和getters;
第一种基础写法(三种)
import { createStore } from 'vuex'
import axios from 'axios'
const store = createStore({
state:{
counter:100,
banner:null
},
mutations: { // 方法 修改state唯一途径 同步操作
increment(state) { // 默认就有个state参数,不用通过this.state
state.counter++
},
decrement(state) {
state.counter--
},
},
actions: { // 如果有异步操作在这里写 比如网络请求
incrementAction(context,number) {
console.log('number',number)
setTimeout(()=>{
context.commit('increment')
},1000)
},
decrementAction(context) {
context.commit('decrement')
},
addBannerList(context){
axios.get('http://123.207.32.32:8000/home/multidata').then((res)=>{
// console.log(res.data.data.banner.list)
context.commit('addBanner',res.data.data.banner.list)
})
}
},
getters: {
},
modules: {
}
})
export default store
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="add">加1</button>
<button @click="decrement">减1</button>
</div>
</template>
<script>
export default {
mounted(){
this.$store.dispatch('addBannerList')//第一种
},
methods:{
add(){
this.$store.dispatch('incrementAction',{count:'ll'})//第二种
},
decrement(){
this.$store.dispatch({//第三种
type:'decrementAction'
})
}
}
}
</script>
<style scoped>
</style>
第二种 options API辅助函数mapActions
vuex上方雷同
页面展示
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="incrementAction">加1</button>
<button @click="decrementAction">减1</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
methods:{
...mapActions(['incrementAction','decrementAction']),//数组
...mapActions({ //对象
add:'incrementAction',
dec:'decrementAction'
})
}
}
</script>
<style scoped>
</style>
第三种方法composition api (2种) setup()与mapActions
vuex上上方雷同
页面展示
<template>
<div class="dome">
{{ $store.state.counter }}
<button @click="incrementAction">加1</button>
<button @click="decrementAction">减1</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
setup(){
const action = mapActions(['incrementAction','decrementAction'])//数组
const action2 = mapActions({//对象
add:'incrementAction',
dec:'decrementAction'
})
return{
...action,
...action2
}
},
}
</script>
<style scoped>
</style>
第四种 高级操作 知道action什么时候结束?通过Promise
import { createStore } from 'vuex'
import axios from 'axios'
const store = createStore({
state:{
banner:null
},
mutations: {
addBanner(state,payload) {
state.banner = payload
},
},
actions: { // 如果有异步操作在这里写 比如网络请求
addBannerList(context){
return new Promise((resove,rejack)=>{
axios.get('http://123.207.32.32:8000/home/multidata').then((res)=>{
context.commit('addBanner',res.data.data.banner.list)
resove('成功')
}).catch((err)=>{
rejack(err)
})
})
}
},
})
export default store
<template>
<div class="dome">
</div>
</template>
<script>
import { onMounted } from 'vue';
import {useStore} from'vuex'
export default {
setup(){
const store = useStore()
onMounted(()=>{
const actionPromise = store.dispatch('addBannerList')
actionPromise.then((res)=>{
console.log(res)
}).catch((err)=>{
console.log(err)
})
})
return{
}
}
}
</script>
<style scoped>
</style>
8.moudle使用
基本使用
// homeModule.js
export default {
namespaced: true,
state() {
return {
title: "home"
}
},
}
// mineModuele.js
export default {
namespaced: true,
state() {
return {
title: "mine"
}
},
}
// rootModule.js
import { createStore } from 'vuex'
import home from './homeModule'
import mine from './mineModule'
const store = createStore({
state() {
return {
counter: 10,
title: 'root'
}
},
mutations: {
},
getters: {
},
actions: {
},
modules: {
home,
mine
}
});
export default store;
// state数据的获取
<div>模板中获取值:{{$store.state.title}}</div>
<div>模板中获取值:{{$store.state.home.title}}</div>
<div>模板中获取值:{{$store.state.mine.title}}</div>
<div>模板中获取值:{{homeTitle}}</div>
computed: {
homeTitle() {
return this.$store.state.mine.title;
}
}
多个module中使用getter和actions
homeModule.js
export default {
namespaced: true,//命名空间,打开
state() {
return {
title: "home"
}
},
mutations: {
changeTitle(state) {
console.log(state);
}
},
getters: {
// getterTitle(state, getters, rootState, rootGetters)
getterTitle(state) {
return state.title + " getter"
},
},
actions: {
// context = {commit, dispatch, state, rootState, getters, rootGetters}
changeTitleAction(context) {
context.commit('changeTitle');
// 派发root module中的mutations
context.commit('changeTitle', null, {root: true});
}
}
}
// 模板
<button @click="changeTitle">changeTitle</button>
<div>{{$store.getters["home/getterTitle"]}}</div>
methods: {
changeTitle() {
this.$store.dispatch('home/changeTitleAction');
}
}
在options API辅助函数中使用
<div>模板中获取值 - mapTitle:{{mapTitle}}</div>
<div>模板中获取值 - mapTitleHome: {{mapTitleHome}}</div>
<button @click="changeTitleAction">map changeTitle</button>
<button @click="homeObject">map homeObject</button>
import { mapState, mapActions,mapGetters,mapMutation } from "vuex";
export default {
setup() {
return {
}
},
methods: {
//写法一
...mapActions('home', ['changeTitleAction']),
//写法二
...mapActions('home', {
homeObject: 'changeTitleAction'
})
//写法一
...mapMutation("home", [incremet]),
//写法二
...mapMutation('home',{
incremet:"incremet"
})
},
computed: {
homeTitle() {
return this.$store.state.mine.title;
},
//写法一
...mapState("home", [title]),
//写法二
...mapState("home", {
mapTitleHome: state => state.title
}),
//写法三
...mapState({
mapTitle: state => state.home.title
}),
//写法一
...mapGetters("home", [doubleHimeCounter]),
//写法二
...mapGetters('home',{
doubleHimeCounter:"doubleHimeCounter"
})
}
}
利用options API createNamespacedHelpers导出使用
import { createNamespacedHelpers } from "vuex";
const {mapState, mapActions,mapGetters,mapMutation} = createNamespacedHelpers("home");
export default {
setup() {
return {
}
},
methods: {
...mapMutation([incremet]),
...mapActions(['changeTitleAction']),
...mapActions({
homeObject: 'changeTitleAction'
})
},
computed: {
...mapState([title]),
...mapState({
mapTitle: state => state.title
}),
...mapGetters([doubleHimeCounter]),
}
}
composition api 封装
文件关系
index.js
import { useGetters } from './useGetters';
import { useState } from './useState';
export {
useGetters,
useState
}
useGetter.js
import { mapGetters, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'
export function useGetters(moduleName, mapper) {
let mapperFn = mapGetters
if (typeof moduleName === 'string' && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapGetters
} else {
mapper = moduleName
}
return useMapper(mapper, mapperFn)
}
useState.js
import { mapState, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'
export function useState(moduleName, mapper) {
let mapperFn = mapState
if (typeof moduleName === 'string' && moduleName.length > 0) {
mapperFn = createNamespacedHelpers(moduleName).mapState
} else {
mapper = moduleName
}
return useMapper(mapper, mapperFn)
}
useMapper.js
import { computed } from 'vue'
import { useStore } from 'vuex'
export function useMapper(mapper, mapFn) {
// 拿到store独享
const store = useStore()
// 获取到对应的对象的functions: {name: function, age: function}
const storeStateFns = mapFn(mapper)
// 对数据进行转换
const storeState = {}
Object.keys(storeStateFns).forEach(fnKey => {
const fn = storeStateFns[fnKey].bind({$store: store})
storeState[fnKey] = computed(fn)
})
return storeState
}
页面使用
<template>
<div>
<hr>
<h2>{{ homeCounter }}</h2>
<h2>{{ doubleHomeCounter }}</h2>
<!-- <h2>{{ doubleRootCounter }}</h2> -->
<button @click="increment">home+1</button>
<button @click="incrementAction">home+1</button>
<hr>
</div>
</template>
<script>
import { createNamespacedHelpers, mapState, mapGetters, mapMutations, mapActions } from "vuex";
import { useState, useGetters } from '../hooks/index'
export default {
setup() {
// {homeCounter: function}
const state = useState("home",["rootCounter"])
const getters = useGetters("home", ["doubleHomeCounter"])
// const mutations = mapMutations(["increment"])
// const actions = mapActions(["incrementAction"])
return {
// ...state,
// ...getters,
// ...mutations,
// ...actions
}
}
}
</script>
<style scoped>
</style>