--- 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>` ```