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
整理一下
- 當按下了按鈕, 就會創立 TodoItem 實例
- 每個 TodoItem 有自己的編號和內容
- 每個 TodoItem 會依照順序被存在 general.todos 裡面
以上,是以一個初學者的程度寫出來的簡易 todoList,了解了物件導向的作法後,就能夠更輕易地擴充各種功能,像是刪除、暫存…之類更完整的功能,例如:
https://glennjong.github.io/noob.todolist/
若有任何建議歡迎與我交流XD