一个vue3的待办列表组件

一个vue3的待办列表组件, 仿企业微信的待办列表

TodoList.vue

js 复制代码
<template>
    <div>
        <el-input v-model="todoInput" placeholder="写下你的待办事项..." class="el-input" @keyup.enter="addTodo"
            input-style="background-color: #EBECED;" />

        <el-table :data="todos" size="small" :show-header="false" @row-dblclick="editTodo">
            <el-table-column width="30">
                <template #default="scope">
                    <el-checkbox v-model="scope.row.completed" @change="toggleTodo(scope.row)">check</el-checkbox>
                </template>
            </el-table-column>
            <el-table-column prop="text" />
        </el-table>

        <div @click="showCompleted = !showCompleted" style="cursor: pointer; text-align: center; margin: 10px 0;">
            <el-divider v-if="!showCompleted">已完成 (点击展开)</el-divider>
            <el-divider v-else>已完成 (点击折叠)</el-divider>
        </div>

        <el-table :data="completedTodos" size="small" :show-header="false" v-if="showCompleted">
            <el-table-column width="30">
                <template #default="scope">
                    <el-checkbox v-model="scope.row.completed" @change="toggleTodo(scope.row)">check</el-checkbox>
                </template>
            </el-table-column>
            <el-table-column prop="text" />
        </el-table>

        <el-dialog title="修改" v-model="editDialogVisible">
            <el-form :model="editingTodo">
                <el-form-item label="内容">
                    <el-input ref="inputRef" v-model="editingTodo.text"></el-input>
                </el-form-item>
                <el-form-item label="状态">
                    <el-checkbox v-model="editingTodo.completed">已完成</el-checkbox>
                </el-form-item>
            </el-form>
            <template #footer>
                <el-button @click="editDialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="confirmEdit()">确 定</el-button>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
// 通用的待办列表
// 使用<TodoList :todoList="todoList" :save="save"></TodoList>
import { ref } from 'vue';

interface Todo {
    id: number;
    text: string;
    completed: boolean;
}

defineOptions({
    name: 'TodoList'
})

const props = defineProps({
    todoList: Array<Todo>,
    save: Function  //外部传入的保存方法,入参是Todo[]
});

const todoInput = ref('');
const todos = ref<Todo[]>([]);
const completedTodos = ref<Todo[]>([]);
const editDialogVisible = ref(false);
const editingTodo = ref({} as Todo);
const showCompleted = ref(false);
const inputRef = ref();

watch(() => props.todoList, (newValue) => {
    if (newValue) {
        newValue.sort((a, b) => b.id - a.id);
        todos.value = newValue.filter(t => !t.completed);
        completedTodos.value = newValue.filter(t => t.completed);
    }
})

const addTodo = () => {
    if (todoInput.value.trim() === '') return;
    todos.value.unshift({
        id: Date.now(),
        text: todoInput.value,
        completed: false
    });
    todoInput.value = '';
    saveTodoList();
};

const toggleTodo = async (todo: Todo) => {
    await new Promise(resolve => setTimeout(() => resolve("delay"), 300)); //产生一个点击后动画效果
    if (todo.completed) {
        if (!completedTodos.value.find(t => t.id == todo.id)) {
            completedTodos.value.unshift(todo);
        }
        todos.value = todos.value.filter(t => t.id !== todo.id);
    } else {
        if (!todos.value.find(t => t.id == todo.id)) {
            todo.id = Date.now();//更新时间到最新,所以每个todo其实是没有唯一值的
            todos.value.unshift(todo);
        }
        completedTodos.value = completedTodos.value.filter(t => t.id !== todo.id);
    }
    saveTodoList();
};

const editTodo = (todo: Todo) => {
    editingTodo.value = { ...todo };
    editDialogVisible.value = true;
    //组件focus的正确方式 setTimeout
    setTimeout(() => {
        inputRef.value?.focus();
    })
};

const confirmEdit = () => {
    editDialogVisible.value = false;
    var todo = todos.value.find(t => t.id == editingTodo.value.id)
    if (todo) {
        todo.text = editingTodo.value.text
        todo.completed = editingTodo.value.completed;
        toggleTodo(todo);
    }
};

const saveTodoList = () => {
    if (props.save) { // 添加空值检查
        props.save(todos.value.concat(completedTodos.value));
    }
}

</script>
<style scoped>
.el-input {
    --el-input-bg-color: #EBECED;
}
</style>
相关推荐
kitsch0x972 小时前
论文学习_LLM4Decompile: Decompiling Binary Code with Large Language Models
1024程序员节
hazy1k3 小时前
51单片机基础-继电器实验
stm32·单片机·嵌入式硬件·51单片机·1024程序员节
Brianna Home7 小时前
大模型如何变身金融风控专家
人工智能·深度学习·机器学习·自然语言处理·stable diffusion·1024程序员节
TDengine (老段)15 小时前
TDengine 数据函数 CORR 用户手册
大数据·数据库·物联网·时序数据库·tdengine·1024程序员节
彩云回1 天前
多维尺度分析法(MDS)
人工智能·机器学习·1024程序员节
j_xxx404_1 天前
Linux:权限复盘扩展|粘滞位|软件包管理器|Linux软件生态
linux·1024程序员节
pp-周子晗(努力赶上课程进度版)1 天前
WebRTC项目架构详解
1024程序员节
Yupureki1 天前
从零开始的C++学习生活 20:数据结构与STL复习课(4.4w字全解析)
c语言·数据结构·c++·学习·visual studio·1024程序员节
Predestination王瀞潞1 天前
Java EE开发技术(第五章:JSP技术)
1024程序员节
AORO20251 天前
三防平板三防是指哪三防?适合应用在什么场景?
服务器·网络·智能手机·电脑·1024程序员节