您好,我是即將邁向32歲,想完成轉職網頁工程師夢想的中年大叔。
下面是第二周的學習紀錄,主要是要勾起自己回憶複習用的,所以大概列幾項覺得重要的而已,可能看起來會有點沒頭沒尾。
這週課程主要內容有:
一、GET跟POST
二、bodyparser套件獲取POST的資料
三、.split()與.concat()
四、將自己的函式輸出成module工具包
五、handlebars裡的{{#if}}
六、Git
一、GET與POST
GET出去的資料會直接顯示在網址上
會在網址上出現資料的有兩種方式,一種是透過form傳到網址上、一種是透過使用者直接打在網址上或點選超連結帶到網址上。
- 透過使用者直接打在網址上或點選超連結帶到網址上(
req.params)
以下面這圖為例,網址上出現http://localhost:3000/popular/languages/Node.js,可能是使用者直接打出來的,或是使用者點了某個超連結出現這個網址,只要搭配express的路由跟req.params就能獲取網址上某一段的資料。

- 透過form傳到網址上(
req.query)
有時候逛網拍,在輸入關鍵字搜尋商品後,網址的後面都會出現?加上一些參數,例如在下圖網站搜尋Jurassic就會出現/search?keyword=Jurassic。

所以/search?keyword=Jurassic哪裡來的?
/search是在<form action=”/search”>設定,告訴程式要把form裡的資料往哪個路徑送,而這個路徑當然也要搭配路由才能順利拿到資料,路由怎麼用這邊就不贅述,詳細可以看第一週的學習紀錄。
?keyword是在<input name=keyword>設定,把該項input的資料稱作keyword,到時候路由搭配req.query.keyword就能獲取使用者輸入的資料。
<!-- ./views/index.handlebars -->
<!-- ... -->
<div class="row" id="search-bar">
<div class="col-12">
<form action="/search">
<div class="input-group mb-3">
<input type="text" name="keyword" class="form-control" placeholder="Enter movie name to search..." aria-label="Movie Name..."
aria-describedby="search-button">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit" id="search-button">Search</button>
</div>
</div>
</form>
</div>
</div>
<!-- ... -->POST出去的資料不會在網址上看到
雖然也是透過form傳出資料,但因為是用POST方法,所以除了網址上看不到資料外,也要用另一個叫做body-parser的套件,搭配路由並用req.body去獲取資料。
也因為POST方法不會直接把資料放到網址上,所以通常會用在比較重要的資料傳出,例如帳號、密碼之類的。
二、使用body-parser獲取POST的資料
POST傳出來的資料不是顯示在網址上,所以沒辦法像前面用req.query獲取資料,所以必須搭配body-parser這個套件將資料存到req.body裡。
- 安裝body-parser
終端機輸入npm install body-parser
- 載入body.parser
app.use() — 表示不管從哪個路由發送進來的請求,都要先經過 app.use,而這段程式碼也要放在所有路由設定前面才行。bodyParser.urlencoded() — 用來處理 URL-encoded 格式的請求
// app.js
// Include packages and define server related variables
const express = require('express')
const exphbs = require('express-handlebars')
const bodyParser = require('body-parser')
// ...
// setting template engine
// ...
// setting body-parser
app.use(bodyParser.urlencoded({ extended: true }))
// setting routes
// ...- 修改<form>的傳送方法 以及 傳送路徑
<form action”/”> — 表示傳到根目錄下<form method=”POST”> — 表示以POST方法送出資料
<form action="/" method="POST">
<input type="number" name="length" class="form-control" id="length" min="4" max="16">
<input type="checkbox" class="custom-control-input" id="lowercase" name="lowercase">
<input type="checkbox" class="custom-control-input" id="uppercase" name="uppercase">
<input type="checkbox" class="custom-control-input" id="numbers" name="numbers">
<input type="checkbox" class="custom-control-input" id="symbols" name="symbols">
<input type="text" name="excludeCharacters" class="form-control" id="exclude-characters">
<button class="btn btn-success" type="submit">Generate Password</button>
</form>- 使用req.body獲取POST傳出的資料
以下兩張圖示範勾選後所產出的資料。
比較特別的是,如果是<input type=”checkbox”>或<input type=”radio”>,req.body回來的資料會是on,如果沒勾選那麼就是不會有那一項的資料,並不會並不會並不會帶回off喔。


三、.split()、concat()
split()— 可以把字串切割成陣列
const str = 'Hello, Node.js REPL'
console.log(str.split()) //['Hello, Node.js REPL']
console.log(str.split(',')) //['Hello', ' Node.js REPL']
console.log(str.split('o')) //['Hell', ', N', 'de.js REPL']concat()— 可以把陣列相加
const hello = ['hello']
const node = ['node']
const helloNode = hello.concat(node)
console.log(helloNode) //['hello', 'node']四、將自己的函式輸出成module工具包
- 將我的函式輸出成module
假設我新增了一隻JS叫做generate_password.js,並且想要讓我的主程式能夠載入這支JS裡的函式,就要在最後面加上module.exports = generatePassword,而這個generatePassword就是JS裡面寫好的函式名。
// define sample function to randomly return an item in an array
function sample(array) {
...
}
// define generatePassword function
function generatePassword(options) {
...
}
// export generatePassword function for other files to use
module.exports = generatePassword- 在主程式載入我的module
這邊require要告訴他檔案的位置,是在跟主程式同樣目錄下的generate_password這支JS
// app.js
// Include packages and define server related variables
const express = require('express')
const exphbs = require('express-handlebars')
const bodyParser = require('body-parser')
const generatePassword = require('./generate_password')
// ...
// setting template engine
// ...- 使用我的module
前面已經require進來了,後面可以直接呼叫函式並帶入參數看會return我預期的東西來。
// app.js
// ...
// setting routes
// ...
app.post('/', (req, res) => {
console.log('random password is: ', generatePassword(req.body))
res.render('index')
})五、handlebars的{{#if}}{{/if}}
用法是如果變數是有東西的,那麼handlebars才會去跑這段要顯示的文字。
{{#if 變數}}
想要顯示的東西
{{/if}}像下面範例的幾個checkbox,if有相對應的資料時,才會讓input的屬性設為checked顯示出來。
<input type="checkbox" class="custom-control-input" id="lowercase" name="lowercase" {{#if options.lowercase}} checked {{/if}}>
<input type="checkbox" class="custom-control-input" id="uppercase" name="uppercase" {{#if options.uppercase}} checked {{/if}}>
<input type="checkbox" class="custom-control-input" id="numbers" name="numbers" {{#if options.numbers}} checked {{/if}}>
<input type="checkbox" class="custom-control-input" id="symbols" name="symbols" {{#if options.symbols}} checked {{/if}}>六、Git
當一個專案目錄使用git init初始化後,就會開始記錄該目錄下所有檔案發生的事情。
而Git會把該目錄下的檔案分成三種狀態,Untracked、Staged、Commited。
一開始所有檔案都是Untracked狀態,要使用git add指令後,檔案才會進入staged狀態。
而Staged狀態要進入Commited狀態,就要使用git commit
以下是幾個Git指令:
git init— 初始化專案,讓git開始控管這個專案,使用後該專案底下會產生隱藏的.git資料夾來儲存所有檔案發生的事。git add 檔案名— 將檔案變成Staged狀態。git add .— 將該目錄下所有檔案變成staged狀態git commit -m “說明文字”— 將Staged狀態的檔案進行Commit。git status— 查詢該專案內檔案目前git狀態git log— 查詢commit紀錄git log --oneline— 以單行呈現git log --graph— 以圖示呈現git checkout 版本號— 切換至特定版本git checkout master— 切回主要分支git diff 版本號1 版本號2— 查詢不同版本的差異git revert 版本號— 復原特定版本號,但此時會跳進一個vi編輯器,要求你填入commit的描述,此時要用:wq就能夠跳出vi編輯器,表示不想要特別加入敘述(w表示write、q表示quit)。git revert 版本號 --no-edit— 若為了要跳過vi編輯器直接復原可以使用此指令。git reset HEAD^— 將HAED重設到目前HEAD所在的上一個版本,並且原先被更動的檔案都會被退回Staged狀態。git reset HEAD^ --hard— 將HAED重設到目前HEAD所在的上一個版本,但是不會把原先被更動的檔案退回Staged狀態,總之就是都弄掉了。git remote— 可以查看遠端目前對應本地專案的是哪個儲存庫。git remote -v— 更詳細地查看。git remote add 遠端儲存庫名 遠端URL— 在遠端加入一個儲存庫名字(可以自由命名,但通常GitHub官方會建議使用origin),遠端URL則是在GitHub上開了遠端資料庫後會給我們的網址。git remote remove 遠端儲存庫名— 可以刪掉遠端的儲存庫。git push 遠端儲存庫名 本地分支— 將所選的本地分支推送到遠端儲存庫,通常本地分支都會是master。git clone 遠端資料庫網址— 在GitHub上看到不錯的專案就能夠複製該專案到本地端。
