JavaScript-DOM操作

  • 680
  • 0
  • JS
  • 2020-10-17

DOM(Document Object Model)指的是文件中(HTML、XML等)的元素、屬性或文字都被視為一個物件的集合,構成文件的每個元素、屬性或文字都稱作為節點(Node)

DOM的操作就是針對節點提供取出、新增、取代或刪除的操作

透過id取得元素節點

id只能是唯一不能有第二個

<p id="node" class="node">我是節點</p>
<script type="text/javascript">
	var node=document.getElementById('node').textContent;
	console.log(node);
</script>

透過標籤取得元素節點

因為標籤是複數,所以是使用getElements

取得標籤會是一個集合元素,所以需要使用迴圈走訪

<p id="node" class="node">我是節點</p>
<script type="text/javascript">
	var node=document.getElementsByTagName('p');
	for(var i=0;i<node.length;i++){
		console.log(node.item(i).textContent);//這裡也可以寫成這樣console.log(node[i].textContent);
	}
</script>

透過名稱(Name)取得元素節點

名稱也有可能是複數所以也是使用getElements

<p id="node" class="node" name="node">我是節點</p>
<script type="text/javascript">
	var node=document.getElementsByName('node');
	for(var i=0;i<node.length;i++){
		console.log(node[i].textContent);
	}
</script>

使用選擇器取得元素

使用querySelector/querySelectorAll選擇器可以比使用get方法設定更複雜的條件,但是效能較差

querySelector:單一元素

querySelectorAll:NodeList物件

<p id="node" class="node" name="node"><span class="innClass">我是內部節點</span></p>
<script type="text/javascript">
	var list=document.querySelectorAll('#node .innClass');//取得id為node底下的innClass的class名稱的元素
	for(var i=0;i<list.length;i++){
		console.log(list[i].textContent);
	}	
</script>

節點尋訪

使用getxxx與queryxxx等方法都是以特定位置取得元素但是這兩個方法都會對整份文件逐一搜尋所以效能不是很好,但是JS還提供以目前節點為出發點透過相對位置取得元素,效能上會比前者兩種方法好

使用節點方式

<form action="#">
		<select id="selectNum">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button id="btn">取得內容</button>
	</form>
	<script type="text/javascript">
		var selectNum=document.getElementById('selectNum');
		var opts=selectNum.childNodes;//取得selectNum的子節點
		for(var i=0;i<opts.length;i++){
			console.log(opts[i].value);
		}
	</script>

使用元素方式

<form action="#">
		<select id="selectNum">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button id="btn">取得內容</button>
	</form>
	<script type="text/javascript">
		var selectNum=document.getElementById('selectNum');
		var opts=selectNum.firstElementChild;//取得子元素
		while(opts){//子節點存在才執行迴圈
			console.log(opts.value);
			opts=opts.nextElementSibling;//取得下一個子元素
		}
	</script>

觸發事件與處理程序

定義觸發事件需要先定義以下三項

  1. 由哪個元素觸發事件
  2. 要觸發什麼事件
  3. 觸發的事件與哪個事件處理程序或監聽器關聯

定義一個click簡單事件

<button id='btn'>觸發事件</button>
	<script type="text/javascript">
		document.getElementById('btn').onclick=()=>alert('觸發click事件');
	</script>

使用addEventListener監聽器

相較於onxxx事件addEventListener可以讓同一個元素同一事件附加多個程序

<button id='btn'>觸發事件</button>
	<script type="text/javascript">
		document.getElementById('btn').addEventListener('click',()=>alert('被觸發了'));
	</script>

取得與設定屬性及文字

使用節點屬性存取

<a id="google" href="https://www.google.com">Google</a>
	<script type="text/javascript">
		var linkGoogle=document.getElementById('google');
		var url=linkGoogle.href;//取得href屬性
		console.log(url);
		linkGoogle.href="https://www.yahoo.com.tw";//設定href屬性
		url=linkGoogle.href;
		console.log(url);
	</script>

使用getAttribute與setAttribute方法

<a id="google" href="https://www.google.com">Google</a>
	<script type="text/javascript">
		var linkGoogle=document.getElementById('google');
		var url=linkGoogle.getAttribute('href');//取得href屬性
		linkGoogle.setAttribute('href','https://www.yahoo.com.tw');//設定href屬性
	</script>

取得與設定文字

<p id="p1">我是字串</p>
	<script type="text/javascript">
		var p1Text=document.getElementById('p1').textContent;//使用textContent屬性
		var p1Inner=document.getElementById('p1').innerHTML;//使用innerHTML屬性
		console.log(p1Text);
		console.log(p1Inner);
		document.getElementById('p1').textContent="被改變後的字串";
		document.getElementById('p1').innerHTML="被改變後的字串";
	</script>
/*
textContent與innerHTML差異在於是否視為HTML字串
如果沒有特殊需求,優先使用textContent
innerHTML有跨網站攻擊的可能性
*/

存取表單元素

取得InputBox與SelectBox的值

<form action="#">
		<input type="text" id="name"/>
		<select>
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button id='btn'>取值</button>
	</form>
	<script type="text/javascript">
		document.getElementById('btn').addEventListener('click',()=>{//監聽button是否click
			var textBox=document.getElementById('name');
			var selectBox=document.getElementsByTagName('option');
			console.log(textBox.value);//透過value取得值
			for(var i=0;i<selectBox.length;i++){
				console.log(selectBox[i].value);//透過value取得值
		}
		});
	</script>

取得CheckBox值

RadioButton也是使用同樣方式

<input type="checkbox" name="num" value="1" />1
	<input type="checkbox" name="num" value="2" />2
	<input type="checkbox" name="num" value="3" />3
	<br><button id="btn">取值</button>
	<script type="text/javascript">

		document.getElementById('btn').addEventListener('click',()=>{
			var checkList=document.getElementsByTagName('input');//使用元素或name都可以取得
			var result=[];
			for(var i=0;i<checkList.length;i++){
				if(checkList[i].checked)
				{
					result.push(checkList[i].value);//將選取的值加入陣列
				}
			}
			console.log(result.toString());
		})
	</script>

取得ListBox值

<select id="num" size="2" width="100px" multiple>//一樣使用select標籤,但是多一個multiple屬性
		<option value="1">1</option>
		<option value="2">2</option>
		<option value="3">3</option>
	</select>
	<br><button id="btn">取值</button>
	<script type="text/javascript">
		document.getElementById('btn').addEventListener('click',function(){
			var result=[];
			var numList=document.getElementsByTagName('option');
			for(var i=0;i<numList.length;i++){
				if(numList[i].selected){//select判斷選取是使用selected
					result.push(numList[i].value);//將選取的value加入陣列
				}
			}
			console.log(result.toString());
		});
	</script>

檔案上傳操作

取得上傳檔案資訊

<label for="file">Upload:</label><input type="file" id="file" name="file"/>
	<br><button id="btn">檔案上傳</button>
	<script type="text/javascript">
		document.getElementById('btn').addEventListener('click',()=>{
			var inputs=document.getElementById('file').files;
			for(var i=0;i<inputs.length;i++){//files回傳的類型是FileList物件所以需要用迴圈讀取
				var input=inputs[i];
				console.log('file name: '+input.name);
				console.log('file type: '+input.type);
				console.log('file size: '+input.size+'byte');
				console.log('file update: '+input.lastModifiedDate);
			}
		});
	</script>

新增、取代、移除節點

建立新節點

createElement:建立元素

createTextNode:建立字串節點

appendChild:新增節點

<form>
		<div>
			<label for="name">網站名稱:</label>
			<input id="name" name="name" type="text" size="30"/>
		</div>
		<div>
			<label for="url">URL:</label>
			<input type="url" id="url" name="url" size="50"/>
		</div>
		<div>
			<input type="button" id="btn" value="新增"/>
		</div>
	</form>
	<div id="list"></div>
	<script type="text/javascript">
		document.addEventListener('DOMContentLoaded',function(){
			document.getElementById('btn').addEventListener('click',function(){
				var name=document.getElementById('name');
				var url=document.getElementById('url');
				var anchor=document.createElement('a');//建立<a>元素
				anchor.href=url.value;//設定<a>元素的href屬性
				var text=document.createTextNode(name.value);//建立一個字串節點
				anchor.appendChild(text);//將字串節點加入到<a>元素
				var br=document.createElement('br');//建立<br/>元素
				var list=document.getElementById('list');
				list.appendChild(anchor);//將<a>元素及節點新增到<div>
				list.appendChild(br);//將<br/>元素新增到<div>
			});
		});
	</script>

取代與移除節點

replaceChild:取代節點

removeChild:刪除節點

firstChild:第一個子節點

lastChild:最後一個子節點

<ul id="list">
		<li><a href="JavaScript:void(0)" value="1">1</li>//JavaScript:void(0)表示顯示超連結但不回傳任何東西
		<li><a href="JavaScript:void(0)" value="2">2</li>
		<li><a href="JavaScript:void(0)" value="3">3</li>
	</ul>
	<input type="button" id="del" value="刪除" disabled="disabled" />
	<div id="pic"></div>
	<script type="text/javascript">
		var list=document.getElementById('list');
		var pic=document.getElementById('pic');
		var del=document.getElementById('del');
		list.addEventListener('click',function(e){
			var listValue=e.target.getAttribute('value');
		if(listValue){
			var img=document.createElement('img');
			img.src=listValue+'.jpg';
			img.height=200;
			img.width=150;
			if(pic.getElementsByTagName('img').length>0){
				pic.replaceChild(img,pic.lastChild);
			}else{
				del.disabled=false;
				pic.appendChild(img);
			}
		}
		});
		del.addEventListener('click',function(){
			pic.removeChild(pic.firstChild);
			del.disabled=true;
		});
	</script>

操作CSS

存取內部CSS

<body>
	<div id="elem">滑鼠移入時變色</div>
	<script type="text/javascript">
		var elem=document.getElementById('elem');
		//這裡使用箭頭函式會出錯,主要是箭頭函式沒有自己的this所以就會向上尋找而找到window
		elem.addEventListener('mouseover',function(){
			this.style.backgroundColor='red';
		});
		elem.addEventListener('mouseout',function(){
			this.style.backgroundColor='';
		});
	</script>
</body>

存取外部CSS

<body>
	<div id="elem">滑鼠移入時變色</div>
	<script type="text/javascript">
		var elem=document.getElementById('elem');
		//這裡使用箭頭函式會出錯,主要是箭頭函式沒有自己的this所以就會向上尋找而找到window
		elem.addEventListener('mouseover',function(){
			this.className='heighlight';//滑鼠移入就套用class
		});
		elem.addEventListener('mouseout',function(){
			this.className='';//滑鼠移出就移除class
		});
	</script>
</body>
//如果要套用多個class this.className='class1 class2 class3'

使用toggle切換

toggle的作用就是對類別(class)做on/off的切換

<body>
	<div id="elem" class="line">滑鼠移入時變色</div>
	<script type="text/javascript">
		var elem=document.getElementById('elem');
		elem.addEventListener('click',function(){
			this.classList.toggle('heighlight');
		});
	</script>
</body>

進階事件處理

註冊與移除事件

<body>
	<button id='btnAlert'>alert</button>
	<button id='btnAdd'>註冊事件</button>
	<button id='btnRemove'>移除事件</button>
	<script type="text/javascript">
		var btnAlert=document.getElementById('btnAlert');
		var btnAdd=document.getElementById('btnAdd');
		var btnRemove=document.getElementById('btnRemove');
		btnAlert.onclick=function(){alert('Hi!')};
		btnRemove.onclick=function(){//移除事件
			btnAlert.onclick=null;
		}
		btnAdd.onclick=function(){//重新註冊事件
			btnAlert.onclick=function(){alert('Hi!')};
		}
	</script>
</body>

移除事件監聽器

<button id="btn">alert</button>
	<script type="text/javascript">
		document.addEventListener('DOMContentLoaded',function(){
			var btn=document.getElementById('btn');
			var listener=function(){
				alert('hello!');
			};
			btn.addEventListener('click',listener,false);//註冊事件監聽器
			btn.removeEventListener('click',listener,false);//移除事件監聽器
		},false);

事件物件基本操作

<button id="btn">alert</button>
	<script type="text/javascript">
		document.getElementById('btn').addEventListener('click',function(e){
			var target=e.target;//e代表接收的事件物件,target代表觸發事件的物件
			console.log('觸發端: '+target.nodeName+'/'+target.id);//顯示是由什麼觸發的,這裡是button
			console.log('種類: '+e.type);//觸發的種類是哪一種,這裡是click
		})
	</script>

取得滑鼠座標

<div id="main" style="position: absolute;margin: 50px;width:300px;height: 300px;border: 1px solid;"></div>
	<script type="text/javascript">
		var main=document.getElementById('main');
		main.addEventListener('mousemove',function(e){
			main.innerHTML=`桌面上座標:${e.screenX}/${e.screenY}<br/>
			頁面上座標:${e.pageX}/${e.pageY}<br/>
			瀏覽器上座標:${e.clientX}/${e.clientY}<br/>
			元素上座標:${e.offsetX}/${e.offsetY}
			`
		});
	</script>

取得鍵盤的keyCode

需要特別注意的一點,如果是使用中文輸入一律只會顯示229

<input type="text" id="key"/>
	<script type="text/javascript">
		document.getElementById('key').addEventListener('keydown',function(e){
			console.log('Code: '+e.keyCode);
		});
	</script>