DOM 結點樹 維基百科
方便 js 選取
方便 css 渲染到對應標籤
當解析完一個網頁內容 ( 開啟一個網頁 ),會生成一個 DOM 也就是網站的節點樹 ( dom tree ) 如下,Document 為最根目錄的地方,所以要先從根目錄開始選取才能選到裡面的標籤 ( 例如 h1 、a )。
簡述 : 網頁一打開,會生成出一個 document。
document.getElementById().textContent
,就是從 Document 依序往內找到 Text 更改裡面的文字。出處 : JavaScript 工程師養成直播班 - 2021 春季班 影音
<body>
<script src="js檔案位置"></script>
</body>
<script src="js檔案位置"></script>
放置到 </body>
結尾前。<body>
內而非 <head>
→ 網頁打開,會從上往下執行,<body>
內的標籤轉化為 DOM 節點後,再依序往下執行 js 檔案才能夠解析到這些 DOM 節點。( 產生之後才能夠讀取 )Document.body
主要是「回傳目前文件的 <body>
節點,如元素不存在則回傳 null
」,因此只有 body
能使用。根據傳入的值,找到 DOM 中 ID 為 'xxx' 的元素 → document.getElementById('xxx');
。
針對給定的 Selector ( 選擇器 ) 條件,回傳第一個或所有符合條件的 NodeList ( 節點列表 )。
document.querySelector('xxx');
document.querySelectorAll('xxx');
getElementById
只可用來選取 ID ( 加井字號 #
) 的語法。<h1 id="textId" class="textClass"> text </h1>
// 程式碼太長
// document.getElementById('textId').textContent = '123';
// 使用變數縮短程式碼
const element = document.getElementById('textId');
element.textContent = '13579';
querySelector()
可以用來選取 ID ( 加井字號 #
) 或 CLASS ( 加點 .
) 的語法。<h1 id="textId" class="textClass">
<em>text</em>
</h1>
const element = document.querySelector('.textClass em')
element.textContent = '2468';
getElementById()
與 querySelector()
差異 ?getElementById()
選取元素侷限於 IDquerySelector()
選取元素包含 HTML 標籤、 ID 元素 、 CLASS 元素 。querySelector()
與 querySelectorAll()
差異 ?
querySelector()
只會抓第一筆資料做更新querySelectorAll()
可選擇多筆資料做更新
querySelector()
只會抓第一筆資料做更新<h1 id="textId" class="textClass">
<em>text</em>
</h1>
<h1 id="textId" class="textClass">
<em>text</em>
</h1>
var element = document.querySelector('.textClass em');
element.textContent ='123';
解析
querySelector()
只會抓第一筆資料做更新,所以只有第一筆有改到內容。querySelectorAll
選擇多筆資料做更新const element = document.querySelectorAll(".textClass em");
// element 數量
const elementTotal = element.length;
for (let i = 0; i < elementTotal; i++) {
//不要把陣列內的數值寫死,所以寫i,讓他去跑小括號內的條件
element[i].textContent = "text一起做更改";
}
querySelectorAll
可選擇多筆資料做更新,指定的東西會回傳陣列。
length
查數量,再帶入迴圈中querySelectorAll
選擇多筆資料做更新<h1 class="textClass">
<em>text</em>
</h1>
<h1 class="textClass">
<em>text</em>
</h1>
const element = document.querySelectorAll('.textClass em')
element[0].textContent = 123;
element[1].textContent = 123;
querySelectorAll
指定的東西會回傳陣列。.textClass em
數量,就可以依序帶值進去console.log(element);
回傳陣列 ( NodeList 為節點列表 ) ▲結構: setAttribute( '要更改的屬性' , '更改的屬性值' )
<a>
標籤的連結<h1 class="textClass">
<a href="#">title</a>
</h1>
const element = document.querySelector('.textClass a');
element.setAttribute('href','https://google.com');
****CodePen範例
<div id="textHere">Hello</div>
const element = document.getElementById('textHere');
//動態改變 textHere 屬性
element.setAttribute('ID','textRed');
setAttribute
把此屬性新增於 element
上,Hello 文字由黑變紅。id="strID"
getAttribute
→ 取出 HTML 中的屬性innerHTML
→ 取出 HTML 中的結構textContent
→ 取出 HTML 中的文字
<h1 class="textTitle">TITLE</h1>
<h2 class="textLink">
<a href="https://google.com">LINK</a>
</h2>
<div class="textTex">Hello</div>
// 方法 1.
const element = document.querySelector('.textLink a').getAttribute('href');
console.log(element);
// 方法 2
const element = document.querySelector('.textLink a');
console.log(element.getAttribute('href'));
getAttribute('屬性')
方式可以撈出 a 標籤內的連結。.textLink
的 HTML 結構<h2 class="textLink">
<a href="https://google.com">LINK</a>
</h2>
//方式一
const element = document.querySelector('.textLink')
console.log(element.innerHTML);
//會撈出 h2 內的所有結構
//<a href="https://google.com">LINK</a>
// 方式二 :先賦予在變數上
const element = document.querySelector('.textLink')
const content = element.innerHTML;
console.log(content);
innerHTML
取出 h2
標籤內的 a
結構。<h1 class="textTitle">TITLE</h1>
<h2 class="textLink">
<a href="https://google.com">LINK</a>
</h2>
<div class="textTex">Hello</div>
const element = document.querySelector('.textTitle').textContent;
console.log(element);
textContent
: 只會抓節點內的 『 文字 』 資訊。出處 : avaScript 工程師養成直播班 - 2021 春季班 影音
<input type="text" class="txt" value="你好嗎?">
const txt =document.querySelector('.txt');
//文字寫在 value 上,直接用 txt 選取 value
console.log(txt.value); // 你好嗎
<input type="text" class="txt" value="你好嗎?">
// 修改 list.value 的作用也不是給 select 賦予 value 值,而是更改它所指向的 option
const txt = document.querySelector('.txt');
txt.value = "Hello !";
console.log(txt.value); // Hello
<select class="list">
<option value="高雄市">高雄市</option>
<option value="台北市">台北市</option>
</select>
const list =document.querySelector('.list');
console.log(list.value);
下拉式選單的文字釘在台北市上。
<select class="list">
<option value="高雄市">高雄市</option>
<option value="台北市">台北市</option>
</select>
// 修改 list.value 的作用也不是給 select 賦予 value 值,而是更改它所指向的 option,因此 console.log(list.value); 一次只會出現一個值。
const list =document.querySelector('.list');
list.value = "台北市";
console.log(list.value);
為什麼 console.log(list.value);
只讀取到高雄市 ?
list
DOM 是選取到 select
這個標籤,select
本身是沒有 value
值的,它實際上只是回傳它所選取到的那個 option
的 value
,並不是直接指向 option
。
修改 list.value
的作用也不是給 select
賦予 value
值,而是更改它所指向的 option
,因此 console.log(list.value);
一次只會出現一個值。
// 可看出 select 本身沒有 value 屬性,但可以回傳它所選取到的那個 option 的 value
const list =document.querySelector('.list');
console.log(list.getAttribute('value')); //回傳 null
innerHTML
createElement('')
innerHTML
有個特性,會在指定的區域把原來的內容清空,放入新的值。
範例 0. 在 main 標籤中使用 innerHTML
<div class="main">TITLE</div>
const main = document.querySelector('.main');
main.innerHTML = '<h1>TITLE</h1>';
TITLE
被清空,以 <h1>TITLE</h1>
取代。範例 1. 在 <div id="main"></div>
內塞 H1 標籤
<div id="main"></div>
//方法1
//'<h1>TITLE</h1>' 也可以寫入class
const element = document.getElementById('main');
element.innerHTML = '<h1>TITLE</h1>'
//方法2
const element = document.getElementById('main');
const titleElement = '<h1>TITLE</h1>';
element.innerHTML = titleElement ;
// 試試 element.innerHTML = titleElement + titleElement; 會跑兩次唷!
// 從開發者工具可見,#main 內新增了 h1 標籤 ▲
➤ ES6 之前的寫法
"<h1 class="blue">123</h1>"
- - - 錯誤
'<h1 class="blue">123</h1>'
- - - 正確
外與內的單引號和雙引號需不同,否則解釋器會因無法分辨開頭結尾而報錯誤。
➤ ES6 樣板字面值寫法 ( 使用反引號 ```` tab 上方的按鍵 )
<h1 class="blue">123</h1>
字串使用反引號
就是 ES6 的樣板字面值寫法,樣板字面值寫法的好處是可以用 ${ }
直接帶入變數,不需使用 +
將每個字串及變數相加。
內容太龐大,可以使用變數以組字串方式帶入 innerHTML,這邊使用 ul
li
為範例。
範例 1. 把 li 內容帶入 ul 中 Codepen範例 ( ES6 之前寫法 )
HTML : <ul class="list"></ul>
const element = document.querySelector('.list');
let name = '卡斯柏'
let webSite = 'https://www.google.com';
//注意內外雙單引號用法& 變數帶入時前後以引號和加號包覆
//先在li外面用引號包起,再把裡面要帶入變數的用不同的引號包起,記得前後要有加號。
element.innerHTML = '<li><a href = "'+webSite+'">'+name+'</a></li>' ;
範例 1-1. 把 li 內容帶入 ul 中 ( ES6 樣板字面值寫法 )
const element = document.querySelector('.list');
let name = '卡斯柏';
let webSite = 'https://www.google.com';
// 使用樣板字面值寫法 - 不須擔心雙引號與單引號錯誤使用
element.innerHTML =`<li><a href='${webSite}'>${name}</a></li>`;
另外也可賦予字串變數,日後如果要新增很多個 li ,可以於 innerHTML 使用組字串的方式,如下 :
const element = document.querySelector('.list');
let name = '卡斯柏';
let webSite = 'https://www.google.com';
let content = `<li><a href='${webSite}'>${name}</a></li>`;
element.innerHTML = content + content;
從 Array 中撈出資料,顯示在網頁上。
範例 1. 列出每個農場農夫的名字。 CODEPEN
//農場陣列資訊
const farms = [
{
farmer: '卡斯伯',
dogs: ['詹姆士', '龐德']
},
{
farmer: '查理',
dogs: ['皮皮']
},
];
防止資料被蓋掉
innerHTML
特性 : 新帶入的值會把舊的值蓋過,所以查理會蓋過卡斯伯。迴圈內每把變數 farmersTotal
帶入跑一次迴圈,組好字串帶入又會把先前資料蓋過。
let farmersName = '';
空值的全域變數,來做累加字串。let farmersName = '';
本來是空字串,在迴圈內 farmersName += farmersAllName;
依序加入變數 farmersAllTotal 的內容 ( <li>${farms[i].farmer}</li>;
),就會有第一筆、第二筆依序跑出陣列中所有資料。// 錯誤寫法
const element = document.querySelector('.list');
const farmsLength=farms.length;
for( let i=0; i<farmsLength; i++){
let farmersAllName = `<li>${farms[i].farmer}</li>`;
// innerHTML 有新值會把舊值蓋掉的特性,所以每跑迴圈一次就會蓋掉之前的資料。網頁都只會顯示查理
element.innerHTML = farmersAllName;
}
// 正確:for 迴圈寫法
const element = document.querySelector('.list');
const farmsLength=farms.length;
let farmersName='';
for(let i=0; i<farmsLength; i++){
let farmersAllName = `<li>${farms[i].farmer}</li>`;
farmersName+=farmersAllName;
}
element.innerHTML=farmersName;
// forEach 寫法
const element = document.querySelector('.list');
let farmersName = '';
farms.forEach((i) => {
farmersName += `<li>${i.farmer}</li>`;
})
list.innerHTML = farmersName;
createElement('')
會保留原本內容,新增的值會依序動態加在原內容後方。 CODEPENappendChild()
在節點增加最後一個子節點。
拆解步驟
const str = document.createElement('em');
str.textContent = '123';
.title
) 內。 document.querySelector('.title').appendChild(str);
使用 appendChild()
會動態掛在 HTML 裡面元素 <em>TITLE</em>
的最後面位置。
<h1 class="title">
<em>TITLE</em>
</h1>
//新增一個節點 (新增 p 元素)
const str = document.createElement('p');
//動態增加內容 → 變數str 放置123文字內容。
str.textContent = '123';
//新增子節點 → 在 .title 的位置掛上子節點,子節點內放入上方新增的 p段落與文字內容 123。
document.querySelector('.title').appendChild(str);
範例 1. 在 HTML 內動態新增文字 567 ,並設定紅色。 codepen
<head>
<style>
.textRed {
color: red;
}
</style>
</head>
<body>
<h1 class="title">
<em>TITLE</em>
</h1>
</body>
//-------方法一
//取出容器
var space = document.querySelector('.title');
//新增p元素
var element = document.createElement('p');
//新增文字
element.textContent = '567';
//新增屬性
element.setAttribute('class','textRed');
//把 element(元素、文字、屬性都在裡面) 丟到容器內
space.appendChild(element);
//-------方法二
//新增節點標籤
let element = document.createElement('p');
//新增節點內容 & 新增 class
element.textContent = '567';
element.setAttribute('class','textRed');
//設定節點位置 (在.title後方掛上子節點,加入上方新增的標籤與內容 )
document.querySelector('.title').appendChild(element);
範例1. 列出每個農場農夫的名字。
//農場陣列資訊
var farms =[
{
farmer:'卡斯伯',
dogs:['詹姆士','龐德']
},
{
farmer:'查理',
dogs:['皮皮']
},
];
XSS ( Cross-site scripting ) 跨網站指令攻擊 : innerHTML
只是其中一個可以使用 XSS 的方法。刻意在 HTML 標籤或 JavaScript 埋一些惡意程式碼,做攻擊的動作。
不是讓使用者自己做操控 →
例如 : 留言板等表單輸入的東西,A 用戶留完 B 用戶看的到,但 A 用戶在裡面塞 <script src='病毒.js'></script>
,雖然網頁表面看不到,但在開發者工具查看會發現已被植入病毒。
通常這些讓用戶自行輸入的留言板,會做一些排錯,過濾掉可疑的語法,都確認沒有錯了才會送入資料庫。
可信任 → 政府提供的 open data 或自己建立的資料庫,例如 : 鄉鎮陣列資料庫 .. 等