這篇要介紹新手常見的作品 - To Do List,筆者在前端使用了網頁三大技術HTML、CSS、JS,後端則是使用Firebase作為工具。這個專案主要是練習照著設計稿切版,並使用組合技完成工作,故僅完成基礎功能,無太多使用者經驗相關的精緻功能。
HTML
什麼是HTML
HTML(Hypertext Makeup Language),中文通常稱為「超文字標示語言」。如同名字所示,HTML主要功能是用來告訴瀏覽器該如何呈現網頁。HTML包含著一系列的元素(Element),元素中包含內容(Content)與標籤(Tag),元素看起來會長的像是
<p>Hello World!</p>
其中<p>就是上述說的標籤,因為HTML未經過瀏覽器解讀並渲染前,其實就是一般的文字,故標籤結束時會多個「/」,目的是要告訴瀏覽器這行內容已經結束了,Hello就是內容。給予不同的標籤,會有不同的效果,例如段落文件標題(h1-h6)、語意的強調(strong、em…)等等,想更全面了解Tag可自行google,網路上有很多資訊,都是針對Tag的介紹(參1)。如果想要實際看看瀏覽器渲染的結果,直接開個記事本寫下HTML程式碼,最後將副檔名.txt改為.html再打開,或想要更有質感一點,也可在codepen(參2)上測試唷。
HTML架構
完整的HTML不僅僅要包含跟內容有關的元素,還要包含瀏覽器工作時必須知道的資訊。例如
- 文件類型 <!DOCTYPE html>
- 根元素 <html>
- <head>
- <body>
上述4個元素都必須存在,文件類型因為早期存在其他HTML版本,瀏覽器為針對不同版本進行不同工作,故需要指定文件的類型,現在大多都是使用HTML5,也為了方便就簡化成現在看到的樣子了。根元素中會包含<head>與<body>,兩者互相合作分工,<body>內放置跟內容直接相關的元素,<head>則放一些類似設定檔的元素,例如<title>、<meta>、<link>等等。未開始撰寫的HTML架構可能會長這樣
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
CSS與JavaScript
CSS
廣泛談到網頁技術,除了HTML之外,CSS與JavaScript也被視為是同一套技術組合,CSS全名為Cascading Style Sheets,中文稱為階層式樣式表。HTML主要目的是要將網頁用結構化文件的方式表達,CSS則用於添加樣式,例如顏色、字體大小等等。筆者認為CSS不難學,重點在於搞懂選擇器、block及inline特性、CSS來源優先順序,命名規則其實慢慢習慣就好。之前看了Amos的金魚系列(參3),覺得對於HTML與CSS講解的非常清楚,有興趣的自行可以去看看囉。
JavaScript
當網頁想要實現更複雜的功能或使用者體驗時,大部分的情況而言,靠HTML及CSS僅能呈現靜態網頁,加入JavaScript後,可實現更多與使用者互動的寫法,透過event的監聽,決定要做些什麼,例如按下按鈕後顯示圖片。為了要能準確的指定要更動的元素,故JavaScript首要的功課就是練習取Dom,例如
document.getElementByClass("item");
但要如何能準確且快速的取到指定的Dom,其實跟寫出來的HTML架構有關係,而取到Dom後,要如何加入或修改CSS也是要考量的,例如使用classList.add、setAttribute等等,所以才說HTML、CSS、JavaScript通常是視為要一起擁有的技術。但取Dom只是JavaScript基本功而已,筆者看了一些資訊,發現更深的技術與概念,那就是非同步,但等日後有實戰且夠經驗再來寫。
ToDoList 基礎功能設計
練習過上面的網頁三大技術後,接下來我們要來著手寫第三個專案,此專案主要目的為練習照著設計稿切版,並使用網頁三大技術完成工作,故筆者僅針完成To Do List的基礎功能,不外乎就是新增、讀取、修改、刪除。更精緻的功能及使用者經驗就先Pass了。另外,因這個階段並沒有實際的後端資料庫可儲存,為測試功能,筆者在這小節先使用物件暫時充當ToDoList的資料。
主要畫面
1、顯示所有計畫(My Tasks):
可調整的參數包含(1)標題、(2)日期與時間、(3)上傳檔案、(4)工作內容註記
2、僅顯示執行中的計畫(In Progress)
若CheckBox被打勾,會視為已完成,並放置到Completed中。
3、僅顯示已完成的計畫(Completed):
可修改上述ToDoList內容、標示已完成、標示重要行程
4、垃圾桶(Trash):
若不要的計畫,可直接刪除,放在垃圾桶中待7天後自動刪除。
<body>
<div class="header">
<div class="header-box">
<div id="header-item_0" class="header-item header-current" onclick="navselect(0)">My Tasks</div>
<div id="header-item_1" class="header-item" onclick="navselect(1)">In Progress</div>
<div id="header-item_2" class="header-item" onclick="navselect(2)">Completed</div>
<div id="header-item_3" class="header-item" onclick="navselect(3)">Trash</div>
</div>
</div>
<div id="wrap"></div>
</body>
JavaScript在這個專案做到的事情
發現了嗎?在這個專案內,header的按鈕是固定不會動的,所以筆者就直接用HTML寫入,當使用者按下按鈕時,再根據按鈕回傳的index,決定要放什麼內容在<wrap>中。這樣就可以初步完成簡單的網頁囉。
1、在同網頁顯示不同內容:
針對使用者按下nav時,作出不同的回應,這裡大家可能會好奇是如何動態加入HTML程式碼的,示範程式碼如下
function initialization(i) {
var target = object[i];
var htmlTarget = document.getElementById("wrap");
htmlTarget.insertAdjacentHTML("beforeend",
`
<div id="container_${i}" class="container ${container_css}">
<div id="list_header_${i}" class="list-header new-list">
<div class="list-box-left">
<input id="checkbox_${i}" class="checkbox" type="checkbox">
<input id="title_${i}" class="listname ${container_css}" type="text" placeholder="Type Something Here…" value=${target.name}>
</div>
<div class="list-box-right">
<i id="star_${i}" class="far fa-star" onclick="starClick('${target.id}',${i})"></i>
<i id="pen_${i}" class="fas fa-pen editing" onclick="penClick(${i})"></i>
<i class="fas fa-trash-alt" onclick="deleteTask('${target.id}',${i})"></i>
</div>
<div id="subheader_${i}"></div>
</div>
</div>
`
)
}
object為筆者暫時放資料的物件,可能長的會像是
var object = [
{
id: _uuid(),
name: "",
date: "",
time: "",
comment: "",
hasAttr: {
important: false,
hasDate: false,
hasTime: false,
hascomment: false
},
isnew: true,
isDelete: false
},
{
id: _uuid(),
name: "test1",
date: "1999-01-01",
time: "12:01",
comment: "這是test1",
hasAttr: {
important: true,
hasDate: true,
hasTime: true,
hascomment: true
},
isnew: false,
isDelete: false
}
]
2、使用者對頁面操作時產生的動畫
例如正在編輯的計畫icon改為藍色、點擊星星icon時讓div顏色變顯眼,這裡使用object當作範例。
function starClick(id, i) {
var target = object.find(x => x.id == id);
target.hasAttr.important = !target.hasAttr.important;
var star_css = target.hasAttr.important == true ? 'fas ' : 'far ';
var container_css = target.hasAttr.important == true ? 'important-to-do ' : '';
var title_css = target.hasAttr.important == true ? 'important-to-do ' : '';
var star = document.getElementById("star_" + i);
var container = document.getElementById("container_" + i);
var title = document.getElementById("title_" + i);
star.setAttribute("class", star_css + "fa-star");
container.setAttribute("class", container_css + "container");
title.setAttribute("class", "listname " + title_css);
}
3、針對物件或Firebase的CRUD
所有CRUD的操作結果都要被記錄下來,這裡以修改計畫內容作為範例,Firebase下個章節會說明。
function saveTask(id, i) {
var target = object.find(x => x.id == id);
target.name = document.getElementById('title_' + i).value;
target.important = document.getElementById('star_' + i).classList.contains('fas') ? true : false;
target.date = document.getElementById('date_' + i).value;;
target.time = document.getElementById('time_' + i).value;
target.comment = document.getElementById('comment_' + i).value;
console.log(target);
alert("已修改成功!!");
}
4、其他
與網頁較無直接關係,如GUID製造器。
到這裡有沒有發現,其實程式碼的概念都很類似,因為筆者在動態加入HTML程式碼時,會以資料流的概念寫程式碼,故不管是新增、刪除、修改之纇的,只要批次跑迴圈讀取object,或直接指定id,即可作後續操作,這麼一來就可以專心的寫業務邏輯了,想看示範影片的人可參考這裡。
FireBase是什麼
FireBase是個NoSQL文檔數據庫,使用FireBase就可以輕鬆的實現後端的儲存工作,但不需要做太多Server端的設定或管理,接下來我們就來看看FireBase要怎麼使用。
建立專案及初始設定
到這裡已經建立好Firebase的專案囉,接著要在網頁的程式碼中加入程式碼,實現資料庫的CRUD。
點擊左欄的設定icon後,可以找到對應的SDK初始化的程式碼片段,複製貼上到HTML中,就可以開始使用Firebase囉。
但因為預設給的是firebase,如果要使用cloud firestore,要加上
<script src="https://www.gstatic.com/firebasejs/8.3.0/firebase-firestore.js"></script>
試試上傳資料firebase上
網路上有很多針對firebase的crud提供初步的教學文章(參6、參7),筆者的寫法只是包裝成function,再傳入GUID跟資料的物件。
function PushData2FireBase(id, data) {
db.collection("todolist")
.doc(id)
.set(data);
};
完整程式碼: https://bitbucket.org/gary781218/todolist/src/master/
參考資料
- https://www.w3schools.com/
- https://codepen.io/
- https://www.youtube.com/watch?v=ZavL9y4Adrk&list=PLqivELodHt3iL9PgGHg0_EF86FwdiqCre&index=1
- https://blog.gcp.expert/cloud-firestore-cloud-native-nosql-introduction/https://blog.gcp.expert/cloud-firestore-cloud-native-nosql-introduction/
- https://firebase.google.com/docs/firestore/rtdb-vs-firestore#which_database_is_right_for_your_project
- https://ithelp.ithome.com.tw/articles/10224016
- https://firebase.google.com/docs/firestore/rtdb-vs-firestore#which_database_is_right_for_your_project