# JS-T [toc] --- [Angular socket with nodejs](/WuSVWB89ReagAkK4ocOKsA) [Node.js](/Uawfp81ARnueCeZhm_sTEw) --- 1. 通常 <script> 會寫在 <head> 標籤裡 因為如果要一開始載入就執行, 通常會寫 -> window.onload:w = funtion() {} 這是全部跑完才會跑得 function, 所以就不會因為寫在 id 上面而讀取不到 2. 如果 <script> 放在最上面, 會讀不到下面的 id 3. 讀取 id, 並放入值 -> document.getElementById("test").innerHTML = '123'; 4. 從 js 寫入 html -> document.write`("<h1>hi</h1>")`; -> 雖然可以從 script 直接寫進去, 但還是把值放入進標籤(ex. h1 的結構會比較好) 5. console.log(), console. table() - 可以在網站按 f12(console), 可以看到 console 結果 - console.table 裡若放 array, console 的結果會用 table 呈現 index 和 value(比較清楚) 6. 在 JS 讀取 CSS 數值 - ex. 把 div1 的字體大小改成 div 的字體大小的 1.5倍, (parseFloat("1.2em") == "1.2") div1.style.fontSize = (parseFloat(div.style.fontSize)) * 1.5 + "em" 6. 變數宣告 -> 也有分 local, global -> 函數裡宣告就是 local 7. let block scope -> 只會在 { } 裡存在 -> ex. for {let i = 0;i < 10;i++)} -> 出了迴圈就消失 8. const -> 會一直持續存在 9. var -> var 也可以當作數字 10. boolean -> var a = true; -> var b = fasle; 11. parseInt 在字串裡把數字找出來, 前提是非數字的都在數字後面(ex. 123tommy) -> parseInt("123tommy") = 123 12. 宣告陣列, 五種都可以, - js 允許不同 type 的變數放在相同陣列 1. var a = new Array() 2. var a = new Array(3); 3. var a = []; 4. var a = new Array(1.5, '2009', true); 5. var a = [1.5, '2009', true] - 類似 dictionary 的陣列 var a = {"t" : 1, "o" : 2} 12-1. 加入陣列 - ex. var a = [] a.push(1); 13. js 函式寫法 var a = function() { } 會等於 function a () { ) var $1 = (id) => { } 等於 var a = function(id) { } 14. JS 不同型態變數運算 var a = "1" var b = 2 - 加, 減 a + b = "12"; - 乘, 除 a * b = 2; 15. == vs === - == 值一樣即可, ex. 1 == "1" 為 true - === 值、型態都要一樣, ex. 1 === "1" 為 false 16. and, or, not in JS -- and && -- or -- not ! 17. if 的另一種寫法 in JS - x = (condition) ? true : false; - ex. c = (1!=1) ? 1 : 2; 為 2 18. switch - 類似 if, 帶入一個參數會等於 case x - 每個(除了最後一個) case 完要加 break, 不加會往下跑直到遇到 break or 最後一個 - ex. switch(a=Today()) { case 1 : console.log(1); break; /* 不加 break 會執行 case 2*/ case 2 : console.log(2); } 19. for in - 把 array or string 的 index 值拿出來, 不是 value - ex. var ForIn = function() { str = "123"; b = [1,2,3]; a = {t : 1, o : 2, m : 3}; for (var i in a) console.log(i); } - in a 會印出 t, o, m - in b 會印出 0, 1, 2 - in c 會印出 0, 1, 2 20. for of - 把 array or string 的 value 拿出來 - ex. var ForOf = function() { /* 拿出 value */ b = [1, 2, 3]; c = "123"; for (var i of c) console.log(i); } - of b, c 都會印出 123 21. arguments 所有帶進去函式的參數會在一個陣列(arguments)裡面 - ex. 會印出 2 Test(1, 2, 3); function Test() { /* 可以不用帶變數去對應 */ console.log(arguments[1]); } 22. Class - JS 的 function 也能當作 class - ex. function A() { this.a = 1; # this 代表這個物件(A)底下的a是1, A.a = 1 this.print = function() { console.log(1); } } var b = new A(); console.log(b.a); # 印出 1 b.print() # 印出 1 23. JSON - Java Script Object notation(敘述) - stringify 把陣列變成字串 - ex. var a = JSON.stringify({a:1, b:'2'}) -> a = "{'a':1,b:'2'}" # 注意, 逗號後的空格不會被讀入字串中 - 可以直接用 key 把 value 拿出來 : ```javascript= a = {name : 123} console.log(a['name']); ``` 24. 常見的 Global function, 屬性 - isNaN 判斷是不是數字 - ex. isNaN("1") or isNaN(1), true isNaN("t") , false - indexOf() - ex. "123".indexOf("2"), 會是 3 - length - ex. "123".length , 會是 3 - substring 如果是負數就是 0, 和 slice 不同 - ex. "12345".substring(-2,2), 為 12 25. split - split 可依照資料在 html 中的換行進行切割 - ex. function GetId(id) { return document.getElementById(id); } window onload = function() { var a = GetId("2").innerHTML.split("\n"); # 遇到換行就 split } <div id = "2">1, a 2, b 3, c </div> 26. replace - 替換字串, 換掉第一個要換的 - ex. "123".replace("1", "a").replace("2", "b"); # 等於 ab3 27. join - 加入到每個陣列之間 - ex. var a = [1, 2, 3]; a.join(+) # 等於 1+2+3 28. push - 直接取代 - ex. var a = [1, 2, 3]; a.push(4); # 等於 4 29. onsubmit, onresetd 30. 類似 dictionary 的東西 -ex. var arrArea=[]; arrArea["台灣"]=["台北", "台中", "台南", "高雄"]; arrArea["日本"]=["東京", "大阪", "京都", "福岡", "札幌"]; 31. 在 JS 插入 selection 表單 - html 的 <select id = "area"> - js function insert() { for (let area in arrArea) { let opt = new Option(); opt.text = area; $("area").add(opt); } } 32. function 加 () 與 不加 加了(), 就是馬上呼叫, 不加就是當某某條件就會觸發 -ex. window.onload = function() { $("ncnu").onclick = putMark; // 當點了就會觸發這個函式 } 33. function(e) e = window.event 34. NaN - 意義 not an number 35. js get option value var num = $("sel_num").selectedIndex; console.log($("sel_num")[num].text); 36. 日期 - 前一日 date = new Date(); date.setDate(date.getDate() - 1); - 設置小時和分鐘 ```javascript= var today = new Date(); today.setHours(0,0,0,0); // 0 點 0 分 0 秒 ``` 37. 把 td 的 value 置中 td { text-align : center // 不能用 align :center } 38. 把 json 的 key 用 變數 var a = 'abc'; {[a] : 1}; 39. 自動按下按鍵 const event = new KeyboardEvent('action', {'keyCode' : num}) // action = keyup, keypress, keydown, num = 按鍵數字 document.dispatchEvent(event); - input checkbox default checked ```javascript= <input type = 'checkbox' name = 'paid' id = 'paid' checked/> ``` - JSON.stringify() doesn't know how to serialize a BigInt 值加上 .toString() ## function - copy function ```javascript= <button type = 'button' id = 'copy_bt'>複製</button> function cpContent() { copy the content to clipboard // select class name = copy var all_need_copy = getClass('copy'); var total_str = ''; // add the value needed to be copied for (let i = 0;i < all_need_copy.length;i++) { total_str += all_need_copy[i].value; total_str += "<new_element>"; } // create a temporary textarea to place the value of copy var el = document.createElement('textarea'); el.value += total_str; // add the value // make textarea unseen and unused el.setAttribute('readonly', ''); el.style = {position: 'absolute', left: '‑9999px'}; document.body.appendChild(el); el.select(); var copy_suc = document.execCommand('copy'); alert(copy_suc ? 'copy successfully' : 'copy failed'); //alert successful or failed document.body.removeChild(el); // remove copt textarea } ``` - paste function ```javascript= <button type = 'button' id = 'paste_bt'>貼上</button> getId("paste_bt").addEventListener('click', pasteContent); // paste the clipboard content async function pasteContent() { // paste the clipboard content var paste_text = await navigator.clipboard.readText(); paste_text = paste_text.split("<new_element>"); // the element need to put in the content of copied var all_need_copy = getClass('copy'); // put clickboard content in for (let i = 0;i < all_need_copy.length;i++) { all_need_copy[i].value = paste_text[i]; } } ``` - isNum ```javascript= function isNum(n) { // 是不是數字 return !isNaN(parseFloat(n)) && isFinite(n); } ``` - output html to pdf - javascript ```javascript= const btn = document.getElementById("button"); btn.addEventListener("click", function(){ // confirm the user if (!confirm('確定輸出 PDF 檔?')) return; // disable button btn.style.display = 'none'; window.jsPDF = window.jspdf.jsPDF; var element = document.getElementById('body'); let imgsData = html2pdf().from(element).set( { margin: -1, filename: 'text', html2canvas: { scale:4, useCORS: true }, jsPDF: {orientation: 'portrait', unit: 'pc', format: 'a3', compressPDF: true} }).output('img',{},'img'); setTimeout(()=>{ if(imgsData && imgsData._result){ let width = imgsData._result.width; let height = imgsData._result.height; let pdf2 = new jsPDF('', 'pt', [width, height]); pdf2.addImage(imgsData._result, 'jpeg', 0, 0, width, height); pdf2.save(getId('stu_year').innerHTML + '_' + getId('name').innerHTML + '_畢業學分檢核表'); } },800) // show button again setInterval(function(){ btn.style.display = 'block'; },1000); }); ``` - html ```html= <button id="button">輸出PDF檔</button> ``` - search ```javascript= function getId(id) { return document.getElementById(id); } var all_no = []; // 全部快捷的編號 var all_real = []; // 全部的真實名稱 var all_rela = []; // 全部的對應快捷 async function putKey() { // 把目前的快捷對應放進 table const {data : hot_key} = await axios.get('/hot_key'); // 清空 all_no = []; all_real = []; all_rela = []; for (let i = 0;i < hot_key.length;i++) { // 放入 table tab.innerHTML += "<tr/><td/>"+ hot_key[i].no + "<td>" + hot_key[i].real_name + "</td>" + "<td>" + hot_key[i].relative + "</td></tr>"; // 放入 array all_no.push(hot_key[i].no); all_real.push(hot_key[i].real_name); all_rela.push(hot_key[i].relative); } getId('search').addEventListener('change', checkSearch); }; putKey(); function checkSearch() { getId('search').addEventListener('change', checkSearch); // 搜尋條件是否為空的 if (getId('search').value == "" || getId('search').value == " ") { // 先清空 table tab.innerHTML = "<tr><td class = 'col_title' colspan = '3'><b>目前快捷</b>" + "<span class = 'position-absolute top-0 end-0' id = 'search_pos'>" + "搜尋 : <input type = 'text' id = 'search'/></span></td></tr>" + "<tr><td>編號</td><td>真實名稱</td><td>對應快捷</td></tr>"; putKey(); return; // 沒有輸入條件 } else { var search_value = getId('search').value; tab.innerHTML = "<tr><td class = 'col_title' colspan = '3'><b>目前快捷</b>" + "<span class = 'position-absolute top-0 end-0' id = 'search_pos'>" + "搜尋 : <input type = 'text' id = 'search'/></span></td></tr>" + "<tr><td>編號</td><td>真實名稱</td><td>對應快捷</td></tr>"; } var is_put = []; // 已經放進去的 // 條件一 : 真實名稱 for (i in all_real) { // 有符合的字串 if (all_real[i].includes(search_value)) { is_put.push(i); putEachKey(i); } } // 條件二 : 對應快捷 for (i in all_rela) { // 還沒放過且有符合的字串 if (!(is_put.includes(i)) && all_rela[i].includes(search_value)) { is_put.push(i); putEachKey(i); } } getId('search').addEventListener('change', checkSearch); getId('search').value = search_value; } function putEachKey(i) { // 把目前的快捷對應放進 table tab.innerHTML += "<tr/><td/>"+ all_no[i] + "<td>" + all_real[i] + "</td>" + "<td>" + all_rela[i] + "</td></tr>"; }; ``` - is collide 偵測碰撞 ```javascript= function isCollide(a, b) { // 偵測左邊球門是不是進球 var aRect = a.getBoundingClientRect(); var bRect = b.getBoundingClientRect(); return !( ((aRect.top + aRect.height) < (bRect.top)) || (aRect.top > (bRect.top + bRect.height)) || ((aRect.left + aRect.width-100) < bRect.left) || (aRect.left > (bRect.left + bRect.width)) ); } ``` - get random, 隨機數 ```javascript= function getRandomInt(max) { // max = 範圍最大值 return Math.floor(Math.random() * max); } ``` - 設置等待後,自動結束,不會一直重複 ```javacript= var myInterval = setInterval(function(){ clearInterval(myInterval); },50); ``` - 設定 table 的 row ```javascript= function mkAddTableRow() { // 製作新增帳務 table 的欄位 var add_tab = getId('add_tab'); // 要新增的 table for (let i = 0;i < total_row;i++) { // 總共幾個 row var tr = document.createElement('tr'); // row // 編號 var td_id = document.createElement('td'); // column td_id.innerHTML = i+1; // 編號 tr.appendChild(td_id); // row append column // reason column var td_reason = document.createElement('td'); var td_reason_input = document.createElement('input'); td_reason_input.id = 'add_reason' + i; td_reason.appendChild(td_reason_input); tr.appendChild(td_reason); // row append column // money column var td_money = document.createElement('td'); var td_money_input = document.createElement('input'); td_money_input.id = 'add_money' + i; td_money.appendChild(td_money_input); tr.appendChild(td_money); // row append column // mark column var td_mark = document.createElement('td'); var td_mark_input = document.createElement('input'); td_mark_input.id = 'add_mark' + i; td_mark.appendChild(td_mark_input); tr.appendChild(td_mark); // row append column add_tab.appendChild(tr); } // submit button var td_submit = document.createElement('button'); td_submit.id = 'submit_add'; td_submit.innerHTML = '送出'; add_tab.appendChild(td_submit); } ``` - bubble sort time or other ```javascript= function bSort(arr) { // bubble sort 排序購買時間和開藥時間 for (let i = 0;i < arr.length-1;i++) { for (let j = 0;j < arr.length-1;j++) { var time = arr[j].purchase_date ? arr[j].purchase_date : arr[j].time; var times = arr[j+1].purchase_date ? arr[j+1].purchase_date : arr[j+1].time; if (time < times) { var temp = arr[j+1]; arr[j+1] = arr[j]; arr[j] = temp; } } } return arr; } ``` - 找 element 的位置,並且基於原本位置更改 : ```javascript= var top = getComputedStyle(getId('xxx')).top; getId('xxx').style.top = (parseInt(top) + num) + 'px'; ``` - 今日日期 : ```javascript= function todayDate() { // 今日日期 var today = new Date(); var dd = String(today.getDate()).padStart(2, '0'); var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! var yyyy = today.getFullYear(); today = yyyy + '-' + mm + '-' + dd; return today; } ``` ## note - aysnc with out function name 1. use in add event listener ```getId('logout').addEventListener('click', async() => {int a;})``` 2. call directly ```javascript= (async() => { int a; })(); ``` - eventlistener 的 target id console.log(event.target.id); - beforeonload 關掉離開的 dialog : ```jvascript= window.addEventListener("beforeunload", async function(e) { e.returnValue = null; return null; }) ``` - beforeonload 離開顯示 dialog : ```javascript= window.onbeforeunload = async function(e) { } ``` - try catch 的 break - 設節點 : ```javascript= omgalabel: try { if( bar ) break omgalabel; console.log( bar ); // code } catch( e ){ // This code should not execute if !!bar } finally { // Code that executes no matter what console.log( true ); } ``` - disable input 的紀錄 : 不能用在 css `<input type = 'text' autocomplete="nope"></input>` - clear canvas ```javascript= const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); ``` - auto press key 自動按鍵 ```javascript= var evt = new KeyboardEvent("keydown", { bubbles: true, cancelable: true, keyCode: 13 }); element.dispatchEvent(evt); ``` - 用字串當變數名稱 ```javacscript= window[variableName]; ``` - transaction ```javascrip= let conn = await pool.getConnection(); // Start Transaction await conn.beginTransaction(); try { // Add Data in a batch,一定要把 value 放在後面,不能直接代入 await conn.batch("insert into test(`a`) values(?)", [1]); await conn.batch("insert into test(`a`) values(?)", ['12t']); // commit await conn.commit(); } catch(e) { console.log(e); // 還原 await conn.rollback(); } conn.release(); ``` - event.path 並不是所有的瀏覽器都有提供 - 解決方法 : `event.composedPath()` - 教學 : - page : 分頁功能 - html : ```html= <!-- table page --> <ul class="nav nav-tabs" id="myTab" role="tablist"> </ul> <div id = 'tab_pos_title' class = 'position-relative'></div> <div id = 'tab_pos' class = 'position-relative'></div> <nav aria-label="Page navigation example" class = 'position-absolute bottom-0' id = "page_top"> </nav> ``` - css : ```css= <style> a { color : #f33; -webkit-user-select:none; -moz-user-select:none; user-select:none; text-align : center; } #page_last { width : 105px; } #page_next { width : 105px; } #last_page { width : 80px; } #first_page { width : 80px; } #page_top { left : 30% } </style> ``` - js : 主要改 putRecord、getPageNum ```javascript= <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script> <script> function lessTime(times) { // 把時間弄得好看一點 if (times == null) // 如果還沒有時間 return null; var new_time = ''; for (let i = 0;i < times.length-5;i++) { // 不要後面五個字元 if (times[i] == 'T') { // 把 T 換掉 new_time += '\n'; continue; } new_time += times[i]; } return new_time; } function getId(id) { return document.getElementById(id); } // make page let now_page = 0; // 現在的頁數 async function putRecord(page) { const {data : user} = await axios.get('/viewPa/nId'); const {data : med_inventory_each} = await axios.get('/med_inventory_each', {params : {aId : user.nId}}); const {data : medicines} = await axios.get('/medicines_normal'); med_inventory_each.sort(function(a,b){ // 從最後看的開始排序 return b.no - a.no; }); var count_records = 0; // 總共有幾個可以放的紀錄, 不包含看完的 var count_added_records = 0; // 真正放了幾個紀錄進 table total_len = 0; // when reset table, reset the total_len too getId("tab").innerHTML = ""; // 每次重新點, 都清空 table await tabTitle(); // 製作 tab title // 把各個批次的藥分開 for (let i = 0;i < med_inventory_each.length;i++) { //console.log(med_inventory_each[i]); count_records++; // 計算總共有加了幾筆紀錄 if (count_records <= (page-1) * limit_records) // 還沒到可以放進去的 index continue; // 重找 if (count_added_records >= limit_records) // 真正放進去的紀錄不能超過限制的次數 break; // 停止 count_added_records++; // 真正放進去的次數 for (let k = 0;k < medicines.length;k++) { if (med_inventory_each[i].code == medicines[k].code) { // 藥碼相同,有此筆藥的資訊 tab.innerHTML += "<tr id = 'each_row'" + i + "/><td/>" + med_inventory_each[i].no + "<td>" + med_inventory_each[i].code + "</td>" + "<td>" + medicines[k].medi_eng + "</td>" + "<td>" + parseFloat(med_inventory_each[i].now_quantity) + "</td>" + "<td>" + med_inventory_each[i].expire + "</td>" + "<td>" + med_inventory_each[i].aId + "</td></tr>"; break; } } } } var total_len = 0; let limit_records = 14; // 頁面能顯示最大的列數量 async function tabTitle() { // 製作 table title const {data : user} = await axios.get('/viewPa/nId'); getId('tab').innerHTML = "<tr><td colspan = '7'>帳號:" + user.nId + "。單次批貨藥品紀錄</td>" + "</tr><tr><td>編號</td><td>藥碼</td><td>藥品名稱</td><td>數量</td><td>過期日期</td><td>負責人員</td>"; } function mkPage(page_num) { // make page with page_num if (getId('page_list')) // if page_list exist, renew one getId("page_list").remove(); // remove // 如果總頁數 < 一行限制最大頁數,一行限制最大頁數 = 總頁數 var temp_max_col_page = total_page_num < max_col_page ? total_page_num : max_col_page; // create and add the needed elements var page_list_element = document.createElement("ul"); page_list_element.className = "pagination"; page_list_element.setAttribute("id", "page_list"); var page_top = getId("page_top"); page_top.appendChild(page_list_element); var page_list = getId('page_list'); var page_list = getId('page_list'); if (page_num >= temp_max_col_page) { // 一行最大只能 10 頁 page_num = temp_max_col_page + parseInt(now_page); } if (page_num >= total_page_num) { // 不能超過最大頁數 page_num = total_page_num; } if (now_page > total_page_num-temp_max_col_page) { // 總共的頁數不能低於 10 ,所以當現在頁數 < 總頁數-10,開始的頁數還是要保持在總頁數 -10 start_page = total_page_num-temp_max_col_page; } else { // 開始頁數 = 現在頁數 start_page = now_page; } // 製作元素 // 上一頁的元素 var page_li= document.createElement("li"); page_li.className = "page-item"; var page_a = document.createElement("a"); page_a.className = "page-link"; page_a.setAttribute("id", "page_last"); page_a.innerHTML = '上一頁'; // start from page 1 page_li.appendChild(page_a); page_list.appendChild(page_li); // 首頁的元素 var page_li= document.createElement("li"); page_li.className = "page-item"; var page_a = document.createElement("a"); page_a.className = "page-link"; page_a.setAttribute("id", "first_page"); page_a.innerHTML = '首頁'; // start from page 1 page_li.appendChild(page_a); page_list.appendChild(page_li); for (let i = start_page;i < page_num;i++) { // make page with page num var page_li= document.createElement("li"); page_li.className = "page-item"; var page_a = document.createElement("a"); page_a.className = "page-link"; page_a.setAttribute("id", "page_"+(i+1)); if (i == now_page) { // 目前的頁數要用黑色字體 page_a.style.color = 'black'; } page_a.style.width = '50px'; page_a.innerHTML = (parseInt(i)+1); // start from page 1 page_li.appendChild(page_a); page_list.appendChild(page_li); } // 尾頁的元素 var page_li= document.createElement("li"); page_li.className = "page-item"; var page_a = document.createElement("a"); page_a.className = "page-link"; page_a.setAttribute("id", "last_page"); page_a.innerHTML = '尾頁'; // start from page 1 page_li.appendChild(page_a); page_list.appendChild(page_li); // 下一頁 var page_li= document.createElement("li"); page_li.className = "page-item"; var page_a = document.createElement("a"); page_a.className = "page-link"; page_a.setAttribute("id", "page_next"); page_a.innerHTML = '下一頁'; // start from page 1 page_li.appendChild(page_a); page_list.appendChild(page_li); } let start_page; // 開始的頁數 let max_col_page = 10; // 一行最多可以有幾個頁數 function mkPageListener(page_num) { // 依照 page 的數量監聽 // 如果總頁數 < 一行限制最大頁數,一行限制最大頁數 = 總頁數 var temp_max_col_page = total_page_num < max_col_page ? total_page_num : max_col_page; mkPage(page_num); // 製作頁面按鈕 if (page_num >= temp_max_col_page) { // 最大只能 15 頁 page_num = temp_max_col_page + parseInt(now_page);; } if (page_num >= total_page_num) { page_num = total_page_num; } getId('page_last').addEventListener('click', turnPage); getId('page_next').addEventListener('click', turnPage); getId('last_page').addEventListener('click', turnPage); getId('first_page').addEventListener('click', turnPage); for (let i = parseInt(start_page)+1;i < page_num+1;i++) // 從第一頁開始監聽 getId('page_'+i).addEventListener('click', turnPage); // put records in table depend on page num } function turnPage(e) { // 翻頁 if (e.target.innerHTML == "上一頁") { // 不能讓上一頁到 -1 if (now_page < 1) { now_page = 0; } else { now_page -= 1; } } else if (e.target.innerHTML == "下一頁") { if (now_page+1 < total_page_num) { // 下一頁不能超過最後一頁 now_page += 1; } } else if (e.target.innerHTML == "首頁") { now_page = 0; } else if (e.target.innerHTML == "尾頁") { now_page = total_page_num-1; } else { // 現在頁數 = 案的頁數-1 now_page = parseInt(e.target.innerHTML)-1; } mkPageListener(total_page_num); // 重新製作頁面按鈕、監聽 putRecord(now_page+1); // 把紀錄放進 table, 現在是第幾個 table, 第幾頁 }; let total_page_num; async function mkDoc(e) { // 製作醫生 table //now_page = 0; if (e == 'first') { var tab_id = 1; } else { var tab_id = getDid(e.target.id); // 取得 dId } now_table = tab_id; //mkTable(tab_id); // 製作該 id 的 table putRecord(tab_id); const {data : user} = await axios.get('/viewPa/nId'); const page_num = axios.get('/getPageNum', {params : {all_med : true, aId : user.nId}}); page_num.then(function(result) { // make page var page_num_result = {data : result}.data.data.page_num; // total records num total_page_num = countPageNum(page_num_result); // total_page_num = all records/limit_records mkPageListener(total_page_num); // make listener of page list }); } function countPageNum(page_num_result) { // count page num let page_num = Math.floor(page_num_result/limit_records); // without float let page_less = page_num_result%limit_records; if (page_less != 0) // is float page_num += 1; // add one more page return page_num; } mkDoc('first'); </script> ``` - 選取全部相同 id ```javascript= for (let i = 0;i < document.querySelectorAll("[id='show_details']").length;i++) { document.querySelectorAll("[id='show_details']")[i].addEventListener('click', showDetail) } ``` # Node.js ## 筆記 - 新增放圖片檔案 教學 : https://www.geeksforgeeks.org/how-to-fetch-images-from-node-js-server/ - config - 1. 物件 var a = { firstName: 'James', lastName: 'Bond' } 2. npm - 只會在單一資料夾裡安裝 npm install 套件 npm -i --save 套件 - 會在全域中安裝 npm install -g 套件 - 解除安裝 npm uninstall 套件 3. 內建的 http module - ex. var http=require('http'); var server=http.createServer(function(req,res){ if(req.url=='/'){ res.writeHead(200,{'Content-Type':'text/html'}); res.write('<html><body>This is Home Page.</body></html>'); res.end(); }else if(req.url=='/student'){ res.writeHead(200,{'Content-Type':'text/html'}); res.write('<html><body>This is student Page.</body></html>'); res.end(); }else if(req.url=='/admin'){ res.writeHead(200,{'Content-Type':'text/html'}); res.write('<html><body>This is admin Page.</body></html>'); res.end(); }else res.end('Invalid Request!'); }); server.listen(5000); 4. express - 安裝 npm install express --save # -- save 會有 .json 檔存放套件資訊 - 路由 ```javascript= app.get('/', function (req, res) { res.send("<html><body><h1>Hello World</h1></body></html>"); }); var server = app.listen(5000, function () { console.log('Node server is running..'); }); ``` 5. express 呼叫寫好的 html - 安裝 body-parser npm install body-parser -ex. ```javascript= var express = require('express'); var app = express(); var bodyParser = require("body-parser"); app.use(bodyParser.urlencoded({ extended: false })); app.get('/', function (req, res) { res.sendFile(__dirname+'/templates/test.html'); // ___ }); var server = app.listen(5000, function () { console.log('Node server is running..'); }); ``` - `npm init` - `npm install` - 6. 永遠執行 .js - 安裝 sudo npm install -g forever # 要為全域的 - 執行 forever start test.js - 查看執行中的檔案 forever list 7. 連線到 mariadb - 安裝 sudo npm install mariadb - ex. const db = require("mariadb"); const pool = db.createPool({ host : 'localhost', user : 'wang', password : 'wang313', database : 'clinic' }); async function connect() { let conn; try { let conn = await pool.getConnection(); let rows = await conn.query('select * from test'); console.log(rows); } catch(err) { console.log(err); } } connect() 8. jade-template engine - 安裝 sudo npm install jade - 建立資料夾放 .jade 檔,預設路徑為相同路徑下的 views 資料夾 vi ./views/test.jade - ex. app.set("view engine", "jade"); app.set("views", "jade"); // 設定資料夾名稱,預設為 views app.get('/', function (req, res) { res.render('test'); // path = ./jade/test.jade }); 9. 傳送資料 - vi .js ```javascript= app.get('/', async function (req, res) { var db = require('mariadb'); const pool = db.createPool({ host : 'localhost', user : 'wang', password : 'wang313', database : 'clinic' }); let conn = await pool.getConnection(); let rows = await conn.query('select * from test'); res.render('test',{test:rows}); }); ``` - vi .jade doctype html html head title 新增病患資料 body ul each item in test li=item.a 10. 接收資料 - 前端 - 後端 要記得加 index - ex. let order = await conn.query('select pa_num from doctors where dId = ?;', req.body.dId); console.log(order[0].pa_num); - 前端 用 JSON.stringify 把 [Object object] 的 value 拿出來 11. sort - ex. rec 是 json, 用 rec 裡的 r_num 大小來排序 rec.sort(function(a,b){ return a.r_num - b.r_num; }); - ex. axios.get('/data').then(function(response) { JSON.stringify(response.data[i].pId) }) 11. 時區問題 - 帶參數執行 env TZ='Taiwan/Taipei' node test.js 12. redirect 帶參數 var string = encodeURIComponent('1'); res.redirect('/?valid=' + string); 13. api 回傳 json 給 html - api return res.json({a : 1}) - html <script> (async() => { const {data : rec} = await axios.get('/records'); })(); </script> 14. jwt cookie - 設定 cookie, 到 api, 先回傳 cookie,res.cookie 完可以再回傳別的(res.json、sendfile) const {data : rec} = await axios.get('/records'); const token = jwt.sign({ data, exp: Math.floor(Date.now() / 1000) + (60 * 15) }, 'my_secret_ key') res.cookie('token', token, { httpOnly: false, secure: false, maxAge: 3600000 }); - 路由查看 cookie, const user = jwt.verify(req.cookies.token, 'my_secret_key'); - html 接收 cookie -> 先到路由設定回傳 cookie 值 router.get('/dId', function(req, res) { const user = jwt.verify(req.cookies.token, 'my_secret_key'); return res.json({dId : user.data.aId}); }); -> 再到 html 接收 const {data : user} = await axios.get('/docMain/dId'); 15. 轉到其他網址 - 第一種 ```javascript= res.statusCode = 302; res.setHeader("Location", "http://localhost:8080/login"); res.end(); // setHeader 的 end 要 () ``` - 第二種 ```javascript= res.redirect('/login') res.end // 不用 () ``` 16. 好用的 js 套件網站 bestofjs 17. cookie - 設置 cookie ``` const data = {update_rId : req.body.rId}; const update_rId = jwt.sign({data, exp: Math.floor(Date.now() / 1000) + (60 * 15) }, 'my_secret_key'); // 加密 res.cookie('update_rId', update_rId, { httpOnly: false, secure: false, maxAge: 3600000 }) ``` - 解 cookie ``const user = jwt.verify(req.cookies.token_name, 'my_secret_key');`` - error : mariadb too many connections close the pool ``pool.end();`` - show Promise { <pending> } - 加上 await : `await conn.query` - 要加上 then let userToken = AuthUser(data) console.log(userToken) // Promise { <pending> } userToken.then(function(result) { console.log(result) // "Some User token" }) - 直接呼叫函式 document.addEventListener("keyup", async(event) => {int a = 0;} - get url, 加上參數 `window.location.href = "/ckPatients?view=true"` - redis : client closed error - 改用 ioredis `npm install ioredis` - `sendfile depreacate, change to sendFile` - 相對路徑 : `res.sendFile('public/appversion.html', { root: '.' });` ## 新增專案 1. 複製 config、node_modules、config.js、package.json、test.js 2. 改 config/default.json 的 file path ## 樣板 - 創一個新的 router : - app.js ```javascript= app.use('/hot_key', require('./api/hot_key')); ``` - 建 ./api/xxx.js ```javascript= const router = require('express').Router(); var bodyParser = require("body-parser"); var db = require('mariadb'); var func = require('../module/func'); var jwt = require('jsonwebtoken'); const pool = db.createPool({ host : 'localhost', user : 'wang', password : 'wang313', database : 'clinic' }); var config = require("config"); // 設定檔 var root = config.get('server.root'); // 根目錄位置 router.get('/', async function(req, res) { // 回傳 json try { const user = jwt.verify(req.cookies.token, 'my_secret_key'); } catch(e) { console.log(e); res.redirect('/login'); res.end(); return; }; let conn = await pool.getConnection(); let medicines_normal = await conn.query('select * from hot_key;'); conn.release(); res.json(medicines_normal); res.end; }); router.get('/relation', async function(req, res) { // 回傳 html try { const user = jwt.verify(req.cookies.token, 'my_secret_key'); } catch(e) { console.log(e); res.redirect('/login'); res.end(); return; }; res.sendFile(root + 'templates/keyRelation.html'); //回應靜態文件 res.end; return; }); module.exports = router; ``` - 建 ./templates/xxx.html ```html= <html> <script src = 'https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js' ></script> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script> <head> 快捷鍵關係圖 </head> <body> <table id = 'tab' border = '1'> <tr> <td colspan = '3'>目前快捷鍵</td> </tr> <tr> <td>編號</td> <td>真實名稱</td> <td>對應快捷</td> </tr> </table> </body> <style> td { text-align : center; } </style> <script> (async() => { const {data : hot_key} = await axios.get('/hot_key'); for (let i = 0;i < hot_key.length;i++) { tab.innerHTML += "<tr/><td/>"+ hot_key[i].no + "<td>" + hot_key[i].real_name + "</td>" + "<td>" + hot_key[i].relative + "</td></tr>"; } })(); </script> </html> ``` ## syntax sugar - 教學 https://sophiali.dev/syntactic-sugar-examples-javascript - IF condition ? expressionIfTrue : expressionIfFalse ex. ``` int i = 2; i > 1 ? console.log('I am true') : console.log('I am false'); ``` ```javascript= `${med_inventory_each[i].expire ? med_inventory_each[i].expire : '無'}` ``` output = I am true - direct use variable in string ``console.log(`${variable}`);`` ## socket.io-聊天室 - 教學 https://single9.net/2017/12/node-js-%e8%88%87-socket-io-%e5%8d%b3%e6%99%82%e8%81%8a%e5%a4%a9%e5%ae%a4%e5%af%a6%e4%bd%9c/ - 後端 ```javascript= io.on('connection', (socket) => { // 斷線 socket.on('disconnect', () => { //console.log('Bye~'); // 顯示 bye~ }); // 前端呼叫這個函式 socket.on("docMsg", (msg) => { // 回傳 "msg", 前端要去 call msg io.emit("msg", msg); }); }) ``` - 前端 ```javascript= // 傳訊息給後端的 docMsg socket.emit("docMsg", msg); // 接收後端 msg 回傳的訊息 socket.on("msg", function (chat_msg) { console.log(chat_msg); }) ``` - return promise pending - solution : use then to get value ex. ```javascript= checkFinancial().then(function(remaining) { console.log(remaining); }) ``` # CSS - scroll (拉霸) - 說明 : 先訂好最大高、寬,如果超出範圍就變成 scroll,如果是 table,要先用 div 包起來,再去設定 div 的長、寬。先把 div 和 table 設 position absolute,table 之後可以再調回 relative,要先去設定 table 的 margin 才能把拉霸的距離設正確。 - ex. ```javascript= html - <div class = 'position-absolute' id = 'scroll_div'> <table class = "position-absolute" id = 'tab' border = '2'> </table> </div> #scroll_div { // div width : 250px; height: 600px; overflow-x: auto; overflow-y: auto; } #now_tab { // 第二種 div,應該是這個才可 position : absolute; height : 10%; width : 50%; overflow-y : auto; } #tab { // table,讓拉霸距離正確 width : 100%; } ``` - 警告 : 如果用 col-md-x,會讓內容和拉霸產生距離。 - 父層和子層的關係 : - 教學 : https://ithelp.ithome.com.tw/articles/10243699 - 主要關係 : ![](https://i.imgur.com/X3fgQSt.png) - 彈出畫面 - 範例 : https://codepen.io/tommygood/pen/dyKQKNK - 文字不能被複製 ```css= div{ -webkit-user-select:none; -moz-user-select:none; user-select:none; } ``` - 兩個物件,其中一個要較上層 ```css= #test { z-index:99; } #test1 { z-index:98; } ``` - 旋轉角度 ```css= .rotate_image_right { transform: rotate(-60deg); } ``` - 資料處理中的顯示 https://codepen.io/tommygood/pen/YzjMYoY # React.JS - install : `npm install --save create-react-app` - 建專案 : `create-react-app app_name` - error : 找不到此命令 可能因為 node 版本太舊,改用 `npx create-react-app app_name` - 語法 : - 值在 return 中要用 div 包起來 - 模板 : - 建 class : - Sid.js ```javascript= import React from 'react'; class Sid extends React.Component { render() { return ( <div> Sid test </div> ) } } export default Sid // 要 export class 才能用 ; ``` - App.js ```javascript= import React from 'react'; import Sid from './Sid'; class App extends React.Component { render() { return( <div> <Sid/> </div> ) } } export default App; ``` - 使用 function - 外部 ```javascript= function Test(props) { return <h2>hello {props.name}</h2>; } class App extends React.Component { render() { return( <div> <Test name = 'fuc'/> </div> ) } } ``` - 內部 ```javascript= insert_texts = (name) => { console.log(name + this.state.name); } render() { return ( {this.insert_texts('a')} ) } ``` - props : property ```javascript= class App extends React.Component { constructor(props) { // 建構子 super(props); // 繼承 props,一定要這行 this.state = { test : 'tommy' }; } render() { return( <div> {this.state.test} </div> ) } } ``` - 註解 : ```javascript= {/* 多行註解 */} { // 單行註解 } ``` - export 多個 class - 要 export 的 js ```javascript= import React from 'react'; class Test2 extends React.Component { render() { return ( <div> Test : </div> ) } } class Test3 extends React.Component { render() { return ( <div> Test : </div> ) } } export { Test2, Test3 } ``` - 要 import 的 js ```javascript= import {Test2, Test3} from './Test'; ``` - map (for) : ```javascript= function MakeName(name) { var new_name = name.map(function (value, index) { // value = 值, index 從 0開始 const new_value = value + 1; return <li id = {index} key = {index}>{new_value}</li> }) // 一定要有 key,不然會有 error return <div>{new_name}</div> } class Test2 extends React.Component { constructor(props) { super(props); this.state = { num : 5, name : ['a', 'b', 'c'] }; } const each_name = MakeName(this.state.name); render { return ( <div> {each_name} </div> ) } } ``` - onchange call function : ```javascript= function detectInput(e) { console.log(e); } <input type = 'text' onChange = {detectInput}/> ``` - change state value : ```javascript= constructor(props) { super(props); this.state = { name : ['a', 'b', 'c'] }; } this.setState({ name: new_name //更新State }) ``` ## router - install : `npm install react-router-dom --save` - 教學 : - https://ithelp.ithome.com.tw/articles/10305953?sc=iThelpR - https://ithelp.ithome.com.tw/articles/10305940 - 設定 : ```javascript= import logo from './logo.svg'; import './App.css'; import React from 'react'; import Sid from './Sid'; import {Test2, Test3} from './Test'; import { BrowserRouter, Routes, Route } from "react-router-dom"; function Test(props) { return <h2>hello {props.name}</h2>; } class App extends React.Component { render() { return( <BrowserRouter basename="/pig"> // 設定 app 的 route // 設定其他 route <Routes> <Route path="/" element={<Sid />} /> <Route path="page1" element={<Test2 />} /> <Route path="*" element={<Test3 />} /> </Routes> </BrowserRouter> ) } } export default App; ``` ## ES6 - 教學 : - https://ithelp.ithome.com.tw/articles/10217085 - function 定義 - 原本的 : ```javascript= function test(a, b) { console.log(a); } ``` - ES6 : ```javascript= function test = (a,b) => { console.log(a); } - 當變數名稱和要傳的物件名稱一樣 - 原本的 : ```javascript= var a = 1; var b = 2; var c = { a : a, b : b } ``` - 可改成 : ```javascript= var a = 1; var b = 2; var c = { a, b }