一、HTML骨架:
1 <header> 2 <section> 3 <form action="javascript:void(0)" id="form"> 4 <label for="title">ToDoList</label> 5 <input type="text" id="title" name="title" placeholder="添加ToDo" autocomplete="off" /> 6 </form> 7 </section> 8 </header> 9 <section id="sec"> 10 <h2>正在进行 <span id="todocount"></span></h2> 11 <ol id="todolist" class="demo-box"> 12 13 </ol> 14 <h2>已经完成 <span id="donecount"></span></h2> 15 <ul id="donelist"> 16 </ul> 17 </section>
二、写上表现:
1 body { 2 margin: 0; 3 padding: 0; 4 font-size: 16px; 5 background: #CDCDCD; 6 } 7 8 header { 9 height: 50px; 10 background: #333; 11 background: rgba(47, 47, 47, 0.98); 12 } 13 14 section { 15 margin: 0 auto; 16 } 17 18 label { 19 float: left; 20 width: 100px; 21 line-height: 50px; 22 color: #DDD; 23 font-size: 24px; 24 cursor: pointer; 25 font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 26 } 27 28 header input { 29 float: right; 30 width: 60%; 31 height: 24px; 32 margin-top: 12px; 33 text-indent: 10px; 34 border-radius: 5px; 35 box-shadow: 0 1px 0 rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset; 36 border: none 37 } 38 39 input:focus { 40 outline-width: 0 41 } 42 43 h2 { 44 position: relative; 45 } 46 47 span { 48 position: absolute; 49 top: 2px; 50 right: 5px; 51 display: inline-block; 52 padding: 0 5px; 53 height: 20px; 54 border-radius: 20px; 55 background: #E6E6FA; 56 line-height: 22px; 57 text-align: center; 58 color: #666; 59 font-size: 14px; 60 } 61 62 ol, 63 ul { 64 padding: 0; 65 list-style: none; 66 } 67 68 li input { 69 position: absolute; 70 top: 2px; 71 left: 10px; 72 width: 22px; 73 height: 22px; 74 cursor: pointer; 75 } 76 77 p { 78 margin: 0; 79 } 80 81 li p input { 82 top: 3px; 83 left: 40px; 84 width: 70%; 85 height: 20px; 86 line-height: 14px; 87 text-indent: 5px; 88 font-size: 14px; 89 } 90 91 li { 92 height: 32px; 93 line-height: 32px; 94 background: #fff; 95 position: relative; 96 margin-bottom: 10px; 97 padding: 0 45px; 98 border-radius: 3px; 99 border-left: 5px solid #629A9C; 100 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07); 101 } 102 103 ol li { 104 cursor: move; 105 } 106 107 ul li { 108 border-left: 5px solid #999; 109 opacity: 0.5; 110 } 111 112 li a { 113 position: absolute; 114 top: 2px; 115 right: 5px; 116 display: inline-block; 117 width: 14px; 118 height: 12px; 119 border-radius: 14px; 120 border: 6px double #FFF; 121 background: #CCC; 122 line-height: 14px; 123 text-align: center; 124 color: #FFF; 125 font-weight: bold; 126 font-size: 14px; 127 cursor: pointer; 128 } 129 130 footer { 131 color: #666; 132 font-size: 14px; 133 text-align: center; 134 } 135 136 footer a { 137 color: #666; 138 text-decoration: none; 139 color: #999; 140 } 141 142 @media screen and (max-device- 620px) { 143 section { 144 width: 96%; 145 padding: 0 2%; 146 } 147 } 148 149 @media screen and (min- 620px) { 150 section { 151 width: 600px; 152 padding: 0 10px; 153 } 154 }
三、最后添加行为:
1 <script> 2 //选择元素 3 var title_ele = document.getElementById("title"); 4 var todo_list_ele = document.getElementById("todolist"); 5 var done_list_ele = document.getElementById("donelist"); 6 var sec_ele = document.getElementById("sec"); 7 // 初始化todo_list数据; 8 var todo_list = initTodoData(); 9 function initTodoData(){ 10 // 1. localstorage 里面没有数据; 11 if(localStorage.getItem("todo_data") === null){ 12 // 返回基础结构; 13 return { 14 todo:[], 15 done:[] 16 } 17 } 18 // todo_data 里面存在数据; 把数据转换成对象, 然后把对象返回回去; 19 // 特殊情况 : 如果JSON.parse 解析的字符串不符合json规则报错; 20 var obj = null; 21 try{ 22 obj = JSON.parse(localStorage.getItem("todo_data")); 23 }catch( e ){ 24 obj = { 25 todo:[], 26 done:[] 27 } 28 } 29 return obj; 30 } 31 32 // 渲染初始页面结构; 33 function renderTodoList( todo_list ){ 34 // 数据为空不需要渲染; 35 if(todo_list.todo.length === 0 && todo_list.done.length === 0){ 36 return false; 37 } 38 // 拼接字符串; 39 var todo_html = ""; 40 todo_list.todo.forEach( function( item ){ 41 todo_html += ` 42 <li> 43 <input type="checkbox"> 44 <p>${item}</p> 45 <a herf="javascrit:void(0)">-</a> 46 </li>` 47 }) 48 todo_list_ele.innerHTML = todo_html; 49 var done_html = ""; 50 todo_list.done.forEach( function( item ){ 51 done_html += ` 52 <li> 53 <input type="checkbox" checked> 54 <p>${item}</p> 55 <a herf="javascrit:void(0)">-</a> 56 </li>` 57 }) 58 done_list_ele.innerHTML = done_html; 59 } 60 renderTodoList(todo_list); 61 // 删除数据; 62 function removeLocalData( type , value ){ 63 todo_list[type].splice( todo_list[type].indexOf(value) , 1); 64 localStorage.setItem("todo_data" , JSON.stringify(todo_list)); 65 } 66 // 更新数据; 67 function updateLocalData( type , old_value , new_value){ 68 todo_list[type].splice( todo_list[type].indexOf(old_value) , 1 , new_value); 69 localStorage.setItem("todo_data" , JSON.stringify(todo_list)); 70 } 71 72 title_ele.onkeydown = function( evt ){ 73 var e = evt || event; 74 var keyCode = e.which || e.keyCode; 75 if( keyCode === 13){ 76 var value = createTodoElement(); 77 saveLocalData("todo",value); 78 } 79 } 80 //将数据存入localstorage; 81 function saveLocalData( type , value ){ 82 todo_list[type].unshift(value); 83 localStorage.setItem("todo_data" , JSON.stringify(todo_list)); 84 } 85 86 function createTodoElement(){ 87 var title_value = title_ele.value; 88 var todo_li = createEle({ 89 tag : "li", 90 children : [ 91 { 92 tag : "input", 93 attributes : { 94 type : "checkbox" 95 } 96 }, 97 { 98 tag : "p", 99 content : title_value 100 }, 101 { 102 tag : "a", 103 attributes : { 104 href : "javascript:void(0)" 105 }, 106 content : "-" 107 } 108 ] 109 }) 110 // 插入元素到todolist位置 : 111 todo_list_ele.insertBefore( todo_li , todo_list_ele.childNodes[0] ); 112 title_ele.value = ""; 113 return title_value; 114 } 115 116 function createEle( options ){ 117 // 1. 创建标签 : 118 var node = document.createElement( options.tag ); 119 if( options.attributes ){ 120 // 遍历属性列表 : 121 for(var attr in options.attributes){ 122 // 给元素设置属性; 123 node.setAttribute( attr , options.attributes[attr]) 124 } 125 } 126 // 3. 给元素添加内容 : 127 if( options.content ){ 128 node.innerHTML = options.content; 129 } 130 // 4. 判定是否存在子集元素; 131 if( options.children && options.children.length > 0 ){ 132 for(var i = 0 ; i < options.children.length ; i ++){ 133 // 如果存在子集 : 创建子集元素插入父级之中; 134 node.appendChild( createEle( options.children[i] ) ); 135 } 136 } 137 return node; 138 } 139 140 // 事件委托; 141 on(todo_list_ele , "change" , "input" , function( e , node ){ 142 // 判定checkbox 是否选中 node.checked; 选中为true , 没有选则为false; 143 if(node.checked){ 144 done_list_ele.appendChild(node.parentNode); 145 // 删除数据 , 添加数据; 146 var value = node.parentNode.children[1].innerHTML; 147 removeLocalData( "todo" , value ); 148 saveLocalData ( "done" , value ); 149 } 150 }); 151 // 同理给done_list 绑定事件; 152 on(done_list_ele , "change" , "input" , function( e , node ){ 153 if(!node.checked){ 154 todo_list_ele.appendChild(node.parentNode); 155 var value = node.parentNode.children[1].innerHTML; 156 removeLocalData( "done" , value ); 157 saveLocalData ( "todo" , value ); 158 } 159 }); 160 on( sec_ele , "click" , "a" , function( e , node ){ 161 node.parentNode.remove(); 162 var type = node.parentNode.children[0].checked ? "done" : "todo"; 163 var value = node.parentNode.children[1].innerHTML; 164 removeLocalData( type , value); 165 }); 166 on(todo_list_ele , "click" , "p" , function( e , node ){ 167 if( node.children.length === 1 ){ 168 return false; 169 }; 170 var old_value = node.innerHTML; 171 node.innerHTML = "<input class='ipt' value='"+ node.innerHTML +"'>"; 172 node.children[0].select(); 173 on( node.children[0], "blur" , eventHanlder) 174 on( node.children[0], "click" , eventHanlder) 175 var has_remove_input = false; 176 function eventHanlder(){ 177 if(has_remove_input) return false; 178 console.log("todo" , old_value , this.value) 179 updateLocalData( "todo" , old_value , this.value) 180 has_remove_input = true 181 node.innerHTML = this.value; 182 183 } 184 }); 185 186 //事件委托封装 187 function on(ele, type, cb_selector, cb) { 188 if (arguments.length === 4 && typeof cb_selector === "string") { 189 ele.addEventListener(type, function (evt) { 190 var e = evt || event; 191 var target = e.target || e.srcElement; 192 var node = target; 193 var selector_start = cb_selector.substr(0, 1); 194 var selector_type = null; 195 var selector = cb_selector; 196 switch (selector_start) { 197 case ".": 198 selector_type = "className"; 199 selector = cb_selector.slice(1); 200 break; 201 case "#": 202 selector_type = "id"; 203 selector = cb_selector.slice(1); 204 break; 205 default: 206 selector_type = "nodeName"; 207 break; 208 } 209 while (node !== ele) { 210 if (!node) break; 211 if (node[selector_type] === (selector_type === "nodeName" ? selector.toUpperCase() : selector)) { 212 cb( e , node ); 213 break; 214 } 215 node = node.parentNode; 216 } 217 }); 218 return false; 219 } 220 ele.addEventListener(type, cb_selector); 221 } 222 223 </script>