1.需求:

实现一个如下页面:

  • 最上面是输入框,后面是add按钮,输入文本点击add按钮,在下面就会出现一行,下面出现的每行最前面是两个按钮,然后后面是todo(要做的事)
  • 第一个按钮是完成按钮,第二个按钮是删除按钮,点击完成按钮后这一行虽然不会消失,但是这一行会有一条横线在上面表示完成,点击删除按钮后这一行的数据就会消失不见
  • 第三个按钮是修改,点击修改即可修改todo中的内容,修改完成后回车或按界面其他地方即可保存
  • 两个按钮后面的第一个是todo,第二个是发布时间

2.实现代码:

HTML:

 <!-- author: wyb -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js todo</title>
<style>
*{
margin: 0;
padding: 0;
}
.container{
width: 60%;
margin: 0 auto;
}
.button{
margin-right: 5px;
}
.complete{
color: red;
text-decoration: line-through;
}
.pub-time{
margin-left: 15px;
}
</style>
</head>
<body> <div class="container">
<!-- todo输入框 -->
<div class="todo-form">
<input type="text" id="input">
<button id="button-add">add</button>
</div>
<!-- todo列表 -->
<div id="todo-list">
<!-- 示例todo -->
<div class="todo-cell">
</div>
</div>
</div> <script src="todo.js"></script>
</body>
</html>

JavaScript:

 // 封装输出
var log = function() {
console.log.apply(console, arguments)
}; // 字符串处理:
var todoTemplate = function (todo) {
// 下面是JavaScript中的字符串替换:
var t = `<div class="todo-cell"><button class="button-complete button">完成</button><button class="button-delete button">删除</button><button class="button-update button">编辑</button><span contenteditable='false' class="todo-label">${todo.task}</span><span class="pub-time">发布时间: ${todo.time}</span>`;
return t;
}; // 插入新元素
var insertTodo = function (todo) {
// 获得todo-cell的HTML字符串:
var todoItem = todoTemplate(todo); var todoList = document.querySelector("#todo-list");
todoList.insertAdjacentHTML('beforeend', todoItem);
}; // 开关一个元素的某个class
var toggleClass = function(element, className) {
if (element.classList.contains(className)) {
element.classList.remove(className)
} else {
element.classList.add(className)
}
}; // 得到当前时间
var currentTime = function () {
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth() + 1;
var day = d.getDate();
var hour = d.getHours();
var minute = d.getMinutes();
var second = d.getSeconds();
// 时间格式处理
if(minute <= 9){
minute = "0" +minute
}
if(second <= 9){
second = "0" +second
} var timeString = `${year}/${month}/${day} ${hour}:${minute}:${second}`;
log("now time is: ", timeString);
return timeString
}; // 返回自己在父元素中的下标
var indexOfElement = function(element) {
var parent = element.parentElement;
for (var i = 0; i < parent.children.length; i++) {
var e = parent.children[i];
if (e === element) {
return i
}
}
}; // 保存 todoList
var saveTodos = function() {
var s = JSON.stringify(todoArray);
localStorage.todoArray = s;
}; var loadTodos = function() {
var s = localStorage.todoArray;
return JSON.parse(s);
}; // 事件处理相关:
// 响应事件函数:
var bindEventAdd = function () {
var buttonAdd = document.getElementById("button-add");
buttonAdd.addEventListener('click', function () {
log("button-add click"); // 获得todo的值:
var task = document.getElementById("input").value;
// log(task);
// 获得todo对象
var todo = {
'task': task,
'time': currentTime(),
};
// 将数据存入数组中
todoArray = loadTodos();
todoArray.push(todo);
saveTodos(); // 插入todo-list:
insertTodo(todo)
});
}; var bindEventEnter = function(){
var todoList = document.querySelector("#todo-list");
todoList.addEventListener('keydown', function (event) {
log('todo keydown: ', event, event.target);
var target = event.target;
if(event.key === 'Enter') {
log('按了回车');
// 失去焦点
target.blur();
// 阻止默认行为的发生, 也就是不插入回车
event.preventDefault();
// 更新todo
var index = indexOfElement(target.parentElement);
log('update index: ', index);
// 把元素在 todoList 中更新
todoArray = loadTodos();
todoArray[index-1].task = target.innerText;
saveTodos();
}
});
}; var bindEventButton = function () {
// bindEventButton -> 复制todo所在div中的3个按钮的响应
var todoList = document.querySelector("#todo-list");
todoList.addEventListener('click', function (event) {
log('click: ', event, event.target);
// 获得点击对象和其父元素(todo的div)
var target = event.target;
var todoDiv = target.parentElement; // complete和delete和update的具体操作:
if(target.classList.contains('button-complete')) {
// 给 todo的div 开关一个状态 class
toggleClass(todoDiv, 'complete')
} else if (target.classList.contains('button-delete')) {
log('delete');
var index = indexOfElement(todoDiv) - 1;
log(index);
// 删除父节点
todoDiv.remove();
// 把元素从 todoArray 删除:
// delete todoArray[index] -> 不是完全删除,删除的数据变成了undefined依然留着数组中
todoArray = loadTodos();
log("delete: ", todoArray[index]);
todoArray.splice(index, 1);
log(todoArray);
saveTodos();
}
else if (target.classList.contains('button-update')) {
log('update');
var cell = target.parentElement;
var span = cell.children[3];
log("span is: ", span);
span.setAttribute("contenteditable", true);
// span.contentEditable = true // 同理
span.focus();
}
});
}; var bindEventBlur = function() {
var todoList = document.querySelector('#todo-list');
todoList.addEventListener('blur', function(event){
log('todo blur: ', event, event.target);
var target = event.target;
if (target.classList.contains('todo-label')) {
log('update and save');
// 让 span 不可编辑
target.setAttribute('contenteditable', 'false');
// 更新todo
var index = indexOfElement(target.parentElement);
log('update index: ', index);
// 把元素在 todoList 中更新
todoArray = loadTodos();
todoArray[index-1].task = target.innerText;
saveTodos()
}
}, true)
}; // 绑定事件:
var bindEvents = function () {
// 添加todo
bindEventAdd();
// 文本框输入todo 按回车保存
bindEventEnter();
// 完成按钮和删除按钮和编辑按钮
bindEventButton();
// 文本框失去焦点后保存todo
bindEventBlur()
}; // 初始化todo:
var initTodos = function () {
var todoArray = loadTodos();
for (var i = 0; i < todoArray.length; i++) {
var todo = todoArray[i];
insertTodo(todo);
}
}; // 存储数据
var todoArray = [];
// 程序主入口
var __main = function (){
// 绑定事件:
bindEvents(); // 程序加载后, 加载 todoArray 并且添加到页面中
initTodos(); }; __main(); // 一些说明:
// 事件委托相关概念
// ===
//
// 问题在于, todo都是运行的时候才添加的元素
// 对于这样的元素, 我们没办法实现绑定事件
// 我们可以把 click 事件绑定在事先存在的父元素上
// 通过父元素响应click事件 调用相应的事件响应函数
// 而事件响应函数会被传入一个参数, 就是事件本身
// 然后在运行的时候通过 event.target 属性(发起事件的元素,例如某个按钮)
// 来检查被点击的对象是否是需要的对象, 这个概念就是事件委托 // 与存储相关的问题:
// ===
// localStorage 可以用来存储字符串数据, 在浏览器关闭后依然存在
// 存储方法如下:
// localStorage.name = 'wyb';
// 关闭浏览器, 注释上一句代码
// 再次用同一个浏览器打开该项目, 仍然能获取到这个值
// log('关闭浏览器后: ', localStorage.name);
// localStorage删除数据:
// localStorage.removeItem("name");
// 注意:
// 利用 localStorage 就可以 存储todo
// 但是 todo存在于array中
// 而 localStorage 只能存储 string 数据
// 所以没办法直接存储todo数据
//
// 可行的办法如下:
// 存储的时候把 array 转换为字符串 读取的时候把字符串转成 array
// 这个过程通常被称之为 序列化 和 反序列化
// 在 js 中, 序列化使用 JSON 格式
//
// var s = JSON.stringify([1, 2, 3, 4]);
// log('序列化后的字符串', typeof s, s);
// var a = JSON.parse(s);
// log('反序列化后的数组', typeof a, a);
// 输出结果:
// 序列化后的字符串 string [1,2,3,4]
// 反序列化后的数组 object Array(4)
//
// 使用 JSON 序列化后, 就可以把 todo存入浏览器的 localStorage 了
//
// 与时间相关的问题: JavaScript中的时间对象 -> Date对象
// ===
// 常用用法如下:
/*
var d = new Date()
d.getFullYear()
年份, 2016
d.getMonth()
月份, 0-11
d.getDate()
日期, 1-31
d.getHours()
小时, 0-23
d.getMinutes()
分钟, 0-59
d.getSeconds()
秒数, 0-59
d.getMilliseconds()
毫秒, 0-999
d.getDay()
星期几, 0-6
*/

3.实现效果:

(1)最开始界面

(2)输入信息点击add

(3)点击完成

(4)点击删除

 

(5)点击编辑 

修改完成后回车后或点击其他页面即可

(6)刷新或关闭网页再次打开依然是之前保存的todo

DOM实战-js todo的更多相关文章

  1. 《Cocos2d-x实战 JS卷 Cocos2d-JS开发》上线了

    感谢大家一直以来的支持! 各大商店均开始销售:京东:http://item.jd.com/11659698.html当当:http://product.dangdang.com/23659808.ht ...

  2. how to get iframe dom in js

    how to get iframe dom in js https://stackoverflow.com/questions/3999101/get-iframes-document-from-ja ...

  3. HTML(.js) – 最简单的方式操作 DOM 的 JS 库

    HTML(.js) 是一个轻量的(压缩后~2kb) JavaScript 库,简化了与 DOM 交互的方法. 这个 JavaScript 库的方法可读性很好,并具有搜索和遍历 DOM 的方法.相比 j ...

  4. 开发成功-cpu-mem监控动态折线图--dom esayui js java

    jsp ------------------------------------------------------------------------------------------- ---- ...

  5. JavaScript DOM实战:创建和克隆元素

    DOM来创建和克隆元素. createElement()和createTextNode() createElement()和createTextNode()做的事情正如它们的名字所说的那样.最常见的J ...

  6. JS操作DOM对象——JS基础知识(四)

    一.JavaScript的三个重要组成部分 (1)ECMAScript(欧洲计算机制造商协会) 制定JS的规范 (2)DOM(文档对象模型)重点学习对象 处理网页内容的方法和接口 (3)BOM(浏览器 ...

  7. JS中的函数、Bom、DOM及JS事件

    本期博主给大家带来JS的函数.Bom.DOM操作,以及JS各种常用的数据类型的相关知识,同时,这也是JavaScript极其重要的部分,博主将详细介绍各种属性的用法和方法. 一.JS中的函数 [函数的 ...

  8. DOM 以及JS中的事件

    [DOM树节点] DOM节点分为三大节点:元素节点,文本节点,属性节点. 文本节点,属性节点为元素节点的两个子节点通过getElment系列方法,可以去到元素节点 [查看节点] 1 document. ...

  9. 从零开始的JS生活(二)——BOM、DOM与JS中的事件

    上回书说道,JS中变量.运算符.分支结构.循环和嵌套循环等内容.本回就由本K给大伙唠唠JS中的BOM.DOM和事件. 一."花心大萝卜"--BOM 1.震惊,FFF团为何对BOM举 ...

随机推荐

  1. Linux环境下 多线程下载 (Python 实现版)

    本文是多年前学习编程时参照一个网友程序的基础之上改写的, 采用Python语音编写, 多线程下载功能, 可以有效提高Linux下原有下载工具中的一些不足,以下给出具体代码. #!/usr/bin/py ...

  2. liunx网络基本命令

    1.ifconfig 查看本机的ip或者网关 更改本机的ip地址 2.sudo reboot    重启 跟 sudo shutdown -r new  是一样的意思

  3. [LeetCode&Python] Problem 590. N-ary Tree Postorder Traversal

    Given an n-ary tree, return the postorder traversal of its nodes' values. For example, given a 3-ary ...

  4. 20155207 2006-2007-2 《Java程序设计》第5周学习总结

    20155207 2006-2007-2 <Java程序设计>第5周学习总结 教材学习内容总结 第八章 语法与继承架构 Java中的错误以对象方式呈现为 java.lang.Throwab ...

  5. Largest Submatrix of All 1’s

    Given a m-by-n (0,1)-matrix, of all its submatrices of all 1’s which is the largest? By largest we m ...

  6. hdu2060-2062

    hdu 2060 斯诺克,读懂题意直接模拟 #include<stdio.h> int main(){ int N; ]; a[]=; ;i<=;i++){ a[i]=(-i)*i/ ...

  7. jquery遍历节点 children(),next(),prev(),siblings()closest() 等一些常用方法...

    函数 描述 .add() 将元素添加到匹配元素的集合中. .andSelf() 把堆栈中之前的元素集添加到当前集合中. .children() 返回被选元素旗下的所有直接子元素 .closest() ...

  8. js循环总结

    js原生的循环有两种,一般的for循环和for...in循环.还有一种常用jQuery.each()循环. 一. js原生循环 a. for循环,代码如下: var myArray = [1,2,3] ...

  9. hasura-graphql 集成 pipelinedb 1.0.0

    pipelinedb 1.0.0 已经是一个标准的pg 扩展了,同时以前的语法也有变动,但是集成进hasura-graphql 更方便了 使用docker-compose 运行 环境准备 docker ...

  10. MongoDB配置成系统服务(Win)

    bin同级目录下创建文件夹data 进入data创建文件夹db和文件夹logs 进入logs创建文件mongo.log 以管理员权限打开cmd,进入mongo的bin目录下执行命令: mongod - ...