学完了ES6,就可以拿一个小项目练练手,todoMVC是一个比较出名的用来练习各种编程语言的项目,可以直接去它官网看。
这里写一个ES6版本的。
点击图片看效果,如果想看Vue2版本的,也可以点这里。
增删改查功能都有,自己看代码。
核心代码:
// 找对象 const newTodoInput = $('.new-todo'); const oTodoList = $('.todo-list'); const oMain = $('.main'); const oFooter = $('.footer'); const oTodoCount = $('.todo-count'); const oClearCompleted = $('.clear-completed'); const oToggleAll = $('.toggle-all'); const oTodoType = $$('.filters a'); // 数据的本地存储 const TODOS_KEY = 'dotos_ES6'; let todosStorage = { get() { return JSON.parse(localStorage.getItem(TODOS_KEY)) || []; }, set(todos) { localStorage.setItem(TODOS_KEY,JSON.stringify(todos)); } } // 全局变量 // 存储数据的todos // let todos = [ // { id: 1, title: '学习', completed: false }, // { id: 2, title: '做饭', completed: true }, // { id: 3, title: '接娃放学', completed: true }, // ] let todos = todosStorage.get(); // 用于区分单击和双击事件 let timer = null; // 初始化渲染 render(todos); // 当enter的时候添加事项 newTodoInput.addEventListener('keyup', (e) => { if (e.key === 'Enter') { // 添加事项 addTodo(); todosStorage.set(todos); // 重新渲染 render(todos); } }) // 因为有很多事项,有很多删除按钮,所以用事件委托性能更高 // ul同时委托了单击事件和双击事件,通过300ms的延迟来判断是单击还是双击 // 如果300ms以后没有单击,则是单击事件,执行对应的代码。 oTodoList.addEventListener('click', function (e) { clearTimeout(timer); timer = setTimeout(function () { const target = e.target; console.log(target); const tempLi = target.closest('li'); // 根据li的id属性找到todos里面该id的数据,数字和字符串的相等用== const todo = todos.find(item => item.id == tempLi.id); // 如果点击的是删除按钮,则删除该事项 if (target.className === 'destroy') { delTodo(todo); } // 如果点击的是复选框按钮,则切换完成和未完成的状态 if (target.className === 'toggle') { todo.completed = target.checked; } // 修复双击下出现输入框编辑的时候,单击输入框的文本,输入框又消失的问题 if (target.className === 'edit') { const oEditing = tempLi.querySelector('.edit'); tempLi.classList.add('editing'); oEditing.focus(); return; } todosStorage.set(todos); render(todos); }, 300); }) // 编辑事项 oTodoList.addEventListener('dblclick', function (e) { // 如果300ms以内又有点击事件,则是双击事件,清掉前面定时器要执行的代码,执行双击对应的代码。 clearTimeout(timer); const target = e.target; console.log(target); const tempLi = target.closest('li'); const todo = todos.find(item => item.id == tempLi.id); if (target.tagName === 'LABEL') { const oEditing = tempLi.querySelector('.edit'); tempLi.classList.add('editing'); oEditing.focus(); // 把输入框的光标放在最后面。 // element.setSelectionRange(selectionStart, selectionEnd [, selectionDirection]); // 如果希望全选输入元素中的文本,你可以使用 HTMLInputElement.select() 方法。 oEditing.setSelectionRange(-1, -1); // 存储输入框以前的数据 const titleBeforeEdit = oEditing.value; oEditing.addEventListener('keyup', function (e) { console.log(e.key) const val = this.value.trim(); // 编辑完成 if (e.key === 'Enter') { if (val === '') { delTodo(todo); } else { todo.title = val; } todosStorage.set(todos); render(todos); } // 取消编辑 if (e.key === 'Escape') { this.value = titleBeforeEdit; render(todos); } }) // 失去焦点的时候,编辑完成 oEditing.addEventListener('blur', function () { const val = this.value.trim(); if (val === '') { delTodo(todo); } else { todo.title = val; } todosStorage.set(todos); render(todos); }) } }) // 删除完成的事项 oClearCompleted.addEventListener('click', function () { todos = todos.filter(todo => !todo.completed); todosStorage.set(todos); render(todos); }) // 点击全选复选框,对所有事项的状态切换 oToggleAll.addEventListener('change', function () { const val = this.checked; for (const todo of todos) { todo.completed = val; } todosStorage.set(todos); render(todos); }) // 根据hash切换a的状态 // 不能点击a的时候获取hash,否则获取的是上一个hash值。 window.onhashchange = function () { // console.log(location.hash); // a被选中的状态 selectedType(); render(todos); } // 找对象的函数 function $(selector) { return document.querySelector(selector); } function $$(selector) { return document.querySelectorAll(selector); } // 渲染事项 function render(todos) { // 对面板的切换 if (todos.length) { oMain.style.display = 'block'; oFooter.style.display = 'block'; } else { oMain.style.display = 'none'; oFooter.style.display = 'none'; } if (!todos.length) { return; }; let renderTodos = []; // 筛选数据 // console.log(location.hash); switch (location.hash) { case '#/active': renderTodos = todos.filter(todo => !todo.completed); break; case '#/completed': renderTodos = todos.filter(todo => todo.completed); break; default: renderTodos = todos; break; } // a的被选中状态 selectedType(); let str = ''; for (const obj of renderTodos) { str += `<li id='${obj.id}' class=${obj.completed ? 'completed' : ''}> <div class="view"> <input class="toggle" type="checkbox" ${obj.completed ? 'checked' : ''}> <label>${obj.title}</label> <button class="destroy"></button> </div> <input class="edit" value="${obj.title}"> </li>` } oTodoList.innerHTML = str; // 得到未完成的事项的个数。 const remainingCount = getRemainingCount(todos); // 状态栏 未完成数量的显示 oTodoCount.innerHTML = `<strong>${remainingCount}</strong> ${remainingCount === 1 ? 'item' : 'items'} left` // 删除完成事项的按钮 // 如果事项的总个数大于未完成事项的个数,则按钮显示 oClearCompleted.style.display = todos.length > remainingCount ? 'block' : 'none'; //对全选复选框的状态设置 if (remainingCount === 0 && todos.length !== 0) { oToggleAll.checked = true; } else { oToggleAll.checked = false; } } // 未完成的事项的个数 function getRemainingCount(todos) { return todos.filter(item => !item.completed).length; } // 添加事项 function addTodo() { let value = newTodoInput.value.trim(); if (!value) return; todos.push({ id: Date.now(), title: value, completed: false }); newTodoInput.value = ''; } // 删除单个事项 function delTodo(todo) { const index = todos.indexOf(todo); if (index !== -1) { todos.splice(index, 1); } } // 事项类别状态设置 function selectedType() { oTodoType.forEach((item, index) => { if (item.hash === location.hash) { oTodoType.forEach(item => item.classList.remove('selected')); item.classList.add('selected'); // console.log(item.hash); } }) }
发表评论:
◎请发表你卖萌撒娇或一针见血的评论,严禁小广告。