一、静态网页原型
1、index.html
<!-- * @Description: * @Version: 1.0 * @Autor: Yu * @Date: 2022-01-02 15:18:35 * @LastEditors: Yu * @LastEditTime: 2022-01-02 16:34:19 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>ToDoList</title> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="contonter"> <!-- 头部开始 --> <header> <input type="text" placeholder="请输入你的任务名称,按回车键确认"/> </header> <!-- 头部结束 --> <!-- 内容部分开始 --> <section> <ul> <li><input type="checkbox"/>吃饭<button>删除</button></li> <li><input type="checkbox"/>睡觉<button>删除</button></li> <li><input type="checkbox"/>逛街<button>删除</button></li> <li><input type="checkbox"/>敲代码<button>删除</button></li> </ul> </section> <!-- 内容部分结束 --> <!-- 底部开始 --> <footer> <div class="footer_left"> <input type="checkbox"/>已完成<span class="done">0</span>/全部<span class="all">4</span> </div> <div class="footer_right"> <button>清除已完成任务</button> </div> </footer> <!-- 底部结束 --> </div> </body> </html>
2、index.css
*{ padding: 0; margin: 0; } ul{ list-style: none; } input[type='checkbox']{ width: 15px; height: 15px; vertical-align: middle; } body{ font-size: 18px; color: #434544; } .contonter{ overflow: hidden; width: 1200px; margin: 10px auto; border: 2px solid #E2E2E2; box-sizing: border-box; border-radius: 10px; padding: 20px; } header{ width: 100%; height: 50px; } header input{ width: 100%; height: 100%; padding-left: 10px; box-sizing: border-box; outline: none; border: 1px solid #DFDFDF; border-radius: 5px; } section ul{ margin: 30px 0; border: 1px solid #E9E9E9; border-radius: 5px; } section ul li{ position: relative; height: 45px; line-height: 45px; padding: 0 10px; box-sizing: border-box; border-bottom: 1px solid #E9E9E9; } section ul li:last-of-type{ border-bottom: none; } section ul li:hover{ background-color: rgb(235, 234, 234); cursor: pointer; } section ul li input{ margin-right: 10px; } section ul li button{ position: absolute; top: 10px; right: 10px; height: 30px; padding: 0 10px; line-height: 30px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; } footer{ width: 100%; height: 50px; float: left; line-height: 50px; } .footer_left{ float: left; padding-left: 10px; box-sizing: border-box; } .footer_left input{ margin-right: 20px; cursor: pointer; } .footer_right{ float: right; } .footer_right button{ padding: 0 20px; height: 40px; line-height: 40px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; }
3、效果图
二、使用原生js实现ToDoList
1、index.html
<!-- * @Description: 原生js实现ToDoList * @Version: 1.0 * @Autor: Yu * @Date: 2022-01-02 15:18:35 * @LastEditors: Yu * @LastEditTime: 2022-02-06 19:24:40 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>ToDoList</title> <!-- 引入css文件 --> <link rel="stylesheet" href="./css/index.css"> <!-- 引入js文件 --> <script src="./js/index.js"></script> </head> <body> <div class="contonter"> <!-- 头部开始 --> <header> <input type="text" id="ipt" placeholder="请输入你的任务名称,按回车键确认"/> </header> <!-- 头部结束 --> <!-- 内容部分开始 --> <section> <ul id="lis"> <li class="empty">暂无数据</li> </ul> </section> <!-- 内容部分结束 --> <!-- 底部开始 --> <footer> <div class="footer_left"> <input type="checkbox" id="done"/>已完成<span class="done"></span>/全部<span class="all"></span> </div> <div class="footer_right"> <button id="del_done">清除已完成任务</button> </div> </footer> <!-- 底部结束 --> </div> <!-- js文件 可以放到此处,好处就是不用监听window的onload,直接写js代码 --> <!-- <script src="./js/index.js"></script> --> </body> </html>
2、index.js
/* * @Description: js文件 * @Version: 1.0 * @Autor: Yu * @Date: 2022-01-02 16:48:34 * @LastEditors: Yu * @LastEditTime: 2022-02-06 21:13:48 */ //1、原始写法 // window.οnlοad=function(){ // alert(111) // } //2、原始写法的es6写法 // window.οnlοad=()=>{ // alert(111) // } //3、监听事件写法 // window.addEventListener('load',function(){ // alert(111) // }) //4、立即执行函数 // ;(function () { // alert(111); // })(); //5、监听事件的es6写法 window.addEventListener('load', () => { // 获取元素 const ipt = document.getElementById('ipt') let lis = document.getElementById('lis') const empty = document.getElementsByClassName('empty')[0] let countTask = 0 countAll() isCheckedAll() countDoneTask() delAllDoneTask() /** * @description: 监听输入框的回车按键 * @param {*} * @return {*} * @author: Yu */ ipt.onkeydown = (event) => { if (event.keyCode == 13) { //判断输入的值是否为空 if (ipt.value.trim() == '') return alert('您输入的任务不能为空,请重新输入!') const doneChecked = document.getElementById('done') doneChecked.checked = false empty.style.display = 'none' //创建一个任务 let taskObj = { id: getUuid(), content: ipt.value, done: false, } //创建节点 let li = document.createElement('li') let input = document.createElement('input') input.setAttribute('type', 'checkbox') let txt = document.createTextNode(taskObj.content) let button = createElementWithTxt('button', '删除') li.appendChild(input) li.appendChild(txt) li.appendChild(button) //向节点的后面添加一个任务 //lis.appendChild(li); //向节点的前面添加一个任务 lis.insertBefore(li, lis.children[0]) ipt.value = '' delToDoList() countAll() isCheckedAll() delAllDoneTask() } } /** * @description: 删除一个任务 * @param {*} * @return {*} * @author: Yu */ function delToDoList() { btns = lis.getElementsByTagName('button') for (let i = 0; i < btns.length; i++) { btns[i].onclick = function (e) { if (confirm('确认要删除该任务吗?')) { lis.removeChild(this.parentNode) btns = lis.getElementsByTagName('button') stopPropagation(e) if (btns.length === 0) empty.style.display = 'block' const checkboxs = lis.getElementsByTagName('input') countTask = 0 for (let i = 0; i < checkboxs.length; i++) { if (checkboxs[i].checked) { countTask++ } } countDoneTask() countAll() const doneChecked = document.getElementById('done') if (btns.length === countTask && btns.length !== 0) { doneChecked.checked = true } else { doneChecked.checked = false } } } } } /** * @description: 统计所有的任务的数量 * @param {*} * @return {*} * @author: Yu */ function countAll() { const all = document.getElementsByClassName('all')[0] const btns = lis.getElementsByTagName('button') all.innerText = btns.length } /** * @description: 统计已完成的任务 * @param {*} * @return {*} * @author: Yu */ function countDoneTask() { const done = document.getElementsByClassName('done')[0] done.innerText = countTask } /** * @description: 全选和取消全选 * @param {*} * @return {*} * @author: Yu */ function isCheckedAll() { const doneChecked = document.getElementById('done') const checkboxs = lis.getElementsByTagName('input') doneChecked.onclick = function () { for (let i = 0; i < checkboxs.length; i++) { checkboxs[i].checked = this.checked } if (this.checked) { countTask = checkboxs.length countDoneTask() } else { countTask = 0 countDoneTask() } } for (let i = 0; i < checkboxs.length; i++) { checkboxs[i].onclick = function () { let flag = true countTask = 0 for (let i = 0; i < checkboxs.length; i++) { if (!checkboxs[i].checked) { flag = false break } } for (let i = 0; i < checkboxs.length; i++) { if (checkboxs[i].checked) { countTask++ } } countDoneTask() // 设置全选按钮的状态 doneChecked.checked = flag } } } /** * @description: 清除所有已完成的任务 * @param {*} * @return {*} * @author: Yu */ function delAllDoneTask() { let checkboxs = lis.getElementsByTagName('input') const delDone = document.getElementById('del_done') delDone.onclick = function () { if (checkboxs.length === 0) return alert('请添加任务!') if (confirm('确认要删除所有已完成的任务吗?')) { countTask = 0 for (let i = 0; i < checkboxs.length; i++) { if (checkboxs[i].checked) { lis.removeChild(checkboxs[i].parentNode) i-- } } checkboxs = lis.getElementsByTagName('input') for (let j = 0; j < checkboxs.length; j++) { if (checkboxs[j].checked) { countTask++ } } countDoneTask() btns = lis.getElementsByTagName('button') if (btns.length === 0) { const doneChecked = document.getElementById('done') doneChecked.checked = false empty.style.display = 'block' } countAll() } } } /** * @description: 阻止事件冒泡 * @param {*} * @return {*} * @author: Yu */ function stopPropagation(e) { e = e || window.event if (e.stopPropagation) { //W3C阻止冒泡方法 e.stopPropagation() } else { e.cancelBubble = true //IE阻止冒泡方法 } } /** * @description: 生成唯一id * @param {*} * @return {*} * @author: Yu */ function getUuid() { var s = [] var hexDigits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' for (var i = 0; i < 36; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1) } s[14] = '4' s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1) s[8] = s[13] = s[18] = s[23] = '-' let uuid = s.join('') return uuid } /** * @description: 生成一个带文本的标签 * @param {*} tagName * @param {*} Txt * @return {*} * @author: Yu */ function createElementWithTxt(tagName, Txt) { // 创建元素节点(标签) var node = document.createElement(tagName) // 创建文本节点 var oTxt = document.createTextNode(Txt) // 将文本节点放到元素节点中 node.appendChild(oTxt) // 返回元素节点 return node } /** * @description: 去空 * @param {*} str * @return {*} * @author: Yu */ function trim(str) { return str.replace(/(^\s*)|(\s*$)/g, '') } })
3、index.css
*{ padding: 0; margin: 0; } ul{ list-style: none; } input[type='checkbox']{ width: 15px; height: 15px; vertical-align: middle; } body{ font-size: 18px; color: #434544; } .contonter{ overflow: hidden; width: 1200px; margin: 10px auto; border: 2px solid #E2E2E2; box-sizing: border-box; border-radius: 10px; padding: 20px; } header{ width: 100%; height: 50px; } header input{ width: 100%; height: 100%; padding-left: 10px; box-sizing: border-box; outline: none; border: 1px solid #DFDFDF; border-radius: 5px; } section ul{ margin: 30px 0; border: 1px solid #E9E9E9; border-radius: 5px; } section ul li{ position: relative; height: 45px; line-height: 45px; padding: 0 10px; box-sizing: border-box; border-bottom: 1px solid #E9E9E9; border-radius:5px; } section ul:nth-last-child(1){ border-bottom: none; } section ul li:hover{ background-color: rgb(235, 234, 234); cursor: pointer; } section ul li input{ margin-right: 10px; } section ul li button{ position: absolute; top: 10px; right: 10px; height: 30px; padding: 0 10px; line-height: 30px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; } footer{ width: 100%; height: 50px; float: left; line-height: 50px; } .footer_left{ float: left; padding-left: 10px; box-sizing: border-box; } .footer_left input{ margin-right: 20px; } .footer_right{ float: right; } .footer_right button{ padding: 0 20px; height: 40px; line-height: 40px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; }
5、原生js升级版
;(function () { // 获取元素 const todoData = document.querySelector('#ipt'); const todoList = document.querySelector('#lis'); const emptyData = document.querySelector('.empty'); const delTodoBtn = document.querySelector('#del_done'); const allNumber = document.querySelector('.all'); const doneNumber= document.querySelector('.done'); let todoItems = document.querySelectorAll('.todo-item'); const todoDone = document.querySelector('#done') // 已完成的任务 let done=0; // 执行方法 delTodoAllItem(); checkTodoItem(); doneTaskNumber(); allTaskNumber(); /* 添加任务 */ todoData.onkeypress = (event) => { if (event.which === 13) { if (todoData.value.trim() == '') return alert('请输入任务名称') addTodoItem(); delTodoItem(); checkTodoItem(); doneTaskNumber(); allTaskNumber(); } } /* 添加任务项 */ function addTodoItem(){ let li = document.createElement('li'); let input = document.createElement('input'); let button = document.createElement('button'); const todoContent = document.createTextNode(todoData.value.trim()); const btnDelete = document.createTextNode('删除'); button.appendChild(btnDelete); button.classList.add('del-item'); input.setAttribute('type', 'checkbox') li.appendChild(input); li.appendChild(todoContent); li.appendChild(button); li.classList.add('todo-item'); todoList.insertBefore(li, todoList.children[0]); todoData.value = ''; emptyData.style.display = 'none'; todoItems = document.querySelectorAll('.todo-item'); todoDone.checked=false; } /* 删除任务项 */ function delTodoItem(){ const delTodo = document.querySelector('.del-item'); delTodo.addEventListener('click',()=>{ if (!confirm('确认要删除该任务吗?')) return delTodo.parentNode.remove(); doneTaskNumber(); allTaskNumber(); if (todoItems.length === done) { todoDone.checked = true } if (todoList.children.length!= 1) return emptyData.style.display = 'block'; todoDone.checked = false; }) } /* 删除任务列表 */ function delTodoAllItem(){ delTodoBtn.addEventListener('click',()=>{ if (done <= 0) return alert('请先添加任务') if (!confirm('确认要删除已完成任务吗?')) return todoItems.forEach(v=>{ if (v.querySelector('input').checked) { v.remove() } }) doneTaskNumber(); allTaskNumber(); if (todoList.children.length != 1) return emptyData.style.display = 'block'; todoDone.checked = false; }) } /* 全选反选 */ function checkTodoItem(){ let todoItemsInput = document.querySelectorAll('.todo-item input'); const todoCheck = document.querySelector('.todo-item input'); todoDone.addEventListener('click',()=>{ if (todoItemsInput.lenth === 0) return todoItemsInput.forEach((v) => (v.checked = todoDone.checked)) doneTaskNumber(); }) if (!todoCheck) return todoCheck.addEventListener('click', () => { todoItemsInput = document.querySelectorAll('.todo-item input'); for (let i = 0; i < todoItemsInput.length; i++) { todoDone.checked = true if (!todoItemsInput[i].checked) { todoDone.checked = false; break; } } doneTaskNumber(); }) } /* 已完成数量 */ function doneTaskNumber(){ done = 0; const todoItemsInput = document.querySelectorAll('.todo-item input'); todoItemsInput.forEach(v=>{ if(v.checked) done++ }) doneNumber.innerText=done } /* 全部任务数量 */ function allTaskNumber(){ todoItems = document.querySelectorAll('.todo-item'); allNumber.innerText = todoItems.length; } })();
三、使用jQuery实现ToDoList
1、index.html
<!-- * @Description: jQuery实现 * @Version: 1.0 * @Autor: Yu * @Date: 2022-01-02 15:18:35 * @LastEditors: Yu * @LastEditTime: 2022-07-30 16:19:28 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>ToDoList</title> <!-- 引入css文件 --> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="contonter"> <!-- 头部开始 --> <header> <input type="text" id="ipt" placeholder="请输入你的任务名称,按回车键确认"/> </header> <!-- 头部结束 --> <!-- 内容部分开始 --> <section> <ul id="lis"> <li class="empty">暂无数据</li> </ul> </section> <!-- 内容部分结束 --> <!-- 底部开始 --> <footer> <div class="footer_left"> <input type="checkbox" id="done"/>已完成<span class="done">0</span>/全部<span class="all">0</span> </div> <div class="footer_right"> <button id="del_done">清除已完成任务</button> </div> </footer> <!-- 底部结束 --> </div> <!-- 引入js文件 --> <script src="./lib/jquery-3.2.0.min.js"></script> <script src="./js/index.js"></script> </body> </html>
2、index.css
*{ padding: 0; margin: 0; } ul{ list-style: none; } input[type='checkbox']{ width: 15px; height: 15px; vertical-align: middle; } body{ font-size: 18px; color: #434544; } .contonter{ overflow: hidden; width: 1200px; margin: 10px auto; border: 2px solid #E2E2E2; box-sizing: border-box; border-radius: 10px; padding: 20px; } header{ width: 100%; height: 50px; } header input{ width: 100%; height: 100%; padding-left: 10px; box-sizing: border-box; outline: none; border: 1px solid #DFDFDF; border-radius: 5px; } section ul{ margin: 30px 0; border: 1px solid #E9E9E9; border-radius: 5px; } section ul li{ position: relative; height: 45px; line-height: 45px; padding: 0 10px; box-sizing: border-box; border-bottom: 1px solid #E9E9E9; border-radius:5px; } section ul:nth-last-child(1){ border-bottom: none; } section ul li:hover{ background-color: rgb(235, 234, 234); cursor: pointer; } section ul li input{ margin-right: 10px; } section ul li button{ position: absolute; top: 10px; right: 10px; height: 30px; padding: 0 10px; line-height: 30px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; } footer{ width: 100%; height: 50px; float: left; line-height: 50px; } .footer_left{ float: left; padding-left: 10px; box-sizing: border-box; } .footer_left input{ margin-right: 20px; } .footer_right{ float: right; } .footer_right button{ padding: 0 20px; height: 40px; line-height: 40px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; }
3、index.js
$(function () { /* 输入框填写任务名称按回车添加任务 */ $('#ipt').keyup(function (event) { if (event.keyCode == 13) { if ($('#ipt').val().trim() === '') return alert('请输入任务名称') addTodoItem() delTodoItem() isCheckedToDo() doneTaskNumber() allTaskNumber() delAllTask() } }) }) /* 添加任务项 */ function addTodoItem() { const li = ` <li class="todo-item"> <input type="checkbox"> ${$('#ipt').val().trim()} <button class="del-item">删除</button> </li>` $('#lis').prepend(li) $('#ipt').val('') $('.empty').css('display', 'none') $('#done').prop('checked', false) } /* 删除任务项 */ function delTodoItem() { $('.del-item').off('click') $('.del-item').on('click', function () { if (!confirm('确认要删除该任务吗?')) return $(this).parent().remove() doneTaskNumber() allTaskNumber() if ($('.todo-item input').length === $('.todo-item input:checked').length) $('#done').prop('checked', true) if ($('#lis').children().length != 1) return $('.empty').css('display', 'block') $('#done').prop('checked', false) }) } /* 全选和反选 */ function isCheckedToDo(){ $('#done').click(function () { doneTaskNumber() $('.todo-item input').each(function () { $(this).prop('checked', $('#done').prop('checked')) }) }) iptArr = $('.todo-item input') iptArr.click(function () { doneTaskNumber() for (let i = 0; i < iptArr.length; i++) { $('#done').prop('checked', true) if (!iptArr[i].checked) { $('#done').prop('checked', false) break } } }) } /* 已完成任务 */ function doneTaskNumber(){ let count = 0; count = $('.todo-item input:checked').length; $('.done').text(count); } /* 全部任务 */ function allTaskNumber(){ $('.all').text($('.todo-item input').length) } /* 清除所有选中任务 */ function delAllTask(){ $('#del_done').off('click') $('#del_done').click(function(){ if ($('.todo-item input').length <= 0) return alert('请先添加任务') if ($('.todo-item input:checked').length <= 0 ) return alert('还没有已完成任务') if (!confirm('确认要删除该任务吗?')) return $('.todo-item input:checked').parent().remove() doneTaskNumber() allTaskNumber() if ($('#lis').children().length != 1) return $('.empty').css('display', 'block') $('#done').prop('checked', false) }) }
四、使用vue实现ToDoList
1、使用vue-cli创建项目
注意使用vue3
2、App
<template> <TodoList/> </template> <script> import TodoList from './views' export default { name: 'App', components: { TodoList } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; } *{ padding: 0; margin: 0; } ul{ list-style: none; } input[type='checkbox']{ width: 15px; height: 15px; vertical-align: middle; } body{ font-size: 18px; color: #434544; } </style>
3、header
<template> <header> <input type="text" id="ipt" v-model.trim="userTask" @keyup.enter="addToDoList" placeholder="请输入你的任务名称,按回车键确认"/> </header> </template> <script> import { ref } from 'vue' export default { name:'Header', setup(props,{emit}) { let userTask=ref('') /* 添加任务 */ function addToDoList(){ if(userTask.value==='') return alert('请输入任务名称') emit('userTask', userTask) userTask.value = '' } return{ userTask, addToDoList } } } </script> <style scoped> header{ width: 100%; height: 50px; } header input{ width: 100%; height: 100%; padding-left: 10px; box-sizing: border-box; outline: none; border: 1px solid #DFDFDF; border-radius: 5px; } </style>
4、list
<template> <section> <ul id="lis"> <Item @delToDoListItemById='delToDoListItemById' @changeCheckedToDoItem='changeCheckedToDoItem'/> </ul> </section> </template> <script> import Item from '@/components/item' export default { name:'List', components:{ Item }, setup(props,{emit}) { /* 删除当前任务 */ function delToDoListItemById(delToDoListItemById){ emit('delToDoListItemById', delToDoListItemById) } /* 改变当前任务选中状态 */ function changeCheckedToDoItem(changeCheckedToDoItem){ emit('changeCheckedToDoItem', changeCheckedToDoItem) } return{ delToDoListItemById, changeCheckedToDoItem } } } </script> <style scoped> section ul{ margin: 30px 0; border: 1px solid #E9E9E9; border-radius: 5px; } </style>
5、item
<template> <div> <li v-if="userTaskItem.length===0" class="empty">暂无数据</li> <li v-else class="todo-item" v-for="item in userTaskItem" :key="item.id"> <input type="checkbox" @change="changeCheckedToDoItem(item.id)" :checked='item.done'> {{item.value}} <button class="del-item" @click="delToDoListItemById(item.id)">删除</button> </li> </div> </template> <script> import { inject } from 'vue' export default { name:'Item', setup(props,{emit}) { let userTaskItem = inject('userTaskItem') /* 删除当前任务 */ function delToDoListItemById(id){ if (!confirm('确认要删除该任务吗?')) return emit('delToDoListItemById', id) } /* 改变当前任务选中状态 */ function changeCheckedToDoItem(id){ emit('changeCheckedToDoItem', id) } return{ userTaskItem, delToDoListItemById, changeCheckedToDoItem } } } </script> <style scoped> section ul li{ position: relative; height: 45px; line-height: 45px; padding: 0 10px; box-sizing: border-box; border-bottom: 1px solid #E9E9E9; border-radius:5px; } section ul li:last-of-type{ border-bottom: none; } section ul:nth-last-child(1){ border-bottom: none; } section ul li:hover{ background-color: rgb(235, 234, 234); cursor: pointer; } section ul li input{ margin-right: 10px; } section ul li button{ position: absolute; top: 10px; right: 10px; height: 30px; padding: 0 10px; line-height: 30px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; } </style>>
6、footer
<template> <footer> <div class="footer_left"> <input ref="myRef" type="checkbox" id="done" @click="checkedAllToDoList"/>已完成<span class="done">{{ doneTaskNumber }}</span>/全部<span class="all">{{userTaskItem.length}}</span> </div> <div class="footer_right"> <button id="del_done" @click="delAllDoneTask">清除已完成任务</button> </div> </footer> </template> <script> import { inject,ref,computed,watch } from 'vue' export default { name:'Footer', setup(props,{emit}) { let userTaskItem = inject('userTaskItem') const myRef = ref(null); /* 全选 */ function checkedAllToDoList(){ emit('checkedAllToDoList', myRef.value.checked) } /* 已完成任务数量 */ const doneTaskNumber = computed(() => { return userTaskItem.value.filter(v=>v.done===true).length }) /* 判断是否全选 */ watch(doneTaskNumber, (newValue) => { if(newValue!==0 && newValue===userTaskItem.value.length){ myRef.value.checked=true }else{ myRef.value.checked=false } }) /* 添加任务时重置全选为false */ watch(userTaskItem, (newValue) => { if(newValue.length>doneTaskNumber.value){ myRef.value.checked=false }else if(newValue.length!==0 && newValue.length===doneTaskNumber.value){ myRef.value.checked=true }else{ myRef.value.checked=false } },{deep:true}) /* 清除所有已完成的任务 */ function delAllDoneTask(){ if(userTaskItem.value.length===0) return if (!confirm('确认要删除该任务吗?')) return emit('delAllDoneTask', delAllDoneTask) } return{ userTaskItem, doneTaskNumber, checkedAllToDoList, myRef, delAllDoneTask } } } </script> <style scoped> footer{ width: 100%; height: 50px; float: left; line-height: 50px; } .footer_left{ float: left; padding-left: 10px; box-sizing: border-box; } .footer_left input{ margin-right: 20px; } .footer_right{ float: right; } .footer_right button{ padding: 0 20px; height: 40px; line-height: 40px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; } </style>
7、index
<template> <div class="contonter"> <Header @userTask="userTask"/> <List @delToDoListItemById='delToDoListItemById' @changeCheckedToDoItem='changeCheckedToDoItem'/> <Footer @delAllDoneTask='delAllDoneTask' @checkedAllToDoList='checkedAllToDoList'/> </div> </template> <script> import { provide, ref } from 'vue' import Header from '@/components/header' import List from '@/components/list' import Footer from '@/components/footer' export default { components:{ Header, List, Footer }, setup() { let userTaskItem=ref([]) /* 添加任务 */ function userTask(userTask){ userTaskItem.value.unshift({ id:userTaskItem.value.length+1, value:userTask.value, done:false }) } /* 删除当前任务 */ function delToDoListItemById(id){ userTaskItem.value=userTaskItem.value.filter(v=>v.id!==id) } /* 改变当前任务选中状态 */ function changeCheckedToDoItem(id){ userTaskItem.value.forEach(v=>{ if (v.id===id) { v.done=!v.done } }) } /* 清除所有已完成的任务 */ function delAllDoneTask(){ userTaskItem.value=userTaskItem.value.filter(v=>v.done===false) } /* 全选 */ function checkedAllToDoList(done){ userTaskItem.value.filter(v=>v.done = done) } provide('userTaskItem',userTaskItem) return{ userTask, delToDoListItemById, changeCheckedToDoItem, delAllDoneTask, checkedAllToDoList } } } </script> <style scoped> .contonter{ overflow: hidden; width: 1200px; margin: 10px auto; border: 2px solid #E2E2E2; box-sizing: border-box; border-radius: 10px; padding: 20px; } </style>>
五、使用react实现ToDoList
1、创建react脚手架
-
检查npm和node是否安装
-
npm install -g create-react-app
-
create-react-app hello-react
-
cd hello-react
-
npm start或者yarn start
2、如下载慢请将npm或yarn镜像切换成taobao镜像
NPM CONFIG SET REGISTRY HTTPS://REGISTRY.NPM.TAOBAO.ORG |
---|
// 配置后可通过下面方式来验证是否成功 |
npm config get registry |
//安装yarn,将yarn镜像切换为淘宝镜像 npm i -g -yarn yarn --vresion // 查看下载源 yarn config get registry // 更换为淘宝源 yarn config set registry https://registry.npm.taobao.org
3、App
import React, { Component } from 'react' import Header from './components/header' import List from './components/list' import Footer from './components/footer' import './App.css' export default class App extends Component { state = { todos: [ { id: 1, name: '吃饭', done: true }, { id: 2, name: '睡觉', done: false }, { id: 3, name: '打代码111', done: true }, ], } /** * @description: 添加item * @param {*} * @return {*} * @author: Yu */ addListItem = (value) => { let { todos } = this.state let newTodos = { id: todos.length + 1, name: value, done: false } this.setState({todos: [newTodos, ...todos] }) } /** * @description: 修改状态 * @param {*} * @return {*} * @author: Yu */ updataDone=(id,done)=>{ const newTodos= this.state.todos.map(v=>{ if(v.id===id){ return {...v,done} } return v }) this.setState({ todos: newTodos }) } /** * @description: 删除item * @param {*} * @return {*} * @author: Yu */ removeListItem=(id)=>{ const newTodos= this.state.todos.filter(v=>{ return v.id!==id }) this.setState({ todos:newTodos }) } /** * @description: 全选 * @param {*} * @return {*} * @author: Yu */ checkedAll=(done)=>{ const newTodos=this.state.todos.map(v=>{ return {...v,done} }) this.setState({ todos: newTodos }) } /** * @description: 删除所有选中的内容 * @param {*} * @return {*} * @author: Yu */ removeAllChecked=()=>{ const newTodos=this.state.todos.filter(v=>!v.done) this.setState({ todos:newTodos }) } render() { return ( <div className="contonter"> <Header addListItem={this.addListItem}></Header> <List todos={this.state.todos} updataDone={this.updataDone} removeListItem={this.removeListItem} ></List> <Footer todos={this.state.todos} checkedAll={this.checkedAll} removeAllChecked={this.removeAllChecked} ></Footer> </div> ) } }
*{ padding: 0; margin: 0; } ul{ list-style: none; } input[type='checkbox']{ width: 15px; height: 15px; vertical-align: middle; } body{ font-size: 18px; color: #434544; } .contonter{ overflow: hidden; width: 1200px; margin: 10px auto; border: 2px solid #E2E2E2; box-sizing: border-box; border-radius: 10px; padding: 20px; }
4、header
import React, { Component } from 'react' import PropType from 'prop-types' import './index.css' export default class index extends Component { static propTypes={ addListItem:PropType.func.isRequired } /** * @description: 监听键盘按下事件 * @param {*} * @return {*} * @author: Yu */ handleKeyUp=(event)=>{ const {target,keyCode}=event //判断是否按得是回车键 if (keyCode!==13) return //判断用户有没有输入值 if (target.value.trim()==='') { alert("您输入的值不能为空,请重新输入!") return } //将用户输入的值传递过去 this.props.addListItem(target.value) //将用户输入的值清空 target.value="" } render() { return ( <header> <input type="text" onKeyUp={this.handleKeyUp} placeholder="请输入你的任务名称,按回车键确认"/> </header> ) } }
header{ width: 100%; height: 50px; } header input{ width: 100%; height: 100%; padding-left: 10px; box-sizing: border-box; outline: none; border: 1px solid #DFDFDF; border-radius: 5px; }
5、list
import React, { Component } from 'react' import PropType from 'prop-types' import Item from '../item' import './index.css' export default class index extends Component { static propTypes={ todos:PropType.array.isRequired, updataDone:PropType.func.isRequired, removeListItem:PropType.func.isRequired } render() { const {todos,updataDone,removeListItem}=this.props return ( <section> <ul className={todos.length>0?'empty':''}> { todos.map(v=>{ return <Item key={v.id} {...v} updataDone={updataDone} removeListItem={removeListItem} ></Item> }) } </ul> </section> ) } }
section ul{ margin: 30px 0; } .empty{ border: 1px solid #E9E9E9; border-radius: 5px; }
6、item
import React, { Component } from 'react' import './index.css' export default class index extends Component { state={ mouse:false } /** * @description: 鼠标移入移出 * @param {*} * @return {*} * @author: Yu */ mouseInOut=(flag)=>{ return ()=>{ this.setState({ mouse:flag }) } } /** * @description: updataDone * @param {*} * @return {*} * @author: Yu */ updataDone=(id)=>{ return (event)=>{ this.props.updataDone(id,event.target.checked) } } /** * @description: removeListItem * @param {*} * @return {*} * @author: Yu */ removeListItem=(id)=>{ return ()=>{ if (window.confirm("确认删除这个任务吗?")) { this.props.removeListItem(id) } } } render() { const {id,name,done} = this.props const {mouse} = this.state return ( <li onMouseLeave={this.mouseInOut(false)} onMouseEnter={this.mouseInOut(true)}> <input type="checkbox" checked={done} onChange={this.updataDone(id)}/>{name}<button onClick={this.removeListItem(id)} style={{display:mouse?'block':'none'}}>删除</button> </li> ) } }
section ul li{ position: relative; height: 45px; line-height: 45px; padding: 0 10px; box-sizing: border-box; border-bottom: 1px solid #E9E9E9; } section ul li:last-of-type{ border-bottom: none; } section ul li:hover{ background-color: rgb(235, 234, 234); cursor: pointer; } section ul li input{ margin-right: 10px; } section ul li button{ position: absolute; top: 10px; right: 10px; height: 30px; padding: 0 10px; line-height: 30px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; }
7、footer
import React, { Component } from 'react' import './index.css' export default class index extends Component { /** * @description: 全选 * @param {*} * @return {*} * @author: Yu */ checkedAll=(event)=>{ this.props.checkedAll(event.target.checked) } /** * @description: 清除所有 * @param {*} * @return {*} * @author: Yu */ removeAllChecked=()=>{ this.props.removeAllChecked() } render() { const {todos}=this.props const sum=todos.reduce((pre,item)=>{ if(item.done){ pre++ } return pre },0) return ( <footer> <div className="footer_left"> <input onChange={this.checkedAll} type="checkbox" checked = {sum === todos.length && todos.length!==0?true:false}/>已完成<span className="done">{sum}</span>/全部<span className="all">{todos.length}</span> </div> <div className="footer_right"> <button onClick={this.removeAllChecked}>清除已完成任务</button> </div> </footer> ) } }
footer{ width: 100%; height: 50px; float: left; line-height: 50px; } .footer_left{ float: left; padding-left: 10px; box-sizing: border-box; } .footer_left input{ margin-right: 20px; cursor: pointer; } .footer_right{ float: right; } .footer_right button{ padding: 0 20px; height: 40px; line-height: 40px; color: #fff; background-color: #D5514C; border-radius: 5px; border: none; cursor: pointer; }
六、效果
帅哥美女点个赞吧,源码:ToDoList: 使用不同版本实现方式来实现ToDoList