先看一下实现效果:

可以看到内部实现的内容有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-lineconst 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 = isCompletedconsole.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.valueif(!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') || '[]')
}

vue3+ts实现todolist功能相关推荐

  1. springboot+vue3+ts实现一个点赞功能

    前端:vite+vue3+ts+elementplus+less 后端:springboot2.7.6+mybatisplus 最终效果大致如下: 后端: 引入pom依赖 <dependenci ...

  2. 2、Gantt 入门 (vue3 + ts)

    首先把 gantt 官网下载的相关文件放入 resource 文件中. 下载地址:https://dhtmlx.com/docs/products/dhtmlxGantt/download.shtml ...

  3. Vue3 + TS(一)- 邂逅Vue

    一.认识Vue.js Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架. 1.1 Vue 的安装 安装方式: CDN引入: 下载Vue的js文件,并手动引入: 通过 ...

  4. vue3+ts实现视频根据时间轴截取,并可以通过传入截取起止时间进行当前剪辑的回显

    公司提出想做一个视频编辑功能,每次只裁剪一段即可,UI同时也想实现时间轴为关键帧图片的效果,从网上也没找到合适的组件,简单思考后觉得并不难,决定自己封装一个吧.组件涉及到的只有vue3+ts+scss ...

  5. 《Vue3+TS》开发一个自己的起始页(二)chrome插件化

    前言 各位小伙伴们大家好,求关注,求收藏,求点赞: 另外为自己拉一波票:https://bbs.csdn.net/topics/603955887?spm=1001.2014.3001.6953,诚实 ...

  6. Vue——vue3+ts

    ![组合式API](https://img-blog.csdnimg.cn/65bc865af9284374ad6ee6ad90e9e2de.png)## 1.vues新增了setup API: se ...

  7. 手把手教你从0到1搭建vue3+ts+vite+element-plus简易后台管理系统

    准备工作 首先请确保你的node.js版本>=12.0.0 因为vite的兼容性,Vite 需要 Node.js 版本 >= 12.0.0. 如果你不知道你的node.js的版本是多少,请 ...

  8. Vue3+TS+Vite无法使用require导入图片的解决方法

    Vue3+TS+Vite无法使用require导入图片的解决方法 问题描述, 当使用const xxx = require('xxx')浏览器会报错, 为啥使用vue-cli脚手架时不会出问题? 是因 ...

  9. 从零开始的大屏可视化拖拽项目(vue3 + TS + EGG)

    项目简介: 平台内置大量Echart图表,可以使用现有的图表进行拖拽编辑,生成一个单页大屏项目,支持导出,生成独立的大屏(不依赖于平台).单图表支持背景色.背景图.大小.API接口(支持定时刷新),大 ...

最新文章

  1. 手写识别python_Python徒手实现识别手写数字—图像识别算法(K最近邻)
  2. extern C 作用
  3. JAVA异常处理正常的逻辑_JAVA异常的思考与总结
  4. 腾讯开源最大规模多标签图像数据集,刷新行业数据集基准
  5. bartender实现即扫即打印功能扫描完后自动打印_日本彩色激光打印机推荐人气排名15款...
  6. 【博客项目】—登录功能实现( 四)
  7. [渝粤教育] 西南科技大学 旅客运输组织 在线考试复习资料
  8. 给网站设置ICO图标
  9. Flink SQL 在快手的扩展和实践
  10. Linux配置java环境(超详细)
  11. 蚂蚁金服 CEO 突然辞职!去向很意外。。。
  12. Ffmpeg常用转码命令
  13. 学生信息管理系统(一)——登录窗体
  14. 中国互联网大人物直播简史
  15. 激光SLAM:LOAM-Livox 算法研究(1) -- 功能包编译与验证
  16. python画椭圆形_Python易学就会(五)turtle绘制椭圆与递归
  17. lae界面开发工具入门之介绍九--简单逻辑篇
  18. 房屋出租系统(第二版)
  19. python 本地音乐播放器制作过程
  20. 组装计算机需要哪九件部件,组装各种电脑配件的规则是什么?组装电脑各配件规则介绍...

热门文章

  1. apicloud打开地图导航
  2. js 大数字单位处理 千、万、千万、亿....
  3. 杭电多校第六场个人补题6 7 9 10 12
  4. 假定网络中的路由器B的路由表有如下的项目(这三列分别表示“目的网络”、“距离”和“下一跳路由器”):
  5. 还在为图片转Excel而烦恼?6种转换方法让你3秒实现转换
  6. Spring cloud 和 Spring Boot 升级到F版和2.x遇到的问题。
  7. mysql general bin区别_MySQL_Mysql常见问题集锦,1,utf8_bin跟utf8_general_ci的区别 - phpStudy...
  8. 安装jupyter步骤
  9. Tk应用程序:密码输入框
  10. 光纤中的多种光学模式芯径_单模光纤和多模光纤的区别特点?选择哪个好?