vue3+ts实现todolist功能

2023-11-18

先看一下实现效果:

 可以看到内部实现的内容有enter输入,单项删除,全选,以及删除选中项等功能

具体在实现前需要常见有ts的vue3项目

项目创建

具体项目创建 就是 vue create 项目名称

在创建后,选择的时候有vue2和vue3的选择,第三项是自定义,在自定义时需要选中ts(选择的键分别是向下键和空格键)

在创建项目之后,先运行,查看是否可运行

TodoList实现

目录结构:

运行文件:App.vue

组件:components下的文件

配置文件:utils   types

文件内容按上述介绍展示:

App.vue

<template>
  <div class="todo-container">
    <div class="todo-wrap">
     <Header :addTodo="addTodo"/>
     <List :todos='todos' :deleteTodo="deleteTodo" :updateTodo="updateTodo"/>
     <Footer :todos="todos" :checkAll="checkAll" :clearAllCompletedTodos="clearAllCompletedTodos"/>
    </div>
  </div>
</template>

<script lang='ts'>
import { defineComponent,reactive,toRefs,watch,onMounted } from 'vue'
// 引入直接的子集组件
import Header from './components/Header.vue'
import List from './components/List.vue'
import Footer from './components/Footer.vue'
import {Todo } from './types/todo'
import {saveTodos, readTodos} from './utils/localStorageUtils'

export default defineComponent({
  name:'App',
  components: {
    Header,
    List,
    Footer
  },
  // 数据存储为数组格式,数组内的为对象,对象中有三个属性(id, title, isSCompleted)
  // 把数据定义到App.vue父级组件
  setup(){
    // 定义一个数组数据
    // const state = reactive<{todos: Todo[]}>({
    //   todos: [
    //     {id: 1,title:'奔驰',isCompleted: false},
    //     {id: 2,title:'宝马',isCompleted: true},
    //     {id: 3,title:'奥迪',isCompleted: false},
    //   ]
    // })
    const state = reactive<{todos: Todo[]}>({
      todos: []
    })
    // 界面加载完毕后再读取数据
    onMounted(() => {
      setTimeout(() => {
        state.todos = readTodos()
      },1000)
    })

    // 添加数据的方法
    // eslint-disable-next-line
    const addTodo = (todo:Todo) => {
      state.todos.unshift(todo)
    }

    // 删除数据的方法
    const deleteTodo = (index:number) =>{
      state.todos.splice(index, 1)
    }

    // 修改todod的 isCompleted属性的状态
    const updateTodo = (todo: Todo,isCompleted: boolean) => {
      todo.isCompleted = isCompleted
      console.log(todo);
    }
    // 全选或者全不选的方法
    const checkAll = (isCompleted:boolean) => {
      // 遍历数组
      state.todos.forEach((todo) => {
        todo.isCompleted = isCompleted
      });
    }
    // 清理所有选中的数据
    const clearAllCompletedTodos = () => {
      state.todos = state.todos.filter(todo=>!todo.isCompleted)
    }

    // 监视操作:如果todos数组的数据变化了,直接存储到浏览器的缓存中
    // watch(() => state.todos, (value)=> {
    //   // 保存到浏览器缓存中
    //   localStorage.setItem('todos_key',value)
    // },{deep:true})

    // watch(() => state.todos, (value)=> {
    //   // 保存到浏览器缓存中
    //   saveTodos(value)
    // },{deep:true})

    watch(() => state.todos, saveTodos, {deep:true})
    return {
      ...toRefs(state),
      addTodo,
      deleteTodo,
      updateTodo,
      checkAll,
      clearAllCompletedTodos
    }
  }
})
</script>

<style scoped>
.todo-container{
  width: 600px;
  margin: 0 auto;
}
.todo-container .todo-wrap{
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
}
</style>

components 下的 Header.vue

<template>
  <div class="todo-header">
    <input type="text" placeholder='请输入你的任务名称,按回车键确认' @keyup.enter='add' v-model='title'>
  </div>
</template>

<script lang='ts'>
import { defineComponent,ref } from 'vue'

export default defineComponent({
  name:'Header',
  props: {
    addTodo: {
      type: Function,
      required: true    // 必须
    }
  },
  setup(props){
    // 定义一个ref类型的数据
    const title = ref('')
    // 回车的事件回调函数,用来添加数据
    const add = () => {
      // 获取文本框中输入的数据,判断不能为空
      const text = title.value
      if(!text.trim()) return
      //此时有数据,创建一个todo对象
      const todo = {
        id: Date.now(),
        title: text,
        isCompleted: false
      }
      // 调用方法addTodo方法
      props.addTodo(todo)
      // 情况文本框
      title.value = ''
    }
    return {
      title,
      add
    }
  }
})
</script>

<style scoped>
.todo-header input{
  width: 560px;
  height: 28px;
  font-size: 14px;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 4px 7px;
}
.todo-header input:focus{
  outline: none;
  border-color: rgba(82,168,236, 0.8);
  box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);
}
</style>

components 下的 List.vue

<template>
  <ul class="todo-main">
    <Item v-for="(todo, index) in todos" :key="todo.id" :index="index" :todo='todo' :deleteTodo="deleteTodo" :updateTodo="updateTodo" />
  </ul>
</template>

<script lang='ts'>
import { defineComponent } from 'vue'
import Item from './Item.vue'

export default defineComponent({
  name:'List',
  components: {
    Item,
  },
  props: ['todos','deleteTodo','updateTodo']
})
</script>

<style scoped>
.todo-main{
  margin-left: 0px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding: 0px;
}
.todo-empty{
  height: 40px;
  line-height: 40px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding-left: 5px;
  margin-top: 10px;
}
</style>

components 下的 Item.vue

<template>
  <li @mouseenter="mouseHandler(true)" @mouseleave="mouseHandler(false)" :style="{backgroundColor:bgColor,color:myColor}">
    <label>
      <input type='checkbox' v-model='isCom'/>
      <span>{{todo.title}}</span>
    </label>
    <button class='btn btn-danger' v-show="isShow" style='display;none' @click="delTodo">删除</button>
  </li>
</template>

<script lang='ts'>
import { defineComponent,ref, computed } from 'vue'
import {Todo} from '../types/todo'

export default defineComponent({
  name:'Item',
  // props: {
  //   todo: Object as () => Todo  // 函数返回的是Todo类型
  // },
  props: {
    todo: {
      type: Object as () => Todo,  // 函数返回的是Todo类型
      required: true
    },
    deleteTodo: {
      type: Function,
      required: true
    },
    index: {
      type: Number,
      required: true
    },
    updateTodo: {
      type: Function,
      required: true
    }
  },
  data(){
    return {
      
    }
  },
  // computed: {
  //   isCom () {
  //     return this.todo.isCompleted 
  //   }
  // },
  setup(props) {
    const bgColor = ref('white')
    const myColor = ref('black')
    const isShow = ref(false)
    // 鼠标进入和离开事件的回调函数
    const mouseHandler = (flag: boolean) => {
      if(flag){
        // 鼠标进入
        bgColor.value = 'pink'
        myColor.value = 'white'
        isShow.value = true
      }else{
        // 鼠标离开
        bgColor.value = 'white'
        myColor.value = 'black'
        isShow.value = false
      }
    }
    // 删除数据的方法
    const delTodo = () => {
      if(window.confirm('确定要删除吗?')){
        props.deleteTodo(props.index)
      }
    } 
    // 计算属性方式---让当前复选框选中
    const isCom = computed({
      get(){
        return props.todo.isCompleted
      },
      set(val){
        props.updateTodo(props.todo, val)
      }
    })
    return {
      mouseHandler,
      bgColor,
      myColor,
      isShow,
      delTodo,
      isCom
    }
  }
})
</script>

<style scoped>
li{
  list-style:none;
  height: 36px;
  line-height: 36px;
  padding: 0 5px;
  border-bottom: 1px solid #ddd;
}
li label{
  float: left;
  cursor: pointer;
}
li label li input{
  vertical-align:middle;
  margin-right: 6px;
  position: relative;
  top: -1px;
}
li button{
  float: right;
  /* display: none; */
  margin-top: 3px;
}
li:before{
  content: initial;
}
li:last-child{
  border-bottom: none;
}
</style>

components 下的 Footer.vue

<template>
  <div class="todo-footer">
    <label>
      <input type='checkbox' v-model="isCheckAll" />
    </label>
    <span><span>已完成{{count}}</span> /全部{{todos.length}} </span>
    <button class='btn btn-danger' @click="clearAllCompletedTodos">清除已完成任务</button>
  </div>
</template>

<script lang='ts'>
import { defineComponent,computed } from 'vue'
import {Todo} from '../types/todo'

export default defineComponent({
  name:'Footer',
  props: {
    todos:{
      type: Array as ()=> Todo[],
      required: true
    },
    checkAll: {
      type: Function, 
      required: true
    },
    clearAllCompletedTodos: {
      type: Function, 
      required: true
    }
  },
  setup(props){
    // 已完成的计算属性操作
    const count = computed(()=>{
      return props.todos.reduce((pre,todo,index)=>pre+(todo.isCompleted?1:0),0)
    })
    const isCheckAll = computed({
      get(){
        return count.value>0&&props.todos.length===count.value
      },
      set(val){
        props.checkAll(val)
      }
    })
    return {
      count,
      isCheckAll
    }
  }
})
</script>

<style scoped>
.todo-footer{
  height: 40px;
  line-height: 40px;
  padding-left: 6px;
  margin-top: 5px;
}

.todo-footer label{
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}
.todo-footer label input{
  position: relative;
  top: -1px;
  vertical-align: middle;
  margin-right: 5px;
}
.todo-footer button{
  float: right;
  margin-top: 5px;
}
</style>

types 下的  todo.ts

// 定义一个接口,约束state的数据类型
export interface Todo{
  id: number,
  title: string,
  isCompleted: boolean
}

utils下的  localStorageUtils.ts

import {Todo} from '../types/todo'

// 保存数据到浏览器的缓存中
export function saveTodos(todos:Todo[]){
  localStorage.setItem('todos_key',JSON.stringify(todos))
}

// 从浏览器缓存读取数据
export function readTodos():Todo[]{
  return JSON.parse(localStorage.getItem('todos_key') || '[]')
}

将 localStorageUtils.ts相关内容全部删除可正常使用!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue3+ts实现todolist功能 的相关文章

  • 如何使用随机数实现自动发扑克牌?

    学习不止 问答不止 一 粉丝问题 二 相关函数说明 1 函数说明 产生随机数的方法很多 常用的是rand srand 来看一下这2个函数的定义 SYNOPSIS include
  • 如何导入符号 emdk?

    我在最新的 Android Studio 中创建了一个新的 android projekt 我想导入和使用 Symbol EMDK 包 虽然我像这样放入 gradle implementation com symbol emdk 9 1 1

随机推荐

  • 一文带您了解软件多租户技术架构

    1 多租户技术概述 随着近几年云计算技术的不断发展和成熟 云计算多租户技术在 SaaS 服务领域获得得快速的发展和广泛的应用 基于多租户技术的业务平台首先要保证不同租户业务的隔离 业务隔离主要包括下面 2 个方面 物理隔离 租户开展业务所依
  • 字符串的字体和显示 (3)

    安卓有三种字符串 String String Array Quantity String Plurals String和String Array容易理解 一个是字符串 一个是字符串数组 通过 String planets res getSt
  • Qt做发布版,解决声音和图片、中文字体乱码问题

    前些天做Qt发布版 发现居然不显示图片 后来才发现原来还有图片的库没加 找找吧 去qt的安装包 我装在了F盘 在F盘F QT qt plugins 找到了plugins 这里面有个 imageformats是图片的库 里面有jpg gif等
  • 谷歌开源代码评审规范:好坏代码应该这样来判断

    谷歌开源了一套代码评审 Code Review 规范 它是谷歌一套通用的工程实战指南 几乎涵盖了所有编程语言与各种类型的项目 这个规范代表了谷歌长期发展以来最佳实战经验的集合 谷歌表示希望开源项目或其他组织能够从这套规范中受益 代码评审 也
  • Docker学习:Docker核心命令

    前言 本讲是从Docker系列讲解课程 单独抽离出来的一个小节 重点介绍八大核心命令和一些常用的辅助命令 比如inspect logs push commit等 如果你想 通过部署Tomcat容器 从查找镜像 到拉取 到运行 最后到移除 来
  • sql server - 将sqlserver安装到虚拟机内

    目录 1 安装 打开虚拟机 1 1 打开vmware 1 2 安装虚拟系统到vmware Windows Server 2016 2 安装SQL server 2014 2 1 把SQL server下载并上传到虚拟机 2 2 安装与配置
  • C++ 虚函数表解析

    C 虚函数表解析 陈皓 http blog csdn net haoel 前言 C 中的虚函数的作用主要是实现了多态的机制 关于多态 简而言之就是用父类型别的指针指向其子类的实例 然后通过父类的指针调用实际子类的成员函数 这种技术可以让父类
  • Web前端学习:jQuery基础 · 小终结【异步处理AJAX】

    目录 一 AJAX介绍 AJAX处理过程 二 AJAX请求 代码演示 案例一 获取txt文本内容 通过页面窗口弹出 案例二 返回json数据 一 AJAX介绍 ajax技术的目的是让javascript发送http请求 与后台通信 获取数据
  • Flask框架-重定向与错误

    在Web服务访问时并不总是能够返回正确的结果 当用户访问了错误的URL 或者传输了错误的请求参数 Web服务就需要返回相关的错误信息进行提示 Flask中针对错误请求的场景提供了相关的API 包括标准错误的响应和标准重定向的响应处理 在We
  • 江波龙深化存储技术优势 紧密结合物联网应用需求创新

    转自 http www chinaflashmarket com Producer Netcom News 142127 云计算 大数据以及移动互联网时代下 全球存储容量以爆发式的速度在增长 根据市场调研机构预测 2020年全球存储容量将从
  • servlet编程会话管理技术

    1 会话管理 浏览器与服务器之间会话过程中产生的会话数据 Cookie特点 1 会话数据放在浏览器端 2 数据类型只能string 而且有大小限制的 3 相对数据存放不安全 Session特点 1 会话数据放在服务器端 服务
  • MES的数据采集方式

    为实现生产车间现场数据的采集 制造业MES系统数据采集方法有手工录入方式和自动化提取采集两大类 主要有以下几类 一 手动方式 1 手工方式 操作员或编程员在MES系统控制面板上 输入特定的触发程序 经DNC服务器的自动翻译 就可得到机床端的
  • Jenkins集成Sonar与Gitlab代码质量检测

    前提默认 安装docker19 与docker compose 安装Jenkins 1 docker compose yaml配置 version 3 services jenkins network mode host 镜像 image
  • 3、Java的If语句与For循环

    一 语句 条件语句 根据不同的条件 执行不同的语句 if if else if else if if else if else if else switch 循环语句 重复执行某些动作 for while do while 1 1 if语句
  • 深度学习算法面试常问问题(三)

    pooling层是如何进行反向传播的 average pooling 在前向传播中 就是把一个patch的值取平均传递给下一层的一个像素 因此 在反向传播中 就是把某个像素的值平均分成n份 分配给上一层 max pooling 在前向传播中
  • 用Odoo创建一个网站

    原贴地址 https www odoo com documentation 10 0 howtos website html 声明 这篇指导假设你有python的知识并安装了Odoo 请注意文件的目录结构 本文的目录结构与原文不同 创建一个
  • 快速打开CMD的几个方法

    1 在开始菜单里面找CMD EXE 很快的哟 2 在资源管理器的地址栏直接键入CMD按回车也能启动CMD 3 资源管理器 按住Shift点右键也能召唤CMD哦 选 在此处打开命令窗口 就行了
  • squirrel-foundation状态机的使用细节

    上一篇文章介绍了stateless4j spring statemachine以及squirrel foundation三款状态机引擎的实现原理 以及我为何选择squirrel foundation作为解决方案 本文主要介绍一下项目中如何使
  • sqlloader出现SQL*Loader-704和ORA-12154的错误

    1 错误描述 生成的sqlloder各个文件完好 权限也具备 但是就是导入oracle数据库的时候报错 错误为 SQL Loader 704 Internal error ulconnect OCIServerAttach 0 ORA 12
  • vue3+ts实现todolist功能

    先看一下实现效果 可以看到内部实现的内容有enter输入 单项删除 全选 以及删除选中项等功能 具体在实现前需要常见有ts的vue3项目 项目创建 具体项目创建 就是 vue create 项目名称 在创建后 选择的时候有vue2和vue3