JavaScript ES5面向對象實現一個todolist


todo-list

前言

最近閱讀了JavaScript設計模式的面向對象篇,但是又苦於實踐,便想到了寫一個簡單的todo-list來鞏固自己JavaScript面向對象設計的思想。希望對和我一樣的小白有幫助。本文代碼使用的是ES5,並非ES6。

要求:了解原型鏈。

遵守

怕文中有人不明白為什么要這么寫,所以這里先說一下一些地方為什么要這么寫。

來自《編寫可維護的JavaScript》

  • 將一些常量和不變的數據,放在配置文件里。
  • CSS和JavaScript分離。
  • 事件處理和業務邏輯單元分離。
// 如:
var config = {
	classShow: 'show',
	classHide: 'hide'
};

開始

布局

首先,先將HTML框架搭好,這里,就沒有特別的做美化了。

<div>
	<input type="text" data-input="work">
	<ul data-list="work">
	</ul>
</div>

設計對象

這個地方,倒是花了我一部分事件,不知道到底該如何設計,因為自己之前寫過Java,Java里封裝類的思想是盡可能單一功能,和組件的思想很像。

而最開始,我就陷入了深深的思考中,因為我想將這個簡單的todo-list封裝成一個對象,如果按單一功能的思想的話,就得將input封裝為一個對象,li封裝為一個對象,ul封裝為一個對象,顯然,這是不可能的。

於是,我轉變思想,將它們整個封裝一個對象。

對象的屬性

對象的屬性有:input, ul, list。為了實例化多個對象,將name傳入函數里。因此, 代碼如下:

var TodoList = function(name) {
	this.list = document.querySelector('[data-list="' + name + '"]');
	this.childs = this.list.querySelectorAll('li');
	this.input = document.querySelector('[data-input="' + name + '"]');
}

事件綁定

仔細思考,其實就是一個增加、刪除、查找的操作, 並且為了將事件處理和邏輯處理單元分隔開,所以事件綁定僅僅處理的是綁定事件。因此,代碼如下:

var TodoList = function(name) {
	this.list = document.querySelector('[data-list="' + name + '"]');
	this.childs = this.list.querySelectorAll('li');
	this.input = document.querySelector('[data-input="' + name + '"]');

	// 綁定事件
	this.init = function() {
		
		// input按下enter鍵
		this.input.addEventListener('keyup', function(event) {
			this.handleKeyup(event);
		}.bind(this));

		// 事件委托,點擊list
		this.list.addEventListener('click', function(event) {
			this.handleListClick(event);
		}.bind(this));
	
		// input的值改變時
		this.input.addEventListener('input', function(event) {
			this.handleInputChange(event);
		}.bind(this));
	};
};


/**
 *
 * 事件與應用單元分離
 * handleKeyup
 * 
 * {param} object event
 *
 */
TodoList.prototype.handleKeyup = function(event) {
	event.preventDefault();
	event.stopPropagation();
	this.addItem(event.keyCode, event.target);
}

/**
 * 事件和應用單元分離
 * 點擊list,事件冒泡階段處理, 委托事件
 * 
 * {param} object event
 */
TodoList.prototype.handleListClick = function(event) {
	event.preventDefault();
	event.stopPropagation();
	this.removeItem(event.target);
}


/**
 * 事件和應用單元分離
 * input內容改變,則模糊查找, 調用findItem()函數
 * 
 * {param} object event
 */
TodoList.prototype.handleInputChange = function(event) {
	var value = event.target.value;
	event.preventDefault();
	event.stopPropagation();
	this.findItem(value);
}

在上面,你可能不知道為什么要綁定this,你需要了解一下bind函數的用處。

而調用事件對象的兩個API是為了阻止事件的默認行為 以及 防止事件對象傳播。

業務邏輯單元的操作

對事件綁定結束后,就需要對

事件綁定成功后,就將進行邏輯單元的代碼編寫。

看下面的代碼:

/**
 *
 * 增加一個todo-item
 * 注意,這里要綁定this
 *
 * {param} number event.keyCode
 * {param} object event.target
 *
 */
TodoList.prototype.addItem = function(keyCode, target) {

	if(event.keyCode == 13 && event.target.value.trim().length > 0) {
		this.append();
		this.clearInput();			
		this.childs = this.list.querySelectorAll('li');
	}
}


/**
 * 刪除一個todo-item
 *
 * {param} object event.target
 */
TodoList.prototype.removeItem = function(target) {
		
	// 初始化執行的時候,不存在target
	if(target) {
		if(target.nodeName == 'BUTTON') {
			target.parentNode.parentNode.removeChild(target.parentNode);
			this.childs = this.list.querySelectorAll('li');
		}
	}
};

/**
 *
 * 查找輸入字符串是否存在
 * 如果不存在,就顯示所有的list
 * 如果存在,就顯示存在的
 *
 */
TodoList.prototype.findItem = function(value) {

	var find = false;

	// 隱藏所有
	for(var i = 0;i < this.childs.length;i++) {
		this.childs[i].className = config.classHide;
	}

	// 如果存在就顯示
	for(var i = 0;i < this.childs.length;i++) {
		var nowEl = this.childs[i];

		if(nowEl.firstChild.innerText.indexOf(value) != -1) {
			nowEl.className = config.classShow;
			find  = true;
		}
	}

	// 如果都沒有就全部顯示
	if(!find) {
		for(var i = 0;i < this.childs.length;i++) {
			this.childs[i].className = config.classShow;
		}
	}
}


/**
 *
 * 清空輸入框
 *
 */
TodoList.prototype.clearInput = function() {
	this.input.value = '';
}


/**
 *
 * 為totolist append一個li標簽
 *
 */
TodoList.prototype.append = function() {
	var oLi = document.createElement('li');
	var oBtn = document.createElement('button');
	var oSpan = document.createElement('span');
	oSpan.innerHTML = this.input.value.trim();
	oBtn.innerHTML = 'delete';
	oLi.appendChild(oSpan);
	oLi.appendChild(oBtn);
	this.list.appendChild(oLi);
};

實例化對象

var todo = new TodoList('work');
todo.init();

如果你想要查看這個簡單的todo-list所有的代碼,請點擊這里

參考

  • 《編寫可維護的JavaScript》
  • 《JavaScript設計模式》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM