簡介 名詞 
Client-side Render(CSR) : API get data 再由 JavaScript 渲染 
Server-side Render(SSR) : 在 Server-side 就先渲染成 HTML 
 Search Engine Optimization(SEO) : 搜尋引擎最佳化,透過了解搜尋引擎的運作規則來調整網站,以及提高目的網站在有關搜尋引擎內排名的方式 
 
JavaScript 的功能 
介面 : 改變介面 
事件 : 監聽事件並做出反應 
資料 : 與伺服器交換資料 
 
 
執行 放於 body 最後 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			height : 100px ; 			width : 100px ; 		} 	</style >  </head > <body > 	<div  class ="box" > </div >  	<script >  		document .querySelector('.box' ) 			.addEventListener('click' , function ( ) { 				document .querySelector('.box' ).style.background = 'red'  		}) 	</script >  </body > </html > 
 
放於 head 最後, 但要加入 DOM loaded(因執行時 DOM 尚未 load 完成) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!DOCTYPE html > <html  lang ="en" > <head > 	...... 	<script >  		 		document .addEventListener('DOMContentLoaded' , function ( ) { 			document .querySelector('.box' ) 				.addEventListener('click' , function ( ) { 					document .querySelector('.box' ).style.background = 'red'  			}) 		}) 	</script >  </head > <body > 	<div  class ="box" > </div >  </body > </html > 
 
head 加入js 檔 1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html > <html  lang ="en" > <head > 	...... 	 	<script  src ="main.js" > </script >  	<title > Document</title >  </head > <body > 	<div  class ="box" > </div >  </body > </html > 
 
1 2 3 4 5 6 7 8 document .addEventListener('DOMContentLoaded' , function ( ) {	document .querySelector('.box' ) 		.addEventListener('click' , function ( ) { 			document .querySelector('.box' ).style.background = 'red'  	}) }) 
 
文件物件模型(Document Object Model, DOM)是 HTML、XML 和 SVG 文件的程式介面。它提供了一個文件(樹)的結構化表示法,並定義讓程式可以存取並改變文件架構、風格和內容的方法。
圖片來自 Wikipedia DOM 
選元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			height : 100px ; 			width : 100px ; 		} 	</style >  </head > <body > 	<div  id ="item1"  class ="box" > </div >  	<div  class ="box box2" > </div >  	<div  class ="box" > </div >  	<script >  		 		const  elements = document .getElementsByTagName('div' ) 		console .log(elements) 		console .log(document .getElementsByClassName('box' )) 		console .log(document .getElementById('item1' )) 		 		console .log(document .querySelector('div' )) 		console .log(document .querySelector('.box2' )) 		console .log(document .querySelector('#item1' )) 		 		const  elementsNode = document .querySelectorAll('div' ) 		console .log(elementsNode) 	</script >  </body > </html > 
 
.parentElement parentElement is the parent element of the current node. 若無父元素或非element則傳回 null 
.parentNode parentNode is the parent of the current node. The parent of an element is an Element node, a Document node, or a DocumentFragment node. 若無父元素或非element則傳回 null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			width : 100px ; 		} 	</style >  </head > <body > 	<div  id ="item1"  class ="box" > 111</div >  	<div  class ="box box2" > 222</div >  	<div  class ="box" > 333</div >  	<script >  		const  element = document .querySelector('.box2' ) 		element.style.background = "red"  		element.style.margin = "10px"  		 		element.style['padding-top' ] = '10px'  		 		element.style.paddingBottom = '20px'  	</script >  </body > </html > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			width : 100px ; 			height : 100px ; 		} 		.active { 			background : red; 		} 	</style >  </head > <body > 	<div  id ="item1"  class ="box" > 111</div >  	<div  class ="box box2 active" > 222</div >  	<div  class ="box box3" > 333</div >  	<script >  		document .querySelector('#item1' ) 			.addEventListener('click' , function ( ) { 				 				document .querySelector('#item1' ).classList.toggle('active' ) 		})  		document .querySelector('.box2' ) 			.addEventListener('click' , function ( ) { 				 				document .querySelector('.box2' ).classList.remove('active' ) 		})  		document .querySelector('.box3' ) 			.addEventListener('click' , function ( ) { 				 				document .querySelector('.box3' ).classList.add('active' ) 		})  	</script >  </body > </html > 
 
check 是否包含某class 1 alert(div.classList.contains("foo" )); 
 
改變內容 innerText, innerHTML, outerHTML 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			width : 200px ; 			font-size : 36px ; 			 		} 		.active { 			background : red; 		} 	</style >  </head > <body > 	<div  id ="item1"  class ="box" >  		111 		<a  href ="#" > hello</a >  	</div >  	<div  class ="box box2 active" >  		222 		<a  href ="#" > hello</a >  	</div >  	<div  class ="box box3" >  		333 		<a  href ="#" > hello</a >  	</div >  	<script >  		document .querySelector('#item1' ) 			.addEventListener('click' , function ( ) { 				element = 	document .querySelector('#item1' ) 				 				console .log(element.innerText) 				element.innerText = 'innerText'  		})  		document .querySelector('.box2' ) 			.addEventListener('click' , function ( ) { 				 				element = 	document .querySelector('.box2' ) 				console .log(element.innerHTML) 				element.innerText = 'innerHTML'  		})  		document .querySelector('.box3' ) 			.addEventListener('click' , function ( ) { 				element = 	document .querySelector('.box3' ) 				 				console .log(element.outerHTML) 				element.outerHTML = 'outerHTML'  		})  	</script >  </body > </html > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // use innerHTML sendAjaxhApi('http://localhost/robert/comment/api_get_comment.php', function(response){ 	const comments = JSON.parse(response) 	console.log(comments.comment[0]) 	let section = document.querySelector('section') 	for(let i=0 ; i < comments.comment.length ; i++ ) { 		let card = document.createElement('div') 		card.classList.add('card') 		card.innerHTML = ` 			<div  class ="card-avatar" > </div >  			<div  class ="card-info" >  				<div  class ="card-title" >   					<span  class ="card-user" > ${comments.comment[i].nickname}</span >  					<span  class ="card-time" > ${comments.comment[i].create_at}</span >  				<div  class ="card-content" >  					${comments.comment[i].content} 				</div >  			</div >  		` 		section.appendChild(card) 	} }) 
 
加入刪除 元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box { 			background : orange; 			width : 200px ; 			font-size : 36px ; 		} 	</style >  </head > <body > 	<div  class ="box" >  		111 		<a  href ="#" > hello</a >  	</div >  	<script >  		element = document .querySelector('.box' ) 		 		element.removeChild(document .querySelector('a' )) 		 		const  item = document .createElement('div' ) 		item.innerText = '123'  		 		element.appendChild(item) 		 		 		const  itemText = document .createTextNode("999" ) 		 		element.appendChild(itemText) 	</script >  </body > </html > 
 
.append() 加入Node物件或DOMString(文字)
1 2 3 4 5 6 7 const  parent = document .createElement('div' )const  child = document .createElement('p' )parent.append(child)   const  parent = document .createElement('div' )parent.append('附加文字' )  
 
.appendChild() 僅能加入Node物件, 不能加入DOMString(文字) 若加入的物件已存在,則會移動到此
1 2 3 4 5 6 7 const  parent = document .createElement('div' )const  child = document .createElement('p' )parent.appendChild(child)  const  parent = document .createElement('div' )parent.appendChild('Appending Text' )  
 
1 2 var  el = document .getElementById('div-02' );el.remove();  
 
addEventListener 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.box1 { 			background : orange; 			width : 200px ; 			font-size : 36px ; 			margin : 5px  0 ; 		} 		.box2 { 			background : orange; 			width : 200px ; 			font-size : 36px ; 		} 	</style >  </head > <body > 	<div  class ="box1" >  		111 		<a  href ="#" > hello</a >  	</div >  	<div  class ="box2" >  		222 	</div >  	<input  class ="input-text"  type ="text" >  	<script >  		const  element = document .querySelector('.box1' ) 		 		element.addEventListener('click' , handleBox1); 		function  handleBox1 (e )  { 			alert('Box1' ) 			 			console .log(e.target) 		} 		document .querySelector('.box2' ) 			 			.addEventListener('click' , function ( ) { 				alert('Box2' ) 			}) 			document .querySelector('.input-text' ) 				.addEventListener('keypress' , function (e ) { 					console .log(e) 					 					console .log(e.key, e.keyCode, e.code) 				}) 	</script >  </body > </html > 
 
click mousedown mouseup dbclick - 短時間內雙擊左鍵觸發 mousemove - 滑鼠移動時觸發(要用到時才綁定,避免不斷觸發) mouseenter - 滑鼠進入元素邊界時觸發(不會 bubble) mouseleave - 滑鼠完全離開元素時觸發(不會 bubble) mouseover - 滑鼠經過不同元素時觸發 mouseout - 滑鼠離開元素時觸發 keypress 
1 2 3 4 /* e.key : 字元 	 e.keyCode : 編碼 ascii code 	 e.code : 字串表示 "KeyQ" for the Q */ 
 
keydown keyup DOMContentLoaded - DOM load complete 1 2 3 4 document .addEventListener('DOMContentLoaded' , function ( ) {	...... }) 
 
表單處理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		body  { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<form  class ="login-form"  action ="" >  		<div >  			name : <input  type ="text"  name ="username" >  		</div >  		<div >  			password : <input  type ="password"  name ="password" >  		</div >  		<div >  				password again : <input  type ="password"  name ="password2" >  		</div >  		<input  type ="submit"  value ="送出" >  	</form >  	<script >  		document .querySelector('.login-form' ) 			.addEventListener('submit' , function  (e )  { 				const  input1 = document .querySelector('input[name=password]' ) 				const  input2 = document .querySelector('input[name=password2]' ) 				 				console .log(input1.value, input2.value) 				 				if (input1.value != input2.value) { 					 					e.preventDefault() 					alert('密碼不同' ) 				} 		}) 	</script >  </body > </html > 
 
阻止預設行為 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		body  { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<div >  		111 		<a  href ="#" > hello</a >  	</div >  	<script >  		document .querySelector('a' ).addEventListener('click' , function (e ) { 			 			e.preventDefault(); 		}) 	</script >  </body > </html > 
 
事件傳遞機制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.outer { 			width : 200px ; 			height : 200px ; 			background : yellow; 		} 		.inner { 			width : 100px ; 			height : 100px ; 			background : orange; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<div  class ="inner" >  			<button  class ="button" > Click</button >  		</div >  	</div >  	<script >  		addEvent('.outer' ) 		addEvent('.inner' ) 		addEvent('.button' ) 		function  addEvent (className )  { 			document .querySelector(className) 				.addEventListener('click' , function ( ) { 					console .log(className) 			}) 		} 	</script >  </body > </html > 
 
詳細事件傳遞機制:捕獲與冒泡 
圖片來自 W3C 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.outer { 			width : 200px ; 			height : 200px ; 			background : yellow; 		} 		.inner { 			width : 100px ; 			height : 100px ; 			background : orange; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<div  class ="inner" >  			<button  class ="button" > Click</button >  		</div >  	</div >  	<script >  		addEvent('.button' ) 		addEvent('.inner' ) 		addEvent('.outer' ) 		function  addEvent (className )  { 			 			document .querySelector(className) 				.addEventListener('click' , function ( ) { 					console .log(className, '捕獲' ) 			}, true ) 			 			document .querySelector(className) 				.addEventListener('click' , function ( ) { 					console .log(className, '冒泡' ) 			}, false ) 		} 	</script >  </body > </html > 
 
別向上級回報:stopPropagation() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.outer { 			width : 200px ; 			height : 200px ; 			background : yellow; 		} 		.inner { 			width : 100px ; 			height : 100px ; 			background : orange; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<div  class ="inner" >  			<button  class ="button" > Click</button >  		</div >  	</div >  	<script >  		addEvent('.button' ) 		addEvent('.inner' ) 		addEvent('.outer' ) 		function  addEvent (className )  { 			 			document .querySelector(className) 				.addEventListener('click' , function (e ) { 					console .log(className, '捕獲' ) 			}, true ) 			 			document .querySelector(className) 				.addEventListener('click' , function (e ) { 					 					if  (className === '.button' ) { 						e.stopPropagation() 					} 					console .log(className, '冒泡' ) 			}, false ) 		} 	</script >  </body > </html > 
 
多重觸發 
1 2 3 4 5 6 7 8 9 10 11 <script > 	document .querySelector('.button' ) 		.addEventListener('click' , function (e ) { 			console .log("button click 1" ) 	}) 	document .querySelector('.button' ) 		.addEventListener('click' , function (e ) { 			console .log("button click 2" ) 	}) </script > 
 
抑制後觸發 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <script > 	document .querySelector('.button' ) 		.addEventListener('click' , function (e ) { 			 			 			e.stopImmediatePropagation() 			console .log("button click 1" ) 	}) 	document .querySelector('.button' ) 		.addEventListener('click' , function (e ) { 			console .log("button click 2" ) 	}) </script >  
 
錯誤的 event for 使用 var 為錯誤, let 即正確 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.btn { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<button  class ="btn" > 1</button >  		<button  class ="btn" > 2</button >  		<button  class ="btn" > 3</button >  		<button  class ="btn" > 4</button >  		<button  class ="btn" > 5</button >  	</div >  	<script >  		const  elements = document .querySelectorAll('.btn' ) 		 		 		 		for  (let  i=0  ; i< elements.length ; i++) { 			elements[i].addEventListener('click' , function ( ) { 				alert(i+1) 			}) 		} 	</script >  </body > </html > 
 
使用 html data-xx attribute 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.btn { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<button  class ="btn"  data-value ="a" > 1</button >  		<button  class ="btn"  data-value ="2" > 2</button >  		<button  class ="btn"  data-value ="3" > 3</button >  		<button  class ="btn"  data-value ="4" > 4</button >  		<button  class ="btn"  data-value ="5" > 5</button >  	</div >  	<script >  		const  elements = document .querySelectorAll('.btn' ) 		for  (let  i=0  ; i< elements.length ; i++) { 			elements[i].addEventListener('click' , function (e ) { 				alert(e.target.getAttribute('data-value' )) 			}) 		} 	</script >  </body > </html > 
 
add new button 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.add-btn, .btn { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<button  class ="add-btn" > add</button >  		<button  class ="btn"  data-value ="1" > 1</button >  		<button  class ="btn"  data-value ="2" > 2</button >  	</div >  	<script >  		let  num = 3  		const  elements = document .querySelectorAll('.btn' ) 		for  (let  i=0  ; i< elements.length ; i++) { 			elements[i].addEventListener('click' , function (e ) { 				alert(e.target.getAttribute('data-value' )) 			}) 		} 		document .querySelector('.add-btn' ) 			.addEventListener('click' , function ( ) { 				const  btn = document .createElement('button' ) 				btn.classList.add('btn' ) 				btn.setAttribute('data-value' , num) 				btn.innerText = num++ 				document .querySelector('.outer' ).appendChild(btn) 		}) 	</script >  </body > </html > 
 
event delegation(代理) 事件代理(Event Delegation),又稱之為事件委託
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.add-btn, .btn { 			font-size : 24px ; 		} 	</style >  </head > <body > 	<div  class ="outer" >  		<button  class ="add-btn" > add</button >  		<button  class ="btn"  data-value ="1" > 1</button >  		<button  class ="btn"  data-value ="2" > 2</button >  	</div >  	<script >  		let  num = 3  		document .querySelector('.add-btn' ) 			.addEventListener('click' , function ( ) { 				const  btn = document .createElement('button' ) 				btn.classList.add('btn' ) 				btn.setAttribute('data-value' , num) 				btn.innerText = num++ 				document .querySelector('.outer' ).appendChild(btn) 		}) 		document .querySelector('.outer' ) 			.addEventListener('click' , function (e )  { 				if  (e.target.classList.contains('btn' )) { 					alert(e.target.getAttribute('data-value' )) 				} 		}) 	</script >  </body > </html > 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  		.item { 			border : 1px  solid #000 ; 		} 	</style >  </head > <body > 	<ul  class ="list" >  		<li  class ="item"  id ="id1" > item1</li >  		<li  class ="item" > item2</li >  		<li  class ="item" > item3</li >  	</ul >  	<script >  		document .addEventListener('click' , function (e ) { 			let  element = e.target 			if  (element.classList.contains('item' )) { 				console .log(element.innerText) 			} 			 			 			 			if (element.id === "id1" ) { 				console .log(element.id) 			} 		}) 	</script >  </body > </html > 
 
DOM loaded 1 2 3 4 document .addEventListener('DOMContentLoaded' , function ( ) {	...... }) 
 
Element Attribute 1 2 3 4 5 6 7 8 9 var  div1 = document .getElementById("div1" );var  align = div1.getAttribute("align" );var  b = document .querySelector("button" );b.setAttribute("name" , "helloButton" ); b.setAttribute("disabled" , "" ); 
 
1 2 3 4 5 document .getElementById("check1" ).checked=true if  (document .getElementById("check1" ).checked){	consloe.log('It' s selected.) } 
 
parentElement 父元素 1 var  x = document .getElementById("myLI" ).parentElement
 
1 2 document .querySelector('.navbar a' ).click()
 
.target - 初觸發事件的物件 tag name 1 2 3 4 5 document .querySelector('.box' )	.addEventListener('click' , function (e ) { 		 		console .log(e.target.tagName.toLowerCase()) 	})  
 
.currentTarget - 處理事件之監聽器所屬的物件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const  request = new  XMLHttpRequest()request.onload = function ( )  { 	if  (request.status >= 200  && request.status < 400 ) { 		console .log(request.responseText) 	} 	else  { 		console .log('response error :' , request.status) 	} } request.onerror = function ( )  { 	console .log('error' ) } request.open('GET' , 'https://google.com' , true ) request.send() 
 
1 2 3 let  searchParams = new  URLSearchParams(window .location.search);let  id = searchParams.get('id' );
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 window .history.back();window .history.forward();window .history.go(-1 );window .history.go(1 );history.pushState(null , null , '/hello' ) pushState()  replaceState()  popstate 事件  
 
fetch and promise fetch API Fetch API 提供了一個能獲取包含跨網路資源在的資源介面,它有點像我們所熟悉的 XMLHttpRequest,回傳為 Promise 的物件
fetch example 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 const  result =  fetch('https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047' )console .log(result)function  printResult (resp )  {	console .log(resp) } const  result =  fetch('https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047' )result.then(printResult) api500 = "https://run.mocky.io/v3/db4c7417-2cf8-473e-9f05-f16ec2cfe725"  api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(api500).then( response  =>  { 		console .log(response.status) }) fetch(api200).then( response  =>  { 		console .log(response.status) }) api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(api200).then( response  =>  { 	response.text().then( text  =>  { 		console .log(text) 	}) 	 }) api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(api200).then( response  =>  { 	response.json().then(text  => { 		console .log(text) 		console .log(text.message) 		return  123  	}).then( abc  => { 		console .log('abc=' , abc) 	}) }) api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(api200).then( response  =>  { 	return  response.json() }).then(json  => { 	console .log(json) })  api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047-err'  fetch(api200).then( response  =>  { 	return  response.json() }).then(json  => { 	console .log(json) }).catch(e  => { 	console .log("error=" , e) })  data = { 	age: 30  } pi200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(pi200, { 	body: JSON .stringify(data),  	headers: { 		'content-type' : 'application/json' 	 	}, 	method: 'POST' , 	 	}).then(response  =>  { 	return  response.json() }).then( json  => { 	console .log(json) }) 
 
fetch 注意事項 
content-type 要填正確,如以下為 json 
 
1 2 3 4 5 6 7 8 9 10 11 12 pi200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  fetch(pi200, { 	body: JSON .stringify(data),  	headers: { 		'content-type' : 'application/json' 	 	}, 	method: 'POST' , 	 	}).then(response  =>  { 	return  response.json() }).then( json  => { 	console .log(json) } 
 
fetch 不會傳送 cookies,除非你有設定 credential
要讓瀏覽器將 credentials 跟著 request 一起送出, 方式就是在 init object 加上 credentials: ‘include’  
想要把 credentials 發送給同源的 URL ,加上credentials: ‘same-origin’。 
要確保瀏覽器不會帶著 credentials 請求,可以用 credentials: ‘omit’ 。 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 fetch('https://example.com' , {   credentials: 'include'  }) fetch('https://example.com' , {   credentials: 'same-origin'  }) fetch('https://example.com' , {   credentials: 'omit'  }) 
 
mode: ‘no-cors’僅告訴 server, don’t card CPRS don’n need response error,並不表示server 不support時,能收到資料 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 data = { 	age: 30  } pi200 = 'https://tw.yahoo.com'  fetch(pi200, { 	body: JSON .stringify(data),  	headers: { 		'content-type' : 'application/json' 	 	}, 	method: 'POST' , 	 	mode: 'no-cors' ,  	}).then(response  =>  { 	return  response.text() 				.then( text  => { 					console .log(text) 				}) }) 
 
Promise Promise應用 clipboard 1 2 3 4 5 var  promise = navigator.clipboard.readText()promise.then(data  => { 	console .log() }) 
 
Promise example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 const  myPromise = new  Promise ( (resolve, reject ) =>  {	resolve(4 ) }) myPromise.then( data  =>  { 	console .log('data=' , data) }).catch(err  => { 	console .log('error='  , err) }) const  myPromise = new  Promise ( (resolve, reject ) =>  {	setTimeout (() =>  { 		resolve(6 ) 	}, 3000 ) }) myPromise.then( data  =>  { 	console .log('data=' , data) }).catch(err  => { 	console .log('error='  , err) }) api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  const  myPromise = new  Promise ((resolve, reject ) =>  {	var  request = new  XMLHttpRequest() 	request.open('GET' , api200, true ) 	 	request.onload = function ( )  { 		if  (this .status >= 200  && this .status < 400 ) { 			var  data = JSON .parse(this .response) 			resolve(data) 		} 	} 	request.onerror = function (err )  { 		reject(err) 	} 	request.send() }) myPromise.then( data  =>  { 	console .log('myPromise data =' , data) }).catch(err  =>  { 	console .log('error =' , err) }) const  sleep = ms  =>  	new  Promise (resolve  =>  setTimeout (resolve, ms)) sleep(1500 ).then( data  =>  {  	console .log('myPromise data' , data) }) .catch (err  =>  {  	console .log('err =' , err) }) 
 
async and await 
await 特性下,會等 promise 任務完成後才會讓程式繼續往下執行 
async,他能夠將 await 包在裡面,被包在裡面的 await 會依序地執行 
 
example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const  response = await  fetch(...)console .log(response)const  sleep = ms  =>	new  Promise (resolve  =>  setTimeout (resolve, ms)) async  function  main ( )  {	console .log('enter main' ) 	await  sleep(1000 ) 	console .log('exit main' )  } main() const  sleep = ms  =>	new  Promise (resolve  =>  setTimeout (resolve, ms)) function  getData ( ) {	const  api200 = 'https://run.mocky.io/v3/d2268e25-bfa4-4e70-a505-b5faf61f7047'  	return  fetch(api200) 	.then( response  =>  { 		return  response.json() 	}).then(json  => { 		console .log(json) 	}) } async  function  main ( )  {	console .log('enter main' ) 	await  sleep(1000 ) 	try  { 		const  result = await  getData() 	} catch (err) { 		console .log(err) 	} 	console .log('exit main' ) } main() 
 
瀏覽器上儲存資料 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  	</style >  </head > <body > 	<div >  		<div >  			id : <input  class ="id"  type ="text" >  		</div >  		<div >  			phone : <input  class ="phone"  type ="text" >  		</div >  		<button  class ="btn-save" > 儲存</button >  	</div >  	<script >  		function  setCookie (cname, cvalue, exdays )  { 			let  d = new  Date () 			 			d.setTime(d.getTime() + exdays*24*60*60*1000) 			let  expires = 'expires='  + d.toGMTString() 			document .cookie = cname + '='  + cvalue + ';'  + expires + ';path=/'  ; 		} 		function  getCookie (cname )  { 			let  name = cname + '='  			let  decodeCookie = decodeURIComponent (document .cookie) 			let  ca = decodeCookie.split(';' ) 			for  (let  i=0  ; i < ca.length ; i++) { 				let  c = ca[i] 				c = c.trimStart(c) 				if (c.indexOf(name) === 0) { 					return  c.substring(name.length, c.length) 				}	 			} 			return  ''  		} 		 		const  oldId = getCookie('user-id' ) 		document .querySelector('.id' ).value = oldId 		document .querySelector('.phone' ).value = getCookie('phone' ) 		 		document .querySelector('.btn-save' ) 		 	.addEventListener('click' , function ( ) { 		 			const  id = document .querySelector('.id' ).value 		 			 					setCookie('user-id' , id, 7 ) 					setCookie('phone' , document .querySelector('.phone' ).value, 7 ) 			}) 	</script >  </body > </html > 
 
儲存與 server 無關資料
simple example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  	</style >  </head > <body > 	<div >  		id : <input  class ="id"  type ="text" >  		<button  class ="btn-save" > 儲存</button >  	</div >  	<script >  		 		const  oldId = window .localStorage.getItem('id' ) 		document .querySelector('.id' ).value = oldId 		document .querySelector('.btn-save' ) 			.addEventListener('click' , function ( ) { 					const  id = document .querySelector('.id' ).value 					 					window .localStorage.setItem('id' , id) 			}) 	</script >  </body > </html > 
 
save job list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  	</style >  </head > <body > 	<div >  		<div >  			job : <input  class ="job"  type ="text" >  			<button  class ="btn-add" > 新增</button >  		</div >  		<div  class ="list" >  		</div >  	</div >  	<script >  		let  jobList = JSON .parse(window .localStorage.getItem('todo-list' )) 		let  idIndex = Number (JSON .parse(window .localStorage.getItem('id-index' ))) 		 		if  (jobList === null ) { 			jobList = [] 		} 		if (idIndex === 0) { 			idIndex++ 		} 		 		showList(jobList) 		document .querySelector('.btn-add' ) 			.addEventListener('click' , function ( )  { 				let  item = {} 				item.job = document .querySelector('.job' ).value 				if  (item.job !== '' ) { 					item.id = idIndex++ 					jobList.push(item) 					 					let  jobListJson = JSON .stringify(jobList) 					window .localStorage.setItem('todo-list' , jobListJson) 					window .localStorage.setItem('id-index' , String (idIndex)) 					 					showList(jobList) 				} 				else  { 					console .log('Input error' ) 				} 			}) 			 			function  showList (job )  { 				const  listDiv = document .querySelector('.list' ) 				listDiv.innerText = ''  				for  (let  i=0  ; i < jobList.length ; i++) { 					let  item = document .createElement('div' ) 					item.innerText = `${job[i].id}  : ${job[i].job} `  					listDiv.appendChild(item) 				} 			} 	</script >  </body > </html > 
 
session storage 網頁關掉即清除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  	<style >  	</style >  </head > <body > 	<div >  		id : <input  class ="id"  type ="text" >  		<button  class ="btn-save" > 儲存</button >  	</div >  	<script >  		 		const  oldId = window .sessionStorage.getItem('id' ) 		document .querySelector('.id' ).value = oldId 		document .querySelector('.btn-save' ) 			.addEventListener('click' , function ( ) { 					const  id = document .querySelector('.id' ).value 					 					window ,sessionStorage.setItem('id' , id) 			}) 	</script >  </body > </html > 
 
傳送資料 表單 from –> Browser 畫面更新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  </head > <body > 	<div  class ="app" >  		 		 		<form  method ="POST"  action ="https://google.com" >  			username: <input  type ="text"  name ="username" >  			<input  type ="submit" >  		</form >  	</div >  </body > </html > 
 
AJAX(Asynchronous JavaScript and XML) –> 資料回傳至 JavaScript AJAX google - 瀏覽器的限制 同源策略(Same-origin policy) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  </head > <body > 	<script >  		const  request = new  XMLHttpRequest() 		 		request.onload = function ( )  { 			if (request.status >= 200 && request.status < 400) { 				console .log(request.responseText) 			} 			else  { 				console .log('response error :' , request.status) 			} 		} 		 		request.onerror = function ( )  { 			console .log('error' ) 		} 		 		request.open('GET' , 'https://google.com' , true ) 		request.send() 	</script >  </body > </html > 
 
AJAX fake data - Access-Control-Allow-Origin : * CORS(全名為 Cross-Origin Resource Sharing) 跨來源資源共享 : server response head 加 Access-Control-Allow-Origin : *
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <!DOCTYPE html > <html  lang ="en" > <head > 	<meta  charset ="UTF-8" >  	<meta  name ="viewport"  content ="width=device-width, initial-scale=1.0" >  	<meta  http-equiv ="X-UA-Compatible"  content ="ie=edge" >  	<title > Document</title >  </head > <body > 	<script >  		const  request = new  XMLHttpRequest() 		 		 		 		 		 		 		 		 		 		 		 		request.onload = function ( )  { 			if (request.status >= 200 && request.status < 400) { 				console .log(request.responseText) 			} 			else  { 				console .log('response error :' , request.status) 			} 		} 		 		request.onerror = function ( )  { 			console .log('error' ) 		} 		 		request.open('GET' , 'https://reqres.in/api/users/2' , true ) 		request.send() 	</script >  </body > </html > 
 
     
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function  sendTwitchApi (url, respProcess )  {	const  request = new  XMLHttpRequest() 	 	request.onload = function ( )  { 		if  (request.status >= 200  && request.status < 400 ) { 			 			respProcess(request.responseText) 		} 		else  { 			console .log('response :' , request) 			console .log('response error :' , request.status) 		} 	} 	 	 	request.onerror = function ( )  { 		console .log('error' ) 	} 	 	 	request.open('GET' , url, true ) 	 	request.setRequestHeader('Accept' ,'application/vnd.twitchtv.v5+json' ); 	request.setRequestHeader('Client-ID' ,'qvtuq71csrlv5ipxo1ljzgbzqn1okh' ); 	request.send() } 
 
JSONP(JSON with Padding) 第三種方式資料交換方式 
img, scrip不受同源限制 
使用 script 傳回 json data 即可不受 同源策略 限制 
若 json 外部可包一個 function 即可方便處理,故要 server 配合 
某些 server 可指定 callback function(如 Twitch) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <script > 	function  receiveData  (response )  { 		console .log(response); 	} </script > <script > 	receiveData( 	 { 		 name: 'Robert' , 		 age: 30 	 } 	) </script > 
 
單向資料傳送(email 或 廣告 追蹤) 擺一張小而透明的檔案,若網頁被打開,server就知道 email/廣告 被打開 
Window method alert() Displays an alert dialog
1 2 3 window .alert("hello!" )alert("hello2 !" ) 
 
load 畫面 1 2 3 4 location.reload() window .location = 'index.html?id='  + respId
 
window load complete 1 2 3 window .onload = function ( )  {	...... } 
 
Snippet for JavaScript escape HTML 1 2 3 4 5 6 7 function  escapeHTML (s )  {   return  s.replace(/&/g , '&' )           .replace(/"/g , '"' )           .replace(/</g , '<' )           .replace(/>/g , '>' )           .replace(/'/g , "'" ); }