一个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>
相关推荐
比奥利奥还傲.9 天前
哪吒监控面板实战:部署 Dashboard、接入 Agent、钉钉告警,再配置固定公网访问
网络·人工智能·分布式·1024程序员节
默 语11 天前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
学传打活1 个月前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续3)
微信公众平台·1024程序员节·汉字·昆仑正义文化
学传打活1 个月前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng1681 个月前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心1 个月前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u0103055272 个月前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055272 个月前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝2 个月前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055272 个月前
Java图像处理实战指南
人工智能·1024程序员节