Vuex_TodoList
1. 初始化项目
-
创建文件夹
vue create vuex_demo
-
安装相关依赖
vue add vuex axios
npm i --save ant-design-vue
-
模板搭建
App.vue
<template> <div id="app"> <a-input placeholder="请输入任务" class="my_ipt"></a-input> <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> <!-- footer --> <div class="footer" slot="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 { data(){ return{ list:[{ "id": 0, "info": "woshixxyi", "done": false }, { "id": 1, "info": "woshixxyi", "done": false }, { "id": 2, "info": "woshixxyi", "done": false } ] } } } </script> <style scoped> #app{ padding: 10px; } .my_ipt{ width: 500px; margin-right:10px; } .dt_list{ width:500px; margin-right: 10px; } .footer{ display:flex; justify-content: space-between; align-items:center; } </style>
main.js
import Vue from 'vue' import './plugins/axios' import App from './App.vue' import store from './store' //导入ant-design-vue组件库 import Antd from 'ant-design-vue'; //导入组件库样式表 import 'ant-design-vue/dist/antd.css'; Vue.config.productionTip = false //安装组件库 Vue.use(Antd); new Vue({ store, render: h => h(App) }).$mount('#app')
2. 项目实现
1. 数据源改进
- 将APP.vue中list数据删除,在public目录下新建list.json文件,将原先的数据存入
- 在index.js(vuex文件)中引入axios
- 在actions中通过axios获取list.json中的数据,并在App.vue中定义生命周期函数created,通过dispatch触发actions函数。
- 在action函数中,通过commit触发mutations函数,将数据传入mutations定义的initList函数中,修改state中list的数据。
- 在App.vue中导入辅助函数mapState,使用computed属性监听数据的变化
list.json
[
{
"id": 0,
"info": "woshixxyi",
"done": false
},
{
"id": 1,
"info": "woshixxyi",
"done": false
},
{
"id": 2,
"info": "woshixxyi",
"done": false
}
]
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
list: []
},
mutations: {
initList(state, step) {
state.list = step
}
},
actions: {
getList(context) {
axios.get('/list.json').then(({ data }) => {
context.commit('initList', data)
})
}
},
modules: {}
})
APP.vue
<script>
import {mapState} from 'vuex'
export default {
data(){
return{
}
},
created(){
this.$store.dispatch('getList')
},
computed:{
...mapState(['list'])
}
}
</script>
2.实现文本框的内容与state中的内容双向数据绑定
- 首先在state中设置一个inputItem,值为"aaa",并将它映射到App.vue中,将它的值绑定到输入框中
- 定义change事件,监听输入框中值的变化,并将值传递给mutations中setInputValue函数。让其改变state中inputItem的值
index.js
state: {
list: [],
inputItem: ""
},
mutations: {
initList(state, step) {
state.list = step
},
setInputValue(state, val) {
state.inputItem = val
}
}
App.vue
<a-input placeholder="请输入任务" class="my_ipt" :value="inputItem" @change='getInputItem'></a-input>
<script>
import {mapState} from 'vuex'
export default {
data(){
return{}
},
computed:{
...mapState(['list','inputItem'])
},
methods:{
getInputItem(e){
this.$store.commit('setInputValue',e.target.value)
}
}
}
</script>
3.实现添加事项
- 在按钮中定义点击事件addInputToList,首先判断输入框中的内容是否为空,若不为空,则使用commit触发mutations来改变state中list中的内容
- 在mutations中定义函数addInputToList来实现state中list中数据的添加,因为原本存在三条数据,故在state中定义nextId为3
App.vue
<a-button type="primary" @click="addInputToList">添加事项</a-button>
// mothods
addInputToList(){
//trim()去除字符串的头尾空格
if(this.inputItem.trim().length <= 0){
return this.$message.warning('文本框内容不能为空')
}
this.$store.commit('addInputToList')
}
index.js
state: {
list: [],
inputItem: "",
nextId: 3
},
mutations: {
addInputToList(state) {
let opt = {
"id": state.nextId,
"info": state.inputItem,
"done": false
}
state.list.push(opt)
state.nextId++
state.inputItem = ""
}
},
4.删除功能实现
- 给删除按钮添加删除事件,通过id进行删除,点击按钮通过commit触发mutations修改state中的数据
- 在mutations中定义removeItemById函数来实现通过传递过来的id删除对应的数据
App.vue
<a slot="actions" @click="removeItemById(item.id)">删除</a>
// mothods
removeItemById(id){
this.$store.commit("removeItemById",id)
}
index.js
removeItemById(state, id) {
let itemId = state.list.findIndex(x => x.id === id)
if (itemId != -1) {
state.list.splice(itemId, 1)
}
}
5.实现复选框状态的绑定
通过:checked来绑定复选框状态的值,在此之前,可以修改list.json中的done值为true来查看是否绑定成功
App.vue
<a-checkbox :checked="item.done">{{item.info}}</a-checkbox>
6.获取复选框状态并拿到响应的数据
- 监听复选框改变事件
- 首先为复选框添加数据改变事件,并为事件添加箭头函数,当数据发生改变触发箭头函数,在箭头函数的函数体中添加cbStatusChange事件,并将箭头函数得到的形参e传递进去,同时将对应的id传入进去
- 在cbStatusChange函数中定义一个参数对象cd,接收对应的id和复选框的状态,然后通过commit触发mutations中的cbStatusChange方法来改变state中的数据
App.vue
<a-checkbox :checked="item.done" @change="(e)=>{cbStatusChange(e,item.id)}">{{item.info}}</a-checkbox>
// mothods
cbStatusChange(e,id){
let cb = {
id:id,
status:e.target.checked
}
this.$store.commit('cbStatusChange',cb)
}
index.js
cbStatusChange(state, cb) {
let i = state.list.findIndex(x => x.id === cb.id)
if (i != -1) {
state.list[i].done = cb.status
}
}
- 统计未选中复选框条数
- 在index.js(vuex文件)中的actions下新增一个getters(对state数据进行过滤操作),在getters下定义函数unDoneLength来获取未被选中的个数。使用filter 过滤获取done值为false的数据
- 在App.vue中挂载mapGetters,并在computed中映射,最后将数据呈现。
index.js
getters: {
unDoneLength(state) {
return state.list.filter(x => x.done === false).length
}
}
App.vue
<span>{{unDoneLength}}条剩余</span>
export default {
import {mapState,mapGetters} from 'vuex'
computed:{
...mapState(['list','inputItem']),
...mapGetters(['unDoneLength'])
}
}
- 清除复选框被选中的数据
- 首先为清除按钮添加点击事件clearDoneTrue,在点击事件中通过commit触发mutations中的clearDoneTrue函数。
- mutations中的clearDoneTrue函数通过filter过滤,得到done的值为false的数据,并将数据重新赋值给state.list
App.vue
<a @click="clearDoneTrue">清除已完成事项</a>
clearDoneTrue(){
this.$store.commit('clearDoneTrue')
}
index.js
clearDoneTrue(state) {
state.list = state.list.filter(x => x.done === false)
}
- 按钮高亮设置
-
定义按钮点击事件btnPrimary(key),并让三个按钮传入三个不同的参数,在btnPrimary函数中,通过commit触发mutations,来改变state中定义的 btnView: 'all'中的值。
-
将btnView映射到App.vue中,通过三元运算符来判断btnView的值,从而为按钮设置tpye属性
App.vue
<a-button-group>
<a-button :type="btnView === 'all'?'primary':'defalut'" @click="btnPrimary('all')">全部</a-button>
<a-button :type="btnView === 'undone'?'primary':'defalut'" @click="btnPrimary('undone')">未完成</a-button>
<a-button :type="btnView === 'done'?'primary':'defalut'" @click="btnPrimary('done')">已完成</a-button>
</a-button-group>
computed:{
...mapState(['item','inputItem','nextId','btnView']),
...mapGetters(['unDoneLength'])
},
btnPrimary(key){
this.$store.commit('btnPrimary',key)
}
index.js
state: {
list: [],
inputItem: "",
nextId: 3,
btnView: 'all'
},
btnPrimary(state, key) {
state.btnView = key
}
- 通过按钮切换数据
- 在getters中定义infolist函数,通过判断btnView的值来返回对应的数据
- 将infolist映射到App.vue中。
- 因为原先的list是全部数据,现在需要改为动态数据infolist,首先删除 ...mapState([])的“list",在 ...mapGetters([])中添加infolist
- 最后将****中的数据源:dataSource绑定的的数据改为infolist
index.js
//getters
infolist(state){
if(state.btnView==='all'){
return state.list
}else if(state.btnView==='undone'){
return state.list.filter(x => x.done ===false)
}else if(state.btnView==='done'){
return state.list.filter(x => x.done ===true)
}
}
App.vue
<a-list bordered :dataSource="infolist" class="dt_list">
........
<a-list>
computed: {
...mapState([ "inputItem",'btnView']),
...mapGetters(['unDoneLength',"infolist"])
},
总结
state
state用于数据的存放。
组件获取数据方式:
-
方式一:
this.$store.state.全局数据名称
-
方式二:
-
从vuex中按需导入mapState辅助函数
import {mapState} from 'vuex'
-
将全局数据映射为当前组件的计算属性
computed:{
...mapState(['数据名称'])
}
-
mutations
用于变更Store中的数据。在vuex中只能通过mutation变更store数据,不可以直接操作store中的数据。优点:可以集中监控所有数据的变化;缺点:操作繁琐
触发mutations的方式:
方式一:
methods:{
方法名(){
this.$store.commit('mutation中的方法名',可选参数)
}
}
方式二:
-
从vuex中按需导入mapMutations辅助函数
import {mapMutations} from 'vuex'
-
将所需的mutations函数,映射为当前组件的methods方法
methonds:{
...mapMutations(['函数名'])
}
接收参数:
mutations:{
方法名(state,参数){}
}
actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
actions: { increment (context) { context.commit('increment') } }
触发方式:
方式一:
this.$store.dispatch("函数名",参数)
方式二:
-
从vuex中按需导入mapActions 辅助函数
import {mapActions } from 'vuex'
-
将所需的mutations函数,映射为当前组件的methods方法
methods: { ...mapActions([ 'increment', // 将
this.increment()
映射为this.$store.dispatch('increment')
//
mapActions
也支持载荷: 'incrementBy' // 将this.incrementBy(amount)
映射为this.$store.dispatch('incrementBy', amount)
]), ...mapActions({ add: 'increment' // 将
this.add()
映射为this.$store.dispatch('increment')
})}
getters
getters用于对store中的数据进行加工处理形成新的数据
访问getters中的数据:
方法一:
通过属性/方法访问
this.$store.getters.属性/方法名
方式二:
-
从vuex中按需导入mapGetters 辅助函数
import {mapGetters } from 'vuex'
-
将所需的mapGetters 函数,映射为当前组件的computed方法
...mapGetters([‘getters中的方法名’])