vue全家桶之vuex数据状态管理

前言:今日课程准备

  • 1.新建一个脚手架项目: 01-vuex
  • 2.添加路由router和vuex
    • 如果创建脚手架的时候没有勾选,可以分别在根目录执行两个命令进行安装
      • vue add router
      • vue add vuex
  • 3.创建三个页面: home.vue my.vue TodoList.vue , 并且配置好对应路由
    • 可以直接从课程资料复制过来
  • 4.今日学习路由
    • 在home.vue 和 my.vue中我们将会学习vuex几乎所有的语法
    • 综合案例:使用vuex重构我们第三天的案例TodoList

01-vuex全局数据管理(vue全家桶04)

​ vue全家桶 = axios(网络请求) + vueRouter(路由单页面应用) + vueCli(脚手架) + vuex(全局数据管理) + vant移动端布局(PC端elementUI)

  • 官网文档:https://vuex.vuejs.org/zh/
  • vuex作用:实现所有组件间的数据共享
  • 本章节学习目标
    • 了解vuex的应用场景 (在哪用)
    • 掌 么用)

1.1-vuex介绍

回顾组件关系和通信方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AwXB64bq-1664019534533)(day07.assets/image-20210323175925844.png)]

序号 组件关系 数据通信
1 父子关系 子传父:$emit ; 父传子:props
2 非父子关系 eventBus: $on + $emit
3 非父子关系 vuex

和我们已经学过的父子通信和兄弟通信类似,vuex也是一种组件通信解决方案

1.1.1-组件传值的几种方式

  • 1.在现代化开发中,组件化已经成为主流开发了。

  • 2.每一个组件的数据是独立的, 每个组件有着自己的状态(数据)

  • 3.在实际开发中,一个组件需要访问另一个组件中的数据是非常常见的。这时候需要进行组件通讯。

  • 常见的组件通讯

    • 父传子 props
      • 单向数据流
    • 子传父 $emit
      • 事件通知
    • 兄弟组件传值(了解即可,现在基本处于废弃状态):event bus 通用组件通讯的解决方案

1.1.2-为什么要有vuex

  • 1.vuex的作用是解决多组件状态共享的问题,在大型的项目中,组件通讯会变得很混乱,使用vuex可以统一管理组件之间的通讯
    • 它是独立于组件而单独存在的,所有的组件都可以把它当作一座桥梁来进行通讯。
  • 2.使用vuex好处
    • 响应式 : 只要vuex中的数据变化,对应的组件会自动更新(类似于vue数据驱动)
    • 操作更简洁 : 类似于sessionStorage,只有几个方法

1.1.3-vuex使用场景

实际开发中,组件传值大多数情况下还是使用 父子组件传值

少部分情况下会用vuex. (数据需要在非常多的页面使用,比如用户头像,好几个页面都要显示那种)

  • 1.不是所有的场景都适用于vuex,只有在必要的时候才使用vuex,如果不必要,尽量别用
    • 使用了vuex之后,会一定程度上增加了项目的复杂度
  • 2.适合使用vuex场景
    • 这个数据需要在很多个地方使用,如果采用组件传值方式,写起来很麻烦,而且多个地方都要写
      • 例如:用户信息(姓名,头像),可能会在很多个地方使用(个人页面,评论页面等)
  • 3.不适合使用vuex场景
    • 这个数据不需要多个地方使用,如果某个数据仅仅只是在两个组件之间通讯,优先使用props或$emit
  • 4.vuex特点
    • (1)所有组件数据共享
    • (2)响应式: 一旦vuex数据修改,所有使用的地方都会自动更新

知识点验收

  • 1.vuex作用
    • 所有组件,共享数据
  • 2.vuex场景 : (思考:是不是有了vuex,以前的父子组件传值就没有用呢?)
    • vuex会增加项目复杂程度,如果不需要使用,尽量不要用
    • vuex使用场景 : (1)多个组件都需要使用的数据:共享 (2)组件传值比较麻烦(不是父子关系)
    • vuex不推荐场景 : (1)数据不需要在多个组件使用:不共享 (2)组件传值比较容易(父子传值)

1.2-vuex使用流程

使用步骤:

  1. vue-cli中整合==(如果使用vue ui创建创建,直接勾选vuex,会自动帮我们完成配置)==
    1. vue add vuex
      1. 如果提示,选择y
      2. 创建了/src/store/index.js
      3. main.js导入并挂载到Vue实例上
    2. state中定义数据
  2. 任意组件中
    1. this.$store.state.xxx即可取值改值
    2. template中可以不用写this
    3. 可以通过计算属性简化编码
  3. .js文件中
    1. 导入store对象即可获取属性

注意:

  1. vue-cli创建的项目中如何整合vuex
    1. vue add vuex
  2. vuex的数据定义在哪里?
    1. state
  3. 组件中如何获取vuex中的数据?
    1. this.$store.state.xxx
    2. html结构中this可以省略

1.3-vuex核心概念-state

  • state作用: 存储公共数据

  • ./vuex/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  //1.state作用:存储数据
  state: {
    user:{
      name:'ikun',
      age:30
    }
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

  • home.vue
    • my.vue也可以使用vuex数据哟
<template>
  <div>
      <h1>首页h1>
      <button>点我修改vuex数据button><br>
      <button>点我发送ajax请求button>
      <div>
          <h2>个人信息h2>
          <p>我的名字是:{{ $store.state.user.name }}p>
          <p>我的年龄是:{{ $store.state.user.age }}p>
      div>
      <div>
          <h2>图书管理信息h2>
          <ul>
              <li>li>
          ul>
      div>
  div>
template>

<script>
export default {
    name:'home',
}
script>

<style scoped>
p{
    color:red;
}
style>

1.4-getters派生状态(计算属性)

  • 语法如下

    • 1.现在getters中声明一个计算属性
  • new Vuex.store({
      // 省略其他...
      getters: {
        // state 就是上边定义的公共数据state
        计算属性名: function(state) {
          return 要返回的值
        }
      }
    })
    
  • 2.使用getter中的计算属性

    • $store.getters.getter的名字
      
  • ./vuex/index.js

  • import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      //1.state作用:存储数据
      state: {
        user:{
          name:'ikun',
          age:30
        }
      },
      /* 2.2.getter作用: 
      官方术语:从state中派生状态(使用state中的数据,计算得出一些新数据)
      说人话: 相当于state的计算属性 
      */
      getters: {
        getInfo(state){
          //state:就是vuex上面的state
          return `我是${state.user.name},我今年${state.user.age}岁了`
        }
      },
      //2.
      mutations: {
      },
      actions: {
      },
      modules: {
      }
    })
    
    
  • home.vue

  • <div>
      <h2>个人信息h2>
      <p>我的名字是:{{ $store.state.user.name }}p>
      <p>我的年龄是:{{ $store.state.user.age }}p>
      <p>自我介绍:{{ $store.getters.getInfo }}p>
    div>
    

1.5-vuex核心概念- Mutations

  • 1.Mutation作用:更新state中的数据

    • 疑问?: 既然可以直接通过this.$store.state来修改,为什么不能这么写呢?
    • 原因: 在组件中直接state,我们的vue tools不会追踪数据的修改,这样不便于维护(不知道这个全局数据什么时候被修改了,再加上vuex是全局响应式的,一旦修改所有使用的地方全部修改。非常不便于维护)
      • 另外:在严格模式下,直接修改state会报错
  • 2.Mutation语法如下:

    • 分两个格式: 注册的格式,调用的格式

    • 定义格式: 如下

      new Vue.store({
        // 省略其他...
        mutations:{
          // 每一项都是一个函数,可以声明两个形参
        	mutation名1function(state [, 载荷]) {
        
        },
          mutation名2function(state [, 载荷]) {
      
          },
      }
      })
      
      • 每一项都是一个函数,可以声明两个形参:
        • 第一个参数是必须的,表示当前的state。在使用时不需要传入
        • 第二个参数是可选的,表示载荷,是可选的。在使用时要传入的数据
          • 专业术语载荷:表示额外的参数
    • 使用格式

      this.$store.commit('mutation名', 载荷实参 )
      
  • ./vuex/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  //1.state作用:存储数据
  state: {
    user:{
      name:'ikun',
      age:30
    }
  },
  /* 2.2.getter作用: 
  官方术语:从state中派生状态(使用state中的数据,计算得出一些新数据)
  说人话: 相当于vuex的计算属性 
  */
  getters: {
    getInfo(state){
      //state:就是vuex上面的state
      return `我是${state.user.name},我今年${state.user.age}岁了`
    }
  },
  //3.mutations作用:修改state中的数据
  mutations: {
    setUser(state,newData){
      state.user = newData
    }
  },
  actions: {
  },
  modules: {
  }
})

  • home.vue

  • export default {
        name:'home',
        methods: {
            doClick(){
                this.$store.commit('setUser', {
                    name:'黑马李宗盛',
                    age:38
                })
            }
        },
    }
    

Vuex-mutaions拓展理解

问:为啥是$store.commit('mutations的名字')而不是$store.mutations的名字()?

答:Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。

问:数据不可以该在组件内部直接修改吗?

答:不能。虽然语法上不报错,也有响应式的特点。但是不推荐。特别是在严格模式下会报错。若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过 mutation的函数,vue就会报错

问:可以传递多个数据吗?

答:参数只能有一个:下面的写法是不对的:

this.$store.commit('setUser', name, age) // age这个参数将无法被接收到 

如果希望传递复杂的数据,第二个参数可以是对象,例如下面的写法

this.$store.commit('setUser', { name, age} )

问:等价写法 this.$store.comit({type: 'mutations的名字'})

1.6-vuex辅助函数-mapState

  • 官网文档:vuex辅助函数-mapState

  • 1.mapState作用: 将vuex中的数据映射到组件的计算属性

    • 我们在组件中访问vuex数据,需要通过this.$store.state.属性名,单词太常,写起来很麻烦。
    • 通过mapState函数,可以在组件中直接通过this.属性名来访问vuex中的数据
  • 2.mapState语法

    • 2.1 在要使用的组件中导入mapState辅助函数: import { mapState } from 'vuex'

    • 2.2 在这个组件的computeds中来映射计算属性

      • export default {
          name: "my",
          computed:{
            //计算属性
            //2.将vuex中的user映射成计算属性(与下面代码完全等价)
            ...mapState(['user'])
        
            //计算属性:本质还是访问vuex中的数据
            // user(){
            //   return this.$store.state.user
            // }
          }
        };
        
      • …mapState( [‘属性名a’ , ‘属性名b’] )

        • 这行代码相当于自动帮你生成一个对应的计算属性 属性名(){ return this.$store.state.属性名 }
  • my.vue

  • <template>
      <div>
        <h1>我的h1>
        <div>
          <h2>个人信息h2>
          <p>我的名字是:{{ $store.state.user.name }}p>
          <p>我的年龄是:{{ user.age }}p>
        div>
        <div>
          <h2>图书管理信息h2>
          <ul>
            <li>li>
          ul>
        div>
      div>
    template>
    
    <script>
    //导入辅助函数mapState
    import { mapState } from 'vuex'
    export default {
      name: "my",
      computed:{
        //计算属性
        //2.将vuex中的user映射成计算属性(与下面代码完全等价)
        ...mapState(['user'])
    
        //计算属性:本质还是访问vuex中的数据
        // user(){
        //   return this.$store.state.user
        // }
      }
    };
    script>
    
    <style scoped>
    p {
      color: green;
    }
    style>
    
    

1.7-vuex核心概念:actions

1.1.1-actions介绍

  • 1.actions与mutations相同点 :都是修改state数据
  • 2.actions与mutations不同点
    • mutations:同步更新
    • actions: 异步更新(例如你的数据来源于ajax)

为什么要有actions, 假如你有一个数据,需要通过ajax请求来获取。然后你想存入vuex,应该怎么做?

方案一:

1.在组件的created钩子中发送ajax请求

2.服务器响应数据之后,调用$store.commit()提交给mutations更新(手动挡)

方案二:

1.直接在actions中发送ajax请求

2.actions会自动帮你把数据提交到mutations更新(自动挡)

你会选择手动更新?还是自动更新呢?

一定要记住:只有你的ajax数据需要存入vuex,才需要在actions中发送ajax请求。 如果不想存入vuex,还是在组件的created钩子中发送。(vuex说:你又不用我,你想干啥与我何干?)

  • 图书接口:https://www.fastmock.site/mock/37d3b9f13a48d528a9339fbed1b81bd5/book/api/books

  • actions语法如下

    • (1)定义格式
      • 这个地方的载荷一般为ajax接口需要的参数,如果没有就不用传
    new Vuex.store({
      // 省略其他...
      actions: {
        // context对象会自动传入,它与store实例具有相同的方法和属性
        action的名字: function(context, 载荷) {
          // 1. 发异步请求, 请求数据
          
          // 2. commit调用mutation来修改数据
          
          // context.commit('mutation名', 载荷)
        }
      }
    })
    
    • (2)调用格式
      • 在组件中通过this.$store.dispatch('actions的名字', 参数)来调用action

1.1.2-练习:使用action请求图书列表

  • 1.给state添加books数组

    • action作用是异步更新state数据,所以state要有数据哟
  • 2.在vuex的index.js页面导入axios

    • 先下载: npm i axios
    • 然后导入: import axios from “axios”
  • 3.给vuex的mutations添加修改books的方法

    • actions只是异步请求数据,请求数据之后会自动调用mutations更新数据
    • actions(异步)->mutations(同步)->state
  • 4.给vuex添加actions

  • ./vuex/index.js

import Vue from "vue";
import Vuex from "vuex";
//导入axios
import axios from "axios";

Vue.use(Vuex);

export default new Vuex.Store({
  //1.state作用:存储数据
  state: {
    user: {
      name: "ikun",
      age: 30
    },
    books:[]
  },
  /* 2.2.getter作用: 
  官方术语:从state中派生状态(使用state中的数据,计算得出一些新数据)
  说人话: 相当于vuex的计算属性 
  */
  getters: {
    getInfo(state) {
      //state:就是vuex上面的state
      return `我是${state.user.name},我今年${state.user.age}岁了`;
    }
  },
  //3.mutations作用:修改state中的数据
  mutations: {
    //更新user
    setUser(state, newData) {
      state.user = newData;
    },
    //更新books
    setBooks(state, newData) {
      state.books = newData;
    },
  },
  //4.action作用: 异步更新数据
  actions: {
    getBooks(context) {
      // 1. 发异步请求
      axios({
        url:
          "https://www.fastmock.site/mock/37d3b9f13a48d528a9339fbed1b81bd5/book/api/books",
        method: "GET"
      }).then(res => {
        console.log(res);
        // 2. 调用mutation
        context.commit("setBooks", res.data.data);
      });
    }
  },
  modules: {}
});

  • 5.在home.vue页面点击按钮调用actions
  • 6.在home.vue页面渲染vuex中的books数据
<template>
  <div>
      <h1>首页h1>
      <button @click="doClick">点我修改vuex数据button><br>
      <button @click="getBookList">点我发送ajax请求button>
      <div>
          <h2>个人信息h2>
          <p>我的名字是:{{ $store.state.user.name }}p>
          <p>我的年龄是:{{ $store.state.user.age }}p>
          <p>自我介绍:{{ $store.getters.getInfo }}p>
      div>
      <div>
          <h2>图书管理信息h2>
          <ul>
              
              <li v-for="(item,index) in $store.state.books" :key="index">
                  <span>书名:{{ item.name }}span> --
                  <span>价格:{{ item.price }}span>
              li>
          ul>
      div>
  div>
template>

<script>
export default {
    name:'home',
    methods: {
        doClick(){
            //调用mutaions
            this.$store.commit('setUser', {
                name:'黑马李宗盛',
                age:38
            })
        },
        getBookList(){
            //调用actions
            this.$store.dispatch('getBooks')
        }
    },
}
script>

<style scoped>
p{
    color:red;
}
style>

1.8-vuex核心概念modules

  • modules作用:模块化处理vuex数据

为什么要有vuex? 假设你的项目非常的复杂,分为四个大模块:首页、个人中心、订单列表、设置中心

每一个模块有10个数据需要使用vuex,那么你的vuex的state中就需要声明40个属性。(是不是非常麻烦呢?)

  • 当vuex中需要存储的数据很多的时候,就需要使用moudles进行模块化处理
    • 一般实际开发中moudles使用不多哈。 只有那种特别复杂,庞大的项目才可能用到

使用modules语法如下

  • export default new Vuex.Store({
      // state: 用来保存所有的公共数据
      state: {},
      getters: {},
      mutations: {},
      actions: {},
      modules: {
      	模块名1{
        		// namespaced为true,则在使用mutations时,就必须要加上模块名
          	namespaced: true, 
      		  state: {},
      			getters: {},
      			mutations: {},
      			actions: {},
      			modules: {}
      	},
        模块名2{
            // namespaced不写,默认为false,则在使用mutations时,不需要加模块名
      		  state: {},
      			getters: {},
      			mutations: {},
      			actions: {},
             modules: {}
      	}  
      }
    })
    
    
  • 也可以把每一个modules单独写在一个js文件中,然后导入进来

    • 目前的案例还支撑不了如此庞大的数据需求,这个可以随着大家对vue越来越熟悉。项目经验越来越丰富之后,自然就知道如何处理了哈。(课外自行学习)
    |--store /
    |------- index.js # 引入模块
    |------- modules
    |-------------- / mod1.js # 模块1
    |-------------- / mod2.js # 模块2
    

访问数据和修改数据的调整

  • 访问模块中的数据,要加上模块名

    获取数据项:  {{$store.state.模块名.数据项名}}
    获取getters: {{$store.getters['模块名/getters名']}}
    
  • 访问模块中的mutations/actions:

    • 如果namespaced为true,则需要额外去补充模块名
    • 如果namespaced为false,则不需要额外补充模块名
    $store.commit('mutations名')        // namespaced为false
    $store.commit('模块名/mutations名')  // namespaced为true
    

将我们案例数据改为modules练习

  • 小建议:可以在./vuex文件夹中新建index01.js,这样两套语法就不会搞混了
    • index.js 放有modules的代码
    • index01.js: 放没有modules的代码
import Vue from "vue";
import Vuex from "vuex";
//导入axios
import axios from "axios";

Vue.use(Vuex);

export default new Vuex.Store({
  //默认的一套语法:放整个项目任何模块都需要使用的公共数据(全局的,例如用户信息)
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  //5.module作用:这里放一些功能模块的数据(例如订单列表、设置中心等)
  modules: {
    //模块名:可以用页面名字
    home: {
      state: {
        user: {
          name: "ikun",
          age: 30
        }
      },
      /* 2.2.getter作用: 
      官方术语:从state中派生状态(使用state中的数据,计算得出一些新数据)
      说人话: 相当于vuex的计算属性 
      */
      getters: {
        getInfo(state) {
          //state:就是vuex上面的state
          return `我是${state.user.name},我今年${state.user.age}岁了`;
        }
      },
      //3.mutations作用:修改state中的数据
      mutations: {
        //更新user
        setUser(state, newData) {
          state.user = newData;
        }
      },
      //4.action作用: 异步更新数据
      actions: {},
      modules: {}
    },
    //模块名:可以用页面名字
    my: {
      state: {
        books: []
      },
      /* 2.2.getter*/
      getters: {
      },
      //3.mutations
      mutations: {
        //更新books
        setBooks(state, newData) {
          state.books = newData;
        }
      },
      //4.action作用
      actions: {
        getBooks(context) {
          // 1. 发异步请求
          axios({
            url:
              "https://www.fastmock.site/mock/37d3b9f13a48d528a9339fbed1b81bd5/book/api/books",
            method: "GET"
          }).then(res => {
            console.log(res);
            // 2. 调用mutation
            context.commit("setBooks", res.data.data);
          });
        }
      },
      //5.module作用:模块化处理vuex数据
      modules: {}
    }
  }
});

  • 页面使用moudules的一些变化

  • home.vue

  • <template>
      <div>
          <h1>首页h1>
          <button @click="doClick">点我修改vuex数据button><br>
          <button @click="getBookList">点我发送ajax请求button>
          <div>
              <h2>个人信息h2>
              <p>我的名字是:{{ $store.state.home.user.name }}p>
              <p>我的年龄是:{{ $store.state.home.user.age }}p>
              <p>自我介绍:{{ $store.getters['getInfo'] }}p>
          div>
          <div>
              <h2>图书管理信息h2>
              <ul>
                  
                  <li v-for="(item,index) in $store.state.my.books" :key="index">
                      <span>书名:{{ item.name }}span> --
                      <span>价格:{{ item.price }}span>
                  li>
              ul>
          div>
      div>
    template>
    
    <script>
    export default {
        name:'home',
        methods: {
            doClick(){
                //调用mutaions
                this.$store.commit('setUser', {
                    name:'黑马李宗盛',
                    age:38
                })
            },
            getBookList(){
                //调用actions
                this.$store.dispatch('getBooks')
            }
        },
    }
    script>
    
    <style scoped>
    p{
        color:red;
    }
    style>
    

1.9-课外拓展(关于mapState其他用法)

  • mapState只是起到简化代码作用,实际开发中这是可选的。

    用 或 不用,对我们使用vuex没有影响

Vuex-辅助函数mapState来使用公共数据

目标

掌握mapState的用法,将state中的变量映射到当前的组件中使用;

问题

当访问某个数据项嵌套太深了,能不能优化一下访问的方式?

用mapState把公共数据(vuex.store) 映射 到本组件内部的计算属性

mapState的使用步骤

映射
// 1. 导入辅助函数mapState,它是在vuex中定义的一个工具函数。
//  es6 按需导入 import { mapState } from 'vuex' 
import { mapState } from 'vuex'

computed: {
   // 说明1: ...对象 是把对象展开,合并到computed
   // 说明2: mapState是一个函数 
   //  ['数据项1', '数据项2']
   ...mapState(['xxx'])...mapState({'新名字': 'xxx'})
}
使用
this.xxx
{{xxx}}

示例

// 步骤
// 1. 导入辅助函数mapState,它是在vuex中定义的一个工具函数。
//  es6 按需导入 import { mapState } from 'vuex' 
import { mapState } from 'vuex'

// 2. 在computed中使用 ...mapState(['books'])
// const res = mapState(['books'])
// res的结果是一个对象: { books: function() {}}
// console.log('mapState', res)

export default {
  computed: {
    c1 () {
      return 'c1'
    },
    // books: function() {}
    // ..res: 把res这个对象合并到computed对象中
    // ...res
    ...mapState(['books'])
  }
}
</script>

小结

  1. mapState是辅助函数,将vuex中的数据投射到组件内部;
  2. computed:{ …mapState() } 这里的…是对象的展开运算符,整体来看是对象的合并。

Vuex-辅助函数mapState对数据重命名

目标

掌握mapState对数据重命名的用法。

场景

vuex中的数据与本组件内的数据名相同

格式

...mapState({'新名字': 'xxx'})

Vuex-map函数用法汇总

如何使用全局state

  • 直接使用: this.$store.state.xxx;

  • map辅助函数:

    computed: { 
      ...mapState(['xxx']), 
      ...mapState({'新名字': 'xxx'})
    }
    

如何使用modules中的state

  • 直接使用: this.$store.state.模块名.xxx;

  • map辅助函数:

    computed: { 
      ...mapState('模块名', ['xxx']), 
      ...mapState('模块名', {'新名字': 'xxx'})
    }
    

如何使用全局getters

  • 直接使用:this.$store.getters.xxx

  • map辅助函数:

    computed: { 
      ...mapGetters(['xxx']), 
      ...mapGetters({'新名字': 'xxx'})
    }
    

如何使用modules中的getters

  • 直接使用: this.$store.getters.模块名.xxx

  • map辅助函数:

    computed: { 
      ...mapGetters('模块名', ['xxx']), 
      ...mapGetters('模块名',{'新名字': 'xxx'})
    }
    

如何使用全局mutations

  • 直接使用:this.$store.commit('mutation名', 参数)

  • map辅助函数:

    methods: { 
      ...mapMutations(['mutation名']), 
      ...mapMutations({'新名字': 'mutation名'})
    }
    

如何使用modules中的mutations(namespaced:true)

  • 直接使用: this.$store.commit('模块名/mutation名', 参数)

  • map辅助函数:

    methods: { 
      ...mapMutations('模块名', ['xxx']), 
      ...mapMutations('模块名',{'新名字': 'xxx'})
    }
    

如何使用全局actions

  • 直接使用:this.$store.dispatch('action名', 参数)

  • map辅助函数:

    methods: { 
      ...mapActions(['actions名']), 
      ...mapActions({'新名字': 'actions名'})
    }
    

如何使用modules中的actions(namespaced:true)

  • 直接使用: this.$store.dispatch('模块名/action名', 参数)

  • map辅助函数:

    methods: { 
      ...mapActions('模块名', ['xxx']), 
      ...mapActions('模块名',{'新名字': 'xxx'})
    }
    

1.10-vuex使用总结

02-作业:使用vuex重构TodoList

  • 我们之前写过的TodoList和购物车,都可以使用vuex重新再也一次哟

  • 而且使用vuex之后,可以省去很多 父子传值组件 呢

  • 核心思路: 把输入框文本、数组全部存入vuex.

    (1)所有的组件都需要再传值了,直接操作vuex数据

    (2)actions没有网络请求用不上

    (3)modules需要非常庞大的项目支撑,用不上

    (4)vuex语法使用最多的是state与mutaions哈

  • 这是之前父子组件传值方式

  • 使用vuex

    • 把list数组存入vuex (taskname可以不存,是header输入框数据)
    • 每一个组件使用计算属性简写vuex的数组
    • 每一个组件不需要父子传值了,直接操作vuex数据
    • 添加和删除会改变vuex的数组,需要通过mutations来修改
  • ./store/index.js

  • import Vue from "vue";
    import Vuex from "vuex";
    
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      //1.state作用:存储数据
      state: {
        list: [
          { name: "吃饭", isDone: true },
          { name: "睡觉", isDone: false },
          { name: "打豆豆", isDone: true }
        ]
      },
      /* 2.2.getter作用: 
      官方术语:从state中派生状态(使用state中的数据,计算得出一些新数据)
      说人话: 相当于vuex的计算属性 
      */
      getters: {},
      //3.mutations作用:修改state中的数据
      mutations: {
          //数组添加
          setList(state,newList){
              state.list = newList
          },
          //数组删除
          delList(state,index){
              state.list.splice(index,1)
          },
      },
      //4.action作用: 异步更新数据
      actions: {},
      //5.module作用:模块化处理vuex数据
      modules: {}
    });
    
    
  • TodoList.vue(注意文件路径)

  • <template>
      <div class="todoapp">
        <TodoHeader >TodoHeader>
        <TodoMain >TodoMain>
        <TodoFooter>TodoFooter>
      div>
    template>
    
    <script>
    //1.导入css样式
    import "../assets/css/base.css"
    import "../assets/css/index.css"
    
    //2.导入局部组件
    import TodoHeader from "../components/TodoHeader.vue"
    import TodoMain from "../components/TodoMain.vue"
    import TodoFooter from "../components/TodoFooter.vue"
    
    export default {
        name:'TodoList',
      //注册组件
      components: {
        TodoHeader,
        TodoMain,
        TodoFooter
      },
      computed: {
        list(){
            return this.$store.state.list
        }
      },
    }
    script>
    
    <style scoped>style>
    
    
  • TodoMain.vue

  • <template>
      <ul class="todo-list">
        
        <li
          v-for="(item, index) in list"
          :key="index"
          :class="{ completed: item.isDone }"
        >
          <div class="view">
            <input v-model="item.isDone" class="toggle" type="checkbox" />
            <label>{{ item.name }}label>
            <button @click="doClick(index)" class="destroy">button>
          div>
        li>
      ul>
    template>
    
    <script>
    export default {
      computed: {
        list() {
          return this.$store.state.list;
        }
      },
      methods:{
        doClick(index){
           
           this.$store.commit('delList',index)
        }
      }
    };
    script>
    
    
  • TodoHeader.vue

  • <template>
      <header class="header">
        <h1>todosh1>
        <input v-model="isAll" id="toggle-all" class="toggle-all" type="checkbox" />
        <label for="toggle-all">label>
        <input
          @keydown.enter="add"
          v-model.trim="taskname"
          class="new-todo"
          placeholder="输入任务名称-回车确认"
          autofocus
        />
      header>
    template>
    
    <script>
    export default {
      data() {
        return {
          taskname: ""
        };
      },
      methods: {
        add() {
          //(1)非空判断
          if (this.taskname == "") {
            return alert("请输入任务名");
          }
          //(2)更新vuex
          this.$store.commit("setList", [
            ...this.list,
            { name: this.taskname, isDone: false }
          ]);
          //(3)清空输入框
          this.taskname = "";
        }
      },
      computed: {
        list() {
          return this.$store.state.list;
        },
        isAll: {
          set(val) {
            // 将所有单选框设置为 val
            this.list.forEach(item => (item.isDone = val));
          },
          get() {
            // 计算是否全部选中
            return this.list.every(item => item.isDone);
          }
        }
      }
    };
    script>
    
    
  • TodoFooter.vue

  • <template>
      <footer class="footer">
        <span class="todo-count">剩余<strong>{{ list.length }}strong>span>
        <button @click="doClear" class="clear-completed" >清除已完成button>
      footer>
    template>
    
    <script>
    export default {
      data() {
        return {
          
        }
      },
      computed:{
        list(){
          return this.$store.state.list
        }
      },
      methods:{
        doClear(){
          this.$store.commit('setList',this.list.filter(item => !item.isDone))
        }
      }
    }
    script>
    

你可能感兴趣的:(vue.js,前端,javascript)