• Vue(七)——vuex(vuex基础,使用,state,getters,mutations,actions基本概念与使用以及基本实现案例)


    一、为什么要用vuex?

    首先,需要清楚为什么要用 vuex ,当我们的应用遇到 多个组件共享状态

    • 多层级父子组件状态传递会特别繁琐

    • 非嵌套父子组件状态传递也会特别繁琐

    组件数据是层层分发共享的,父子级传递数据有两种方式:

    1. 父级传给子级;
    2. 子级通过事件调用将自己的数据传递给父级,父级进行监听;
    3. 通过eventBus中间件的方式,用组件进行存储;

    二、vuex是什么?

    Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式,类似 redux

    这种状态管理模式包含:

    • State : 状态数据源

    • View : 使用状态数据源的视图(不同组件直接从state单向获取数据)

    • Actions : 修改更新数据源的操作(视图更新数据不能直接更改,必须通过actions更改)

    这种模式遵循的是 单向数据流 模式

    三、vuex的工作流

    • State : 存储应用状态数据(React 中的 State)

    • Vue Component : 消费State ,即从State中获取数据

    • Actions : 提交修改State的动作(包括异步行为,主要负责异步提交)(React 中的 action)

    • Mutations : 唯一更改 State 的位置(React 中的 Reducer)(真正进行修改操作)

    四、安装vuex

    1. npm i vuex
    2. // or
    3. yarn add vuex

     安装报错解决:

    1. npm ERR! code ERESOLVE
    2. npm ERR! ERESOLVE unable to resolve dependency tree
    3. npm ERR!
    4. npm ERR! While resolving: vuex@0.1.0
    5. npm ERR! node_modules/vue
    6. npm ERR! vue@"^2.6.11" from the root project
    7. npm ERR!
    8. npm ERR! Could not resolve dependency:
    9. npm ERR! peer vue@"^3.0.2" from vuex@4.0.2
    10. npm ERR! node_modules/vuex
    11. npm ERR! vuex@"4.0.2" from the root project
    12. npm ERR!
    13. npm ERR! Fix the upstream dependency conflict, or retry
    14. npm ERR! this command with --force, or --legacy-peer-deps
    15. npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
    16. npm ERR!
    17. npm ERR! See C:\Users\Administrator\AppData\Local\npm-cache\eresolve-report.txt for a full report.
    18. npm ERR! A complete log of this run can be found in:
    19. npm ERR! C:\Users\Administrator\AppData\Local\npm-cache\_logs\2022-06-14T09_14_49_535Z-debug-0.log

     问题出现原因:

    查看项目的package.json文件,查看vue的版本和vuex的版本( vue2 对应vuex3, vue3 对应vuex4) 切记不可弄错,否则就会报错

    解决:安装指定版本vuex

    npm install vuex@3.6.2 --save

     查看package.json文件中是否安装成功

     

    五、两种方式引入vuex

    5.1通过 <script> 引入

    1. <script src="vue.js"></script>
    2. <script src="vuex.js"></script>

     通过 <script> 方式引入,vuex 会自动安装(也就是主动调用 Vue.use(Vuex)

    5.2通过 import 引入

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)

    通过 import 方式引入,需要手动安装(手动调用 Vue.use(Vuex))  

    六、从Store开始

    Store 就是仓库,我们前面提到的 state 就存储在 store 中,同时提交动作、修改状态的方法也都由 store 提供和管理

    6.1创建一个Store

    1. import Vue from 'vue'
    2. import Vuex from 'vuex'
    3. Vue.use(Vuex)
    4. let store = new Vuex.Store({
    5. state: {},
    6. getters: {},
    7. mutations: {},
    8. actions: {}
    9. })

    必须在 Vue.use(Vuex) 之后创建 store  

    七、核心概念

    • state
    • getters
    • mutations
    • actions

    7.1 state

    7.1.1 state的创建

    存储应用状态数据的对象,state 的值可以是一个对象,也可以是一个返回对象的函数,类似 vue 中组件的 data ,使用函数的方式返回对象可以避免对象引用导致的副作用问题(如下例,state值为对象时,返回100,100;state值为返回对象的函数时,返回100,1)

    • 通过 store.state 访问状态数据

    • state 数据与组件 data 一样是被追踪的

    1. // state值为对象
    2. let state = {a: 1};
    3. // state值为返回对象的函数
    4. // let state = _=>({ a:1 });
    5. const store = new Vuex.Store({state});
    6. const store2 = new Vuex.Store({state});
    7. // 如果state为对象true,如果为返回对象的函数则为false
    8. console.log(store.state == store2.state);
    9. store.state.a = 100;
    10. // 使用函数的方式返回对象可以避免对象引用导致的副作用问题:state值为对象时,100,100;state值为返回对象的函数时,100,1
    11. console.log(store.state.a, store2.state.a);

    7.1.2在组件中使用store

    1. // stores/index.js
    2. import Vue from 'vue';
    3. import Vuex from 'vuex';
    4. import state from './state';
    5. Vue.use(Vuex);
    6. const store = new Vuex.Store({
    7. state
    8. })
    9. export default store;
    1. // stores/state.js
    2. // state为返回函数的对象
    3. export default () => ({
    4. title: '商品列表',
    5. content: '首页汇总'
    6. })

    1. <template>
    2. <div class="home">
    3. <h2>{{title}}</h2>
    4. <div>{{content}}</div>
    5. </div>
    6. </template>
    7. <script>
    8. import store from '@/stores'
    9. export default {
    10. name: 'home',
    11. data() {
    12. return {
    13. title: store.state.title,
    14. content: store.state.content
    15. }
    16. }
    17. }
    18. </script>

     问题:state 的更新并不会更新视图 

    解决 :使用 computed (这种方式也不是特别推荐,推荐使用辅助函数mapState)

    1. <template>
    2. <div class="home">
    3. <h2>{{title}}</h2>
    4. <div>{{content}}</div>
    5. </div>
    6. </template>
    7. <script>
    8. import store from '@/stores'
    9. store.state.title = "所有商品列表";
    10. export default {
    11. name: 'home',
    12. computed: {
    13. title() {
    14. return store.state.title
    15. },
    16. content() {
    17. return store.state.content
    18. }
    19. }
    20. }
    21. </script>

    7.1.3 store配置

    如果每个组件在使用 store 的时候都 import 会比较繁琐,这个时候,我们通过 vuex 提供的 store 选项把 store 对象注入到 vue 的原型上

    1. import Vue from 'vue'
    2. import App from './App.vue'
    3. import router from './router'
    4. import store from '@/stores'
    5. Vue.config.productionTip = false
    6. new Vue({
    7. router,
    8. store,
    9. render: h => h(App)
    10. }).$mount('#app')

    配置注入后,我们就可以在组件实例中使用 this.$store 来访问 store 对象了

    注意因为注入到实例vue上了,所以,在export以外this为undefined,所以不能在其范围外更改store里的state值了,如下例this.$store.state.title = "所有商品列表";可以在created方法中使用

    1. <template>
    2. <div class="home">
    3. <h2>{{title}}</h2>
    4. <div>{{content}}</div>
    5. </div>
    6. </template>
    7. <script>
    8. // import store from '@/stores' // 可以去掉了
    9. // 注意在组件内部才能使用this,所以不能在这里使用this.$store
    10. // this.$store.state.title = "所有商品列表";
    11. export default {
    12. name: 'home',
    13. created() {
    14. this.$store.state.title = "所有商品列表";
    15. },
    16. computed: {
    17. title() {
    18. return this.$store.state.title
    19. },
    20. content() {
    21. return this.$store.state.content
    22. }
    23. }
    24. }
    25. </script>

    7.1.4使用辅助函数mapState

    当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键,通常我们把 storestate 通过 mapState 函数映射到组件的 computed

    1.mapState中使用数组

    1. <template>
    2. <div class="home">
    3. <h2>{{title}}</h2>
    4. <div>{{content}}</div>
    5. </div>
    6. </template>
    7. <script>
    8. import {mapState} from 'vuex'
    9. export default {
    10. name: 'home',
    11. created() {
    12. this.$store.state.title = "所有商品列表";
    13. },
    14. computed: mapState([
    15. 'title','content'
    16. ])
    17. }
    18. </script>

    2.mapState中使用对象:通过对象方式进行映射

    场景:当组件中已有与 store 同名的数据名称(当组件data中已有与 `store` 同名的数据名称时,需要使用对象重新定义属性名)

    1. <template>
    2. <div class="home">
    3. <h1>{{title}}</h1>
    4. <h2>{{subTitle}}</h2>
    5. <div>{{content}}</div>
    6. </div>
    7. </template>
    8. <script>
    9. import {mapState} from 'vuex'
    10. export default {
    11. name: 'home',
    12. data() {
    13. return {title: 'Vuex'}
    14. },
    15. computed: mapState({
    16. subTitle: 'title',
    17. content: ({content}) => content.length <= 12 ? content : content.substring(0, 12) + '......'
    18. })
    19. }
    20. </script>

    3.mapState中使用对象函数,如上例的content

    7.1.5使用扩展运算符组合——把 mapState 返回的 state 属性与组件已有计算属性进行融合

    通过对象扩展运算符,可以把 mapState 返回的 state 属性与组件已有计算属性进行融合。融合后只有一个title值

    1. <script>
    2. import {mapState} from 'vuex'
    3. export default {
    4. computed:{
    5. ...mapState({
    6. subTitle:'title',
    7. content: 'content'
    8. })
    9. },
    10. }
    11. </script>

    7.2 getters

    有时候我们需要从 store 中的 state 中派生出一些状态,类似组件的 datacomputedstore 也提供了一个 getters 对象来处理派生数据

    7.2.1 getters函数

    与组件属性一样,我们是通过定义一个函数的形式来返回派生数据的,getters 函数接受两个参数

    • 第一个参数:state 对象

    • 第二个参数:getters 对象

    Getter 也可以接受其他 getter 作为第二个参数:

    1. getters: {
    2. // ...
    3. doneTodosCount (state, getters) {
    4. return getters.doneTodos.length
    5. }
    6. }
    store.getters.doneTodosCount

    7.2.2通过属性访问

    同样的,与组件计算属性一样,默认是通过属性的方式去访问 getters 中的数据的,这种方式与组件的计算属性一样,也是会缓存结果的

    7.2.3通过方法访问

    我们还可以通过闭包函数的形式返回一个函数,来实现给 getters 函数传参,需要注意的是这种方式不支持结果缓存

    1. //Home.vue
    2. <template>
    3. ...
    4. <button @click="type='Apple'">显示Apple</button>
    5. <button @click="type='XiaoMi'">显示XiaoMi</button>
    6. <button @click="type='HuaWei'">显示HuaWei</button>
    7. </template>
    8. <script>
    9. ...
    10. data() {
    11. return {
    12. ...
    13. type: '',
    14. ...
    15. };
    16. },
    17. computed:{
    18. ...
    19. items(){
    20. return this.$store.getters.showItems(this.type);
    21. }
    22. },
    23. </script>
    1. //store.js
    2. ...
    3. getters: {
    4. showItems(state) {
    5. return function(type) {
    6. if (type === '')
    7. return state.items;
    8. return state.items.filter(item => {
    9. return item.vendor == type;
    10. })
    11. };
    12. }
    13. },

     

    7.2.4使用辅助函数mapGetters

    mapState 函数类似,通常映射到组件的 computed

    7.3 mutations

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation(类似 redux 中的 action + reducer),Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)

    mutation 中的函数不要直接调用

    7.3.1提交

    type 要提交的 mutation 回调函数名称

    payload 载荷:提交的额外数据,任意格式

    1. store.commit(type, payload)
    2. // or
    3. store.commit({
    4. type: ...,
    5. payload: ...
    6. })

    7.3.2 mutation函数

    mutation 中的函数被 commit 执行的时候,接收两个参数

    • 第一个参数:state 对象

    • 第二个参数: commit 提交的 payload

    mutation 函数中,我们就可以通过 state 对象进行状态数据的修改

    7.3.3使用辅助函数mapMutations

    mapMutations 函数的使用与 mapStatemapGetters 类似,但是其一般是把组件的 methods 映射为 storemutationscommit 调用

    7.3.4 mutation 函数必修是同步的

    commit 方法没有返回值

    7.4 actions

    action 中的函数与 mutation 中的函数类似,但是它主要用来进行异步任务的处理,然后通过提交 mutation 来修改 state

    注意:action 中的函数不要直接修改 state

    7.4.1 提交

    1. store.dispatch(type, payload)
    2. // or
    3. store.dispatch({
    4. type: ...,
    5. payload: ...
    6. })

    action 任务需要通过 dispatch 方法来提交(派发),与 commit 类似

    dispatch 方法有返回值,且一定返回一个 promise 对象

    7.4.2 action函数

    action 中的函数执行的过程中也接受两个参数

    • 第一个参数:store 对象

    • 第二个参数: dispatch 提交的 payload

    7.4.3使用副主函数mapActions

    mapMutations 函数类似,把组件的 methods 映射为 storeactionsdispatch 调用

    八、学习案例实现全过程及代码展示

    1:创建一个新的项目,首页显示所有商品名称,点击名称进入商品详情页
    2:商品详情页需要获取商品信息,而所有的商品信息在首页都已经获取过,通过父组件传递数据到子页面(商品详情页)可以实现,但是当数据特别复杂,子页面特别多时会不好处理
    3:将store注入vue实例,通过store管理数据,并传递给商品详情页
    4:直接修改store仓库中的state数据,vue视图不会立即改变。示例:通过edit按钮点击测试直接修改state数据,页面的变化
    5:页面不会刷新,解决方案:在computed中更改state数据
    6:当一个组件需要获取多个状态即state数据时,如果将这些数据都声明为computed计算属性,就会繁琐和冗余。为此,可以通过mapState辅助函数帮助生成计算属性
    7:mapState计算属性的三种用法(使用数组,使用对象,使用函数),且当vuex的计算函数和vue自身的computed重合时,使用扩展运算符进行融合
    8:有时需要从Store中的State中派生出一些数据(类似组件的data和computed属性的关系),此时Store提供了getters对象来处理派生数据。案例:分类显示商品
    9:getters函数的三种访问方式(属性、方法、辅助函数mapGetters)
    10:mutations函数:用于提交修改Store中的数据状态,可以提交数据但是没有数据返回。案例:新增商品信息页面(保证后端各接口可用)。
    11:actions函数:可以异步提交数据,有返回数据,返回值包装在Promise对象中。 案例:新增商品信息页面,并获取返回值
    12:串通组件、mutations、actions三者实现新增商品信息。提交过程:在created方法中发起dispatch请求,请求到actions中的commit()发起后端请求,然后调用mutations的commit()更改仓库数据
    13:怎么更新视图?Add组件中点击添加,调用异步方法addItem(),此方法中通过this.$store.dispatch()方法调用actions()中的addItem(),actions()中的addItem()发起请求后端处理数据,当成功返回后,通过commit('addItem', payload)调用mutations方法,mutations方法只处理store相关的操作,即改变state数据状态;
    14:商品信息展示页面也使用store而不直接请求并显示:首次进入页面,通过created()调用commit(),调用actions中的getItems()发起后端请求获取所有商品数据信息,成功返回后,通过mutations中的updateItems()方法更新state数据状态

    15.组件调用时,如果直接调用mutations发起请求,需要使用commit方法:this.$store.commit('getItems');如果调用action方法发起请求需要使用dispatch方法this.$store.dispatch('getItems');

    案例代码

    此案例使用vue3实现,在router配置和main.js实例注入方式上会有些不一样的地方:

    1. //main.js
    2. import { createApp } from 'vue'
    3. import App from './App.vue'
    4. import Router from '@/router/router.js'
    5. import Store from '@/store/store.js'
    6. createApp(App).use(Router).use(Store).mount('#app')

     

    1. //App.vue
    2. <template>
    3. <div id="app">
    4. <h1>vuex</h1>
    5. <div id="nav">
    6. <router-link to="/">首页</router-link>
    7. </div>
    8. <router-view></router-view>
    9. </div>
    10. </template>
    11. <script>
    12. export default {
    13. name: 'App',
    14. components: {
    15. }
    16. }
    17. </script>
    18. <style>
    19. #app {
    20. font-family: Avenir, Helvetica, Arial, sans-serif;
    21. -webkit-font-smoothing: antialiased;
    22. -moz-osx-font-smoothing: grayscale;
    23. text-align: center;
    24. color: #2c3e50;
    25. margin-top: 60px;
    26. }
    27. </style>
    1. //router.js
    2. // 注意vue3和vue2引入方式和写法不同
    3. import { createRouter, createWebHistory } from "vue-router";
    4. const vuexRouter = createRouter({
    5. history: createWebHistory(),
    6. routes: [{
    7. name: 'home',
    8. path: '/',
    9. title: '首页',
    10. // 注意vue3一定要用这种加载组件方式component:Home这种会报错
    11. component: () =>
    12. import ('@/views/Home.vue'),
    13. },
    14. {
    15. name: 'item',
    16. path: '/item/:itemId',
    17. title: '商品详情页',
    18. props: true,
    19. component: () =>
    20. import ('@/views/Item.vue'),
    21. },
    22. {
    23. path: '/*',
    24. title: '404',
    25. // 注意vue3一定要用这种加载组件方式component:Home这种会报错
    26. component: () =>
    27. import ('@/views/NotFound.vue'),
    28. },
    29. ]
    30. });
    31. export default vuexRouter;
    1. //Home.vue
    2. <template>
    3. <div class="home">
    4. <hr />
    5. <button @click="edit">清空store,测试视图是否改变?</button>
    6. <br>
    7. <button @click="addItem">新增商品</button>
    8. <input type="text" ref="name"/>
    9. <div id="mesg" v-show="mesg">*商品名称错误*</div>
    10. <hr />
    11. <br />
    12. <button @click="type='Apple'">显示Apple</button>
    13. <button @click="type='XiaoMi'">显示XiaoMi</button>
    14. <button @click="type='HuaWei'">显示HuaWei</button>
    15. <div v-if="success">
    16. <ul>
    17. <li v-for="item in items" :key="item.id">
    18. <router-link :to="{name:'item',params:{itemId:item.id}}">{{item.name}}</router-link>
    19. </li>
    20. </ul>
    21. </div>
    22. <div v-else>
    23. <NotFound />
    24. </div>
    25. </div>
    26. </template>
    27. <script>
    28. // import axios from "axios";
    29. import NotFound from "@/views/NotFound.vue";
    30. import {mapState} from 'vuex';
    31. export default {
    32. name: "Home",
    33. components: {
    34. NotFound
    35. },
    36. data() {
    37. return {
    38. // 使用了store中的items,这里就不用注册了
    39. // items: this.$store.state.items,
    40. // itemId: 0,
    41. success: "",
    42. type: '',
    43. // 错误信息显示
    44. mesg:false
    45. };
    46. },
    47. async created() {
    48. console.log("created------");
    49. // 通过mutations发起请求用commit,通过action发起请求用dispatch
    50. // this.$store.commit('getItems');
    51. //不再直接发起请求,而是通过store的action发起请求
    52. // 因为需要请求并获取数据后,得到success再渲染,所以使用异步
    53. await this.$store.dispatch('getItems');
    54. this.success = (Object.keys(this.$store.state.items).length === 0 ? false:true);
    55. },
    56. // 直接更改store,视图不会改变,可以在computed中监听修改后立即改变视图。计算属性监听items数据变化
    57. // 当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 `mapState` 辅助函数帮助我们生成计算属性
    58. computed:{
    59. success(){
    60. return this.success;
    61. },
    62. items(){
    63. // return this.$store.state.items;
    64. // 通过getters获取派生数据
    65. return this.$store.getters.showItems(this.type);
    66. }
    67. },
    68. methods: {
    69. edit() {
    70. // 发现直接修改store中的数据,视图不会更改(虽然也可以直接更改store数据然后通过computed监听,或者html中直接使用this.$store.state.items进行渲染,但是不建议如此使用)
    71. // console.log(this.$store.state.items);
    72. this.$store.state.items = [];
    73. // console.log(this.$store.state.items);
    74. },
    75. async addItem(){
    76. // 带上数据itemName(通过ref属性获取)
    77. let name = this.$refs.name.value;
    78. if(name===''){
    79. this.mesg = true;
    80. return;
    81. }
    82. await this.$store.dispatch('addItems',name);
    83. // 清空input
    84. this.$refs.name.value = '';
    85. }
    86. }
    87. };
    88. </script>
    89. <style scoped>
    90. ul {
    91. margin: 0 0;
    92. }
    93. li {
    94. list-style-type: none;
    95. padding: 4px 4px;
    96. }
    97. #mesg {
    98. color:red;
    99. }
    100. </style>
    1. //Item.vue
    2. <template>
    3. <div><hr>{{this.item.name}}</div>
    4. </template>
    5. <script>
    6. import axios from "axios";
    7. export default {
    8. // 从仓库中通过itemId取数据
    9. name: "Item",
    10. //通过组件props传参,需要在路由中设置props:true
    11. props: ["itemId"],
    12. data() {
    13. return {
    14. item: null
    15. };
    16. },
    17. created() {
    18. //从store中筛选数据
    19. let itemData = this.$store.state.items.filter(
    20. item => item.id == this.itemId
    21. );
    22. // 获取的数据是Proxy {0: Proxy}对象,需要从里面解析出数据
    23. this.item = JSON.parse(JSON.stringify(itemData))[0];
    24. }
    25. };
    26. </script>
    1. <template>
    2. <div>
    3. 错误-----未找到商品信息!!!
    4. </div>
    5. </template>

     

    1. //store.js 用于处理vuex store相关操作
    2. import Vuex from 'vuex'
    3. import axios from "axios";
    4. const store = new Vuex.Store({
    5. state: {
    6. // 写死数据,测试getters派生数据(类似组件的data与computed的关系)
    7. // items: [{ "id": 3, "name": "Macbook Pro 15.4", "vendor": "Apple", "price": 1949900 }, { "id": 4, "name": "Apple iMac", "vendor": "Apple", "price": 1629900 }, { "id": 9, "name": "游戏本2019款", "vendor": "XiaoMi", "price": 879900 }, { "id": 6, "name": "Apple Watch Series 4", "vendor": "Apple", "price": 599900 }, { "id": 1, "name": "iPhone XR", "vendor": "Apple", "price": 542500 }, { "id": 11, "name": "HUAWEI P30 Pro", "vendor": "HuaWei", "price": 498800 }, { "id": 2, "name": "Apple iPad Air 3", "vendor": "Apple", "price": 377700 }, { "id": 10, "name": "HUAWEI P30", "vendor": "HuaWei", "price": 368800 }, { "id": 7, "name": "小米9", "vendor": "XiaoMi", "price": 259900 }, { "id": 12, "name": "华为平板 M6 10.8英寸", "vendor": "HuaWei", "price": 229900 }, { "id": 16, "name": "Redmi K20", "vendor": "XiaoMi", "price": 199900 }, { "id": 13, "name": "HUAWEI WATCH GT", "vendor": "HuaWei", "price": 128800 }, { "id": 5, "name": "Apple Magic Mouse", "vendor": "Apple", "price": 72900 }, { "id": 8, "name": "小米手环4", "vendor": "XiaoMi", "price": 16900 }],
    8. // 通过请求获取数据放入仓库时就不需要写死
    9. items: []
    10. },
    11. getters: {
    12. // Getter 也可以接受其他 getter 作为第二个参数:
    13. showItems(state) {
    14. // 在此方法中根据type显示数据
    15. // 注意如果以函数方式调用,则getters中的方法返回值也需要是一个函数,参数为调用时传入的参数this.type
    16. return function(type) {
    17. if (type === '')
    18. return state.items;
    19. return state.items.filter(item => {
    20. return item.vendor == type;
    21. })
    22. };
    23. }
    24. },
    25. mutations: {
    26. // 只负责和Store有关操作。两个参数分别为store中state数据和请求数据
    27. updateItems(state, payload) {
    28. console.log("mutations------");
    29. console.log(payload);
    30. // 将数据存放进仓库。
    31. state.items = payload;
    32. },
    33. addItems(state, payload) {
    34. console.log("mutations------addItems");
    35. console.log(payload);
    36. state.items.unshift(payload);
    37. }
    38. },
    39. actions: {
    40. // 在actions中提交请求,在mutations中更改仓库数据
    41. async getItems(context) {
    42. console.log("actions------");
    43. // 发起请求
    44. await axios({
    45. url: "/api/items"
    46. })
    47. .then(res => {
    48. // 参数分别为mutations的方法和需要放进仓库的数据
    49. if (res.status === 200) {
    50. context.commit('updateItems', res.data);
    51. }
    52. })
    53. .catch(err => {
    54. console.log(err);
    55. });
    56. },
    57. async addItems(context, name) {
    58. console.log("actions------addItems" + name);
    59. // 发起请求
    60. await axios({
    61. url: "/api/addItem",
    62. method: 'post',
    63. // 数据
    64. data: {
    65. name
    66. }
    67. })
    68. .then(res => {
    69. console.log(res);
    70. // 参数分别为mutations的方法和需要放进仓库的数据
    71. if (res.status === 200) {
    72. context.commit('addItems', res.data);
    73. }
    74. })
    75. .catch(err => {
    76. console.log(err);
    77. });
    78. }
    79. }
    80. });
    81. export default store;

    后端请求接口(node.js简单实现):

    1. //app.js
    2. const Koa = require('koa');
    3. const KoaRouter = require('koa-router');
    4. //接收post参数,需要使用koa-bodyparser模块
    5. const bodyParser = require("koa-bodyparser");
    6. let datas = {
    7. items: require('./data/items.json'),
    8. users: require('./data/users.json')
    9. }
    10. // console.log(datas);
    11. const app = new Koa();
    12. const router = new KoaRouter();
    13. // 新增商品id
    14. let currentId = 20;
    15. router.get('/', async ctx => {
    16. ctx.body = 'api';
    17. });
    18. router.get('/items', async ctx => {
    19. let sort = ctx.request.query.sort || 'desc';
    20. let items = datas.items.sort((a, b) => sort === 'asc' ? a.price - b.price : b.price - a.price);
    21. ctx.body = items;
    22. });
    23. router.get('/item/:id', async ctx => {
    24. let id = Number(ctx.params.id);
    25. let item = datas.items.find(item => item.id === id);
    26. if (!item) {
    27. // return ctx.body = {
    28. // code: 1,
    29. // message: '没有该商品的信息'
    30. // }
    31. ctx.throw(404, '没有该商品信息');
    32. return;
    33. }
    34. ctx.body = item;
    35. });
    36. // 新增商品
    37. router.post('/addItem', async ctx => {
    38. let item = ctx.request.body;
    39. if (item.name != '') {
    40. currentId++;
    41. item.id = currentId;
    42. item.vendor = 'Apple';
    43. item.price = 251205;
    44. datas.items.unshift(item);
    45. console.log(datas.items);
    46. }
    47. // 返回item数据用于存储在store中
    48. ctx.body = item;
    49. });
    50. app.use(bodyParser());
    51. app.use(router.routes());
    52. app.listen(7777);

     

    九、Module

    这个更多的是基于一种代码组织结构上的辅助

    https://vuex.vuejs.org/zh/guide/modules.html

    https://vuex.vuejs.org/zh/guide/structure.html

    Module | Vuex

    项目结构 | Vuex

  • 相关阅读:
    esp-01刷固件/下载软件到内部单片机的方法
    web概述13
    java毕业生设计悦途旅游网计算机源码+系统+mysql+调试部署+lw
    伦敦银条有多大投资价值?
    H5 tab点击切换CSS样式- 微信小程序开发技术要点总结(一)
    十、Mysql - 全备份 - 根据二进制日志还原数据
    C++ STL 顺序结构 vector
    2023年天津财经大学珠江学院专升本经济学专业课考试大纲
    LeetCode3. 无重复字符的最长子串
    Java学习笔记(三十二)
  • 原文地址:https://blog.csdn.net/qq_34569497/article/details/113397395