Vuex状态管理

1、Vuex 是什么?

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

简单理解

Vuex可以帮我们管理全局的属性,并且是是响应式的,状态的变化是可以跟踪的

什么是“状态管理模式”?

<template><h3>count1</h3><p>{{count}}</p><button @click="add">加1</button>
</template><script setup>import {ref} from "vue";const count = ref(0);  //其实就是状态function add() {count.value++;}
</script>

这个状态自管理应用包含以下几个部分

  • 状态,驱动应用的数据源;就是count

  • 视图,以声明方式将状态映射到视图;就是将count显示到template
  • 操作,响应在视图上的用户输入导致的状态变化;就是点击按钮时count发生变化

但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏,就像count在多个组件中使用时。

  • 多个视图依赖于同一状态。
  • 来自不同视图的行为需要变更同一状态

问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。

问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!

什么情况下我应该使用 Vuex?

Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。引用 Redux 的作者 Dan Abramov 的话说就是:您自会知道什么时候需要它

2、项目中引入Vuex

安装vuex

npm install vuex@next --save

main.js文件配置vuex

import { createApp } from 'vue'
import App from './App.vue'
//1.引入vuex
import {createStore} from "vuex";//2.创建vuex对象
const store = createStore({//3.创建状态state:{count:10,}
})//4.挂载vuex
const app = createApp(App);
app.use(store)
app.mount('#app')

 在count1和count2页面上显示

<template><h3>count1</h3><p>{{ $store.state.count}}</p>
</template>

 一般是将vuex的配置放在一个单独的文件并到出,在main.js文件引入。

//1.引入vuex
import {createStore} from "vuex";
//2.创建vuex对象
const store = createStore({//3.创建状态state:{count:10}
})
export default store
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'//4.挂载vuex
const app = createApp(App)
app.use(store)
app.mount('#app')

3、核心概念-State

Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 ”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。换言之,vuex全部的数据都是存放在state中的。

import {createStore} from "vuex";
const store = createStore({state:{count:10,message:'vuex单一的数据'}
})
export default store
<template><!-- 显示标题 --><h3>count1,获取vuex数据的两种方式</h3><!-- 方式一:直接使用 $store 获取 Vuex 中的 state 数据 --><p>方式一:{{ $store.state.count }}</p><!-- 方式二:通过计算属性 count 获取 Vuex 中的 state 数据 --><p>方式二:{{ count }}</p>
</template><script setup>
// 引入 Vue 的 computed 函数,用于创建计算属性
import { computed } from "vue";
// 引入 Vuex 的 useStore 函数,用于获取 Vuex store 实例
import { useStore } from "vuex";// 获取 Vuex store 实例
const store = useStore();// 定义一个计算属性 count,用于从 Vuex store 中获取 state 的 count 值
// computed 会监听 store.state.count 的变化,并在变化时自动更新 count 的值
const count = computed(() => store.state.count);
</script>

mapState 辅助函数

只能在选项式API存在

<template><h3>count2</h3><!-- 显示从 Vuex 获取的 `count` 状态 --><p>{{ count }}</p><!-- 显示从 Vuex 获取的 `message` 状态 --><p>{{ message }}</p>
</template><script>
// 从 Vuex 中引入 mapState 辅助函数
import { mapState } from "vuex";export default {// 使用 Vue 的 computed 属性computed: {// 使用扩展运算符 (...), 将 Vuex 中的 state 映射到本地计算属性...mapState(["count", "message"]),/*以上代码等价于以下手动定义的计算属性:count() {return this.$store.state.count;},message() {return this.$store.state.message;}*/}
};

4、核心概念-Getter

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)

添加Getters

import {createStore} from "vuex";
const store = createStore({state:{count:10,message:'vuex单一的数据'},getters:{getCount(state){return "当前的count为:"+state.count}}
})
export default store

选项式API获取Getters

<template>
<h3>count2</h3><p>直接在标签中获取:{{$store.getters.getCount}}</p>
<p>通过计算属性获取:{{getCount}}</p>
</template><script>export default {computed:{getCount(){return this.$store.getters.getCount;}}
}
</script>

组合式API获取Getters

<template><h3>count1</h3><p>直接在标签获取:{{ $store.getters.getCount}}</p><p>计算属性获取:{{currentCount}}</p>
</template><script setup>
import {computed} from "vue";
import {useStore} from "vuex";
const store = useStore();
const currentCount = computed(() => {return store.getters.getCount;
})
</script>

mapGetters 辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。

<template>
<h3>count2</h3><p>直接在标签中获取:{{$store.getters.getCount}}</p><p>通过mapGetters获取:{{getCount}}</p>
</template><script>
import {mapGetters} from "vuex";export default {computed:{...mapGetters(['getCount'])}
}
</script>

 5、核心概念-Mutation

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

在Vue中添加mutation

import { createStore } from 'vuex'
const store = createStore({state:{count: 10},getters: {getCount(state) {return "当前Count值为: "+state.count;}},mutations:{increment(state){state.count++},decrement(state){state.count--}}
})
export default store

选项式API使用mutation

<template><h3>count2</h3><!-- 显示从 Vuex 的 getters 中获取的值 --><p>{{ getCount }}</p><!-- 点击按钮调用 addHandler 方法,触发 Vuex 的 increment mutation --><button @click="addHandler">增加</button><!-- 点击按钮调用 minHandler 方法,触发 Vuex 的 decrement mutation --><button @click="minHandler">减少</button>
</template><script>
// 从 Vuex 中引入 mapGetters 辅助函数
import { mapGetters } from "vuex";export default {// 定义计算属性computed: {// 使用 mapGetters 将 Vuex 的 getters 映射到本地计算属性// 这里将 Vuex 的 getCount getter 映射到本地的 getCount 属性...mapGetters(['getCount'])},// 定义组件的方法methods: {// 定义增加按钮的点击事件处理函数addHandler() {// 调用 Vuex 的 commit 方法,触发 increment mutationthis.$store.commit('increment');},// 定义减少按钮的点击事件处理函数minHandler() {// 调用 Vuex 的 commit 方法,触发 decrement mutationthis.$store.commit('decrement');}}
};

组合式API使用mutation

<template><h3>count1</h3><!-- 显示当前计数器的值,通过计算属性 currentCount 获取 --><p>{{ currentCount }}</p><!-- 点击按钮调用 addHandler 方法,通过 Vuex 的 increment mutation 增加计数 --><button @click="addHandler">增加</button><!-- 点击按钮调用 minHandler 方法,通过 Vuex 的 decrement mutation 减少计数 --><button @click="minHandler">减少</button>
</template><script setup>
import { computed } from "vue"; // 引入 Vue 的 computed 函数,用于定义计算属性
import { useStore } from "vuex"; // 引入 Vuex 的 useStore 函数,用于获取 Vuex store 实例// 获取 Vuex store 实例
const store = useStore();// 定义一个计算属性 currentCount,用于从 Vuex 的 getters 中获取值
const currentCount = computed(() => {// 通过 store.getters 获取 Vuex 的计数器值return store.getters.getCount;
});// 定义增加按钮的点击事件处理函数
const addHandler = () => {// 调用 Vuex 的 commit 方法,触发 increment mutationstore.commit("increment");
};// 定义减少按钮的点击事件处理函数
const minHandler = () => {// 调用 Vuex 的 commit 方法,触发 decrement mutationstore.commit("decrement");
};
</script>

Mutation-携带参数

你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload)。

vuex配置

import { createStore } from 'vuex' // 引入Vuex的createStore方法,用于创建Vuex存储实例// 创建Vuex存储实例
const store = createStore({// 定义状态(state):Vuex中存储应用的数据,所有组件都可以访问这些数据state: {count: 10 // 定义一个名为count的状态,初始值为10},// 定义Getter:用于从state中派生出一些状态,相当于计算属性,可以对state进行加工getters: {// 定义一个名为getCount的Getter,接收state作为参数getCount(state) {return "当前Count值为: " + state.count; // 返回一个字符串,包含state中的count值}},// 定义Mutations:用于更改state中的数据,是唯一可以同步修改state的地方mutations: {// 定义一个名为increment的Mutation,接收state和num作为参数increment(state, num) {state.count += Number(num); // 将state中的count值加上num的数值},// 定义一个名为decrement的Mutation,接收state和num作为参数decrement(state, num) {state.count -= Number(num); // 将state中的count值减去num的数值}},}
})// 导出Vuex存储实例,以便在Vue应用中使用
export default store

选项式API传递参数

<template><!-- 显示一个标题 --><h3>count2</h3><!-- 显示从 Vuex store 中获取的 getCount 值 --><p>{{ getCount }}</p><!-- 输入框,用于输入要增加或减少的数值,v-model 实现双向绑定 --><input type="text" v-model="num" /><!-- 增加按钮,点击时调用 addHandler 方法 --><button @click="addHandler">增加</button><!-- 减少按钮,点击时调用 minHandler 方法 --><button @click="minHandler">减少</button>
</template><script>
// 引入 Vuex 的 mapGetters 辅助函数,用于将 Vuex 的 getters 映射到组件的 computed 属性中
import { mapGetters } from "vuex";export default {// 定义组件的 data 属性data() {return {// 输入框的绑定变量,初始为空字符串num: ""};},// 计算属性computed: {// 使用 mapGetters 将 Vuex 中的 getCount getter 映射到组件的计算属性中...mapGetters(["getCount"])},// 方法methods: {// 增加按钮点击事件处理函数addHandler() {// 调用 Vuex 的 commit 方法,提交名为 'increment' 的 mutation,并传递当前输入框的值this.$store.commit("increment", this.num);},// 减少按钮点击事件处理函数minHandler() {// 调用 Vuex 的 commit 方法,提交名为 'decrement' 的 mutation,并传递当前输入框的值this.$store.commit("decrement", this.num);}}
};
</script>

 组合式API传递参数

<template><!-- 显示标题 --><h3>count1</h3><!-- 显示当前的 count 值,该值来自 Vuex store 的计算属性 --><p>{{ currentCount }}</p><!-- 输入框,用于输入要增加或减少的数值,通过 v-model 实现双向绑定 --><input type="text" v-model="num" /><!-- 增加按钮,点击时调用 addHandler 方法 --><button @click="addHandler">增加</button><!-- 减少按钮,点击时调用 minHandler 方法 --><button @click="minHandler">减少</button>
</template><script setup>
// 引入 Vue 的核心响应式函数
import { computed } from "vue";
// 引入 Vuex 的 useStore 函数,用于访问 Vuex store
import { useStore } from "vuex";
// 引入 Vue 的 ref 函数,用于创建响应式变量
import { ref } from "vue";// 创建一个响应式引用变量 num,初始化为 0
const num = ref(0);// 使用 useStore 获取 Vuex store 实例
const store = useStore();// 定义一个计算属性 currentCount,用于获取 Vuex store 中的 getCount 值
const currentCount = computed(() => {// 从 Vuex store 的 getters 中获取 getCount 的值return store.getters.getCount;
});// 定义增加按钮的点击处理函数
const addHandler = () => {// 通过 store.commit 提交名为 'increment' 的 mutation,并传递 num 的当前值store.commit("increment", num.value);
};// 定义减少按钮的点击处理函数
const minHandler = () => {// 通过 store.commit 提交名为 'decrement' 的 mutation,并传递 num 的当前值store.commit("decrement", num.value);
};
</script>

注意组合式API获取ref创建的值的时候要使用.value获取 

 对象风格的传参方式

选项式

  methods:{addHandler(){this.$store.commit({type: 'increment',num: this.num});},minHandler(){this.$store.commit({type: 'decrement',num: this.num});}}

组合式

const addHandler = () => {store.commit({type: 'increment',num: this.num});
}
const minHandler = () => {store.commit({type: 'decrement',num: this.num});
}

注意:

此时在mutation 中获取的num参数要变为{num}

    mutations:{increment(state, {num}){state.count += Number(num)},decrement(state, {num}){state.count -= Number(num)}}

Mutation 必须是同步函数

一条重要的原则就是要记住 mutation 必须是同步函数

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的

 Mutation-辅助函数

你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store

<template><!-- 显示标题 --><h3>count2</h3><!-- 显示从 Vuex store 中获取的 getCount 值 --><p>{{ getCount }}</p><!-- 输入框,用于输入要增加或减少的数值,通过 v-model 实现双向绑定 --><input type="text" v-model="num" /><!-- 增加按钮,点击时调用 addHandler 方法 --><button @click="addHandler">增加</button><!-- 减少按钮,点击时调用 minHandler 方法 --><button @click="minHandler">减少</button>
</template><script>
// 引入 Vuex 的 mapGetters 和 mapMutations 辅助函数
import { mapGetters, mapMutations } from "vuex";export default {data() {return {// 输入框的绑定变量,初始为空字符串num: ""};},computed: {// 使用 mapGetters 将 Vuex 的 getters 映射到组件的计算属性中...mapGetters(["getCount"])},methods: {// 使用 mapMutations 将 Vuex 的 mutations 映射到组件的方法中...mapMutations(["increment", "decrement"]),// 增加按钮点击事件处理函数addHandler() {// 调用映射的 increment 方法,并传递一个对象,包含 num 属性this.increment({num: this.num // 将输入框的值传递给 mutation});},// 减少按钮点击事件处理函数minHandler() {// 调用映射的 decrement 方法,并传递一个对象,包含 num 属性this.decrement({num: this.num // 将输入框的值传递给 mutation});}}
};
</script>

6、核心概念-Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

在Vue中增加Actions

import { createStore } from 'vuex' // 引入Vuex的createStore方法// 创建Vuex存储实例
const store = createStore({// 定义状态(state):存储应用的数据state: {count: 10 // 定义一个名为count的状态,初始值为10},// 定义Getter:从state中派生出一些状态,相当于计算属性getters: {// 定义一个名为getCount的Getter,接收state作为参数getCount(state) {return "当前Count值为: " + state.count; // 返回一个字符串,包含state中的count值}},// 定义Mutation:用于更改state中的数据,必须是同步操作mutations: {// 定义一个名为increment的Mutation,接收state和解构后的numincrement(state, { num }) {state.count += Number(num); // 将state中的count值加上num的数值},// 定义一个名为decrement的Mutation,接收state和解构后的numdecrement(state, { num }) {state.count -= Number(num); // 将state中的count值减去num的数值}},// 定义Action:用于处理异步操作,可以提交Mutation来更改stateactions: {// 定义一个名为asyncIncrement的Action,接收context和num作为参数asyncIncrement(context, num) {context.commit('increment', num); // 提交名为increment的Mutation,将num作为参数},// 定义一个名为asyncDecrement的Action,接收context和num作为参数asyncDecrement(context, num) {context.commit('decrement', num); // 提交名为decrement的Mutation,将num作为参数}}
})// 导出Vuex存储实例,以便在Vue应用中使用
export default store

选项式API使用Actions

<template><!-- 显示标题 --><h3>count2</h3><!-- 显示从 Vuex store 中获取的 getCount 值 --><p>{{ getCount }}</p><!-- 输入框,用于输入要增加或减少的数值,通过 v-model 实现双向绑定 --><input type="text" v-model="num" /><!-- 增加按钮,点击时调用 addHandler 方法 --><button @click="addHandler">增加</button><!-- 减少按钮,点击时调用 minHandler 方法 --><button @click="minHandler">减少</button>
</template><script>
// 引入 Vuex 的 mapGetters 辅助函数
import { mapGetters } from "vuex";export default {data() {return {// 输入框的绑定变量,初始为空字符串num: ""};},computed: {// 使用 mapGetters 将 Vuex 的 getters 映射到组件的计算属性中...mapGetters(["getCount"])},methods: {// 增加按钮点击事件处理函数addHandler() {// 调用 Vuex 的 dispatch 方法,触发名为 'asyncIncrement' 的 action,并传递一个对象,包含 num 属性this.$store.dispatch("asyncIncrement", {num: this.num // 将输入框的值传递给 action});},// 减少按钮点击事件处理函数minHandler() {// 调用 Vuex 的 dispatch 方法,触发名为 'asyncDecrement' 的 action,并传递一个对象,包含 num 属性this.$store.dispatch("asyncDecrement", {num: this.num // 将输入框的值传递给 action});}}
};
</script>

组合式API使用Actions

<template><h3>count1</h3><p>{{ currentCount }}</p><input type="text" v-model="num"><button @click="addHandler">增加</button><button @click="minHandler">减少</button>
</template><script setup>
import {computed} from "vue";
import {useStore} from "vuex";
import {ref} from "vue";const num = ref("");const store = useStore();
const currentCount = computed(() => {return store.getters.getCount;
})const addHandler = () => {store.dispatch("asyncIncrement", num.value);
}
const minHandler = () => {store.dispatch("asyncDecrement",num.value);
}
</script>

Action-异步操作

安装依赖

npm install --save axios

实现异步Action

import { createStore } from 'vuex' // 引入 Vuex 的 createStore 方法
import axios from "axios" // 引入 Axios,用于发送 HTTP 请求// 创建 Vuex 存储实例
const store = createStore({// 定义状态(state):存储应用的数据state: {// 定义一个名为 banner 的状态,用于存储从接口获取的数据banner: []},// 定义 Mutation:用于更改 state 中的数据,必须是同步操作mutations: {// 定义一个名为 setBanner 的 Mutation,接收 state 和 banner 参数setBanner(state, banner) {// 将传入的 banner 数据赋值给 state.bannerstate.banner = banner;}},// 定义 Action:用于处理异步操作,可以提交 Mutation 来更改 stateactions: {// 定义一个名为 asyncSetBanner 的 Action,接收 context 和 url 参数asyncSetBanner(context, url) {// 使用 Axios 发送 GET 请求到指定的 URLaxios.get(url).then((res) => {// 请求成功后,调用 Mutation 的 setBanner 方法,并将返回的 banner 数据传递给它context.commit("setBanner", res.data.banner);}).catch((error) => {// 请求失败时,可以在这里处理错误console.error("获取 banner 数据失败:", error);});}}
});// 导出 Vuex 存储实例,以便在 Vue 应用中使用
export default store;

banner.vue组件

<template><!-- 点击按钮时调用 getBannerHandler 方法 --><button @click="getBannerHandler">获取数据</button><!-- 使用 v-for 循环渲染 banner 数据 --><ul><!-- 遍历 $store.state.banner 数组,输出每个元素的 title 和 content --><li v-for="(item, index) in $store.state.banner" :key="index"><h3>{{ item.title }}</h3><p>{{ item.content }}</p></li></ul>
</template><script setup>
// 引入 Vuex 的 useStore 函数,用于访问 Vuex store
import { useStore } from "vuex";// 获取 Vuex store 实例
const store = useStore();// 定义一个函数,用于触发获取 banner 数据的 action
function getBannerHandler() {// 调用 Vuex 的 dispatch 方法,触发名为 asyncSetBanner 的 action,并传递一个 URL 参数store.dispatch("asyncSetBanner", "http://iwenwiki.com/api/blueberrypai/getIndexBanner.php");
}
</script>

 Action辅助函数

也是只能在选项式API使用。

<template><button @click="getBannerHandler">获取数据</button><ul><li v-for="(item,index) in $store.state.banner" :key="index"><h3>{{ item.title }}</h3><p>{{ item.content }}</p></li></ul>
</template>
<script>
import { mapActions } from "vuex"
export default {methods:{...mapActions(["asyncSetBanner"]),getBannerHandler(){this.asyncSetBanner("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php")}}
}
</script>

7、核心概念-Module

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

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

在store下创建Login文件夹并在文件夹下创建index.js文件

export default {state:{token:"asdasdlhcHDIHIO"}
}

在store下创建Order文件夹并在文件夹下创建index.js文件

export default {state:{order:[{id:101,name:"佳洁士"},{id:102,name: "舒肤佳"}]}}

在store主文件引入模块

import { createStore } from 'vuex'
import Login from "@/store/Login/index.js";
import Order from "@/store/Order/index.js";
const store = createStore({modules:{Login,Order}
})
export default store

 在Login.vue页面获取token数据

<template><h3>登录页面</h3><p>{{token}}</p>
</template><script setup>import {computed} from "vue";import {useStore} from "vuex";const store = useStore();const token = computed(() => store.state.Login.token);
</script>

 在Order.vue页面获取order数据

<template><h3>订单页面</h3><ul><li v-for="(item,index) of order" :key="index"><p>{{item.id}}</p><p>{{item.name}}</p></li></ul>
</template><script setup>
import {computed} from "vue";
import {useStore} from "vuex";
const store = useStore();
const order = computed(()=>{return store.state.Order.order;
})
</script>

挂在到APP.vue页面上并显示

 Module-模块的局部状态

每个模块拥有自己的 state、mutation、action、getter

这里拿login模块举例子

export default {state: {token: "asdasdlhcHDIHIO" // 定义初始状态,存储 token 值},// rootState: 顶级的 state,可以访问其他 module 或根 Vuex store 的 stategetters: {getToken(state, getters, rootState) {// 定义一个 getter,用于格式化 token 的输出// state: 当前 module 的 state// getters: 当前 module 的其他 getter// rootState: 整个 Vuex store 的根 state(如果需要访问其他 module 的 state)return "当前的 token 为: " + state.token; // 返回格式化后的 token 文本}},// 修改 statemutations: {updateToken(state, token) {// 定义一个 mutation,用于更新 state 中的 token 值// state: 当前 module 的 state// token: 传入的新的 token 值state.token = token; // 将传入的 token 值赋值给 state.token}},// 调用 mutations// rootState: 主文件中的根 stateactions: {asyncUpdateToken({ commit, rootState, state }, token) {// 定义一个 action,用于异步更新 token 值// commit: 用于提交 mutation// rootState: 整个 Vuex store 的根 state// state: 当前 module 的 state// token: 传入的新的 token 值commit('updateToken', token); // 调用 updateToken mutation,更新 token}}
}
<template><h3>登录页面</h3><p>{{token}}</p><p>{{currentToken}}</p><input type="text" v-model="newtoken"><button @click="updateToken">修改token</button>
</template><script setup>
import {computed, ref} from "vue";import {useStore} from "vuex";const store = useStore();const newtoken = ref("");//读取state的时候需要加上模块的名字const token = computed(() => store.state.Login.token);//读取getters时候不需要加上模块的名字const currentToken = computed(() => {return store.getters.getToken})function updateToken(){store.dispatch("asyncUpdateToken",newtoken.value);
}
</script>

Module-命名空间

简单来说,Vuex 默认是全局的,也就是说同一个 actionmutationgetter 名字不能在不同模块中重复,否则会发生冲突。

但是,你可以通过添加 namespaced: true 给模块加上“命名空间”,这样它的 actionmutationgetter 就不会和其他模块冲突了,就像给它们自动加了个前缀,限制在自己的模块内。

  • 如果不加命名空间(默认全局),不同模块中的 actionmutationgetter 名字不能重复,否则会报错。

  • 它们会“混在一起”,无法区分属于哪个模块。

例如下面的模块配置:

const moduleA = {namespaced: true,state: { count: 0 },mutations: {increment(state) {state.count++;}},actions: {incrementAction({ commit }) {commit('increment');}}
};
const moduleB = {namespaced: true,state: { count: 0 },mutations: {increment(state) {state.count++;}},actions: {incrementAction({ commit }) {commit('increment');}}
};

在全局访问时,你需要通过模块名区分:

store.commit('moduleA/increment');
store.commit('moduleB/increment');store.dispatch('moduleA/incrementAction');
store.dispatch('moduleB/incrementAction');

注意state不存在命名空间的概念,因为在调用的时候就要加上模块的名称。

8、核心概念-Vuex项目结构

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的
  3. 异步逻辑都应该封装到 action 里面

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例

├── index.html
├── main.js
├── api
│  └── ... # 抽取出API请求
├── components
│  ├── App.vue
│  └── ...
└── store
  ├── index.js      # 我们组装模块并导出 store 的地方
  ├── actions.js     # 根级别的 action
  ├── mutations.js    # 根级别的 mutation
  └── modules
    ├── cart.js    # 购物车模块
    └── products.js  # 产品模块
 

9、Vuex严格模式

开启严格模式,仅需在创建 store 的时候传入 strict: true

const store = createStore({strict: true
})

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失

10、Vuex表单处理

如果Vuex中处理的是表单输入框的数据,并且需要双向数据绑定效果该如何实现呢?

<template><h3>搜索</h3><input v-model="message"> <!-- 输入框,绑定到 computed 属性 message --><p>{{ message }}</p> <!-- 显示输入框的值 -->
</template><script setup>
import { computed } from "vue" // 从 Vue 中引入 computed 函数
import { useStore } from "vuex" // 从 Vuex 中引入 useStore 钩子const store = useStore(); // 获取 Vuex 的 store 实例// 定义 computed 属性 message
const message = computed({// 获取 Vuex 中的 message 状态get() {return store.state.message; // 从 store 的 state 中获取 message},// 设置 Vuex 中的 message 状态set(value) {store.commit('updateMessage', value); // 调用 mutation 更新 message}
});
</script>

  1. v-model="message":

    • 输入框的值与 message 双向绑定。

    • 当输入框的值发生变化时,messageset 方法会被触发。

    • message 的值发生变化时,输入框的值也会自动更新。

  2. computed 属性:

    • get 方法:从 Vuex 的 state 中获取 message 值。

    • set 方法:当输入框的值发生变化时,调用 Vuex 的 mutation (updateMessage) 更新 state

  3. Vuex 的 state:

    • store.state.message 是 Vuex 中的状态,存储了当前的 message 值。

    • 通过 store.commit 调用 mutation,可以更新 state

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/11778.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DBASE DBF数据库文件解析

基于Java实现DBase DBF文件的解析和显示 JDK19编译运行&#xff0c;实现了数据库字段和数据解析显示。 首先解析数据库文件头代码 byte bytes[] Files.readAllBytes(Paths.get(file));BinaryBufferArray bis new BinaryBufferArray(bytes);DBF dbf new DBF();dbf.VersionN…

亚博microros小车-原生ubuntu支持系列:20 ROS Robot APP建图

依赖工程 新建工程laserscan_to_point_publisher src/laserscan_to_point_publisher/laserscan_to_point_publisher/目录下新建文件laserscan_to_point_publish.py #!/usr/bin/env python3import rclpy from rclpy.node import Node from geometry_msgs.msg import PoseStam…

冷启动+强化学习:DeepSeek-R1 的原理详解——无需监督数据的推理能力进化之路

本文基于 DeepSeek 官方论文进行分析,论文地址为:https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf 有不足之处欢迎评论区交流 原文翻译 在阅读和理解一篇复杂的技术论文时,逐字翻译是一个重要的步骤。它不仅能帮助我们准确把握作者的原意,还能为后续…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构中的问题。它通过设置两个指针&#xff0c;在数据结构上进行遍历和操作&#xff0c;从而实现高效解决问题。 二、算法题精讲 2.1. 查找总价格为目标值…

数据结构之栈和队列(超详解)

文章目录 概念与结构栈队列 代码实现栈栈是否为空&#xff0c;取栈顶数据、栈的有效个数 队列入队列出队列队列判空&#xff0c;取队头、队尾数据&#xff0c;队列的有效个数 算法题解有效的括号用队列实现栈用栈实现队列复用 设计循环队列数组结构实现循环队列构造、销毁循环队…

解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作

目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中&#xff0c;同义词&#xff08;Synonym&#xff09;是对数…

DeepSeek-R1 本地部署教程(超简版)

文章目录 一、DeepSeek相关网站二、DeepSeek-R1硬件要求三、本地部署DeepSeek-R11. 安装Ollama1.1 Windows1.2 Linux1.3 macOS 2. 下载和运行DeepSeek模型3. 列出本地已下载的模型 四、Ollama命令大全五、常见问题解决附&#xff1a;DeepSeek模型资源 一、DeepSeek相关网站 官…

【C语言入门】解锁核心关键字的终极奥秘与实战应用(二)

目录 一、sizeof 1.1. 作用 2.2. 代码示例 二、const 2.1. 作用 2.2. 代码示例 三、signed 和 unsigned 3.1. 作用 3.2. 代码示例 四、struct、union、enum 4.1. struct&#xff08;结构体&#xff09; 4.1.1. 作用 4.1.2. 代码示例 4.2. union&#xff08;联合…

如何确认Linux嵌入式系统的触摸屏对应的是哪个设备文件?如何查看系统中所有的输入设备?输入设备的设备文件有什么特点?

Linux嵌入式系统的输入设备的设备文件有什么特点&#xff1f; 在 Linux 中&#xff0c;所有的输入设备&#xff08;如键盘、鼠标、触摸屏等&#xff09;都会被内核识别为 输入事件设备&#xff0c;并在 /dev/input/ 目录下创建相应的 设备文件&#xff0c;通常是&#xff1a; …

ESP32-c3实现获取土壤湿度(ADC模拟量)

1硬件实物图 2引脚定义 3使用说明 4实例代码 // 定义土壤湿度传感器连接的模拟输入引脚 const int soilMoisturePin 2; // 假设连接到GPIO2void setup() {// 初始化串口通信Serial.begin(115200); }void loop() {// 读取土壤湿度传感器的模拟值int sensorValue analogRead…

Hive:窗口函数(1)

窗口函数 窗口函数OVER()用于定义一个窗口&#xff0c;该窗口指定了函数应用的数据范围 对窗口数据进行分区 partition by 必须和over () 一起使用, distribute by经常和sort by 一起使用,可以不和over() 一起使用.DISTRIBUTE BY决定了数据如何分布到不同的Reducer上&#xf…

【react-redux】react-redux中的 useDispatch和useSelector的使用与原理解析

一、useSelector 首先&#xff0c;useSelector的作用是获取redux store中的数据。 下面就是源码&#xff0c;感觉它的定义就是首先是createSelectorHook这个方法先获得到redux的上下文对象。 然后从上下文对象中获取store数据。然后从store中得到选择的数据。 2、useDispatc…

java异常处理——try catch finally

单个异常处理 1.当try里的代码发生了catch里指定类型的异常之后&#xff0c;才会执行catch里的代码&#xff0c;程序正常执行到结尾 2.如果try里的代码发生了非catch指定类型的异常&#xff0c;则会强制停止程序&#xff0c;报错 3.finally修饰的代码一定会执行&#xff0c;除…

传输层协议 UDP 与 TCP

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 前置复盘&#x1f98b; 传输层&#x1f98b; 再谈端口号&#x1f98b; 端口号范围划分&#x1f98b; 认识知名端口号 (Well-Know Port Number) 二&#xf…

The Simulation技术浅析(三):数值方法

The Simulation ,通常涉及使用数值方法对物理、工程或金融等领域的问题进行建模和求解。数值方法是解决复杂数学问题的关键技术,常见的数值方法包括 有限差分法(FDM)、有限元法(FEM) 和 蒙特卡洛方法(Monte Carlo Method)。 1. 有限差分法(FDM) 有限差分法是一种用于…

深度学习-98-大语言模型LLM之基于langchain的代理create_react_agent工具

文章目录 1 Agent代理1.1 代理的分类1.2 ReAct和Structured chat2 代理应用ReAct2.1 创建工具2.1.1 嵌入模型2.1.2 创建检索器2.1.3 测试检索结果2.1.4 创建工具列表2.2 初始化大模型2.3 创建Agent2.4 运行Agent3 参考附录1 Agent代理 Agent代理的核心思想是使用语言模型来选择…

小试牛刀,AI技术实现高效地解析和转换多种文档格式

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据、人工智能领域创作者。目前从事python全栈、爬虫和人工智能等相关工作&#xff0c;主要擅长领域有&#xff1a;python…

WPF进阶 | WPF 动画特效揭秘:实现炫酷的界面交互效果

WPF进阶 | WPF 动画特效揭秘&#xff1a;实现炫酷的界面交互效果 前言一、WPF 动画基础概念1.1 什么是 WPF 动画1.2 动画的基本类型1.3 动画的核心元素 二、线性动画详解2.1 DoubleAnimation 的使用2.2 ColorAnimation 实现颜色渐变 三、关键帧动画深入3.1 DoubleAnimationUsin…

自制虚拟机(C/C++)(三、做成标准GUI Windows软件,扩展指令集,直接支持img软盘)

开源地址:VMwork 要使终端不弹出&#xff0c; #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") 还要实现jmp near 0x01类似的 本次的main.cpp #include <graphics.h> #include <conio.h> #include <windows.h> #includ…

tomcat核心组件及原理概述

目录 1. tomcat概述 1.1 概念 1.2 官网地址 2. 基本使用 2.1下载 3. 整体架构 3.1 核心组件 3.2 从web.xml配置和模块对应角度 3.3 如何处理请求 4. 配置JVM参数 5. 附录 1. tomcat概述 1.1 概念 什么是tomcat Tomcat是一个开源、免费、轻量级的Web服务器。 Tomca…