---
title: 'Javascript筆記'
disqus: Pai
---
# 壹、目錄及代辦事項
## Table of Contents
[TOC]
## 待學習項目
- [ ] - 30天AJAX串接挑戰[影片一](https://www.youtube.com/watch?v=DxdTWIYqIzU&feature=youtu.be)[影片二](https://www.youtube.com/watch?v=OtIOxstrhzY&feature=youtu.be)[影片三](https://www.youtube.com/watch?v=g71d4eyjyMY&feature=youtu.be)[串接資源](https://github.com/hsiangfeng/APIList)
- [ ] -
- [ ] -
- [ ] -
# 貳、基礎內容文件要點說明
## 一、文字與語意化
### 1.段落的語意
# 參、變數
## 一、變數簡介
### 1. 變數裡可以放進的值
- 數字
- 字串
- 布林
## 二、變數 number 介紹
### 1.指定id來變換變數
```html=
<p>這個紅豆餅的價錢是<em id="price"></em>元</p>
<script>
var cookiePrice = 35;
document.getElementById('price').textContent = cookiePrice;
</script>
```
- 或是使用getElementsByClassName來指定,但是要[]選擇第幾個class,class代表很多,所以getElementsByClassName的elements要加s
```javascript=
var cookiePrice = 35;
document.getElementsByClassName('price')[0].textContent = cookiePrice;
```
## 三、 變數 string 介紹
- 宣告string變數,內容記得要加""
- string也可以使用+號來將文字串成句子。
```javascript=
var expensive = "很貴"
var cookiePrice = "三十五塊";
var total = expensive + cookiePrice +",你要買嗎?";
document.getElementById('price').textContent = total;
```
- 透過變數指定id,並使用innerHTML增加html語法
```html=
<div id="wrap"></div>
<script>
var title = document.getElementById('wrap');
title.innerHTML = '<span>hello<span><br><span>hello<span>'
</script>
```
## 四、變數規則:注意事項
### 1.命名變數注意事項
- 開頭不能用數字
- 不能使用JS已經定義的關鍵字。ex:if、in、float..
[參考網址](https://www.w3schools.com/js/js_reserved.asp)
- 大小寫有區分
- 不能使用-和.
- 變數需要有語意化
## 五、變數 - 數字的運算
```javascript=
var snackPrice = 35;
var myMoney = 10;
var needMoney = snackPrice - myMoney;
var total = snackPrice * 5;
```
# 肆、函式
## 一、全域與區域變數
- 全域變數
```javascript=
var total=1;
console.log("變數total值是"+total);
```
- 函式內的區域變數
```javascript=
function count(num1,num2){
var total = num1 * num2;
console.log("這個值是"+total);
}
count(4,5);
```
- 如果全域變數內的值也想讓函式使用的話。全域變數去宣告,函式直接使用全域變數
```javascript=
var total;
function count(num1,num2){
total = num1 * num2;
console.log("這個值是"+total);
}
count(4,5);
console.log("變數total值是"+total);
```
- 但如果區域和全域都宣告了同一個變數,就會變成獨立的變數,值不互相干擾
```javascript=
var total=1;
function count(num1,num2){
var total = num1 * num2;
console.log("這個值是"+total);
}
count(4,5);//這個值是20
console.log("變數total值是"+total);//變數total值是1
```
## 二、hoisting 、var 觀念
```javascript=
console.log(phone); // undefined
var phone = 'myphone';
console.log(phone); // myphone
//如果在 var 的變數前加入 console.log(),這個時候並不會出錯,則是會跳出 undefined,這表示這個變數在記憶體中已經有一個位置,只不過目前並沒有值。
call('mike');//call mike
function call(name){
console.log("call "+name);
}
call('mike');//call mike
//function declaration 函式陳述式中(function 放在最前方的寫法),無論函式放在哪,整個函式都會被提升到最前方。所以就算call()放在函式前也可以呼叫的到。
```
## 三、 function 計算機案例
- parseInt: 使用parseInt將type轉換成Int
- typeof: 使用來查詢變數的type
```javascript=
document.getElementById('countId').onclick = function(){
var burgerPrice = 50;
var cokePrice =30;
var burger = parseInt(document.getElementById('burgerId').value)*burgerPrice;//使用parseInt將type轉換成Int
var coke = parseInt(document.getElementById('cokeId').value)*cokePrice;
console.log(typeof(burger));//可以藉由typeof()來查詢變數的type
console.log(typeof(coke));
document.getElementById('totalId').textContent = burger + coke;
}
```
## 四、function搭配return寫法
<iframe height="265" style="width: 100%;" scrolling="no" title="js-點餐程式練習" src="https://codepen.io/PaiP/embed/NWPMvpR?height=265&theme-id=default&default-tab=js,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/PaiP/pen/NWPMvpR'>js-點餐程式練習</a> by 白家齊
(<a href='https://codepen.io/PaiP'>@PaiP</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
# 伍、陣列與物件
## 一、陣列
### 1.寫法
- var field = [0,0,2];
### 2. 增加陣列內容
- 方法一
```javascript=
var field = [];
field.push(1);
field.push(2);
field.push(3);
出來的結果 [1,2,3]
```
- 方法二
```javascript=
var field = [];
field[0]=1;
field[1]=2;
// 出來的結果
[1,2]
// 此方法也可以指定陣列位置修改內容
field[0]=100;
// 出來的結果
[100,2]
```
### 3. 計算陣列長度
```javascript=
var field = [0,0,2];
console.log(field.length);
//計算結果
//3
```
## 二、物件
### 1. 寫法
- 注意物件裡面是用:來宣告,分隔每個變數是用,
```javascript=
var = farm{
farmer:'Mike',
chick: 2,
}
```
### 2.增加物件內的內容
```javascript=
var = farm{
farmer:'Mike',
chick: 2,
}
farm.dog = ['happy','lucky']
// 出來的結果:
farm{
farmer:'Mike',
chick : 2 ,
dog : ['happy','lucky'],
}
```
### 3.尋找物件裡的陣列
```javascript=
console.log(farm.dog[0]);
出來的結果:
happy
```
## 三、物件 + function 運用技巧
### 1.在物件中加入function
```javascript=
farm{
farmer:'Mike',
chick : 2 ,
dog : ['happy','lucky'],
goDinner: function(){
console.log(farmer+'回家吃飯')
}
}
farm.goDinner();
//出來的結果
Mike回家吃飯
```
### 1.在物件中再加入陣列
```javascript=
var text = document.querySelector('.text');
var farms = [
{
farmer:'milk',
dog : ['happy','lucky']
},
{
farmer:'Tom',
dog : ['funny','nicer'],
goDinner : function(){
text.innerText=farms[1].dog[1]+'回家吃飯';
}
}
];
farms[1].goDinner();
// 運算結果
nicer回家吃飯
```
# 陸、控制判斷(運算子、if、switch)
## 一、比較運算子:==、!==,程式碼範例
- 使用==,會自動幫忙轉型
- 使用!==,不會自動幫忙轉型,必須兩側的type都一樣。
```htmlmixed=
<p>您預定 5 個人來逛,而現在只有<input type="number" id="peopleNumber">,所以人到齊了嗎?<button id="peopleNumberVerify">確認</button></p>
<p>顧客:<em id="peopleNumberCheckResponse"></em></p>
```
```javascript=
document.getElementById('peopleNumberVerify').onclick = function(){
var nowPeople = parseInt(document.getElementById('peopleNumber').value);
console.log(typeof(nowPeople));
var reservedPeople = 5;
console.log(typeof(reservedPeople));
var peopleCheck = nowPeople == reservedPeople;
//就算兩個值,左邊是字串,右邊是數字,但使用==和!=的話,javascript會自動轉型
//但如果使用!==,就會不自動幫你轉型
document.getElementById('peopleNumberCheckResponse').textContent = peopleCheck;
};
```
## 二、比較運算子:嚴謹模式 ===
1 == '1' //true 因為JS會自動轉型
1 === '1' //false 三個等於屬於嚴謹模式,不會自動轉型
'1' === '1' //true
true == 1 //true JS會自動將1轉型為true
true === 1 //false
## 三、邏輯運算子
&& and
|| or
! not
## 四、if、else if
```javascript=
if(判斷式){
執行內容....
}else if(判斷式){
執行內容
}else if(判斷式){
執行內容
}
.
.
.
else{
其他狀況,執行內容
}
```
## 五、switch
```javascript=
switch(變數){
case 判斷:
執行內容;
break;
case 判斷:
執行內容;
break;
case 判斷:
執行內容;
break;
.
.
.
default:
其他狀況,執行內容;
break;
}
//例子1
var status = 10;
switch(true){
case status>=1&&status<=3:
console.log('我很餓');
break;
case status>3&&status<=7:
console.log('我有點餓');
break;
default:
console.log('我不餓')
break;
}
//例子2
var alert = 'red';
switch(alert){
case 'red':
console.log('紅色警報');
break;
case 'blue':
console.log('藍色警報');
break;
default:
console.log('警報解除')
break;
}
```
# 柒、迴圈
## 一、for迴圈
```javascript=
//for(var宣告 初始狀態;條件;更新內容)
for(var i=0;i<3;i++){
console.log(i);
}
//範例一:九九乘法
for(var i=1;i<10;i++){
for(var j=1;j<10;j++){
console.log(i+"*"+j+"="+j*i);
}
}
//結果
//0
//1
//2
```
## 二、for-array 寫法
- 犯的錯誤: 物件內的宣告是用:、分隔物件內的變數是用,
```javascript=
var farms = [
{
farmer :'Tom',
dog : 2 ,
},
{
farmer :'John',
dog : 2 ,
},
{
farmer : 'Mary',
dog : 2 ,
}
];
for(var i=0 ;i<farms.length ;i++){
console.log('第'+(i+1)+'個農場主人是'+farms[i].farmer)
};
```
## 三、for if 寫法
```javascript=
var farms = [
{
farmer :'Tom',
dog : 13,
},
{
farmer :'John',
dog : 2 ,
},
{
farmer : 'Mary',
dog : 12 ,
}
];
//篩選出有十隻狗狗以上的農場
for(var i=0 ;i<farms.length ;i++){
if(farms[i].dog>10){
console.log(farms[i].farmer+'的狗狗超過十隻')
}
};
```
## 四、for 加總+=
```javascript=
var farms = [
{
farmer :'Tom',
dog : 13,
},
{
farmer :'John',
dog : 2 ,
},
{
farmer : 'Mary',
dog : 12 ,
}
];
var dogTotal = 0;
for(var i=0 ;i<farms.length ;i++){
dogTotal += farms[i].dog; //等同於dogTotal = dogTotal+farms[i].dog
};
console.log('全部的狗狗有' + dogTotal + '隻');
```
## 五、for 與 break 運用
- break要放在if裡面,不然跑第一次的時候就會被中斷掉。只會跑一次。
```javascript=
var farms = [
{
farmer :'Tom',
dog : 13,
chick:51,
},
{
farmer :'John',
dog : 2 ,
chick:26,
},
{
farmer : 'Mary',
dog : 12 ,
chick:100,
}
];
//找到小雞有超過指定數量的農場
var buyChick = 60;
for(var i=0 ;i<farms.length ;i++){
if(farms[i].chick>buyChick){
console.log(farms[i].farmer+'的農場小雞有超過'+buyChick+'隻,我買走'+buyChick+'隻');
farms[i].chick -= buyChick;//farms[i].chick-buyChick = farms[i].chick
console.log(farms[i].farmer+'的農場剩下'+farms[i].chick+'隻小雞');
break;
}
};
```
## 六、return、break 和 break的差別
break : 當迴圈的值符合條件時候就立刻跳出迴圈,即使之後有其他的值也符合條件,[範例](https://codepen.io/HexSchool_yuko/pen/OejrLM)
continue: 在迴圈內的意思是,看到它就直接跳到下一圈,無視剩下的程式碼,[範例](https://codepen.io/HexSchool_yuko/pen/Yzzyzqm)
return: 回傳指定 function 的值,只能放在function內[範例](https://codepen.io/HexSchool_yuko/pen/NVZgZP)
# 捌、DOM
## 一、什麼是 DOM ?
![](https://i.imgur.com/dc4oks4.png)
## 二、querySelector - 選擇單一元素
- 選擇ID
```javascript=
document.getElementById('titleId').textContent = "1234";
//簡化document.getElementById('titleId');
var el = document.getElementById('titleId');
el.textContent = "12345";
```
- ID和Class的方法:querySelector(單個class)
```javascript=
//選擇ID
var el = document.querySelector("#title");
el.textContent = "123456";
//選擇Class
var el = document.querySelector(".titleClass em");
el.textContent = "12345678";
```
## 二、querySelectorAll - 選擇多個元素
```htmlmixed=
<h1 class="title"><em></em></h1>//顯示12345678
<h1 class="title"><em></em></h1>//顯示87654321
```
```javascript=
//選擇所有.titleClass下的em
var el = document.querySelectorAll(".titleClass em");
el[0].textContent = "12345678";
el[1].textContent = "87654321";
```
## 三、增加與取出標籤屬性
```htmlmixed=
<h1 class="titleClass">
<a href="#">yahoo</a>
</h1>
```
### 1.setAttribute - 修改標籤屬性
```javascript=
//將href="#"的內容修改為google的首頁
var el = document.querySelector('.titleClass a');
el.setAttribute('href','http://www.google.com.tw/');
////變更結果href="http://www.google.com.tw/"
```
### 2.getAttribute - 取出標籤內容
```javascript=
//取出href內容
var el1 = document.querySelector('.titleClass a').getAttribute('href');
console.log(el1);
////取出結果http://www.google.com.tw/
```
### 3.innerHTML - 取出整個Html標籤
```javascript=
//取出titleClass的html標籤
var el2 = document.querySelector('.titleClass').innerHTML;
console.log(el2);
////取出結果<a href="http://www.google.com.tw/">yahoo</a>
```
## 四、插入 HTML 標籤的兩種方法
![](https://i.imgur.com/o786VEu.png)
### 1. innerHTML
```htmlmixed=
<h2 id="bodyId"></h2>
<ul class="list"></ul>
```
- 增加Html標籤
```javascript=
var el3 = document.getElementById('bodyId');
var str = '<p class="blue">hello<p>'; //class內要使用雙引號做出區分
el3.innerHTML = str; //這邊要使用 =
```
- 在innerHTML加入變數
- 訣竅:加入'++'
```javascript=
//在innerHTML加入變數
var el4 = document.querySelector('.list');
var booking = 'http://www.booking.com'
var website = '訂房網站'
el4.innerHTML = '<li><a href="' + booking + '"> ' + website + ' </a></li>';
```
- innerHTML結合for迴圈
```htmlmixed=
<ul class="js-zooClass"></ul>
```
```javascript=
var zoo = [
{
zooName:'木柵動物園',
lion:10,
},
{
zooName:'新竹動物園',
lion:8,
}
]
var zooLength = zoo.length;
var el5 = document.querySelector('.js-zooClass');
var com = '';
for(var i = 0 ; i < zooLength ; i++){
var zooNameTotal = '<li>第'+i+'間動物園的名字叫'+zoo[i].zooName+'</li>';
com += zooNameTotal;
//必須把zooNameTotal的資料保留在com裡面,因為innerHTML的特性只要寫入一次就會把裡面的東西全洗掉
}
el5.innerHTML=com;
```
### 2. createElement
- 使用createElement增加子節點
原本的內容
```htmlmixed=
<ul class="js-cook">
<em>abcd</em>
</ul>
```
js
```javascript=
var str = document.createElement('em');
str.textContent = 'ABCD'; //預先寫好em裡面的字串
str.setAttribute('class','blue'); //預先寫好em裡面的class名稱
//後來才宣告出來,增加的em會接續在原本的em後面,不會把原先的內容洗掉
var el6 = document.querySelector('.js-cook').appendChild(str);
```
經過js後
```htmlmixed=
<ul class="js-cook">
<em>abcd</em>
<em>ABCD</em>
</ul>
```
- createElement 與 for 運用
原本的內容
```htmlmixed=
<ul class="js-zoo2Class">
<li>tiger</li>
</ul>
```
js
```javascript=
var zoo2 = [
{
zooName:'木柵動物園',
lion:10,
},
{
zooName:'新竹動物園',
lion:8,
}
]
var zoo2Length = zoo2.length;
var el7 = document.querySelector('.js-zoo2Class');
for(i = 0 ; i < zoo2Length ; i++){
var ptt = document.createElement('li');
ptt.textContent = '農場' + i + '獅子數量:'+zoo2[i].lion;
el7.appendChild(ptt);
}
```
js後的內容
```htmlmixed=
<ul class="js-zoo2Class">
<li>tiger</li>
<li>農場0獅子數量:10</li>
<li>農場1獅子數量:8</li>
</ul>
```
# 玖、event事件
## 一、什麼是event
- [w3cSchool網址](https://www.w3schools.com/tags/ref_eventattributes.asp)
## 二、event 物件 - 告知你當下元素資訊
```htmlmixed=
<input type="button" class="apple" value="點擊">
<script>
var el = document.querySelector('.apple');
el.onclick = function(e){
console.log(e)
};
</script>
```
- 使用chorme瀏覽器去看console,e裡面會呈現許多資訊。
- ![](https://i.imgur.com/ZZ75FbM.png)
## 三、addEventListener - 事件監聽
```htmlmixed=
<input type="button" class="pineapple" value="點擊2">
<script>
var el2 = document.querySelector('.pineapple');
////事件,帶入匿名function,false
el2.addEventListener('click',function(e){ alert('pineapple');},false)
</script>
```
## 四、綁定事件的語法差異
```htmlmixed=
<input type="button" class="on" value="onclick">
<input type="button" class="add" value="addclick">
```
```javascript=
var elOn = document.querySelector('.on');
var elAdd = document.querySelector('.add');
//使用onclick只會出現on2的事件
elOn.onclick = function(){
alert('on1')
};
elOn.onclick = function(){
alert('on2')
};
//使用監聽兩個事件都會出現
elAdd.addEventListener('click',function(e){alert('add1')},false);
elAdd.addEventListener('click',function(e){alert('add2')},false);
```
- 使用onclick只會出現on2的事件
- 使用監聽兩個事件都會出現
## 五、Event Bubbling、Event Capturing 差異
```htmlmixed=
<div class="outbox">
<div class="box"></div>
</div>
```
```javascript=
var outelbox = document.querySelector('.outbox');
var elbox = document.querySelector('.box');
outelbox.addEventListener('click',function(){alert('out')},true);
elbox.addEventListener('click',function(){alert('in')},true);
```
- false冒泡事件:會從box->outbox由內向外監聽(預設)
- true捕捉事件:會從outbox->box由外向內監聽
## 六、stopPropagation 終止氣泡
```javascript=
var outelbox = document.querySelector('.outbox');
var elbox = document.querySelector('.box');
outelbox.addEventListener('click',function(e){alert('out')},false);
elbox.addEventListener('click',
function(e){
e.stopPropagation();//告訴事件不要再往外找
alert('in');
}
,false);
```
## 七、preventDefault - 取消預設觸發行為
```htmlmixed=
var elcancel = document.querySelector('.post');
elcancel.addEventListener
('click',
function(e){
e.preventDefault();
},false
)
```
- 常用在
- 取消a連結預設行為
- 取消submit將資料傳到後端,先用js檢查表格內容,再使用post去傳送
## 八、e.target - 了解目前所在元素位置
```htmlmixed=
<div class="header">
<ul>
<li>
<a href="#">HEKKO</a>
</li>
</ul>
</div>
```
```javascript=
////要怎麼知道我現在點擊到的是ul、li還是a連結
var elPos = document.querySelector('.header');
elPos.addEventListener('click',function(e){
console.log(e.target);
},false)
```
- 使用e.target找出目前點擊的位置
## 九、change - 表單內容更動內容時觸發
- 使用下拉式選單選取option,配合change觸發事件,讀取data增加li項目
```htmlmixed=
<select name="" id="areaId">
<option value="大社區">大社區</option>
<option value="岡山區">岡山區</option>
<option value="路竹區">路竹區</option>
</select>
<ul class="show"></ul>
```
```javascript=
var data = [
{
seq: 1,
行政區: "大社區",
臨時停車處所: "老人文康活動中心",
可提供小型車停車位: "10",
地址: "金龍路65號"
},
{
seq: 3,
行政區: "岡山區",
臨時停車處所: "嘉興國中",
可提供小型車停車位: "16",
地址: "嘉興里信中街486號"
},
{
seq: 9,
行政區: "岡山區",
臨時停車處所: "壽天國小",
可提供小型車停車位: "40",
地址: "公園東路55號"
},
{
seq: 10,
行政區: "路竹區",
臨時停車處所: "蔡文國小",
可提供小型車停車位: "60",
地址: "國昌路548號"
},
{
seq: 11,
行政區: "路竹區",
臨時停車處所: "一甲國中",
可提供小型車停車位: "50",
地址: "一甲路 111 號"
},
{
seq: 12,
行政區: "路竹區",
臨時停車處所: "路竹高中",
可提供小型車停車位: "30",
地址: "中華路292號"
}];
var elArea = document.querySelector('#areaId');
var elShow = document.querySelector('.show');
var updatefunction = function(e){
var dataLen = data.length;
var select = e.target.value;
var listArea = '';
for(var i = 0 ; i<dataLen ; i++){
if(select == data[i].行政區){
listArea += '<li>編號:' + data[i].seq + '</li>';
}
}
elShow.innerHTML = listArea; //innerHTML是用等於=
}
elArea.addEventListener('change',updatefunction,false);
////可以把function另外獨立寫出來再帶進去
```
## 十、keyCode - 點擊鍵盤,射發火箭!
- 使用keycode去指定鍵盤按鈕,觸發事件。
- 鍵盤1的keycode按鈕是49,當按下1時就會觸發Rock-1發射
<iframe height="265" style="width: 100%;" scrolling="no" title="keyCode - 點擊鍵盤,射發火箭!" src="https://codepen.io/PaiP/embed/WNbyGow?height=265&theme-id=default&default-tab=html,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/PaiP/pen/WNbyGow'>keyCode - 點擊鍵盤,射發火箭!</a> by 白家齊
(<a href='https://codepen.io/PaiP'>@PaiP</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
## 十一、blur - 離開焦點時進行事件觸發
狀態focus: ![](https://i.imgur.com/FiDnu6S.png)->移開滑鼠點擊其他地方->狀態blur: ![](https://i.imgur.com/c9vkXMe.png)
- 練習目標: input內不得為字串、空白或負數,按下計算按鈕時前確認兩欄都有填寫[範例](https://codepen.io/PaiP/pen/MWYXbKB?editors=1010)
```htmlmixed=
<div class="wrap">
<div class="wrap-inner">
<h1>六角西餐廳 - 顧客點餐篇</h1>
<p>服務生:Hello,請問您想要點什麼?</p>
<p> 顧客:給我 <input type="text" id="hamNumId" > 個漢堡,再 <input type="text" id="cokeNumId"> 杯可樂吧!</p>
<p>服務生:<input type="button" Id="countId" value="計算中">,好的,總計是<em id="totalId" class="tag"></em>元</p>
</div>
</div>
```
```javascript=
//方法一: 使用if
function checkContent1(e){
var ta = e.target.value;
var taInt = parseInt(ta);
if(ta==''){
alert('此欄位不可為空'); //不得為空值
};
if(isNaN(taInt)&&ta != ''||taInt<0){
alert('此欄位必須為正值'); //不得為字串或負值
}
};
//方法二: 使用break
function checkContent2(e){
var ta = e.target.value;
var taInt = parseInt(ta);
switch(true){
case ta == '':
alert('此欄位不可為空');
break;
case isNaN(taInt)&&ta != ''||taInt<0: //一開始我使用case isNaN(parseInt(ta))無法運行
alert('此欄位必須為正值');
break;
};
}
function count(){
var ham = document.getElementById('hamNumId').value;
var coke = document.getElementById('cokeNumId').value;
var hamPrice = 30;
var cokePrice = 20;
var elTotal = document.getElementById('totalId');
if (ham == '' || coke == '') {//點擊計算前,確認兩欄都有填入
alert('你兩個都要買!!!');
return; //如果沒填入使用return停止
}
totalPrice = parseInt(ham)*hamPrice+parseInt(coke)*cokePrice
elTotal.textContent = totalPrice;
};
document.querySelector('#hamNumId').addEventListener('blur',checkContent1,false);
document.querySelector('#cokeNumId').addEventListener('blur',checkContent2,false);
document.querySelector('#countId').addEventListener('click',count,false);
```
## 十二、 mouse - 當滑鼠滑入指定內容時觸發
[老師範例](https://jsbin.com/segurubixa/edit?html,css,js,console,output)
```htmlmixed=
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
<div class="box box4"></div>
<div class="box box5"></div>
<div class="box box6"></div>
```
```javascript=
var el = document.querySelectorAll('.box');
var Len = el.length;
for(var i = 0;i<Len;i++){
el[i].addEventListener('mousemove',function(e){
alert('你輸了!');
});
}
```
## 十三、網頁座標 - 了解 screen、page、client 箇中差異
- screen 是整個螢幕的解析度的座標點
- PAGE 以整個網頁寬高為主,y軸拖曳軸多長都會算
- CLIENT 是以瀏覽器窗口計算
## 十四、事件監聽優化篇 - 從父元素來監聽子元素內容
```javascript=
//只有點選到li時才會出現alert
var al = document.querySelector('.list');//先選取整個父元素,在從這個範圍內篩選我要的
al.addEventListener('click',function(e){
if(e.target.nodeName != 'LI'){return};
alert(e.target.textContent);
},false);
```
# 拾、localStorage - 瀏覽器資料儲存
## 一、setItem、getItem 基本操作
### 1.儲存當地資料:
localStorage.setItem('key',儲存的資料);
### 2.讀取當地資料:
localStorage.getItem('key');
```htmlmixed=
<label for="name">請輸入你的名字</label>
<input type="text" class="inputName">
<input type="button" class="enterBtn" value="點擊">
<input type="button" class="callBtn" value="呼叫">
```
```javascript=
//宣告變數
var inputValue = document.querySelector('.inputName');
var enter = document.querySelector('.enterBtn');
var call = document.querySelector('.callBtn');
//函式編寫
function save(e){
var str = inputValue.value;
localStorage.setItem('Name',str); //儲存資料
}
function callName(e){
var str = localStorage.getItem('Name'); //讀取資料
alert('儲存的名字是'+str);
//監聽
enter.addEventListener('click',save,false);
call.addEventListener('click',callName,false);
}
```
### 3.刪除個別數據
localStorage.removeItem('key')
### 4.刪除所有數據
localStorage.clear()
## 二、透過 JSON.parse、JSON.stringify 來編譯資料
因為LocalStorage只能把資料存成String,所以收到Array資料時必須做編譯
### 1. JSON.stringify
- 將Array轉成String
JSON.stringify(陣列名稱)
### 2. JSON.parse
- 將String轉成Array
JSON.parse(陣列名稱)
```javascript=
var farms = [
{
farmer: 'Toma', //文字記得要括號
},
{
farmer: 'Mike',
},
];
var farmsString = JSON.stringify(farms);//將物件轉為字串
localStorage.setItem('farmer',farmsString);//字串才能儲存
var farmsArray = JSON.parse(farmsString);//將字串轉為物件
console.log(farmsArray[1].farmer);//物件及陣列才能讀取
//console: Mike
```
## 三、data-* - 透過 dataset 讀取自訂資料
### HTML內的data-*
在html內可以自訂data-名稱="數字或字串"
### JS讀取
var 變數名稱 = e.target.dataset.data名稱;
```htmlmixed=
<ul class="list">
<li data-num="0" data-cat="3">吉米</li>
<li data-num="0" data-cat="1">米zo</li>
</ul>
```
```javascript=
var dataGet = document.querySelectorAll('.list li');
function add(e){
var num = e.target.dataset.num;
var cat = e.target.dataset.cat;
console.log('編號' + num + ',貓'+cat+'隻');
}
var temp = document.querySelector('.list');
var len = temp.getElementsByTagName('li').length;
for(var i=0 ; i<len ; i++){
dataGet[i].addEventListener('click',add,false);
}
```
## 四、dataset、array 運用
選取大範圍的ul,不要單選小範圍的ul li,
使用e.target.nodeName去限定選取的標籤,如果不是li就使用return中斷。
```htmlmixed=
<ul class="list">
</ul>
```
```javascript=
var data = [{
farmer : '卡斯柏',
},
{
farmer : '喬恩',
},
];
var el = document.querySelector('.list');
function dataCount(e){
var dataLen = data.length;
var str ='';
for(var i = 0 ; i<dataLen ; i++){
var count = data[i].farmer;
str += '<li data-num="' + i + '">第' + i + '個農夫是' + count +'</li>';
}
el.innerHTML = str; //使用innerHTML更新陣列資料
}
dataCount();
el.addEventListener('click',function(e){
var ta = e.target.nodeName; //選取nodeName
if(ta !== 'LI'){return;};//如果不是LI就return
var num = e.target.dataset.num;//選取dataset資料
console.log(data[num].farmer);
});
```
## 四、splice - 刪除 array 資料
### splice
- 陣列名稱.splice(位置,刪除數量);
```javascript=
var data = [{
farmer : '卡斯柏',
},
{
farmer : '喬恩',
},
{
farmer : '喬瑟夫',
},
];
var el = document.querySelector('.list');
function dataCount(e){
var dataLen = data.length;//dataLen要寫在方程式裡面,不然再次宣告時會找不到。
var str ='';
for(var i = 0 ; i<dataLen ; i++){
var count = data[i].farmer;
str += '<li data-num="' + i + '">第' + i + '個農夫是' + count +'</li>';
}
el.innerHTML = str;
}
dataCount();
el.addEventListener('click',function(e){
var num = e.target.dataset.num;
if(e.target.nodeName !== 'LI'){return;};
data.splice(num,1);
dataCount();
});
```
# 拾壹、瀏覽器功能探索 (BOM)
## 一、瀏覽器功能簡介
![](https://i.imgur.com/ZooE7zu.png)
- window
- history:歷史紀錄
- frames:iframe插件
- location: 目前位置href...
- DOM: document... html、element
- screen: 目前使用裝置寬高
- navigator: 瀏覽器版本、是否連上網
## 二、回上頁功能實作
- 第一次第一頁不能用JS的下一頁功能,因為還沒有history
- 第二次紀錄完後就可以使用了
```htmlmixed=
<h1>第一頁</h1>
<a href="b.html">連到第二頁</a>
<br>
<a href="#" id="next">下一頁(JS版)</a>
<script>
document.getElementById('next').onclick = function () {
window.history.forward();
}
</script>
```
-這時因為有history就可以回到上一頁了。
```htmlmixed=
<h1>第二頁</h1>
<input type="button" id="back" value="回到上一頁">
<script>
document.getElementById('back').onclick = function () {
window.history.back();
}
</script>
```
## 三、透過 JS 設計列印功能
```javascript=
document.getElementById('print').onclick = function () {
window.print()//出現列印畫面
}
document.getElementById('locat').onclick = function () {
console.log(location)//顯示location資料
}
document.getElementById('open').onclick = function () {
window.open('http://www.google.com.tw')//新開視窗轉址到指定網址
}
```
## 四、動態擷取瀏覽器高度 - innerHeight
- innerHeight:因為瀏覽器上面有工具欄,顯示屏又有工作列,所以會被擠掉。
- outerHeight:整個瀏覽器的高度
- 透過window.innerHeight來擷取網頁高度
```javascript=
document.querySelector('.hero').style.height = window.innerHeight+"px";
//當使用者一開始打開瀏覽器時,讀取到的瀏覽器高度
window.onresize = function(){
document.querySelector('.hero').style.height = window.innerHeight+"px"
}
//當使用者調整瀏覽器高度時(onresize),更新瀏覽器高度
```
# 拾貳、JS 開發邏輯思維養成
- 1. 資料model:先處理好資料的新增、刪除、修改
- 2. 事件event:使用者行為觸發程式
- 3. 介面View
init為一開始要注入的初始資料。
# 拾叁、AJAX
## 一、透過 XMLHttpRequest 物件跨瀏覽器撈資料
### 1、readyState:0 (var xhr = new XMLHttpRequest())
產生出XMLHttpRequest,但還沒連接
### 2、readyState:1 (xhr.open())
- 使用了open(),但還沒完送資料出去
- open('格式','讀取的網址',同步與非同步)
格式 : get(讀取資料)、post(傳送資料到伺服器)
### 3、readyState:2
使用send
### 4、readyState:3
loading
### 5、readyState:4
數據已經接收到
```javascript=
var xhr = new XMLHttpRequest();
xhr.open('get','https://hexschool.github.io/ajaxHomework/data.json',true);
xhr.send(null);
```
## 二、 AJAX 非同步觀念
open('格式','讀取的網址',同步與非同步)
- 非同步true: 不會等值撈回來,程式就會繼續往下跑,等到回傳時,才會自動回傳
- 同步false: 會等值撈回來,程式才繼續往下跑
但因為同步如果資料量太龐大,網頁會等太久,通常會使用非同步。
### 1.如何使用非同步讀取資料
```javascript=
xhr.onload = function(){ //onload代表確認資料有回傳回來
console.log(xhr.responseText);
var str = JSON.parse(xhr.responseText);
document.querySelector('.message').textContent = str[0].name;
}
```
## 三、HTTP狀態碼
```javascript=
xhr.onload = function(){
if(xhr.status == 200){
var str = JSON.parse(xhr.responseText);
document.querySelector('.section2').textContent = str[0].name;
}else{
alert('資料錯誤');
}
}
```
- **1xx - 參考資訊 (Informational)**
這些狀態碼代表主機先暫時回應用戶端一個狀態,所以在接收一般的回應之前,用戶端應準備接收一個或多個 1xx 的回應。我以前在寫 ASP 的時候比較有看到 IIS 使用到這些狀態碼回應,在 Apache 的環境我還未曾遇到過。
- 100 - 繼續。
- 101 - 切換通訊協定。
- 2xx - 成功 (OK)
- **2xx - 狀態碼表示伺服器成功接收到用戶端要求、理解用戶端要求、以及接受用戶端要求。**
- 200 - 確定。 用戶端要求成功。
- 201 - 已建立。
- 202 - 已接受。
- 203 - 非授權資訊。
- 204 - 無內容。
- 205 - 重設內容。
- 206 - 部分內容。
- 207 - 多重狀態 (WebDAV) -- 這好像只有在 IIS 中才有,HTTP/1.1 並沒有定義這個狀態。這狀態會出現在可以包含多個不同回應代碼 (視子要求數量而定) 的 XML 訊息之前。
- **3xx - 重新導向 (Redirection)**
用戶端瀏覽器必須採取更多動作才能完成要求。例如:瀏覽器可能必須重新發出 HTTP Request 要求伺服器上的不同頁面。
- 301 - 要求的網頁已經永久改變網址。此狀態要求用戶端未來在連結此網址時應該導向至指定的 URI。
- 302 - 物件已移動,並告知移動過去的網址。針對表單架構驗證,這通常表示為「物件已移動」。 要求的資源暫時存於不同的 URI 底下。 由於重新導向可能偶而改變,用戶端應繼續使用要求 URI 來執行未來的要求。 除非以 Cache-Control 或 Expires 標頭欄位表示,此回應才能夠快取。
ASP.NET 預設的 Response.Redirect 方法,就是以 302 Found 做回應。
- 303 - 通知 Client 連到另一個網址去查看上傳表單的結果(POST 變成 GET),當使用程式作網頁轉向時,會回應此訊息。
在 ASP.NET 中要輸出 HTTP 303 轉向的程式碼如下:
Response.StatusCode = 303;
Response.RedirectLocation = "/PageB.aspx";
- 304 - 未修改。用戶端要求該網頁時,其內容並沒有變更,應該回傳 304 告知網頁未修改。此時用戶端僅需要取得本地快取(Local Cache)的副本即可。
- 305 - 要求的網頁必須透過 Server 指定的 proxy 才能觀看 ( 透過 Location 標頭 )
- 306 - (未使用) 此代碼僅用來為了向前相容而已。
- 307 - 暫時重新導向。要求的網頁只是「暫時」改變網址而已。
- **4xx - 用戶端錯誤 (Client Error)**
這代表錯誤發生,且這錯誤的發生的原因跟「用戶端」有關。例如:用戶端可能連結到不存在的頁面、用戶端的權限不足、或可能未提供有效的驗證資訊(輸入的帳號、密碼錯誤)。下次看到 4xx 的回應千萬不要傻傻的一直查程式哪裡寫錯誤了(不過也有可能是程式造成的)。
- 400 - 錯誤的要求。
- 401 - 拒絕存取。 IIS 定義數個不同的 401 錯誤,以表示更詳細的錯誤原因。 這些特定的錯誤碼會顯示在瀏覽器中,但不會顯示在 IIS 記錄檔中:
- 401.1 - 登入失敗。
- 401.2 - 因為伺服器設定導致登入失敗。
- 401.3 - 因為資源上的 ACL 而沒有授權。
- 401.4 - 篩選授權失敗。
- 401.5 - ISAPI/CGI 應用程式授權失敗。
- 401.7 - Web 伺服器上的 URL 授權原則拒絕存取。 這是 IIS 6.0 專用的錯誤碼。
- 403 - 禁止使用。 IIS 定義數個不同的 403 錯誤,以表示更詳細的錯誤原因:
- 403.1 - 禁止執行存取。
- 403.2 - 禁止讀取存取。
- 403.3 - 禁止寫入存取。
- 403.4 - 需要 SSL。
- 403.5 - 需要 SSL 128。
- 403.6 - IP 位址遭拒。
- 403.7 - 需要用戶端憑證。
- 403.8 - 網站存取遭拒。
- 403.9 - 使用者過多。
- 403.10 - 設定無效。
- 403.11 - 密碼變更。
- 403.12 - 對應程式拒絕存取。
- 403.13 - 用戶端憑證已撤銷。
- 403.14 - 目錄清單遭拒。
- 403.15 - 超過用戶端存取授權數量。
- 403.16 - 用戶端憑證不受信任或無效。
- 403.17 - 用戶端憑證已經過期或尚未生效。
- 403.18 - 無法在目前的應用程式集區中執行要求的 URL。 這是 IIS 6.0 專用的代碼。
- 403.19 - 無法在這個應用程式集區中執行用戶端的 CGI。 這是 IIS 6.0 專用的代碼。
- 403.20 - Passport 登入失敗。 這是 IIS 6.0 專用的錯誤碼。
- 404 - 找不到。
- 404.0 - (無) – 找不到檔案或目錄。
- 404.1 - 無法在要求的連接埠上存取網站。
- 404.2 - 網頁服務延伸鎖定原則阻止這個要求。
- 404.3 - MIME 對應原則阻止這個要求。
- 405 - 用來存取這個頁面的 HTTP 動詞不受允許 (方法不受允許)。
- 406 - 用戶端瀏覽器不接受要求頁面的 MIME 類型。
- 407 - 需要 Proxy 驗證。
- 412 - 指定條件失敗。
- 413 - 要求的實體太大。
- 414 - 要求 URI 太長。
- 415 - 不支援的媒體類型。
- 416 - 無法滿足要求的範圍。
- 417 - 執行失敗。
- 423 - 鎖定錯誤。
- **5xx - 伺服器錯誤 (Server Error)**
這代表錯誤發生,且這錯誤發生的原因跟「伺服器」有關。伺服器因為發生錯誤或例外狀況(Exception)而無法完成要求(Request)時,就會回應 5xx 的錯誤,且這肯定跟伺服器有關。
- 500 - 內部伺服器錯誤。
- 500.12 - 應用程式正忙於在 Web 伺服器上重新啟動。
- 500.15 - 不允許直接要求 Global.asa。
- 500.16 – UNC 授權認證不正確。 這是 IIS 6.0 專用的錯誤碼。
- 500.18 – 無法開啟 URL 授權存放區。 這是 IIS 6.0 專用的錯誤碼。
- 500.19 - 此檔案的資料在 Metabase 中設定不當。
- 500.100 - 內部的 ASP 錯誤。
- 501 – 標頭值指定未實作的設定。
- 502 - Web 伺服器在作為閘道或 Proxy 時收到無效的回應。
- 502.1 - CGI 應用程式逾時。
- 502.2 - CGI 應用程式中發生錯誤。
- 503 - 服務無法使用。 這是 IIS 6.0 專用的錯誤碼。
- 504 - 閘道逾時。
- 505 - 不支援的 HTTP 版本。
## 四、AJAX POST 寫法
```javascript=
var xhr = new XMLHttpRequest();
xhr.open('get','https://hexschool-tutorial.herokuapp.com/api/signin',true);
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');//post-api最常用的格式
xhr.send('email=asad@gmail.com&password=12345678');
```
## 五、AJAX 作業
```javascript=
var loginSend = document.querySelector('.js-loginSend');
var signupSend = document.querySelector('.js-signupSend');
var login = function(e){
var loginMail = document.querySelector('.js-loginMail').value;
var loginPwd = document.querySelector('.js-loginPwd').value;
var loginAlert = document.querySelector('.js-loginAlert');
var loginArr = {};
loginArr.email = loginMail;
loginArr.password = loginPwd;
var xhrLogin = new XMLHttpRequest();
xhrLogin.open('post','https://hexschool-tutorial.herokuapp.com/api/signin',true);
xhrLogin.setRequestHeader('Content-type','application/json');
xhrLogin.send(JSON.stringify(loginArr));
xhrLogin.onload = function(){
console.log(xhrLogin);
var callBackLogin = JSON.parse(xhrLogin.responseText);
loginAlert.textContent = callBackLogin.message;//助教建議修改
}
}
var signup = function(e){
var signupMail = document.querySelector('.js-signupMail').value;;
var signupPwd = document.querySelector('.js-signupPwd').value;;
var signupAlert = document.querySelector('.js-signupAlert');
var signupArr = {};
signupArr.email = signupMail;
signupArr.password = signupPwd;
var xhrSignup = new XMLHttpRequest;
xhrSignup.open('post','https://hexschool-tutorial.herokuapp.com/api/signup',true);
xhrSignup.setRequestHeader('Content-type','application/json');
xhrSignup.send(JSON.stringify(signupArr));
xhrSignup.onload = function(){
console.log(xhrSignup);
var callBackSignup = JSON.parse(xhrSignup.responseText);
signupAlert.textContent = callBackSignup.message;//助教建議修改
}
}
loginSend.addEventListener('click',login,false);
signupSend.addEventListener('click',signup,false);
```
# 拾參、ECMAScript 6 入門 - let、const
let和const是用來宣告區塊裡的變數。
## 一、let - if、function 用法
### 1.使用let避免汙染到全域變數
## 二、const 特性
### 1.特性:唯讀,不能去做修改
```javascript=
const a = 10;
a = 11;
//Uncaught TypeError
```
### 2.可以修改的特例
- 陣列和物件
```javascript=
const obj = {
url:'http://dd.com'
}
obj.url = 'http.xx.com';
console.log(obj);
//"http.xx.com"
```
- 如何不被修改Object.freeze()
```javascript=
const obj = {
url:'http://dd.com'
}
Object.freeze(obj);//凍結
obj.url = 'http.xx.com';
console.log(obj);
//'http://dd.com'
```
### 3.let、const 注意事項與使用時機
- 不會向上提升
```javascript=
console.log(a);
let a =1
console.log(a);
```
- 不可重複命名
- 不會被放到window全域變數裡面
參考[網站](https://liangyingc.github.io/post/c01d9809.html)
# 拾肆、ECMAScript 6 入門 - 字串篇
## 一、Template literals - 輕鬆進行字串相加
### innerHTML
在原本字串相加的部分可以改由` ${img} `
```javascript=
title.innerHTML = `<div>${img}</div>`
```