DOM實戰-js todo

1.需求:html

實現一個以下頁面:數組

  • 最上面是輸入框,後面是add按鈕,輸入文本點擊add按鈕,在下面就會出現一行,下面出現的每行最前面是兩個按鈕,而後後面是todo(要作的事)
  • 第一個按鈕是完成按鈕,第二個按鈕是刪除按鈕,點擊完成按鈕後這一行雖然不會消失,可是這一行會有一條橫線在上面表示完成,點擊刪除按鈕後這一行的數據就會消失不見
  • 第三個按鈕是修改,點擊修改便可修改todo中的內容,修改完成後回車或按界面其餘地方便可保存
  • 兩個按鈕後面的第一個是todo,第二個是發佈時間

 

 

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

相關文章
相關標籤/搜索