Vue3+vite+ts实现TodoList(详)

一.组件架构


        a. 根组件App.vue

        b. 添加事件组件 AddToDo.vue 

        c.列表组件 ToDoList.vue

        d.列表的li组件 ToDItem.vue

二.实现效果


三.公布代码 


 1.App.vue

<template>
  <div>
    <h1>Todo List</h1>
    <AddToDo @add-todo="addNewTodo"/>
    <ToDoList :todos="todos" @toggle-todo="toggleTodo" @delete-todo="deleteTodo"/>
  </div>
</template>

<script lang="ts" setup>
  import { reactive } from 'vue';
  import AddToDo from './components/AddToDo.vue';
  import ToDoList from './components/ToDoList.vue';
  interface Todo{
    id:number;
    title:string;
    completed:boolean;
  }

  const todos = reactive<Todo[]>([])
  const addNewTodo = (newTodo:string)=>{
    todos.push({id:todos.length+1,title:newTodo,completed:false})
  }

  const toggleTodo = (todoId:number)=>{
    const todo= todos.find(item => item.id===todoId)
    if(todo){
      todo.completed = !todo.completed
    }
  }

  const deleteTodo = (todoId:number) =>{
    const index = todos.findIndex(item => item.id===todoId)
    if(index !== -1){
      todos.splice(index,1)
    }
  }
</script>

<style>
  body {
    font-family: 'Arial', sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    height: 100vh;
    align-items: center;
  }

  #app {
    background: white;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    width: 400px;
  }

  h1 {
    text-align: center;
    color: #333;
  }

</style>

2.AddToDo.vue 

<template>
    <div>
        <input v-model.trim="todoElement" @keyup.enter="submitTodo">
        <button @click="submitTodo">Add</button>
    </div>
</template>

<script lang="ts" setup>
    import { ref } from 'vue';
    const todoElement = ref('')
    const emit = defineEmits(['add-todo'])
    const submitTodo = ()=>{
        if(todoElement.value){
            emit('add-todo',todoElement.value)
            todoElement.value=''
        }
    }
</script>

<style scoped>
    div {
        margin-bottom: 20px;
        text-align: center;
    }
    input {
        padding: 10px;
        border: 1px solid #ddd;
        border-radius: 4px;
        width: 70%;
        margin-right: 10px;
    }
    button {
        padding: 10px 15px;
        background-color: #5cb85c;
        border: none;
        border-radius: 4px;
        color: white;
        cursor: pointer;
    }

    button:hover {
        background-color: #4cae4c;
    }
</style>

3.ToDoItem.vue

<template>
  <li :class="{completed:todo?.completed}">
    {{ todo?.title }}
    <button @click="toggleTodo">Toggle</button>
    <button @click="deleteTodo">Delete</button>
  </li>
</template>

<script lang="ts" setup>
  import { defineProps, defineEmits } from 'vue';
  interface Todo {
    id: number;
    title: string;
    completed: boolean;
  }
  const props = defineProps({
    todo:Object as ()=>Todo
  })
  const emit = defineEmits(['toggle-todo','delete-todo'])
  const toggleTodo = ()=>{
    emit('toggle-todo',props.todo?.id)
  }
  const deleteTodo = ()=>{
    emit('delete-todo',props.todo?.id)
  }
</script>

<style scoped>
  li {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  button {
    padding: 5px 10px;
    background-color: #d9534f;
    border: none;
    border-radius: 4px;
    color: white;
    cursor: pointer;
  }

  button:hover {
    background-color: #c9302c;
  }

  .completed {
    color: #777;
    text-decoration: line-through;
  }

</style>

4.ToDoList.vue

<template>
  <ul>
    <ToDoItem v-for="todo in todos" :key="todo.id" :todo="todo" @toggle-todo="toggleTodo" @delete-todo="deleteTodo"/>
  </ul>
</template>

<script lang="ts" setup>
  import { defineProps, defineEmits } from 'vue';
  import ToDoItem from './ToDoItem.vue';
  interface Todo {
    id: number;
    title: string;
    completed: boolean;
  }
  const props = defineProps({
    todos:Array as ()=>Todo[]
  })

  const emit = defineEmits(['toggle-todo','delete-todo'])

  const toggleTodo = (id:number)=>{
    emit('toggle-todo',id)
  }

  const deleteTodo =(id:number)=>{
    emit('delete-todo',id)
  }
</script>

<style scoped>
  ul {
    list-style-type: none;
    padding: 0;
    /* border: 1px solid transparent; */
  }
  /* ul:not(:empty){
    border-color: #ddd;
  } */
  li {
    padding: 10px;
    border-bottom: 1px solid #ddd;
  }

  li:last-child {
    border-bottom: none;
  }
</style>

四.探讨和总结 

        首先只要把握好组件信息的通信,让每个组件分工合作,那么这个功能就很容易实现。

        其实本人对于TypeScript的语法也只是一般般了解,所以一般是看到标红再去寻找解决办法,代码是可以顺利跑的,只要项目创建好,导入组件的路径设置正确,都是可以展示出上面的效果的,但是我在上面import子组件的时候,一直标红,就类似于:

        我按照搜索到的各种方法去更改设置,也没有解决 ,下面就是一些大佬说的方法,但是并没有在我这边把标红效果消除,希望有知道的佬在评论区告诉一声

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于Vue3和Vite的开发环境,需要在项目中安装Vue3和Vite相应的包。然后,通过在Vite配置文件中配置mock数据,实现TodoList数据的模拟。 首先,在项目根目录下安装VueVite: ``` npm install vue@next vite --save-dev ``` 然后,在Vite的配置文件vite.config.js中配置mock数据: ```javascript module.exports = { server: { // 模拟API // 然后在api路径下,也就是在example/src/api路径下, // 根据接口路径,创建对应名称的.js文件,如/todo.js port: 3000, open: true, // 这里需要配置一下,否则会断开连接 cors: true, // 利用中间件,可以实现 mock 数据 // https://www.cnblogs.com/zero--007/p/11227108.html // 具体的编写方式可以参考上述链接 middleware: [createMockMiddleware()], }, }; ``` 其中,createMockMiddleware()方法是自定义的mock函数,示例代码如下: ```javascript const { createMockMiddleware } = require('vite-plugin-mock'); // 模拟数据 const todoData = [ { id: 1, label: "学习Vue3", done: false }, { id: 2, label: "学习Vite", done: false }, { id: 3, label: "学习TypeScript", done: true }, { id: 4, label: "整理网络知识", done: false }, ] module.exports = function () { return createMockMiddleware({ // 基于api路径,返回对应的数据 // 比如,在example/src/api/todo.js,就可以定义获取todoList数据的方法 // 比如: // export default [ // { // url: '/api/todo/list', // method: 'post', // response: () => { // return { // code: 200, // data: todoData // } // } // }, // ]; mockFiles: "src/api/*.js", }); }; ``` 在api路径下,就可以创建对应名称的js文件,如/todo.js。在该文件中,就可以定义获取todoList数据的方法,示例代码如下: ```javascript const todoData = [ { id: 1, label: "学习Vue3", done: false }, { id: 2, label: "学习Vite", done: false }, { id: 3, label: "学习TypeScript", done: true }, { id: 4, label: "整理网络知识", done: false }, ]; export default [ { url: "/api/todo/list", method: "post", response: () => { return { code: 200, data: todoData, }; }, }, ]; ``` 最后,在组件中使用api路径,获取todoList数据: ```javascript import { reactive, toRefs, onMounted } from "vue"; import axios from "axios"; export default { setup() { const state = reactive({ todoList: [], }); // 获取 todoList 数据 const getTodoList = () => { axios.post("/api/todo/list").then((res) => { state.todoList = res.data.data; }); }; // 组件加载时执行获取 todoList 数据 onMounted(() => { getTodoList(); }); // 最后需要将响应式对象转换为普通对象 return { ...toRefs(state) }; }, }; ``` 这样就可以实现Vue3和Vite环境下的TodoList数据模拟。请注意,本示例仅是提供了一个参考,实际的代码实现可能需要更加细、复杂的设计,具体的实现方式可以参考VueVite的官方文档,或者搜索相关的博客、论坛等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值