第十九章-派发器之TodoList

51 阅读1分钟

用派发器做一个TodoList

目录如下 image.png

组件书写

toList/index.vue

<template>
    <div>
        <td-title :title="title"/>
        <td-form @dispatch="dispatch"/>
        <td-list :data="todoData" @dispatch="dispatch"/>
    </div>
</template>

<script>
import TdTitle from './TdTitle.vue';
import TdForm from './TdForm.vue';
import TdList from './TdList.vue';
import dispatch from '@/dispatch/todoList';

export default {
    name: "TodoList",
    components: {
        TdTitle,
        TdForm,
        TdList
    },
    data() {
        return {
            title: "todoList",
            todoData: []
        }
    },
    methods: {
        dispatch(...args) {
            dispatch(this)(...args);
        }
    }
}
</script>

todoList/TdTitle.vue

<template>
    <h1>{{ title }}</h1>
</template>

<script>
export default {
    name: "TdTitle",
    props: {
        title: String
    }
}
</script>

todoList/TdForm.vue

<template>
    <div>
        <form
            @submit.prevent="submitText"
        >
            <input 
                type="text"
                v-model.trim="todoText"
                placeholder="请输入"
            />
        </form>
    </div>
</template>

<script>
export default {
    name: 'TdForm',
    data() {
        return {
            todoText: ""
        }
    },
    methods: {
        submitText(e) {
            if(this.todoText.length === 0) return;

            this.$emit('dispatch', 'ADD', {
                id: Date.now(),
                text: this.todoText,
                completed: false,//是否完成了
            });

            this.$nextTick(() => this.todoText = "")
        }
    }
}
</script>

todoList/TdList.vue

<template>
    <div>
        <ul class="todoList">
            <list-item v-for="item of data" :key="item.id" :item="item" @handlerItem="handlerItem"/>
        </ul>
    </div>
</template>

<script>
import ListItem from './ListItem.vue';
export default {
    name: 'TdList',
    components: {
        ListItem
    },
    props: {
        data: Array,
        default: () => []
    },
    methods: {
        handlerItem(...args) {
            this.$emit('dispatch', ...args);
        }
    }
}
</script>

todoList/ListItem.vue

<template>
    <li>
        <input 
            type="checkbox" 
            :checked="item.completed ? 'checked' : ''"
            @click="handlerItem(COMPLETED, item.id)"
        />
        <span :class="{completed: item.completed}">{{ item.text }}</span>
        <button @click="handlerItem(REMOVE, item.id)">删除</button>
    </li>
</template>

<script>
import {COMPLETED, REMOVE} from '@/actions/todoList';
export default {
    name: "ListItem",
    props: {
        item: Object
    },
    data() {
        return {
            REMOVE,
            COMPLETED
        }
    },
    methods: {
        handlerItem(...args) {
            this.$emit('handlerItem', ...args);
        }
    }
}
</script>
<style>
.completed {
    text-decoration: line-through;
}
</style>

书写派发器

actions/todoList.js

const COMPLETED = "COMPLETED";
const REMOVE = "REMOVE";
const ADD = "ADD";

export {
    COMPLETED,
    REMOVE,
    ADD
}

reducers/todoList.js

export default function todoReducer(data) {//todoData
    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
    }
}

dispatch/todoList.js

import todoReducer from '@/reducers/todoList';
import { ADD, REMOVE, COMPLETED } from '@/actions/todoList'

export default (ctx) => {
    const {
        addItem,
        removeItem,
        changeCompleted
    } = todoReducer(ctx.todoData);

    return function(type, arg) {
        switch(type) {
            case ADD:
                ctx.todoData = addItem(arg);
                break;
            case REMOVE:
                ctx.todoData = removeItem(arg);
                break;
            case COMPLETED:
                ctx.todoData = changeCompleted(arg);
                break;
            default:
                break;
        }
    }    
}
  • 上述代码如下图所示:

image.png

image.png

image.png