Vuex 使用指南(todoList 案例)

前言

Vuex 是为 Vue 专门制定的状态管理工具。其核心思想是将所有的状态集中在顶层进行统一管理。通过不同的事件类型,进行统一分发不同的状态,再通过状态去影响视图层。

在使用前执行npm install Vuex下载 Vuex。

案例需求

实现一个 todoList (任务管理功能),包含的功能有:

  1. 获取初始任务列表;
  2. 添加待办事项;
  3. 编辑任务状态(将任务置为未完成或者已完成);
  4. 删除待办事项;
  5. 查询任务列表(按状态已完成/未完成/所有查询)。

第一步:state

state 是驱动应用的数据源,是一棵单一状态树。根据案例所示,需要创建一个 taskList,用来储存任务列表信息。

  state: {
    taskList:[],//初始化任务列表
    filter:'all'//初始化任务状态,默认显示所有列表
  },

第二步:Getter

如果多个组件需要使用到同一个变量,可以封装在 Getter 中。或者 Getter 中也可以改变状态。根据案例所示,需要创建一个改变 filter 状态的方法 changeFilter,是否展示任务项方法 isDisplay。

    //是否展示任务项
    isDisplay:state => item =>{
      if(state.filter == 'all'){
        return true
      };
      if(state.filter == 'completed'){
        if(item.done){
          return true
        }else {
          return false
        }
      }
      if(state.filter == 'uncompleted'){
        if(!item.done){
          return true
        }else {
          return false
        }
      }
    },
   //改变过滤状态
    changeFilter: state =>flag=> {
     state.filter = flag;
    },

第三步:Mutation

更改 state 状态的唯一办法就是 Mutation,并且 Mutation 必须是同步函数。根据案例所示,需要创建添加任务方法 addTodo,获取初始任务列表方法 getInitData,编辑任务状态方法 changeStatus、删除任务方法 delTask。

    //添加任务列表
    addTodo(state,item){
      //新添加item的id根据列表最后的id自增
      item.id = state.taskList[state.taskList.length-1].id+1;
      state.taskList = [...state.taskList,item];
    },
    //获取初始任务列表
    getInitData(state,arr){
      state.taskList = arr;
    },
    //修改任务状态
    changeStatus(state,item){
      item.done = !item.done;
    },
    //删除任务
    delTask(state,index){
      state.taskList.splice(index,1);
    }

第四步:Action

Action 中主要是分发 Mutation,与 Mutation 的区别是可以在这里处理异步操作。比如调取接口获取初始任务列表信息。

    //模拟异步获取任务列表
    getDataAsync (context) {
      var arr = [];
      setTimeout(() => {
        arr = [{
          text:"国际会议",id:1,done:true
        }];
        context.commit('getInitData',arr);
      }, 1000)
    }
  }

第五步:属性或者方法整合

mapState:是将所有的 State 整合在一起。
mapGetters:是将所有的 Getters 整合在一起。
mapMutations:是将所有的 Mutations 整合在一起。
mapActions:是将所有的 Actions 整合在一起。
以上带 map 的方法是一个整合作用,在使用多个 state 或者方法时可以直接用 this.的形式,而不用 this.$ store.形式,比如对于被 state 储存的 taskList。在组件中使用时可以直接this.taskList,而不用 this.$store.state.taskList。

实现功能

  1. 在项目跟目录新建 store 文件夹,在其文件夹下新建 index.js。

index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
//创建Store实例
const store = new Vuex.Store({
  state: {
    taskList:[],//初始化任务列表
    statusList:[
      {
        label:"所有",
        flag:'all'
      },{
        label:"已完成",
        flag:'completed'
      },{
        label:"未完成",
        flag:'uncompleted'
      }
    ],//任务状态列表
    filter:'all'//初始化任务状态
  },
  getters: {
    //是否展示任务项
    isDisplay:state => item =>{
      if(state.filter == 'all'){
        return true
      };
      if(state.filter == 'completed'){
        if(item.done){
          return true
        }else {
          return false
        }
      }
      if(state.filter == 'uncompleted'){
        if(!item.done){
          return true
        }else {
          return false
        }
      }
    },
   //改变过滤状态
    changeFilter: state =>flag=> {
     state.filter = flag;
    },
  },
  mutations: {
    //添加任务列表
    addTodo(state,item){
      //新添加item的id根据列表最后的id自增
      item.id = state.taskList[state.taskList.length-1].id+1;
      state.taskList = [...state.taskList,item];
    },
    //获取初始任务列表
    getInitData(state,arr){
      state.taskList = arr;
    },
    //修改任务状态
    changeStatus(state,item){
      item.done = !item.done;
    },
    //删除任务
    delTask(state,index){
      state.taskList.splice(index,1);
    }
  },
  actions: {
    //模拟异步获取任务列表
    getDataAsync (context) {
      var arr = [];
      setTimeout(() => {
        arr = [{
          text:"国际会议",id:1,done:true
        }];
        context.commit('getInitData',arr);
      }, 1000)
    }
  }
});
export default store;
  1. 新建 Vuex.vue 文件,编写功能代码。
<template>
  <div class="vuex-m-20">
    <div class="vuex-tx-c">todo list 案例</div>
    <div class="vuex-m-20">
      <input type="text" v-model="text"><button @click="add">添加待办</button>
    <div v-for="(item,index) in taskList" v-if="show(item)" >
     <span :class="item && item.done?'vuex-line':''" @click="operate('change',item)">{{item.text}}</span><span class="vuex-ml-20" @click="operate('del',index)">删除</span>
    </div>
    </div>
    <div>
      <div class="vuex-mtb-20">
        <span @click="query(item.flag)" class="vuex-ml-20" v-for="item in statusList" >{{item.label}}</span>
      </div>
    </div>
  </div>
</template>
<script>
  import { mapState,mapGetters,mapMutations,mapActions} from 'vuex';
  export default {
    name: 'Vuex',
    data () {
      return {
        text:""
      }
    },
    created(){
      //获取初始任务列表
      this.getDataAsync();
    },
    computed: {
      //监听任务列表变化
      taskList(){
        return this.taskList;
      },
      //任务状态列表
      statusList(){
        return this.statusList;
      },
      //过滤任务列表
      show(){
       return item =>{
         return this.isDisplay(item);
        }
      },
      ...mapGetters([
        'changeFilter',
        'isDisplay'
      ]),
      ...mapState([
        'taskList',
        'statusList',
        'filter'
      ])
    },
    methods: {
      ...mapMutations([
        'addTodo',
        'changeStatus',
        'delTask'
      ]),
      ...mapActions([
        'getDataAsync'
      ]),
      add(){
        // 添加任务项
        this.addTodo({
          text:this.text,done:false
        });
      },
      //按完成状态查询任务列表
      query(status){
        this.changeFilter(status);
      },
      //编辑任务状态和删除任务
      operate(str,param){
          if(str == 'change'){
            this.changeStatus(param);
          }else {
            this.delTask(param)
          }
      }
    }
  }
</script>
<style scoped>
  .vuex-m-20{
    margin: 20px;
  }
  .vuex-line{
    text-decoration:line-through
  }
  .vuex-ml-20{
    margin-left: 20px;
  }
  .vuex-tx-c{
    text-align: center;
  }
  .vuex-mtb-20{
    margin: 20px 0;
  }
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值