派发器深入之TodoList组件设计
<template>
<div>
<td-title :title="title" />
<td-form @dispatch="dispatch" />
<td-list :todoData="todoData" @dispatch="dispatch" />
</div>
</template>
<script>
import TdTitle from "./Title";
import TdForm from "./Form";
import TdList from "./List/Index";
import dispatch from "@/dispatchers/todoList"
export default {
name: "TodoList",
components: {
TdTitle, TdForm, TdList
},
data () {
return {
title: "TodoList",
todoData: []
}
},
methods: {
dispatch (...args) {
dispatch(this)(...args);
}
}
}
</script>
<template>
<h1>{{title}}</h1>
</template>
<script>
export default {
name: "TdTitle",
props: {
title: String
}
}
</script>
<template>
<div>
<form @submit="submitText">
<input type="text" v-model.trim="todoText" placeholder="Input what you wanna add!" />
</form>
</div>
</template>
<script>
export default {
name: "TdForm",
data () {
return {
todoText: ""
}
},
methods: {
submitText (e) {
e.preventDefault();
if (this.todoText.length === 0) {
return;
}
this.$emit("dispatch", "ADD", {
id: Date.now(),
text: this.todoText,
completed: false
});
this.todoText = "";
}
}
}
</script>
<template>
<div>
<ul>
<list-item
v-for="(item, index) of todoData"
:key="index"
:item="item"
@handelItem="handelItem"
/>
</ul>
</div>
</template>
<script>
import ListItem from './ListItem.vue'
export default {
name: "TdList",
components: {
ListItem
},
props: {
todoData: Array
},
methods: {
handelItem (...args) {
this.$emit("dispatch", ...args);
}
}
}
</script>
<template>
<li>
<input
type="checkbox"
:checked="item.completed ? 'checked' : '' "
@click="handelItem('COMPLETED', item.id)"
/>
<span :class="{completed: item.completed}">{{item.text}}</span>
<button @click="handelItem('REMOVE', item.id)">删除</button>
</li>
</template>
<script>
export default {
name: "ListItem",
props: {
item: Object
},
methods: {
handelItem (...args) {
this.$emit("handelItem", ...args);
}
}
}
</script>
<style scoped>
.completed {
text-decoration: line-through;
}
</style>
<!-- src/actions/todoList.js -->
const ADD = "ADD"
const REMOVE = "REMOVE"
const COMPLETED = "COMPLETED"
export {
ADD,
REMOVE,
COMPLETED
}
<!
function todoListReducers (data) {
function addItem (newItem) {
return data.concat(newItem);
}
function removeItem (id) {
return data.filter(item => item.id !== id);
}
function changeCompleted (id) {
return data.map((item) => {
if (item.id === id) {
item.completed = !item.completed;
}
return item;
})
}
return {
addItem,
removeItem,
changeCompleted
}
}
export default todoListReducers;
<!-- src/dispatchers/todoList.js -->
import todoListReducers from "../reducers/todoList";
import { ADD, REMOVE, COMPLETED } from "@/actions/todoList";
export default (ctx) => {
const {
addItem,
removeItem,
changeCompleted
} = todoListReducers(ctx.todoData);
return function (type, args) {
console.log(type, args)
switch (type) {
case ADD:
ctx.todoData = addItem(args);
break;
case REMOVE:
ctx.todoData = removeItem(args);
break;
case COMPLETED:
ctx.todoData = changeCompleted(args);
break;
default:
break;
}
}
}