1.需求:html
實現一個以下頁面:數組
2.實現代碼:瀏覽器
HTML:app
1 <!-- author: wyb --> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>js todo</title> 7 <style> 8 *{ 9 margin: 0; 10 padding: 0; 11 } 12 .container{ 13 width: 60%; 14 margin: 0 auto; 15 } 16 .button{ 17 margin-right: 5px; 18 } 19 .complete{ 20 color: red; 21 text-decoration: line-through; 22 } 23 .pub-time{ 24 margin-left: 15px; 25 } 26 </style> 27 </head> 28 <body> 29 30 <div class="container"> 31 <!-- todo輸入框 --> 32 <div class="todo-form"> 33 <input type="text" id="input"> 34 <button id="button-add">add</button> 35 </div> 36 <!-- todo列表 --> 37 <div id="todo-list"> 38 <!-- 示例todo --> 39 <div class="todo-cell"> 40 </div> 41 </div> 42 </div> 43 44 <script src="todo.js"></script> 45 </body> 46 </html>
JavaScript:函數
1 // 封裝輸出 2 var log = function() { 3 console.log.apply(console, arguments) 4 }; 5 6 // 字符串處理: 7 var todoTemplate = function (todo) { 8 // 下面是JavaScript中的字符串替換: 9 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>`; 10 return t; 11 }; 12 13 // 插入新元素 14 var insertTodo = function (todo) { 15 // 得到todo-cell的HTML字符串: 16 var todoItem = todoTemplate(todo); 17 18 var todoList = document.querySelector("#todo-list"); 19 todoList.insertAdjacentHTML('beforeend', todoItem); 20 }; 21 22 // 開關一個元素的某個class 23 var toggleClass = function(element, className) { 24 if (element.classList.contains(className)) { 25 element.classList.remove(className) 26 } else { 27 element.classList.add(className) 28 } 29 }; 30 31 // 獲得當前時間 32 var currentTime = function () { 33 var d = new Date(); 34 var year = d.getFullYear(); 35 var month = d.getMonth() + 1; 36 var day = d.getDate(); 37 var hour = d.getHours(); 38 var minute = d.getMinutes(); 39 var second = d.getSeconds(); 40 // 時間格式處理 41 if(minute <= 9){ 42 minute = "0" +minute 43 } 44 if(second <= 9){ 45 second = "0" +second 46 } 47 48 var timeString = `${year}/${month}/${day} ${hour}:${minute}:${second}`; 49 log("now time is: ", timeString); 50 return timeString 51 }; 52 53 // 返回本身在父元素中的下標 54 var indexOfElement = function(element) { 55 var parent = element.parentElement; 56 for (var i = 0; i < parent.children.length; i++) { 57 var e = parent.children[i]; 58 if (e === element) { 59 return i 60 } 61 } 62 }; 63 64 // 保存 todoList 65 var saveTodos = function() { 66 var s = JSON.stringify(todoArray); 67 localStorage.todoArray = s; 68 }; 69 70 var loadTodos = function() { 71 var s = localStorage.todoArray; 72 return JSON.parse(s); 73 }; 74 75 76 // 事件處理相關: 77 // 響應事件函數: 78 var bindEventAdd = function () { 79 var buttonAdd = document.getElementById("button-add"); 80 buttonAdd.addEventListener('click', function () { 81 log("button-add click"); 82 83 // 得到todo的值: 84 var task = document.getElementById("input").value; 85 // log(task); 86 // 得到todo對象 87 var todo = { 88 'task': task, 89 'time': currentTime(), 90 }; 91 // 將數據存入數組中 92 todoArray = loadTodos(); 93 todoArray.push(todo); 94 saveTodos(); 95 96 // 插入todo-list: 97 insertTodo(todo) 98 }); 99 }; 100 101 var bindEventEnter = function(){ 102 var todoList = document.querySelector("#todo-list"); 103 todoList.addEventListener('keydown', function (event) { 104 log('todo keydown: ', event, event.target); 105 var target = event.target; 106 if(event.key === 'Enter') { 107 log('按了回車'); 108 // 失去焦點 109 target.blur(); 110 // 阻止默認行爲的發生, 也就是不插入回車 111 event.preventDefault(); 112 // 更新todo 113 var index = indexOfElement(target.parentElement); 114 log('update index: ', index); 115 // 把元素在 todoList 中更新 116 todoArray = loadTodos(); 117 todoArray[index-1].task = target.innerText; 118 saveTodos(); 119 } 120 }); 121 }; 122 123 var bindEventButton = function () { 124 // bindEventButton -> 複製todo所在div中的3個按鈕的響應 125 var todoList = document.querySelector("#todo-list"); 126 todoList.addEventListener('click', function (event) { 127 log('click: ', event, event.target); 128 // 得到點擊對象和其父元素(todo的div) 129 var target = event.target; 130 var todoDiv = target.parentElement; 131 132 // complete和delete和update的具體操做: 133 if(target.classList.contains('button-complete')) { 134 // 給 todo的div 開關一個狀態 class 135 toggleClass(todoDiv, 'complete') 136 } else if (target.classList.contains('button-delete')) { 137 log('delete'); 138 var index = indexOfElement(todoDiv) - 1; 139 log(index); 140 // 刪除父節點 141 todoDiv.remove(); 142 // 把元素從 todoArray 刪除: 143 // delete todoArray[index] -> 不是徹底刪除,刪除的數據變成了undefined依然留着數組中 144 todoArray = loadTodos(); 145 log("delete: ", todoArray[index]); 146 todoArray.splice(index, 1); 147 log(todoArray); 148 saveTodos(); 149 } 150 else if (target.classList.contains('button-update')) { 151 log('update'); 152 var cell = target.parentElement; 153 var span = cell.children[3]; 154 log("span is: ", span); 155 span.setAttribute("contenteditable", true); 156 // span.contentEditable = true // 同理 157 span.focus(); 158 } 159 }); 160 }; 161 162 var bindEventBlur = function() { 163 var todoList = document.querySelector('#todo-list'); 164 todoList.addEventListener('blur', function(event){ 165 log('todo blur: ', event, event.target); 166 var target = event.target; 167 if (target.classList.contains('todo-label')) { 168 log('update and save'); 169 // 讓 span 不可編輯 170 target.setAttribute('contenteditable', 'false'); 171 // 更新todo 172 var index = indexOfElement(target.parentElement); 173 log('update index: ', index); 174 // 把元素在 todoList 中更新 175 todoArray = loadTodos(); 176 todoArray[index-1].task = target.innerText; 177 saveTodos() 178 } 179 }, true) 180 }; 181 182 183 // 綁定事件: 184 var bindEvents = function () { 185 // 添加todo 186 bindEventAdd(); 187 // 文本框輸入todo 按回車保存 188 bindEventEnter(); 189 // 完成按鈕和刪除按鈕和編輯按鈕 190 bindEventButton(); 191 // 文本框失去焦點後保存todo 192 bindEventBlur() 193 }; 194 195 196 // 初始化todo: 197 var initTodos = function () { 198 var todoArray = loadTodos(); 199 for (var i = 0; i < todoArray.length; i++) { 200 var todo = todoArray[i]; 201 insertTodo(todo); 202 } 203 }; 204 205 // 存儲數據 206 var todoArray = []; 207 // 程序主入口 208 var __main = function (){ 209 // 綁定事件: 210 bindEvents(); 211 212 // 程序加載後, 加載 todoArray 而且添加到頁面中 213 initTodos(); 214 215 }; 216 217 __main(); 218 219 220 221 // 一些說明: 222 // 事件委託相關概念 223 // === 224 // 225 // 問題在於, todo都是運行的時候才添加的元素 226 // 對於這樣的元素, 咱們沒辦法實現綁定事件 227 // 咱們能夠把 click 事件綁定在事先存在的父元素上 228 // 經過父元素響應click事件 調用相應的事件響應函數 229 // 而事件響應函數會被傳入一個參數, 就是事件自己 230 // 而後在運行的時候經過 event.target 屬性(發起事件的元素,例如某個按鈕) 231 // 來檢查被點擊的對象是不是須要的對象, 這個概念就是事件委託 232 233 // 與存儲相關的問題: 234 // === 235 // localStorage 能夠用來存儲字符串數據, 在瀏覽器關閉後依然存在 236 // 存儲方法以下: 237 // localStorage.name = 'wyb'; 238 // 關閉瀏覽器, 註釋上一句代碼 239 // 再次用同一個瀏覽器打開該項目, 仍然能獲取到這個值 240 // log('關閉瀏覽器後: ', localStorage.name); 241 // localStorage刪除數據: 242 // localStorage.removeItem("name"); 243 // 注意: 244 // 利用 localStorage 就能夠 存儲todo 245 // 可是 todo存在於array中 246 // 而 localStorage 只能存儲 string 數據 247 // 因此沒辦法直接存儲todo數據 248 // 249 // 可行的辦法以下: 250 // 存儲的時候把 array 轉換爲字符串 讀取的時候把字符串轉成 array 251 // 這個過程一般被稱之爲 序列化 和 反序列化 252 // 在 js 中, 序列化使用 JSON 格式 253 // 254 // var s = JSON.stringify([1, 2, 3, 4]); 255 // log('序列化後的字符串', typeof s, s); 256 // var a = JSON.parse(s); 257 // log('反序列化後的數組', typeof a, a); 258 // 輸出結果: 259 // 序列化後的字符串 string [1,2,3,4] 260 // 反序列化後的數組 object Array(4) 261 // 262 // 使用 JSON 序列化後, 就能夠把 todo存入瀏覽器的 localStorage 了 263 // 264 // 與時間相關的問題: JavaScript中的時間對象 -> Date對象 265 // === 266 // 經常使用用法以下: 267 /* 268 var d = new Date() 269 d.getFullYear() 270 年份, 2016 271 d.getMonth() 272 月份, 0-11 273 d.getDate() 274 日期, 1-31 275 d.getHours() 276 小時, 0-23 277 d.getMinutes() 278 分鐘, 0-59 279 d.getSeconds() 280 秒數, 0-59 281 d.getMilliseconds() 282 毫秒, 0-999 283 d.getDay() 284 星期幾, 0-6 285 */
3.實現效果:spa
(1)最開始界面3d
(2)輸入信息點擊addcode
(3)點擊完成orm
(4)點擊刪除htm
(5)點擊編輯
修改完成後回車後或點擊其餘頁面便可
(6)刷新或關閉網頁再次打開依然是以前保存的todo