【Vue】Vuex管理状态入门到实战 - 计数器demo - todoList项目 - 组件间共享数据 - State - Mutation - Action - Getter

文章目录

  • 1. Vuex概述
    • 1.1 组件间共享数据的方式
    • 1.2 Vuex 是什么(实现组件间数据共享)
    • 1.3 使用 Vuex 统一管理状态的好处
    • 1.4 什么样的数据适合存储到 Vuex 中
  • 2. Vuex 的基本使用
    • 1. 安装 vuex 依赖包
    • 2. 导入 vuex 包
    • 3. 创建 store 对象
    • 4. 将 store 对象挂载到 vue 实例中
  • 3. 案例项目1 计数器
    • Addition.vue
    • Subtraction.vue
    • App.vue
  • 4. Vuex 的核心概念
    • 4.1 核心概念概述
    • 4.2 State (声明)
      • 案例 store/index.js
      • 组件访问 State 中数据的第一种方式
      • 案例 Addition.vue
      • 组件访问 State 中数据的第二种方式
      • 案例 Subtraction.vue
    • 4.3 Mutation (变化)
      • 4.3.1 触发的第一种方式
      • 案例 store/index.js
      • 案例 Addition.vue
      • 4.3.1 触发的第二种方式
      • 案例 store/index.js
      • 案例 Subtraction.vue
    • 4.4 Action (行动)
      • 触发的第一种方式
      • 案例 store/index.js
      • 案例 Addition.vue
      • 触发的第二种方式
      • 案例 store/index.js
      • 案例 Subtraction.vue
      • 案例 简化 Subtraction.vue
    • 4.5 Getter
      • 使用 getters 的第一种方式
      • 案例 store/index.js
      • 案例 Addition.vue
      • 使用 getters 的第二种方式
      • 案例 Subtraction.vue
    • 4.6 展示
  • 5. 案例项目2 TodoList
    • 5.1 初始化项目
      • main.js
      • App.vue
    • 5.2 完成具体功能
      • 5.2.1 动态加载任务列表list数据
        • 1. `main.js` 导入并挂载store
        • 2. 将App.vue中data的list数组 剪切 到`public/list.json`中
        • 3. 在`store/index.js`中使用axios发请求获取数据
        • 4. 将数据存储到state中,在mutations中为list赋值
        • 5. 在App.vue中将store中的数据映射过来
      • 5.2.2 文本框内容 与 store数据 双向绑定
        • 1. 创建state声明 inputValue
        • 2. 将全局inputVale映射到当前组件的计算属性中---组件中调用state(方式二)
        • 3. 监听文本框内容变化 change事件(获取输入框的值)
        • 4. 将输入框获得的值 保存到 inputVaule上 (为state赋值)
        • 5. 组件中调用mutations(方式一)
      • 5.2.3 添加任务事项
        • 1. 为button按钮绑定单击事件处理函数
        • 2. 判断输入是否为空,为空就返回错误信息
        • 3. mutations中定义 添加 列表项 (改变list)
        • 4. 输入内容不为空 就 调用mutations中的addItem执行添加任务项
      • 5.2.4 删除任务事项
        • App.vue/template
        • store/index.js/mutations
        • App.vue/script/methods
      • 5.2.5 动态绑定复选框的选中状态
      • 5.2.6 修改任务事项的完成状态
        • App.vue/template
        • App.vue/script/mehods
        • store/index.js/mutations
      • 5.2.7 统计未完成的任务的条数
        • store/index.js/getters
        • App.vue/script
        • App.vue/template
      • 5.2.8 清除已完成的任务事项
        • App.vue/template
        • App.vue/script/methods
        • store/index.js/mutations
      • 5.2.9 实现任务列表点击高亮切换
        • 1. 为不同按钮绑定相同的单击响应函数changeList
        • 2. 将接受到的字符串存储到全局的store中
        • 3. 将viewKey映射为当前组件的计算属性
        • 4. 根据viewKey的值动态计算决定按钮高亮(三元表达式)
      • 5.2.10 实现任务列表数据的动态切换
        • 1. 使用Getter将list进行包装,按需显示希望用户看到的数据
        • 2. 将infoList映射到组件的计算属性中,可以删除映射的state/list
        • 3. 将infoList替代list作为动态绑定的数据源
    • 5.3 效果展示

1. Vuex概述

1.1 组件间共享数据的方式

之前学习过的一些方法
【Vue】组件定义与使用-组件间通信
【Vue】vuex - 状态自管理应用 - state - view - actions

父向子传值:v-bind 属性绑定
子向父传值:v-on 事件绑定
兄弟组件之间共享数据: EventBus

  • $on 接收数据的那个组件
  • $emit 发送数据的那个组件

1.2 Vuex 是什么(实现组件间数据共享)

Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享.
【Vue】Vuex管理状态入门到实战 - 计数器demo - todoList项目 - 组件间共享数据 - State - Mutation - Action - Getter_第1张图片

1.3 使用 Vuex 统一管理状态的好处

① 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
② 能够高效地实现组件之间的数据共享,提高开发效率
③ 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步

1.4 什么样的数据适合存储到 Vuex 中

一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中;
对于组件中的私有数据,依旧存储在组件自身的 data 中即可。

2. Vuex 的基本使用

1. 安装 vuex 依赖包

cnpm install vuex --save

2. 导入 vuex 包

import Vuex from 'vuex'
Vue.use(Vuex)

3. 创建 store 对象

const store = new Vuex.Store({
     
	// state 中存放的就是全局共享的数据
	state: {
      count: 0 }
})

4. 将 store 对象挂载到 vue 实例中

new Vue({
      
	el: '#app', 
	render: h => h(app), 
	router, 
	// 将创建的共享数据对象,挂载到 Vue 实例中 
	// 所有的组件,就可以直接从 store 中获取全局的数据了 
	store
})

3. 案例项目1 计数器

推荐自动生成—在vue ui 面板中创建一个vue项目,添加vuex

Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:xxxh3>
    <button>+1button>
  div>
template>

Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:xxxh3>
    <button>-1button>
  div>
template>

App.vue

<template>
  <div>
    <my-addition>my-addition>
    <p>------------p>
    <my-subtraction>my-subtraction>
  div>
template>

<script>
import Addition from './components/Addition.vue'
import Subtraction from './components/Subtraction.vue'

export default {
      
  data() {
      
    return {
      }
  },
  components: {
      
    'my-addition': Addition,
    'my-subtraction': Subtraction
  }
}
script>

最后在项目根目录(与src平级)中创建 .prettierrc 文件,编写代码如下

{
     
    "semi":false,
    "singleQuote":true
}

4. Vuex 的核心概念

4.1 核心概念概述

Vuex 中的主要核心概念如下:

  • State
  • Mutation
  • Action
  • Getter

4.2 State (声明)

  1. State 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储

例如,打开项目中的store/index.js文件,在State对象中可以添加我们要共享的数据,如:count:0

// 创建store数据源,提供唯一公共数据
const store = new Vuex.Store({
     
	state: {
      
		count: 0 
	}
})

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  }
})

组件访问 State 中数据的第一种方式

this.$store.state.全局数据名称

案例 Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { $store.state.count }}h3>
    <button>+1button>
  div>
template>

组件访问 State 中数据的第二种方式

// 1. 从 vuex 中按需导入 mapState 函数
import {
      mapState } from 'vuex'

通过刚才导入的 mapState 函数,将当前组件需要的全局数据,映射为当前组件的

computed 计算属性:
// 2. 将全局数据,映射为当前组件的计算属性 
computed: {
      
	...mapState(['count']) 
}

案例 Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { count }}h3>
    <button>-1button>
  div>
template>

<script>
import {
       mapState } from 'vuex'
export default {
      
  data() {
      
    return {
      }
  },
  computed: {
      
    ...mapState(['count'])
  }
}
script>

4.3 Mutation (变化)

Mutation 用于变更 Store中的数据。
①只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。
②通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化

4.3.1 触发的第一种方式

// 定义 Mutation 
const store = new Vuex.Store({
      
	state: {
      count: 0 }, 
	mutations: {
      
		add(state) {
      
			// 变更状态 
			state.count++ 
		} 
	} 
})
// 触发mutation 
methods: {
      
	handle1() {
      // 触发 mutations 的第一种方式 
		this.$store.commit('add') 
	} 
}

可以在触发 mutations 时传递参数:

// 定义Mutation
const store = new Vuex.Store({
     
	state: {
     
		count: 0
	},
	mutations: {
     
		addN(state, step) {
     
			// 变更状态
			state.count += step
		}
	}
})
// 触发mutation 
methods: {
      
	handle2() {
      
		// 在调用 commit 函数, 
		// 触发 mutations 时携带参数 
		this.$store.commit('addN', 3) 
	} 
}

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  },
  mutations: {
     
    add(state) {
     
      // 变更状态
      state.count++
    },
    addN(state, step) {
     
      // 变更状态
      state.count += step
    }
  }
})

案例 Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { $store.state.count }}h3>
    <button @click="btnHandler1">+1button>
    <button @click="btnHandler2">+Nbutton>
  div>
template>

<script>
export default {
      
  data() {
      
    return {
      }
  },
  methods: {
      
    btnHandler1() {
      
      this.$store.commit('add')
    },
    btnHandler2() {
      
      // commit作用就是调用某个mutation函数
      this.$store.commit('addN', 3)
    }
  }
}
script>

4.3.1 触发的第二种方式

this.$store.commit() 是触发 mutations 的第一种方式,触发 mutations 的第二种方式:

// 1. 从 vuex 中按需导入 mapMutations 函数
import {
      mapMutations } from 'vuex'

通过刚才导入的 mapMutations 函数,将需要的 mutations 函数,映射为当前组件的 methods 方法:

// 2. 将指定的 mutations 函数,映射为当前组件的 methods 函数
methods: {
     
	...mapMutations(['add', 'addN'])
}

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  },
  mutations: {
     
    add(state) {
     
      // 变更状态
      state.count++
    },
    addN(state, step) {
     
      // 变更状态
      state.count += step
    },
    sub(state) {
     
      state.count--
    },
    subN(state, step) {
     
      // 变更状态
      state.count -= step
    }
  }
})

案例 Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { count }}h3>
    <button @click="btnHandler1">-1button>
    <button @click="btnHandler2">-Nbutton>
  div>
template>

<script>
import {
       mapState, mapMutations } from 'vuex'
export default {
      
  data() {
      
    return {
      }
  },
  computed: {
      
    ...mapState(['count'])
  },
  methods: {
      
    ...mapMutations(['sub', 'subN']),
    btnHandler1() {
      
      this.sub()
    },
    btnHandler2() {
      
      this.subN(3)
    }
  }
}
script>

4.4 Action (行动)

Action 用于处理异步任务。

如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action 中还是要通过触发Mutation 的方式间接变更数据。

触发的第一种方式

// 定义 Action 
const store = new Vuex.Store({
      
	// ...省略其他代码 
	mutations: {
      
		add(state) {
      
			state.count++ 
		} 
	}, 
	actions: {
      
		addAsync(context) {
      
			setTimeout(() => {
      
				context.commit('add') 
			}, 1000) 
		} 
	} 
})
// 触发 Action
methods: {
     
	handle() {
     
		// 触发 actions 的第一种方式
		this.$store.dispatch('addAsync')
	}
}

触发 actions 异步任务时携带参数:

// 定义 Action 
const store = new Vuex.Store({
      
	// ...省略其他代码 
	mutations: {
      
		addN(state, step) {
      
			state.count += step 
		} 
	}, 
	actions: {
      
		addNAsync(context, step) {
      
			setTimeout(() => {
      
				context.commit('addN', step) 
			}, 1000) 
		} 
	} 
})
// 触发 Action 
methods: {
      
	handle() {
      
		// 在调用 dispatch 函数, 
		// 触发 actions 时携带参数 
		this.$store.dispatch('addNAsync', 5) 
	} 
}

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  },
  // 只有 mutations 中定义的函数,才有权利修改 state 中的数据
  mutations: {
     
    add(state) {
     
      // 变更状态
      state.count++
    },
    addN(state, step) {
     
      // 变更状态
      state.count += step
    },
    sub(state) {
     
      state.count--
    },
    subN(state, step) {
     
      // 变更状态
      state.count -= step
    }
  },
  actions: {
     
    addAsync(context) {
     
      setTimeout(() => {
     
        // 在actions中不能直接修改state中的数据
        // 必须通过 context.commit() 触发某个 mutations 才行
        context.commit('add')
      }, 1000)
    },
    addNAsync(context, step) {
     
      setTimeout(() => {
     
        context.commit('addN', step)
      }, 1000)
    }
  }
})

案例 Addition.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { $store.state.count }}h3>
    <button @click="btnHandler1">+1button>
    <button @click="btnHandler2">+Nbutton>
    <button @click="btnHandler3">+1 Asyncbutton>
    <button @click="btnHandler4">+N Asyncbutton>
  div>
template>

<script>
export default {
      
  data() {
      
    return {
      }
  },
  methods: {
      
    btnHandler1() {
      
      this.$store.commit('add')
    },
    btnHandler2() {
      
      // commit作用就是调用某个mutation函数
      this.$store.commit('addN', 3)
    },
    // 异步让count自增+1
    btnHandler3() {
      
      // 这里的 dispatch 函数 专门用来触发 action
      this.$store.dispatch('addAsync')
    },
    btnHandler4() {
      
      this.$store.dispatch('addNAsync', 5)
    }
  }
}
script>

触发的第二种方式

this.$store.dispatch() 是触发 actions 的第一种方式,触发 actions 的第二种方式:

// 1. 从 vuex 中按需导入 mapActions 函数 
import {
      mapActions } from 'vuex'

通过刚才导入的 mapActions 函数,将需要的 actions 函数,映射为当前组件的 methods 方法:

// 2. 将指定的 actions 函数,映射为当前组件的 methods 函数 
methods: {
      ...mapActions(['addASync', 'addNASync']) }

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  },
  // 只有 mutations 中定义的函数,才有权利修改 state 中的数据
  mutations: {
     
    add(state) {
     
      // 变更状态
      state.count++
    },
    addN(state, step) {
     
      // 变更状态
      state.count += step
    },
    sub(state) {
     
      state.count--
    },
    subN(state, step) {
     
      // 变更状态
      state.count -= step
    }
  },
  actions: {
     
    addAsync(context) {
     
      setTimeout(() => {
     
        // 在actions中不能直接修改state中的数据
        // 必须通过 context.commit() 触发某个 mutations 才行
        context.commit('add')
      }, 1000)
    },
    addNAsync(context, step) {
     
      setTimeout(() => {
     
        context.commit('addN', step)
      }, 1000)
    },
    subAsync(context) {
     
      setTimeout(() => {
     
        context.commit('sub')
      }, 1000)
    },
    subNAsync(context, step) {
     
      setTimeout(() => {
     
        context.commit('subN', step)
      }, 1000)
    }
  }
})

案例 Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { count }}h3>
    <button @click="btnHandler1">-1button>
    <button @click="btnHandler2">-Nbutton>
    <button @click="btnHandler3">-1 Asyncbutton>
    <button @click="btnHandler4">-N Asyncbutton>
  div>
template>

<script>
import {
       mapState, mapMutations, mapActions } from 'vuex'
export default {
      
  data() {
      
    return {
      }
  },
  computed: {
      
    ...mapState(['count'])
  },
  methods: {
      
    ...mapMutations(['sub', 'subN']),
    ...mapActions(['subAsync', 'subNAsync']),

    btnHandler1() {
      
      this.sub()
    },
    btnHandler2() {
      
      this.subN(3)
    },

    btnHandler3() {
      
      this.subAsync()
    },
    btnHandler4() {
      
      this.subNAsync(5)
    }
  }
}
script>

案例 简化 Subtraction.vue

<template>
  <div>
    <h3>当前最新的count值为:{
    { count }}h3>
    <button @click="sub">-1button>
    <button @click="subN(3)">-Nbutton>
    <button @click="subAsync">-1 Asyncbutton>
    <button @click="subNAsync(5)">-N Asyncbutton>
  div>
template>

<script>
import {
       mapState, mapMutations, mapActions } from 'vuex'
export default {
      
  data() {
      
    return {
      }
  },
  computed: {
      
    ...mapState(['count'])
  },
  methods: {
      
    ...mapMutations(['sub', 'subN']),
    ...mapActions(['subAsync', 'subNAsync'])
  }
}
script>

4.5 Getter

Getter 用于对 Store 中的数据进行加工处理形成新的数据。只起到包装的作用。
①Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。
②Store 中数据发生变化,Getter 的数据也会跟着变化。

它只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化

// 定义 Getter
const store = new Vuex.Store({
     
	state: {
     
		count: 0
	},
	getters: {
     
		showNum: state => {
     
			return '当前最新的数量是【'+ state.count +'】'
		}
	}
})

使用 getters 的第一种方式

this.$store.getters.名称

案例 store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    count: 0
  },
  // 只有 mutations 中定义的函数,才有权利修改 state 中的数据
  mutations: {
     
    add(state) {
     
      // 变更状态
      state.count++
    },
    addN(state, step) {
     
      // 变更状态
      state.count += step
    },
    sub(state) {
     
      state.count--
    },
    subN(state, step) {
     
      // 变更状态
      state.count -= step
    }
  },
  actions: {
     
    addAsync(context) {
     
      setTimeout(() => {
     
        // 在actions中不能直接修改state中的数据
        // 必须通过 context.commit() 触发某个 mutations 才行
        context.commit('add')
      }, 1000)
    },
    addNAsync(context, step) {
     
      setTimeout(() => {
     
        context.commit('addN', step)
      }, 1000)
    },
    subAsync(context) {
     
      setTimeout(() => {
     
        context.commit('sub')
      }, 1000)
    },
    subNAsync(context, step) {
     
      setTimeout(() => {
     
        context.commit('subN', step)
      }, 1000)
    }
  },
  getters: {
     
    showNum(state) {
     
      return `当前最新的数量是【${
       state.count}】`
    }
  }
})

案例 Addition.vue

<template>
  <div>
    
    <h3>{
    { $store.getters.showNum }}h3>
    <button @click="btnHandler1">+1button>
    <button @click="btnHandler2">+Nbutton>
    <button @click="btnHandler3">+1 Asyncbutton>
    <button @click="btnHandler4">+N Asyncbutton>
  div>
template>

使用 getters 的第二种方式

import {
      mapGetters } from 'vuex'
computed: {
     
	...mapGetters(['showNum'])
}

案例 Subtraction.vue

<template>
  <div>
    
    <h3>{
    { showNum }}h3>
    <button @click="sub">-1button>
    <button @click="subN(3)">-Nbutton>
    <button @click="subAsync">-1 Asyncbutton>
    <button @click="subNAsync(5)">-N Asyncbutton>
  div>
template>

<script>
import {
       mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
      
  data() {
      
    return {
      }
  },
  computed: {
      
    ...mapState(['count']),
    ...mapGetters(['showNum'])
  },
  methods: {
      
    ...mapMutations(['sub', 'subN']),
    ...mapActions(['subAsync', 'subNAsync'])
  }
}
script>

4.6 展示

【Vue】Vuex管理状态入门到实战 - 计数器demo - todoList项目 - 组件间共享数据 - State - Mutation - Action - Getter_第2张图片

5. 案例项目2 TodoList

5.1 初始化项目

① 通过 vue ui 命令打开可视化面板,创建新项目 vuex_todolist
② 安装运行依赖 axios 和 ant-design-vue
③ 实现 Todos 基本布局(基于已有样式模板)

main.js

import Vue from 'vue'
import App from './App.vue'

// 1. 导入 ant-design-vue 组件库
import Antd from 'ant-design-vue'
// 2. 导入组件库的样式表
import 'ant-design-vue/dist/antd.css'

Vue.config.productionTip = false
// 3. 安装组件库
Vue.use(Antd)

new Vue({
     
  render: h => h(App)
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <a-input placeholder="请输入任务" class="my_ipt" />
    <a-button type="primary">添加事项a-button>

    <a-list bordered :dataSource="list" class="dt_list">
      <a-list-item slot="renderItem" slot-scope="item">
        
        <a-checkbox>{
    { item.info }}a-checkbox>
        
        <a slot="actions">删除a>
      a-list-item>

      
      <div slot="footer" class="footer">
        
        <span>0条剩余span>
        
        <a-button-group>
          <a-button type="primary">全部a-button>
          <a-button>未完成a-button>
          <a-button>已完成a-button>
        a-button-group>
        
        <a>清除已完成a>
      div>
    a-list>
  div>
template>

<script>
export default {
      
  name: 'app',
  data() {
      
    return {
      
      list: [
        {
      
          id: 0,
          info: 'Racing car sprays burning fuel into crowd.',
          done: false
        },
        {
       id: 1, info: 'Japanese princess to wed commoner.', done: false },
        {
      
          id: 2,
          info: 'Australian walks 100km after outback crash.',
          done: false
        },
        {
       id: 3, info: 'Man charged over missing wedding girl.', done: false },
        {
       id: 4, info: 'Los Angeles battles huge wildfires.', done: false }
      ]
    }
  }
}
script>

<style scoped>
#app {
      
  padding: 10px;
}

.my_ipt {
      
  width: 500px;
  margin-right: 10px;
}

.dt_list {
      
  width: 500px;
  margin-top: 10px;
}

.footer {
      
  display: flex;
  justify-content: space-between;
  align-items: center;
}
style>

【Vue】Vuex管理状态入门到实战 - 计数器demo - todoList项目 - 组件间共享数据 - State - Mutation - Action - Getter_第3张图片

5.2 完成具体功能

5.2.1 动态加载任务列表list数据

1. main.js 导入并挂载store

import store from './store/index.js'
new Vue({
     
  render: h => h(App),
  store
}).$mount('#app')

2. 将App.vue中data的list数组 剪切 到public/list.json

[
  {
     
    "id": 0,
    "info": "Racing car sprays burning fuel into crowd.",
    "done": false
  },
  {
      "id": 1, "info": "Japanese princess to wed commoner.", "done": false },
  {
     
    "id": 2,
    "info": "Australian walks 100km after outback crash.",
    "done": false
  },
  {
      "id": 3, "info": "Man charged over missing wedding girl.", "done": false },
  {
      "id": 4, "info": "Los Angeles battles huge wildfires.", "done": false }
]

3. 在store/index.js中使用axios发请求获取数据

4. 将数据存储到state中,在mutations中为list赋值

App.vue

<script>
export default {
      
  name: 'app',
  data() {
      
    return {
      
      list: []
    }
  },
  created() {
      
    this.$store.dispatch('getList')
  }
}
script>

store/index.js

import axios from 'axios'

export default new Vuex.Store({
     
  state: {
     
    // 所有的任务列表
    list: []
  },
  mutations: {
     
    initList(state, list) {
     
      state.list = list
    }
  },
  actions: {
     
    getList(context) {
     
      axios.get('./list.json').then(({
      data }) => {
     
        console.log(data) // (5)[{…}, {…}, {…}, {…}, {…}]
        context.commit('initList', data)
      })
    }
  },
  modules: {
     }
})

5. 在App.vue中将store中的数据映射过来

<script>
import {
       mapState } from 'vuex'
export default {
      
  name: 'app',
  data() {
      
    return {
      }
  },
  created() {
      
    this.$store.dispatch('getList')
  },
  computed: {
      
    ...mapState(['list'])
  }
}
script>

5.2.2 文本框内容 与 store数据 双向绑定

1. 创建state声明 inputValue

store/index.js

state: {
     
  // 所有的任务列表
  list: [],
  // 文本框的内容
  inputValue: 'aaa'
}

2. 将全局inputVale映射到当前组件的计算属性中—组件中调用state(方式二)

App.vue

<template>
  <a-input placeholder="请输入任务" :value="inputValue"/>
template>

<script>
import {
       mapState } from 'vuex'
export default {
      
  computed: {
      
    ...mapState(['list', 'inputValue'])
script>

3. 监听文本框内容变化 change事件(获取输入框的值)

App.vue

<template>
  <a-input placeholder="请输入任务" @change="handleInputChange"/>
template>

<script>
import {
       mapState } from 'vuex'
export default {
      
  computed: {
      
    ...mapState(['list', 'inputValue'])
  },
  methods: {
      
    // 监听文本框内容变化
    handleInputChange(e) {
      
      console.log(e.target.value)
    }
  }
}
script>

4. 将输入框获得的值 保存到 inputVaule上 (为state赋值)

store/index.js

mutations: {
     
    setInputValue(state, val) {
     
      state.inputValue = val
    }
}

5. 组件中调用mutations(方式一)

App.vue/script/methods

// 监听文本框内容变化
handleInputChange(e) {
     
  // console.log(e.target.value)
  this.$store.commit('setInputValue', e.target.value)
}

5.2.3 添加任务事项

1. 为button按钮绑定单击事件处理函数

App.vue

<a-button type="primary" @click="addItemTodoList">添加事项a-button>

2. 判断输入是否为空,为空就返回错误信息

App.vue/script/methods

methods: {
     
  // 向列表中新增 item 项
  addItemTodoList() {
     
    if (this.inputValue.trim().length <= 0) {
     
      return this.$message.warning('文本框内容不能为空!')
    }
  }
}

3. mutations中定义 添加 列表项 (改变list)

store/index.js

state: {
     
  // 下一个id
  nextId: 5
},
mutations: {
     
  // 添加列表项
  addItem(state) {
     
    const obj = {
     
      id: state.nextId,
      info: state.inputValue.trim(),
      done: false
    }
    state.list.push(obj)
    state.nextId++
    state.inputValue = ''
  }
}

4. 输入内容不为空 就 调用mutations中的addItem执行添加任务项

App.vue/script/methods

// 向列表中新增 item 项
addItemTodoList() {
     
  if (this.inputValue.trim().length <= 0) {
     
    return this.$message.warning('文本框内容不能为空!')
  }
  this.$store.commit('addItem')
}

5.2.4 删除任务事项

App.vue/template

<a slot="actions" @click="removeItemById(item.id)">删除a>

store/index.js/mutations

mutations: {
     
  // 删除id对应的列表项
  removeItem(state, id) {
     
    // 1. 根据id查找对应项的索引
    const index = state.list.findIndex(x => x.id === id)
    if (index !== -1) {
     
      // 2. 根据索引删除对应元素
      state.list.splice(index, 1)
    }
  }
}

App.vue/script/methods

methods: {
     
  // 根据id删除对应任务事项
  removeItemById(id) {
     
    this.$store.commit('removeItem', id)
  }
}

5.2.5 动态绑定复选框的选中状态

App.vue


<a-checkbox :checked="item.done">{
    { item.info }}a-checkbox>

5.2.6 修改任务事项的完成状态

App.vue/template


<a-checkbox :checked="item.done" @change="(e) => {cbStatusChanged(e, item.id)}">{
    { item.info }}a-checkbox>

App.vue/script/mehods

// 监听复选框选中状态变化的事件
cbStatusChanged(e, id) {
     
  // 通过 e.target.checked 可以接收到最新的选中状态
  const params = {
     
    id: id,
    status: e.target.checked
  }
  this.$store.commit('changeStatus', params)
}

store/index.js/mutations

// 修改列表项中的选中状态
changeStatus(state, param) {
     
  const index = state.list.findIndex(x => x.id === param.id)
  if (index !== -1) {
     
    state.list[index].done = param.status
  }
}

5.2.7 统计未完成的任务的条数

store/index.js/getters

getters: {
     
  // 统计未完成任务条数
  unDoneLength(state) {
     
    return state.list.filter(x => x.done === false).length
  }
}

App.vue/script

import {
      mapState, mapGetters } from 'vuex'
export default {
     
  computed: {
     
    ...mapState(['list', 'inputValue']),
    ...mapGetters(['unDoneLength'])
  }
}

App.vue/template


<span>{
    { unDoneLength }}条剩余span>

5.2.8 清除已完成的任务事项

App.vue/template


<a @click="clean">清除已完成a>

App.vue/script/methods

// 清除已完成的任务
clean() {
     
  this.$store.commit('cleanDone')
}

store/index.js/mutations

// 清除已完成的任务
cleanDone(state) {
     
  state.list = state.list.filter(x => x.done === false)
}

5.2.9 实现任务列表点击高亮切换

1. 为不同按钮绑定相同的单击响应函数changeList

App.vue/template


<a-button-group>
  <a-button type="primary" @click="changeList('all')">全部a-button>
  <a-button type="default" @click="changeList('undone')">未完成a-button>
  <a-button type="default" @click="changeList('done')">已完成a-button>
a-button-group>

2. 将接受到的字符串存储到全局的store中

store/index.js/state

viewKey: 'all'

App.vue/script/methods

// 修改页面上展示的列表数据
changeList(key){
     
  this.$store.commit('changeViewKey', key)
}

store/index.js/mutations

// 修改视图的关键字
changeViewKey(state, key) {
     
  state.viewKey = key
}

3. 将viewKey映射为当前组件的计算属性

App.vue/script/computed

...mapState(['list', 'inputValue', 'viewKey'])

4. 根据viewKey的值动态计算决定按钮高亮(三元表达式)

App.vue/template


<a-button-group>
  <a-button
    :type="viewKey === 'all' ? 'primary' : 'default'"
    @click="changeList('all')"
    >全部a-button
  >
  <a-button
    :type="viewKey === 'undone' ? 'primary' : 'default'"
    @click="changeList('undone')"
    >未完成a-button
  >
  <a-button
    :type="viewKey === 'done' ? 'primary' : 'default'"
    @click="changeList('done')"
    >已完成a-button
  >
a-button-group>

5.2.10 实现任务列表数据的动态切换

1. 使用Getter将list进行包装,按需显示希望用户看到的数据

store/index.js/getters

// 根据viewKey的值决定list
infoList(state) {
     
  if (state.viewKey === 'all') {
     
    return state.list
  }
  if (state.viewKey === 'undone') {
     
    return state.list.filter(x => !x.done)
  }
  if (state.viewKey === 'done') {
     
    return state.list.filter(x => x.done)
  }
  return state.list
}

2. 将infoList映射到组件的计算属性中,可以删除映射的state/list

App.vue/script/computed

...mapState(['inputValue', 'viewKey']),
...mapGetters(['unDoneLength', 'infoList'])

3. 将infoList替代list作为动态绑定的数据源

App.vue/template

<a-list bordered :dataSource="infoList" class="dt_list">

5.3 效果展示

【Vue】Vuex管理状态入门到实战 - 计数器demo - todoList项目 - 组件间共享数据 - State - Mutation - Action - Getter_第4张图片

你可能感兴趣的:(前端框架Vue,vue,js)