Vuex简单理解及实现TodoList

一、Vuex起步

Vuex基本概念

Vuex是在Vue项目开发时使用的状态管理工具,是实现组件全局状态和数据管理的一种机制,可以方便的实现组件之间的数据共享。

为什么使用Vuex

我们在项目开发中频繁的使用组件传参的方式来操作data中的值,项目肯定会变的臃肿,管理和维护这些值将是相当耗时的工作。所以Vue为这些被多个组件频繁使用的值提供了一个统一管理的工具VueX。有了Vuex,我们只需要把这些值定义在VueX中,就可在整个Vue项目的组件中使用。

核心api

  1. state 存放状态
  2. mutations state成员操作
  3. getters 包装state成员给外界
  4. actions 异步操作
  5. modules 模块化状态管理

安装

npm i vuex -s

一般呢在项目初始化的时候会有安装选项,勾选安装接着执行下一步即可。这里就先讲下手动安装并配置Vuex相关文件。在src文件夹下新建store文件夹并创建index.js。创建完成的目录如下:

│ App.vue
│ main.js

├─assets
│ logo.png

├─components
│ HelloWorld.vue

├─router
│ index.js

└─store
index.js

初始化store

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
 
  },
  mutations: {
    
  },
  getters: {
 
  },
  modules:{
    
  }
})

以上初始化Vuex就完成了。

二、TodoList

安装antdv

为了使demo好看些这里使用antdv作为UI库

npm install ant-design-vue --save

引入antdv和挂载:

import Vue from 'vue'
import App from './App.vue'
import store from './store'
//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({
  store,
  render: h => h(App)
}).$mount('#app')

安装axios并mock数据

npm install axios

public文件夹下创建source.json,mock数据

[
  {
    "id": 0,
    "txt": "Racing car sprays burning fuel into crowd.",
    "done": false
  },
  {
    "id": 1,
    "txt": "Jack car sprays burning fuel into crowd.",
    "done": true
  },
  {
    "id": 2,
    "txt": "Alien car sprays burning fuel into crowd.",
    "done": false
  },
  {
    "id": 3,
    "txt": "Wed car sprays burning fuel into crowd.",
    "done": true
  },
  {
    "id": 4,
    "txt": "Carry car sprays burning fuel into crowd.",
    "done": false
  }
]

TodoList页面搭建

<template>
  <div id="app">
    <a-input
      class="add_input"
      placeholder="请输入添加项" 
    />
    <a-button type="primary">添加</a-button>
    <a-list size="small" bordered :data-source="getSatusList" class="todo_list">
      <a-list-item slot="renderItem" slot-scope="item">
        <a-checkbox></a-checkbox>
        <span>{{ item.txt }}</span>
        <a-button type="link">删除</a-button>
      </a-list-item> 
      <div slot="footer" class="footer"> 
        <span>剩余0项未完成</span> 
        <a-button-group>
          <a-button type="primary" @click="setStatus('all')">全部</a-button>
          <a-button type="default">未完成</a-button>
          <a-button type="default">已完成</a-button>
        </a-button-group> 
        <a>清除已完成</a>
      </div>
    </a-list>
  </div>
</template>

<script>
export default {
  data() {
    return {
    getSatusList:[] //这里先给列表个空数组,之后删除
    };
  } 
};
</script>

<style>
#app {
  width: 460px;
  min-height: 300px;
  margin: 10px;
  padding: 10px;
  border: 1px solid #fafafa;
}
.add_input {
  width: 361px !important;
  margin-right: 10px !important;
}
.todo_list {
  width: 435px;
  margin-top: 10px !important;
}
.footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>

没数据的情况下就是下面这个样子
在这里插入图片描述

axios请求数据

这里使用Action来处理异步任务,如果通过异步操作变更数据,必须通过Action,而不能通过Mutation,但是再Action中还是要通过触发Mutation的方式间接变更数据。

首先state里添加list属性用来存放列表数据,mutations里添加修改state里list的方法,actions里添加请求数据方法,返回数据赋值给state.list

  //store index.js
  state: {
    list: []
  },
  mutations: {
    initList(state, list) {
      state.list = list
    }
  },
  actions: {
    getList(context) {
      axios.get('/source.json').then(({
        data
      }) => {
        context.commit('initList', data);
      })
    }
  }

App.vue文件里引入Vuex,首先created函数中用dispatch触发actions里的getList方法获取数据改变state的list,使用Vuex的mapState方法获取store.list列表,然后绑定到列表组件中。

import { mapState } from "vuex";
export default {
  data() {
    return {};
  },
  created() {
    this.$store.dispatch("getList");  //触发store异步请求方法
  },
  computed: {
    ...mapState(["list"])
  }
}
<!--为了省时间,这里省略了上下代码,找到组件对应位置添加list-->
<a-list size="small" bordered :data-source="list" class="todo_list">

渲染效果如下:
在这里插入图片描述

双向绑定和列表添加数据

state添加ipatVal属性用来双向绑定输入框

//store index.js
state: {
    list: [],
    iptVal: ''
},

computed计算属性里获取iptVal

//App.vue
computed: {
    ...mapState(["iptVal"])
},

绑定输入框并添加change事件

<!--App.vue-->
<a-input
  class="add_input"
  placeholder="请输入添加项"
  :value="iptVal"
  @change="iptChange"
/>

store里mutations API中添加修改state.iptVal的方法setIptVal, 然后App.vue页面methods中定义change事件对应的方法从而触发mutations里的方法改变state.iptVal

//store index.js
mutations: {
  initList(state, list) {  //修改list列表
    state.list = list
  },
  setIptVal(state, val) {  //对应列表输入框用来双向绑定
    state.iptVal = val
  }
}
//App.vue
methods: {
    iptChange(e) {  //输入框change事件
      this.$store.commit("setIptVal", e.target.value);
    }
}

到这里就完成了state与视图的双向绑定。接下来是添加列表数据,首先mutations里定义添加方法。

//store index.js
mutations: {
    initList(state, list) {
      state.list = list
    },
    setIptVal(state, val) {
      state.iptVal = val
    },
    addItem(state) {   //列表添加方法
      const obj = {
        id: state.list.length,
        txt: state.iptVal,
        done: false
      }
      state.list.push(obj)
      state.iptVal = ''
    }
}

页面加入事件add

<a-button type="primary" @click="add">添加</a-button>

methods定义add并触发mutations里addItem方法。

methods: {
    iptChange(e) {
      this.$store.commit("setIptVal", e.target.value);
    },
    add() {
      if (this.iptVal.trim().length <= 0) {
        return this.$message.warning("输入内容不可为空");
      }
      this.$store.commit("addItem");
    }
}

双向绑定和列表添加就完成了。

删除列表数据

mutations添加删除方法delItem

//store index.js
delItem(state, id) {
  const i = state.list.findIndex(item => item.id === id);
  if (i > -1) {
    state.list.splice(i, 1);
  }
}

methods添加del方法

//App.vue
del(id) {
  this.$store.commit("delItem", id);
}

接着方法给到button按钮并将id传入

<a-button type="link" @click="del(item.id)">删除</a-button>

至此删除方法也完成了。

勾选选框完成事项

mutations定义改变完成状态方法

//store index.js
checkBoxChange(state, id) {
  const i = state.list.findIndex(item => item.id === id);
  if (i > -1) {
    state.list[i].done = !state.list[i].done;
  }
}

methods定义选框change方法

checkChange(id){
  this.$store.commit("checkBoxChange", id);
}

选框绑定change方法并传入id

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

完成事项逻辑结束。

清空已完成和显示未完成条数

mutations定义清空完成项的方法

//store index.js
cleanItem(state) {
  state.list = state.list.filter(item => !item.done)
}

methods定义清空方法

//App.vue
clean(){
  this.$store.commit("cleanItem");
}

清空按钮绑定方法

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

显示未完成事项剩余条数,这里要用到getters API 来将未完成包装一下

//store index.js
getters: {
  unDoneLength(state) {
    return `剩余${state.list.filter(item=>!item.done).length}项未完成`
  }
}

App.vue里引入mapGetters,computed计算属性里获取未完成事项数量方法

computed: {
  ...mapState(["iptVal"]),
  ...mapGetters(["unDoneLength"])
}

绑定到视图中

<div slot="footer" class="footer"> 
        <span>{{ unDoneLength }}</span> 

切换按钮状态以及根据状态变更列表数据

state添加status状态属性

//store index.js
state: {
  list: [],
  iptVal: '', 
  status: 'all' //默认值是所有状态的数据
}

mutations里添加修改status属性的方法

setItemStatus(state, status) {
  state.status = status
}

computed计算属性引入status

//App.vue
computed: {
  ...mapState(["iptVal","status"]),
  ...mapGetters(["unDoneLength"]),
}

methods中定义触发mutations里status的方法

setStatus(status){
  this.$store.commit("setItemStatus", status);
}

给footer里的按钮绑定status来切换按钮状态并绑定用来触发mutations方法的click事件,并传入对应的状态值。

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

最后封装一个getters方法,这个方法会根据不同的状态展示对应状态的数据并反馈到列表。

//store index.js
getSatusList(state) {
 switch (state.status) {
   case 'all':
     return state.list
   case 'undone':
     return state.list.filter(item => !item.done) 
   case 'done':
     return state.list.filter(item => item.done) 
   default:
     break;
 }
}

在computed计算属性中引入

computed: {
  ...mapState(["iptVal","status"]),
  ...mapGetters(["unDoneLength","getSatusList"]),
}

由于已经根据不同状态反馈数据到视图中了,所以列表数据源切换到getters封装好的方法getSatusList

<a-list size="small" bordered :data-source="getSatusList" class="todo_list">

至此基于Vuex的TodoList就完成了。

完整代码地址:https://github.com/karainsun/Vuex-TodoList.git

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值