菜鳥筆記:簡易的 Todo-list

GlennJong
9 min readJul 22, 2017

--

https://glennjong.github.io/noob.todolist/

回歸原生 Javascript,用物件導向的概念來寫 Todo-list 功能。

快速介紹物件導向

舉一個簡單的例子

function Person(first, last) {
this.first = first;
this.last = last;
this.say = function(){
return 'I am ' + this.first + ' ' + this.last + '.'
};
}
var p = new Person('Peter', 'Parker')> p
< Person {first: 'Peter', last: 'Parker', say: function}
> p.say()
< "I am Peter Parker."

這個例子中,有個叫做 Person 的函式,以名字當作引數(arguments)設定成這個 Person 的屬性。
接著來設定一個變數 p,把 Peter、Parker 當作引數給了 Person 這個函式,用 new 建構出一個 Person 物件(object)。
所以輸入 p 時,他回傳了 Person {first: ‘Peter’, last: ‘Parker’, say: function} 物件,也就是創造出 Person 的實例。
而物件的屬性當然也可以設定成函式,就像賦予這個 Person 一個動作一樣,所以輸入 p.say() 時,則會回傳 ‘I am Peter Parker.’

透過這種方式產生出 Javascript 物件,可以確保產生的物件格式相同,並且可以快速產生,也較容易理解。
如此以來就能夠快速的建立物件,像這樣:
var b = new Person(‘Bruce’, ‘Wayne’)
var c = new Person(‘Clark’, ‘Kent’)

更詳細的物件導向請看:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

應用在 Todo-list

程式拆解

Todo-list 的步驟可以理解成:
1. 建構出統一的 TodoItem 物件
2. 將取得的資訊放到 TodoItem 的屬性
3. 把這個 TodoItem 的前台物件印在 HTML 上

所以可以先把程式拆解成這樣:

function TodoList() {
// 程式的主體
var todoItem = new TodoItem('...')
}
function TodoItem(title, id) {
// TodoList 的小單元叫做 TodoItem,然後定義各種 TodoItem 的屬性
this.title = title;
this.id = id;
...
return this
}

先定義好每個 TodoItem 裡面應該要有 title(內容) …等各式獨特的屬性。

除此之外,還需要一個儲存每一個 todoItem 和紀錄 id(編號)的地方:

var general = {
// 儲存每個 todoItem 的陣列
todos: [],
//從 0 開始計算的編號
globalID: 0
}

賦予程式更多的動作

這邊筆記一下,添加動作的寫法不只一種,以下兩種寫法功能上是一樣的:(不過意義上不同)

function Test() {
this.doSomething = function() {...}
}
Test.prototype.doSomething = function() {...}

前台的結構

接著,要建構前台能夠看得到的單位,預期應該是要這樣子的 HTML 結構:

前台看到的結構
<div>
<input type="text" \>
<button>產生todoItem</button>
<ul>
// TodoItem 的前台元素
<li>
<input type="checkbox" id="t1" \>
<label for="t1">TodoItem的內容</label>
</li>
// TodoItem 的前台元素
</ul>
</div>

結構和步驟大致上可以拆成這樣:
1. TodoList 這邊要建立一個 <ul> 來放置 TodoItem 的 <li>。
2. 透過 <button> 取得 <input> 的值作為 TodoItem 的內容。
3. TodoItem 的內容放到 <label> 裡面,並且對應 checkbox 的 id。

因此要擴展 TodoList 和 TodoItem 「建立前台元素」的動作:

TodoList 的前台元素:

function TodoList() {
...
this.$elem = this.buildElem()
}
TodoList.prototype.buildElem = function() {
// 建立 TodoList 需要用到的前台元素
var $ul = document.createElement('ul'),
$btn = document.createElement('button'),
$input = document.createElement('input'),
$container = document.createElement('div')
// 做出可輸入的 input text 區
$input.setAttribute('type', 'text')
// 把這些前台元素都幫起來放到 $container 裡面
$container.append($input)
$container.append($btn)
$container.append($ul)
return $container
}

TodoItem 的前台元素:

function TodoItem(title, id) {
...
this.$elem = this.buildElem()
}
TodoItem.prototype.buildElem = function() {
// 建立 TodoItem 需要用到的元素
var $li = document.createElement('li'),
$label = document.createElement('label'),
$checkbox = document.createElement('input')
// 放入 <input> 的內容
$label.textContent = title
// 給 checkbox 和 label 相同的編號
$label.setAttribute('for', id)
$checkbox.setAttribute('type', 'checkbox')
$checkbox.setAttribute('id', id)
// 把所有前台元素放到 <li> 裡面
$li.append($checkbox)
$li.append($label)
return $li
}

賦予更多事件或動作

賦予這些元素各種動作,讓 <button> 按下之後取得 <input> 的值,並且以此創造出 new TodoItem 實例。

function TodoList() {
...
this.bindEvents()
}
TodoList.prototype.bindEvents = function() {
// 找到元素中的 <button>,並賦予他 onCreateTodo 的動作
var button = this.$elem.querySelector('button')
button.addEventListener('click', this.onCreateTodo.bind(this))
}
TodoList.prototype.onCreateTodo = function() {
var input = this.$elem.querySelector('input')
var ul = this.$elem.querySelector('ul')
// 取得 <input> 的內容
var title = input.value
// 從 general.globalID 取得目前的編號,並且 +1
var id = general.globalID ++
// newTodo 就是一個新的 TodoItem,並且把 id 和 title 放進去
var newTodo = new TodoItem(id, title)
// 把這個 newTodo 的前台元素新增到 <ul> 裡面
ul.appendChild(newTodo.$elem)
// 把新的 newTodo 存到 general.todos
general.todos.push(newTodo)
}

最後步驟

如此一來就完成了一個系列的程式動作了,最後別忘了 TodoList() 也是一個物件,也必須創造出他的實例:

var todoList = new TodoList()
document.body.appendChild(todoList.$elem)

這樣就算是完成了一個極簡版的 TodoList 了!https://glennjong.github.io/noob.todolist/easy.html

整理一下

  1. 當按下了按鈕, 就會創立 TodoItem 實例
  2. 每個 TodoItem 有自己的編號和內容
  3. 每個 TodoItem 會依照順序被存在 general.todos 裡面

以上,是以一個初學者的程度寫出來的簡易 todoList,了解了物件導向的作法後,就能夠更輕易地擴充各種功能,像是刪除、暫存…之類更完整的功能,例如:
https://glennjong.github.io/noob.todolist/

若有任何建議歡迎與我交流XD

--

--