# 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://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
}