📖
JavaScript - 網站程式設計
  • JavaScript - 網站程式設計
  • 1. 簡介
    • 1.1 講者簡介
    • 1.2 課程簡介
    • 1.3 開發工具簡介
  • 2. JS 在網頁上的基本觀念
    • 2.1 變數宣告
    • 2.2 資料型態
    • 2.3 基礎節點操控
    • 2.4 套用方式
  • 3. 瀏覽器物件模型 (BOM)
    • 3.1 Window
    • 3.2 Location
    • 3.3 內建彈出視窗
  • 4. 文件物件模型 (DOM)
    • 4.1 DOM 簡介
    • 4.2 取得節點、內容、屬性
    • 4.3 節點查找(Traversing)
    • 4.4 更新節點
    • 4.5 新增節點
    • 4.6 刪除節點、屬性
    • 4.7 操控 class 屬性
    • 4.8 練習
  • 5. 事件 (Events)
    • 5.1 事件(Event)簡介
    • 5.2 事件物件(Event Object)
    • 5.3 window 及 document 事件
    • 5.4 滑鼠相關事件
    • 5.5 鍵盤相關事件
    • 5.6 scroll 事件
    • 5.7 表單事件及停止元素預設行為
    • 5.8 動態事件綁定
    • 5.9 練習
  • 6. 表單 (Form)
    • 6.1 取得表單資料
    • 6.2 設定表單資料
    • 6.3 練習
  • 7. 儲存機制(Storage)
    • 7.1 Cookies
    • 7.2 localStorage
  • 8. ECMAScript (ES)
    • 8.1 Template String
    • 8.2 Arrow Function
    • 8.3 Spread and Rest Operator
    • 8.4 物件屬性簡寫
    • 8.5 解構賦值
  • 9. 作業
  • 10. 參考資料
Powered by GitBook
On this page
  • 待辦事項(To-Do List)
  • 介面
  • 第一步:基本介面及 text 欄位事件
  • 第二步:新增待辦事項
  • 第三步:移除與清空
  • 第四步:更新待辦事項
  • 第五步:排序
  • 第六步:重要性的星號
  • 資料更新至 localStorage
  • 第一步:新增資料至 localStorage
  • 第二步:從 localStorage 取得資料
  • 第三步:移除 localStorage 裡的資料
  • 第四步:更新 localStorage 中,name 的資料
  • 第五步:更新 localStorage 中的排序
  • 第六步:更新 localStorage 中,star 的資料
  • 繳交期限
  • 繳交方式
  • 參考作法

9. 作業

待辦事項(To-Do List)

在 javascript 資料夾中,建立 assignment 資料夾。然後在 assignment 資料夾內,建立以下資料夾及檔案:

  • index.html

  • css/index.css

  • js/index.js

建議執行順序:

介面1 → 介面2 → 資料1 → 資料2 → 介面3 → 資料3 → 介面4 → 資料4 → 介面5 → 資料5 → 介面6 → 資料6。

介面

第一步:基本介面及 text 欄位事件

提供 html 及 CSS:

<article class="task_container">
  <h1 class="title1">任務管理</h1>

  <div class="task_add_block">
    <input type="text" class="task_name" placeholder="輸入待辦事項…">
    <button type="button" class="task_add">新增</button>
  </div>

  <div class="task_list_parent">
    <ul class="task_list">
    </ul>
  </div>
</article>
/* 基本 CSS */
* {
  box-sizing: border-box;
}
html{
  font-size: 62.5%;
}
body{
  margin: 0;
  background: rgb(10,0,36);
  background: radial-gradient(circle, rgba(10,0,36,0.1110819327731093) 0%, rgba(9,9,121,0.1110819327731093) 5%, rgba(0,212,255,0.04665616246498594) 100%);
}
article.task_container{
  width: 600px;
  margin: 50px auto;
  border-radius: 5px;
  padding: 10px;
  box-shadow: 1px 1px 5px gray;
}
h1.title1{
  font-size: 2.4rem;
  margin: 0 0 10px 0;
}

/* ===== 任務新增 ===== */
div.task_add_block{
  font-size: 0;
  transition: transform .5s, box-shadow .5s;
}
div.task_add_block.-on{
  box-shadow: 0 0 5px gray;
  transform: scale(1.01);
  transform-origin: center center;
}
div.task_add_block input.task_name{
  width: calc(100% - 50px);
  border: 1px solid lightgray;
  border-radius: 3px 0 0 3px;
  height: 40px;
  font-size: 2rem;
  padding: 5px 10px;
  outline: none;
  display: inline-block;
  vertical-align: top;
}
input.task_name::placeholder{
  color: lightgray;
}
div.task_add_block button.task_add{
  display: inline-block;
  width: 50px;
  height: 40px;
  vertical-align: top;
  border: 1px solid lightgray;
  border-left: 0;
  background-color: white;
  box-shadow: none;
  font-size: 1.6rem;
  cursor: pointer;
  outline: none;
  border-radius: 0 3px 3px 0;
}
div.task_add_block button.task_add:active{
  box-shadow: 1px 1px 3px lightgray inset, -1px -1px 3px lightgray inset;
  background-color: #fcfcfc;
  font-size: 1.5rem;
}

完成以下項目:

  • index.html 頁面需載入 index.js 及 index.css 檔。

  • input.task_name 在 focus 事件觸發時,div.task_add_block 加上 -on class。

  • input.task_name 在 blur 事件觸發時,div.task_add_block 移除 -on class。

結果示意:

第二步:新增待辦事項

更新 html、css:

<!-- 載入 Font Awesome -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
/* ===== 任務列表 ===== */
div.task_list_parent{
  margin-top: 30px;
}
div.task_list_parent ul.task_list{
  margin: 0;
  padding: 0;
  list-style: none;
}
div.task_list_parent ul.task_list > li{
  margin-bottom: 20px;
  border-bottom: 1px solid gray;
  padding-bottom: 20px;
  opacity: 1;
  transition: opacity 1s;
}
div.task_list_parent ul.task_list > li.fade_out{
  opacity: 0;
}
div.task_list_parent ul.task_list > li:first-child{
  border-top: 1px solid black;
  padding-top: 20px;
}
div.task_list_parent ul.task_list > li:last-child{
  margin-bottom: 0;
  border-bottom: 0;
}
div.task_list_parent ul.task_list > li > div.item_flex{
  display: flex;
  /* border: 1px solid black; */

}
div.task_list_parent ul.task_list > li > div.item_flex > div{
  /* border: 1px solid blue; */
}
div.task_list_parent ul.task_list > li > div.item_flex > div.left_block{
  width: 100px;
  flex-shrink: 0;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.left_block div.btn_flex{
  display: flex;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.left_block div.btn_flex > button{
  flex-grow: 1;
  outline: none;
  height: 40px;
  font-size: 1.6rem;
  padding: 0;
  margin: 0;

  background: none;
  background-color: white;
  border: 0;
  cursor: pointer;
  border: 1px solid #eee;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.middle_block{
  font-size: 1.8rem;
  flex-grow: 1;
  padding-left: 10px;
  padding-right: 10px;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.middle_block p.para{
  margin: 0;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.right_block{
  width: 100px;
  flex-shrink: 0;
}

div.task_list_parent ul.task_list > li > div.item_flex > div.right_block div.btn_flex{
  display: flex;
}
div.task_list_parent ul.task_list > li > div.item_flex > div.right_block div.btn_flex > button{
  flex-grow: 1;
  outline: none;
  height: 40px;
  font-size: 1.6rem;
  padding: 0;
  margin: 0;

  background: none;
  background-color: white;
  border: 0;
  cursor: pointer;
  border: 1px solid #eee;
}

新增「待辦事項」的 html:

<li>
  <div class="item_flex">
    <div class="left_block">
      <div class="btn_flex">
        <button type="button" class="btn_up">往上</button>
        <button type="button" class="btn_down">往下</button>
      </div>
    </div>
    <div class="middle_block">
      <div class="star_block">
        <span class="star" data-star="1"><i class="fas fa-star"></i></span>
        <span class="star" data-star="2"><i class="fas fa-star"></i></span>
        <span class="star" data-star="3"><i class="fas fa-star"></i></span>
        <span class="star" data-star="4"><i class="fas fa-star"></i></span>
        <span class="star" data-star="5"><i class="fas fa-star"></i></span>
      </div>
      <p class="para">這是任務這是任務這是任務這是任務這是任務這是任務這是任務這是任務這是任務這是任務這是任務這是任務</p>
    </div>
    <div class="right_block">
      <div class="btn_flex">
        <button type="button" class="btn_update">更新</button>
        <button type="button" class="btn_delete">移除</button>
      </div>
    </div>
  </div>
</li>

完成以下項目:

  • 按下「新增」按鈕時,將以上的待辦事項 html,新增到 ul.task_list 裡面的最前面。

  • 如果沒有輸入待辦事項,按「新增」的話,不能有任何反應。

  • 新增成功的話,待辦事項欄位要清空。

  • 輸入的待辦事項,如果文字的最左邊、最右邊有空格,需移除。(語法:JS 內建的 trim() 函式)。

  • 按下「Enter」鍵,也要能新增待辦事項。

結果示意:

第三步:移除與清空

更新 index.html:

將以下這行放到 h1 標籤之前:

<button type="button" class="btn_empty">清空</button>

更新 index.css:

/* ===== 清空按鈕 ===== */
button.btn_empty{
  float: right;
  background: none;
  background-color: white;
  padding: 0;
  margin: 0;
  border: 1px solid lightgray;
  border-radius: 3px;
  height: 30px;
  width: 50px;
  outline: none;
  font-size: 1.6rem;
  cursor: pointer;
}

完成以下項目:

  • 按下「移除」按鈕,需詢問使用者是否要移除,若確定的話,ul.task_list 裡的第一層子元素 li 標籤,加上 fade_out 這個 class,就會淡出 1 秒,然後請移除該筆待辦事項。

  • 按下「清空」按鈕,需詢問使用者是否要清空,若確定的話,ul.task_list 裡的第一層子元素 li 標籤,加上 fade_out 這個 class,就會淡出 1 秒,然後請清除全部的待辦事項。

結果示意:

第四步:更新待辦事項

index.js 檔案更新,待辦事項更新以下結構,以老師自己寫的為例,有以下這行:

<p class="para">${item.name}</p>;

在其下方,加上這行(留意有加上 -none 這個 class,即預設是消失狀態):

<input type="text" class="task_name_update -none" placeholder="更新待辦事項…" value="${item.name}">

更新 index.css:

div.middle_block input.task_name_update{
  width: 100%;
  border: 1px solid lightgray;
  border-radius: 3px 0 0 3px;
  height: 40px;
  font-size: 2rem;
  padding: 5px 10px;
  outline: none;
}
div.middle_block input.task_name_update::placeholder{
  color: lightgray;
}

.-none{
  display: none;
}

完成以下項目:

  • 按下「更新」按鈕,出現一般文字框,然後可以更新。

  • 再按下「更新」按鈕,回到不可編輯的狀態,但待辦事項要是更新的。

  • 如果所更新的待辦事項,沒有輸入文字,跳出提醒視窗(alert),顯示「請輸入待辦事項」。

  • 待辦事項的文字若最左邊、最右邊有空格的話,需移除。

結果示意:

第五步:排序

更新 index.css:

div.task_list_parent ul.task_list > li:first-child button.btn_up{
  background-color: lightgray !important;
  cursor: not-allowed !important;
  color: gray;
}
div.task_list_parent ul.task_list > li:last-child button.btn_down{
  background-color: lightgray !important;
  cursor: not-allowed !important;
  color: gray;
}

完成以下項目:

  • 按下「往上」按鈕,與上面的待辦事項對調。(註:每個待辦事項是以 li 為單位。)

  • 按下「往下」按鈕,與下面的待辦事項對調。

  • 第一個的待辦事項,「往上」按鈕按了要沒反應;最後一個的待辦事項,「往下」按鈕按了要沒反應。

結果示意:

第六步:重要性的星號

更新 index.css:

/* ===== 重要性的星號 ===== */
div.star_block{
  display: inline-block;
}
div.star_block > span.star{
  cursor: pointer;
  display: inline-block;
  margin-right: 3px;
}
div.star_block > span.star.-on{
  color: yellow;
}

完成以下項目:

  • 點擊星號的時候,該星號加上 -on 這個 class,然後該筆待辦事項,星號數( data-star )小於等於點擊的星號數的話,也要加上 -on 這個 class;反之則移除。

結果示意:

資料更新至 localStorage

第一步:新增資料至 localStorage

資料儲存至 localStorage,提供參考原始碼如下:

let item_id = Date.now(); // timestamp 當做該項的 id

// 儲存到 localStorage
let task = {
  "item_id": item_id,
  "name": task_text, // 新增的待辦事項文字
  "star": 0 // 預設 0
};
let tasks = JSON.parse(localStorage.getItem("tasks"));
if(tasks){ // 若存在
  tasks.unshift(task);
}else{ // 若不存在
  tasks = [task];
}
localStorage.setItem("tasks", JSON.stringify(tasks));

第二步:從 localStorage 取得資料

提示:頁面 DOMContentLoaded 事件發生之後,執行某個函式(例:get_tasks()),這段函式用途是將 localStorage 裡的資料抓出來,然後進行資料的處理,拼裝完 html 之後,再丟回到頁面上:

在 DOMContentLoaded 事件發生之後,執行以下程式:

document.addEventListener("DOMContentLoaded", function(){

  get_tasks(); // DOMContentLoaded 事件發生時,執行這裡的程式
  
});

第三步:移除 localStorage 裡的資料

移除 localStorage 中的單筆待辦事項:

// 抓取待辦事項的 id
let item_id = e.target.closest("li").getAttribute("data-id");

// 從 localStorage 取得資料
let tasks = JSON.parse(localStorage.getItem("tasks"));

let updated_tasks = tasks.filter(function(item, i){
  return item_id != item.item_id;
});

// 回存至 localStorage
localStorage.setItem("tasks", JSON.stringify(updated_tasks));

清空 localStorage 所有的資料,內建就有的程式語法:

localStorage.clear();

第四步:更新 localStorage 中,name 的資料

提示:將待辦事項從 localStorage 裡全部抓出來,然後跑迴圈,然後找到欲更新的待辦事項,將 name 換掉,然後回存至 localStorage,部份原始碼:

// 取得待辦事項的 id
let item_id = e.target.closest("li").getAttribute("data-id");
// 從 localStorage 取得資料
let tasks = JSON.parse(localStorage.getItem("tasks"));
tasks.forEach(function(task, i){
  
});
// 回存至 localStorage
localStorage.setItem("tasks", JSON.stringify(tasks));

第五步:更新 localStorage 中的排序

提供寫好的參考原始碼:

function items_sort(item_id, direction){

  let tasks = JSON.parse(localStorage.getItem("tasks"));

  if(direction == "up"){ // 往上
    for(let i = 0; i < tasks.length; i++){
      if(item_id == tasks[i].item_id){
        [tasks[i - 1], tasks[i]] = [tasks[i], tasks[i - 1]];
        break;
      }
    }
  }

  if(direction == "down"){ // 往下
    for(let i = 0; i < tasks.length; i++){
      if(item_id == tasks[i].item_id){
        [tasks[i], tasks[i + 1]] = [tasks[i + 1], tasks[i]];
        break;
      }
    }
  }

  localStorage.setItem("tasks", JSON.stringify(tasks));
}

第六步:更新 localStorage 中,star 的資料

仿照第四步更新 name 的部份,很類似。提供部份原始碼:

// 取得待辦事項的 id
let item_id = span_el.closest("li").getAttribute("data-id");

// 從 localStorage 取得資料
let tasks = JSON.parse(localStorage.getItem("tasks"));
tasks.forEach(function(task, i){
  
});

// 回存至 localStorage
localStorage.setItem("tasks", JSON.stringify(tasks));

完成。

繳交期限

0/(日) 晚上 點之前繳交。

繳交方式

將 assignment 資料夾,壓成一個壓縮檔,然後繳交至 Tibame 後台。

參考作法

Previous8.5 解構賦值Next10. 參考資料

Last updated 1 year ago

提示:先認識 陣列.filter() 函式:

前端班後台網址:

JAVA班後台網址:

https://codepen.io/carlos411/pen/RwBmybr
https://frontend.tibame.com/
https://java.tibame.com/