-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 141 KB
/
content.json
1
{"posts":[{"title":"【VSCode】在 VSCode terminal 使用 git bash","text":"本篇重點 為什麼要使用 git bash VSCode terminal 選項新增 git bash 將 git bash 設定為 VSCode 的預設終端機 我本身是使用 Windows 系統,為了熟悉 Linux 環境和 Git 的相關指令,嘗試了一些方法 虛擬環境 - VirtualBox、docker windows 子系統 - WSL git for windows - git bash 剛開始是使用 VirtualBox 創建 ubuntu 來熟悉 linux 的指令,後來覺得每次都要啟動虛擬機很麻煩,最後選擇 git bash 來在本機實做。 為什麼要使用 git bash在 windows 環境下: 可以使用大部分的 linux 系統指令,例如 ls、cp、mv、rm 等 可以使用 git 版本控制工具 無須安裝虛擬機或 Windows 子系統 在 VSCode terminal 新增 git bash 選項一直都是有需要使用 git 的時候才叫出 git bash 執行指令,但這樣其實有點麻煩,而且還需要不斷切換視窗。 隨著對 VSCode 的了解,才知道 VSCode 有內建 terminal,windows 預設的 terminal 是 cmd 或是 powersell。接下來會把 git bash 設定到 VSCode 的 terminal 選項,這樣就可以直接在 VSCode 中使用了! 1. 開啟 VSCode 設定檔 (JSON檔)方法一、使用快捷鍵開啟 使用按鍵 F1 或是 ctrl + shift + p 顯示所有命令 輸入 open settings 選取 Preferences: Open User Settings (Json) 3. 即可開啟設定檔 settings.json 方法二、從設定中開啟 點擊VSCode 左下角齒輪裡的設定 (快捷鍵 ctrl + ,) 2. 點擊右上角的 開啟設定(json) 3. 即可開啟設定檔 settings.json 2. 新增 git bash 到 terminal 選項 當前使用的 VSCode 版本為 1.84 將設定值寫入 settings.json settings.json12345"terminal.integrated.profiles.windows": { "Git Bash": { "path": "C:\\\\Program Files\\\\Git\\\\bin\\\\bash.exe", }} 健忘筆記 "path" 請設定自己 git bash 的路徑,以及這邊的檔案是 bash.exe 不是 git-bash.exe。 "terminal.integrated.profiles 的其他設定可以到官方文件查看。 設定後存檔,重新開啟 VSCode,使用按鍵 ctrl + ‵ ( ‵ 就是 ~ 鍵) 開啟終端機,就可以在選項中看到 git bash 了! 終端機名稱設定 "Git Bash" 如果顯示不行使用或是終端機選項中沒有出現,嘗試修改名稱,使用 "GitBash" 或 "Git_Bash" 等,我的兩台電腦一台可以使用 "Git Bash" 一台則不行,爬文的結果此問題應該是 VSCode 版本導致,建議更新版本後再設定。 將 git bash 設定為 VSCode 的預設終端機terminal 增加 git bash 選項後,將其設為預設終端機,之後每次開終端機就都是 git bash 了 將設定值寫入 settings.json settings.json1"terminal.integrated.defaultProfile.windows": "Git Bash" 設定後存檔重新開啟 VSCode,終端機就會自動選擇 git bash 開啟了! 健忘筆記 "terminal.integrated.profiles.windows" 和 "terminal.integrated.defaultProfile.windows" 是最新的設定參數,"terminal.integrated.shell.windows" 已是舊設定值無法使用。 快速切換 shell在終端機命令列打上 shell 名稱 bash / powershell / cmd 就可以快速切換。 切換 powershell 切換 cmd 切換 git bash 結論對我來說,能夠在同一個視窗內完成所有工作,直接在 VSCode 中查看程式並執行指令是最方便的方式。 這邊整理需要注意的地方: 查看 VSCode 版本,有些版本設定會有問題,當前使用的版本為 1.84 設定 git bash 的路徑 “path”,請填寫自己 bash.exe 的檔案位置 \"terminal.integrated.shell.windows\" 已棄用,請使用 \"terminal.integrated.profiles.windows\" 和 \"terminal.integrated.defaultProfile.windows\" 你們覺得這樣方便嗎? 歡迎分享你的看法~ 延伸閱讀 [官方文件] VSCode terminal 介紹 [官方文件] VSCode terminal 設定檔 [為你自己學Git] 終端機是甚麼? [為你自己學Git] 什麼是Git?為什麼要學習它?","link":"/Other/VSCode/Using-Git-Bash-in-VSCode/"},{"title":"【PHP】4種判斷變數或陣列是否存在的方法","text":"本篇重點 使用 empty()、is_null()、isset() 或是直接使用if ($variable) 判斷式來判斷變數或陣列是否存在 資料檢查甚麼時候會有錯誤訊息(php error) 先了解這些會幫助你更快理解唷😁 【PHP】解析邏輯運算子 and、or、&&、|| 之間的差異 在開發動態網頁時,後端程式扮演了一個重要的角色,可能會處理來自前端程式的資料,也有可能處理來自資料庫的資料,在這種情況下,我們必須嚴謹地檢查數據的完整性,以確保後續的程式能夠順暢運行。那麼有哪些函數能夠進行這樣的檢查? 首先先了解各種類型的判斷,判斷的類型有 無效值(null) 布林值(boolean) 字串(string) 數值(integer) 陣列(array) 判斷差異表比較不同的function在各種情況下的判斷 型態 if ($x) empty() isset() is_null() $x = null null false true false true $x is undefined null false true false true $x = true boolean true false true false $x = false boolean false true true false $x = ‘’ string false true true false $x = ‘1’ string true false true false $x = ‘0’ string false true true false $x = ‘-1’ string true false true false $x = ‘hello’ string true false true false $x = ‘true’ string true false true false $x = ‘false’ string true false true false $x = 1 integer true false true false $x = 0 integer false true true false $x = -1 integer true false true false $x = 666 integer true false true false $x = array() array false true true false $x = array(‘a’, ‘b’) array true false true false if ($x) 和 empty() 的判斷結果相反 isset() 和 is_null() 的判斷結果相反 螢光標記是我覺得特別要注意的判斷結果 範例 用戶填寫表格資料並送出資料,這些資料會從前端傳到後端程式,此時我們需要驗證是否有填入資料或是資料是否正確 php12345678<?php// 使用 isset() 搭配 intval() 確認是否有參數傳入且為大於 0 的數值$age = isset($_POST['age']) && intval($_POST['age']) > 0 ? intval($_POST['age']) : 0;// 初步整理 $age 值後,檢查是否需要返回前端重新填寫年齡if ($age == 0) { // 返回前端請用戶重新填寫年齡} 情境一,填寫年齡 30 傳入後端,isset() 為 true,且 intval() 後數值大於零,$age = 30 往下接續處理 情境二,填寫年齡 0 傳入後端,isset() 為 true,但 intval() 後數值等於零,$age = 0 返回前端處理 情境三,無填寫年齡傳入後端,isset() 為 false,$age = 0 返回前端處理 健忘筆記 ? : 是一種條件運算符,稱為 三元運算符,可以用來做因果判斷 動手做做看 前端資料傳入後端後做資料檢查 情境一,填寫年齡 30 傳入後端,isset() 為 true,且 intval() 後數值大於零,$age = 30 往下接續處理情境二,填寫年齡 0 傳入後端,isset() 為 true,但 intval() 後數值等於零,$age = 0 返回前端處理情境三,無填寫年齡傳入後端,isset() 為 false,$age = 0 返回前端處理 動手做做看 從資料庫撈取資料,並檢測是否有資料,如果為無資料需要做處理 情境一,從資料庫撈取會員資訊,並取得完整資料 php12345678910111213141516171819<?php$user_data = array( 'name' => '小明', 'gender' => 'Male',);// 使用 if (!$user_data) 確認變數內是否有資料if (!$user_data) { // 無資料時的處理}// 結果:if (!$user_data) 判斷為 false,原本 if ($user_data) 為 true,但碰到驚嘆號反轉布林值結果,因此為 false 跳過判斷// 使用 !is_array($user_data) 搭配 empty($user_data) 確認變數內是否有資料if (!is_array($user_data) || empty($user_data)) { // 無資料時的處理}// 結果:!is_array($user_data) 為 false,empty($user_data) 也為 false,因此跳過判斷 動手做做看 情境一,從資料庫撈取會員資訊,並取得完整資料 資料檢查1:if (!$user_data) 判斷為 false,原本 if ($user_data) 為 true,但碰到驚嘆號反轉布林值結果,因此為 false 跳過判斷資料檢查2:!is_array($user_data) 為 false,empty($user_data) 也為 false,因此跳過判斷 動手做做看 情境二,從資料庫撈取會員資訊,但沒有撈到資料寫入空陣列 php12345678910111213141516<?php$user_data = array();// 使用 if (!$user_data) 確認變數內是否有資料if (!$user_data) { // 無資料時的處理}// 結果:if (!$user_data) 判斷為 true 進入無資料處理// 使用 !is_array($user_data) 搭配 empty($user_data) 確認變數內是否有資料if (!is_array($user_data) || empty($user_data)) { // 無資料時的處理}// 結果:!is_array($user_data)為 false,但 empty($user_data) 為 true,因此進入無資料處理 動手做做看 情境二,從資料庫撈取會員資訊,但沒有撈到資料寫入空陣列 資料檢查1:if (!$user_data) 判斷為 true 進入無資料處理資料檢查2:!is_array($user_data)為 false,但 empty($user_data) 為 true,因此進入無資料處理 動手做做看 情境三,從資料庫撈取會員資訊,但沒有撈到資料寫入字串 php1234567891011121314<?php$user_data = 'no_data';if (!$user_data) { // 無資料時的處理}// 結果:if (!$user_data) 判斷為 false 跳過判斷if (!is_array($user_data) || empty($user_data)) { // !is_array()為 true,因此進入無資料處理 // 無資料時的處理}// 結果:!is_array($user_data) 判斷為 true,因此進入無資料處理 健忘筆記 如果查找資料庫,沒有取得資料會寫入 array 以外的型態,那使用 !is_array($x) 搭配 empty() 來檢查資料會是更謹慎的做法 動手做做看 情境三,從資料庫撈取會員資訊,但沒有撈到資料寫入字串 資料檢查1:if (!$user_data) 判斷為 false 跳過判斷資料檢查2:!is_array($user_data) 判斷為 true,因此進入無資料處理 動手做做看 錯誤訊息在進行資料完整性檢查時,要確保資料的完整性,但又不希望出現錯誤訊息,那麼應該採用哪種函數? 這四種驗證方式除了兩兩相反外,還有一個很重要的差異 “錯誤訊息” 也就是PHP error。當變數 $x 沒有被賦值時,使用 if ($x) 和 is_null($x) 會引發錯誤訊息,但使用 isset($x) 和 empty($x) 不會,不過這些錯誤屬於較輕微的 E_NOTICE 級別,所以在沒有開啟PHP的所有錯誤提示的情況下是不會對網頁造成影響,但還是應該盡量處理這些錯誤。 範例 情境一,檢查陣列中不存在的索引 php12345<?php$a = [];var_dump($a[1]); // NULL,錯誤訊息 Notice: Undefined offset: 1var_dump(isset($a[1])); // bool(false),無錯誤訊息 $a 設定為一個空陣列,卻指定不存在的索引1,因此在 var_dump($a[1]) 的情況下會出現錯誤訊息 動手做做看 情境一,檢查陣列中不存在的索引 $a 設定為一個空陣列,卻指定不存在的索引1,因此在 var_dump($a[1]) 的情況下會出現錯誤訊息 動手做做看 情境二,判斷不存在的變數 php1234<?php// $b 沒有被賦值var_dump(is_null($b)); // bool(true),Notice: Undefined variable: b var_dump(empty($b)); // bool(true),無錯誤訊息 $b 沒有被賦值,因此在 is_null($b) 的情況下會出現錯誤訊息。 動手做做看 情境二,檢查不存在的變數 $b 沒有被賦值,因此在 is_null($b) 的情況下會出現錯誤訊息 動手做做看 情境三,有個陣列內的值需要做處理,但這個值不一定存在,如果不存在就不需要處理 php123456789101112131415161718192021222324252627282930<?php// 如果$user內沒有'age'$user = array( 'name' => '小明');if ($user['age']) { $user['adult'] = ($user['age'] >= 18) ? true : false;}// 結果:出現錯誤訊息 Notice: Undefined index: age 並跳出判斷,'adult'沒有寫入資料// 為了不跳出錯誤訊息且正常判斷,可以改成!empty($user['age'])if (!empty($user['age'])) { $user['adult'] = ($user['age'] >= 18) ? true : false;}// 結果:無錯誤訊息跳出判斷// 如果$user內有'age'$user = array( 'name' => '小明', 'age' => 10);if (!empty($user['age'])) { $user['adult'] = ($user['age'] >= 18) ? true : false;}// 結果:!empty($user['age'])判斷為true,$user['adult'] 寫入 false 判斷用戶是否成年,而 $user 內 ‘age’ 的值不一定存在,因此需要檢查 ‘age’ 是否存在再做處理 健忘筆記 在不確定資料內部狀況的情況下,可以使用 empty() 來讓錯誤訊息消失 動手做做看 情境三,有個陣列內的值需要做處理,但這個值不一定存在,如果不存在就不需要處理 資料檢查1:出現錯誤訊息 Notice: Undefined index: age 並跳出判斷,'adult'沒有寫入資料資料檢查2:無錯誤訊息跳出判斷資料檢查3:!empty($user['age'])判斷為true,$user['adult'] 寫入 false 動手做做看 結論依不同的需求,使用function 來判斷變數或陣列的完整性。 if ($x) 和 empty($x) 的判斷結果相反 isset($x) 和 is_null($x) 的判斷結果相反 無設定 $x 值的狀況下 if ($x) 和 is_null($x) 會跳錯誤訊息 isset($x) 和 empty($x) 則不會跳錯誤訊息 檢查完整性可以減少 bug 的發生,不用修 bug 就是開心😆~ 你平常會檢查變數或陣列的資料完整性嗎? 是用甚麼方法處理呢? 歡迎留言跟大家分享! 動手做做看 PHP 線上編輯器 參考資料 【官方文件】PHP類型比較表 延伸閱讀 【官方文件】資料類型的介紹 【官方文件】判斷式(if)介紹 【官方文件】布林值false的定義 【官方文件】PHP error 介紹","link":"/Backend/PHP/4-Ways-to-Check-If-a-Variable-or-Array-Exists/"},{"title":"【PHP】解析邏輯運算子 and、or、&&、|| 之間的差異","text":"本篇重點 and 和 &&之間有什麼差別,它們分別代表什麼意思? or 和 || 之間有什麼差別,它們分別代表什麼意思? 邏輯運算子的執行順序 邏輯運算子使用建議 「分數有及格嗎?」、「考卷的姓名和學號都是正確的嗎?」、「這張考卷是 john 還是tom 的?」,在日常生活中很常用到的條件判斷,在程式中也很常出現,PHP 提供了很多符號來輔助我們,使用邏輯運算子來達到目的。 &&、AND vs || 、OR &&、AND 是「且、和」的意思,符號兩邊的條件都達成,結果為 true,反之為 false ||、OR 是「或」的意思,符號兩邊依左至右判斷,如果有條件達成,結果為 true,反之為 false 範例依學生的資訊做條件處理 實例搶先看 &&、AND vs || 、OR &&、AND:「且、和」的意思,符號兩邊的條件都達成,結果為 true,反之為 false||、OR:「或」的意思,符號兩邊依左至右判斷,如果有條件達成,結果為 true,反之為 false 實例搶先看 php12345678910111213141516171819202122232425262728293031323334353637383940414243<?php// 設定學生 'john' 的資訊$name = 'john';$score = 60;$gender = 'male';// &&、AND 範例// 判斷學生是 john,且分數是及格if ($name == 'john' && $score >= 60) { echo '判斷為true,學生是 john,且分數是及格';} else { echo '判斷為false';}// 結果:if ($name == 'john' && $score >= 60) 判斷為true,「&&」兩邊的條件皆正確// 判斷學生不是john,且性別是男生if ($name != 'john' AND $gender == 'male') { echo '判斷為true,學生不是john,且性別是男生';} else { echo '判斷為false';}// 結果:if ($name != 'john' AND $gender == 'male') 判斷為 false,第一個條件學生不是 john 是錯誤的,因此也不用看第二個條件了,整個判斷式直接錯誤// ||、OR 範例// 判斷學生是john或是學生是女生if ($name == 'john' || $gender == 'female') { echo '判斷為true,學生是john,或是學生是女生';} else { echo '判斷為false';}// 結果:if ($name == 'john' || $gender == 'female') 判斷為 true,第一個條件學生是 john 是正確的,因此也不用看第二個條件了,整個判斷式直接正確// 判斷學生分數不及格或是這位學生不是男生if ($score < 60 OR $gender != 'male') { echo '判斷為true,學生分數不及格或是這位學生不是男生';} else { echo '判斷為false';}// 結果:if ($name == 'john' || $gender == 'female') 判斷為 false,第一個條件不正確,接續判斷第二個條件,第二個條件也不正確 動手做做看 動手做做看 && vs AND 以及 || vs OR接著來比較 and 和 && 之間以及 or 和 || 之間的差異 簡單來說它們的差異就是執行的優先順序(Operator Precedence)不同 「&&」的執行順序比「=」高,而「=」的執行順序比「AND」高 「||」的執行順序比「=」高,而「=」的執行順序比「OR」高 範例依學生的資訊做條件處理 實例搶先看 && vs AND 以及 || vs OR 「&&」的執行順序比「=」高,而「=」的執行順序比「AND」高「||」的執行順序比「=」高,而「=」的執行順序比「OR」高 實例搶先看 php123456789101112131415161718192021222324252627282930313233<?php// 設定學生 'Tom' 的資訊$student_id = 123;$name = 'tom';$gender = 'male';$score = 49;// &&、AND 範例// 判斷學生學號是123,且分數是及格$answer = $student_id == 123 && $score >= 60;// 結果:判斷結果為 fasle,第二個條件錯誤$answer = $student_id == 123 AND $score >= 60;// 結果:判斷結果為 true,因為「=」的執行順序比「AND」高,因此變成先執行「$answer = $student_id== 123」,導致 $answer 先賦值$answer = ($student_id == 123 AND $score >= 60);// 結果:判斷結果為 false,因為加了括號改變執行順序,先執行「$student_id == 123 AND $score >= 60」// 判斷這位學生是 john 還是 tom$answer = $name == 'john' || $name == 'tom';// 結果:判斷結果為 true,第一個條件正確$answer = $name == 'john' OR $name == 'tom';// 結果:判斷結果為 false,因為「=」的執行順序比「OR」高,因此變成先執行「$answer = $name == 'john'」,導致 $answer 先賦值$answer = ($name == 'john' OR $name == 'tom');// 結果:判斷結果為 true,因為加了括號改變執行順序,先執行「$name == 'john' OR $name == 'tom'」 健忘筆記 判斷式建議使用 && 和 || ,如果要使用 AND 和 OR 記得加上括號減少錯誤發生~詳細的執行順序看這裡! 動手做做看 動手做做看 結論條件判斷時,依需求使用不同的邏輯運算子幫助我們達到目的。 「&&」、「AND」 是「且」的意思,符號兩邊的條件皆須達成時使用 「||」、「OR」 是「或」的意思,符號兩邊的條件只需要有一個條件達成時使用 「&&」的執行順序比「=」高,而「=」的執行順序比「AND」高 「||」的執行順序比「=」高,而「=」的執行順序比「OR」高 運算子的執行優先順序大大的影響判斷的結果,所以在使用時要多加注意,不然會得到意想不到的結果😆,建議使用「&&」和「||」可以減少錯誤的發生~ 動手做做看 PHP 線上編輯器 延伸閱讀 【官方文件】邏輯運算子介紹 【官方文件】運算子優先級","link":"/Backend/PHP/Comparing-the-Differences-Between-Logical-Operators/"},{"title":"【jQuery、css】解析六種組合選擇器:相連、+、~、>、,、空格","text":"本篇重點 組合選擇器是甚麼 選擇器內的符號( +、~、> 、, 等)有甚麼含意 jQuery 要使用組合選擇器還是原生的函式 設定 CSS 樣式或是 jQuery 要操作 DOM 元素時,會用到選擇器選取元素,兩者的選擇器類似,你可能看過選擇器中有一些符號,例如 +、~、> 或是空格,這些將兩個元素組合起來的選擇器就稱為「組合選擇器 Combinator」,熟悉符號的意思可以加速抓到想要的元素,甚至提升整體效能,那來了解這些符號分別代表甚麼意思吧! 標籤之間的關係先了解 HTML 階層間的關係,可以用家族的關係來了解每個階層。 舉例來說,以 <div id="john"> 角度出發,看看下面標籤之間的關係 html12345678<div>john的父親(父層) <p>john的哥哥或姊姊</p> <div id="john"> <p>john的孩子(子層)</p> </div> <p>john的弟弟或妹妹</p></div><div>john父親的弟弟或妹妹</div> 接下來會使用家族關係來解釋各個組合選擇器的使用方法。 健忘筆記 可以使用 tag、id、class 等選擇器做組合選擇器 相連的選擇器選擇器相連且中間沒有空格或是符號,表示同一個 tag 要同時符合所有條件 範例 實例搶先看 相連的選擇器 選擇器相連且中間沒有空格或是符號,表示同一個 tag 要同時符合所有條件 html123456<div id="father"> john的父親(父層) <div class="select" id="tom">tom (john的哥哥)</div> <p class="select" id="john">john</p> <p>john的弟弟或妹妹</p></div> css1234567#john.select { background-color: orange;}div.select#tom { background-color: gray;} jQuery1234567$("#john.select").click(function () { alert("john");});$("div#tom.select").click(function () { alert("tom");}); 空格相連的選擇器指定元素層內的所有指定元素,表示同一家族內的指定元素都會選擇 範例 實例搶先看 空格相連的選擇器 指定元素層內的所有指定元素,表示同一家族內的指定元素都會選擇 html12345678910<p class="select">class="select"</p><div id="father"> john的父親(父層) <p class="find">class="find"</p> <div class="select" id="tom">tom (john的哥哥)</div> <p class="select" id="john">john</p> <p id="joy">joy (john的<b class="select">弟弟或妹妹</b>)</p> <p class="find">class="find"</p></div><p class="select">class="select"</p> css1234567#father .select { background-color: orange;}div #joy { background-color: gray;} 健忘筆記 使用空格只會選取 <div id="father"> 內層的元素,因此在 <div id="father"> 外層上下的 class="select" 元素不會有反應 jQuery1234567$("#father .select").click(function () { alert("orange");});$("div #joy").click(function () { alert("gray");}); 實作這個例子時你會發現,點擊文字”弟弟或妹妹” 會發現先跳出 orange 再跳出 gray,這是JS的事件冒泡,如果要解決這個問題可以使用 、event.stopPropagation() 來處理。 jQuery1234$("#father .select").click(function() { alert("orange"); event.stopPropagation()}); 健忘筆記 事件冒泡:指內層元素觸發事件,外層元素也跟著觸發 選取同一家族內的指定元素,也可以使用 jquery 函數的 .find() 來選取 jQuery123$("#father").find('.find').click(function () { alert("find");}); 「+」相連的選擇器同一層後的第一個元素,表示會選取大弟或大妹 範例 實例搶先看 「+」相連的選擇器 同一層後的第一個元素,表示會選取大弟或大妹 html1234567<p class="select">father的大哥或大姐</p><div id="father">father <p id="john">john</p> <p id="joy">joy (john的弟弟或妹妹)</p></div><p class="select" id="first">father的大弟或大妹</p><p class="select">father的二弟或二妹</p> css123#father + .select { background-color: orange;} 健忘筆記 使用「+」只會選取 <div id="father"> 同層後的第一個元素,所以只有 <p class="select" id="first"> 會被選取 jQuery123$("#father + .select").click(function() { alert("click");}); 同層後的第一個元素,也可以使用 jquery 函數的 .next() 來選取 jQuery12345678$("#john").next().click(function () { alert(".next()");});// 指定同層後的第一個元素$("#first").next(".select").click(function () { alert(".next('.select')");}); 健忘筆記 如果 .next() 有指定元素例如 .next(".select"),表示會選取同一層後第一個是 class="select" 的元素,如果第一個元素不是則不會選取 「~」相連的選擇器同一層後的所有指定元素,表示會選取所有指定弟弟或妹妹 範例 實例搶先看 「~」相連的選擇器 同一層後的所有指定元素,表示會選取所有指定弟弟或妹妹 html12345678910<p class="select">father的大哥或大姐</p><div id="father">father <p id="john">john</p> <p id="joy" class="nextAll">joy (john的弟弟或妹妹)</p> <p id="betty">betty (joy的弟弟或妹妹)</p> <p id="tom" class="nextAll">tom (joy的弟弟或妹妹)</p></div><p class="select" id="first">father的大弟或大妹</p><p id="second">father的二弟或二妹</p><p class="select" id="second">father的三弟或三妹</p> css123#father ~ .select { background-color: orange;} 健忘筆記 使用「~」只會選取 <div id="father"> 同層後的所有指定元素,所以 <p class="select">father的大哥或大姐</p> 不會反應 jQuery123$("#father ~ .select").click(function () { alert("click");}); 同層後的所有元素,也可以使用 jquery 函數的 .nextAll() 來選取 jQuery12345678$("#john").nextAll().click(function(){ alert('nextAll');})// 指定同層後的所有指定元素$("#john").nextAll(".nextAll").click(function(){ alert('nextAll(".nextAll")');}) 健忘筆記 如果 .nextAll() 有指定元素例如 .nextAll(".nextAll"),表示會選取同一層後所有有 class="nextAll" 的元素,如果沒有則不會選取 「>」相連的選擇器剛好在下一層的所有指定元素,表示會選取親生的指定小孩 範例 實例搶先看 「>」相連的選擇器 剛好在下一層的所有指定元素,表示會選取親生的指定小孩 html1234567891011121314<p class="select">father的哥哥或姐姐</p><div id="father">father <p id="john" class="select">john</p> <div id="joy">joy <p id="tim" class="select">tim (joy的小孩)</p> </div> <p id="tom" class="select">father的子層</p></div><p class="select">father的大弟或大妹</p><div id="mother">mother <p id="ken" class="select">ken</p> <p id="eason">eason</p> <p id="kevin" class="select">kevin</p></div> 這邊比較以空格和以「>」相連的差別 css1234567#father .select { color: green;}#father > .select { background-color: orange;} jQuery123$("#father > .select").click(function () { alert("click");}); 健忘筆記 使用「>」只會選取 <div id="father"> 下一層的所有指定元素,因此不會選取到 <p id="tim" class="select">tim (joy的小孩)</p><div> 下一層的所有元素,也可以使用 jquery 函數的 .children() 來選取 jQuery12345678$("#mother").children().click(function(){ alert('children()');})// 指定元素下一層的所有指定元素$("#mother").children(".select").click(function(){ alert('children(".select")');}) 健忘筆記 如果 .children() 有指定元素例如 .children(".select"),表示會選取下一層中所有有 class="select" 的元素,如果沒有則不會選取 「,」相連的選擇器需要相同樣式或是相同行為的元素綁在一起 範例 實例搶先看 「,」相連的選擇器 需要相同樣式或是相同行為的元素綁在一起 html1234567<p class="example1">example1</p><p class="example2">example2</p><p class="example3">example3</p><div>div <p class="example4">example4</p> <span class="example5">example5</span></div> css12345.example1,.example3,div > span { background-color: orange;} jQuery123$(".example1, .example3, div > span").click(function () { alert("click");}); 健忘筆記 可以使用各種選擇器選取元素,再用「,」綁在一起 jQuery 要使用組合選擇器還是原生的函式jQuery 選取元素有很多方法,這邊比較組合選擇器和使用 jQuery 的函數的差異 例如:選取 id=”father” 層底下的所有 class=”select” 元素 jQuery12345/* 組合選擇器 */$("#father .select")/* jQuery 的函數 */$("#father").find(".select") 兩種方式都可以達到同樣的效果。在選取元素數量較少的情況下,兩者的差異非常微小,因為目前的瀏覽器及 jQuery 有對此進行優化。但如果選取的元素數量龐大,使用組合選擇器是較有效率的。 總結來說,如果不用考慮效能,則根據個人喜好和代碼的可讀性選擇一種方法來撰寫。覺得使用原生函式較容易閱讀及維護,那就直接使用原生函式吧! 結論 相連的選擇器:選擇器中間沒有空格或是符號,表示同一個 tag 要同時符合所有條件 空格相連的選擇器:指定元素層內的所有指定元素,表示同一家族內的指定元素都會選擇 「+」相連的選擇器:同一層後的第一個元素,表示會選取大弟或大妹 「~」相連的選擇器:同一層後的所有指定元素,表示會選取所有指定弟弟或妹妹 「>」相連的選擇器:剛好在下一層的所有指定元素,表示會選取親生的指定小孩 「,」相連的選擇器:需要相同樣式或是相同行為的元素綁在一起 選擇器用的好,書寫方面會更方便、選取某個元素時會更快速,也可以降低程式的複雜度,閱讀起來更舒服! 你有什麼常用的選擇器嗎?歡迎跟大家分享~ 動手做做看 codepen 線上編輯器 延伸閱讀 [官方文件] MDN CSS selectors [iT邦幫忙] JQuery 選擇器的補充 [iT邦幫忙] 事件冒泡","link":"/Frontend/JQuery/Analyzing-Six-Types-of-Combinator/"},{"title":"【Linux】解析資料重定向","text":"本篇重點 基本重定向用法:<、<<、>、>>、 2>、2>> 重定向的判讀方式 重定向符號的前後順序不影響命令的結果 特殊重定向用法:/dev/null、&>、 2>&1 、 1>&2 在 Linux 中,資料重定向是一個非常重要且強大的功能。它可以將命令的輸入或輸出重定向到不同的文件或設備,讓我們能更靈活地處理資料。 基本重定向用法標準輸入 stdin,代號:0 < 輸入重定向將文件內容作為命令輸入 範例 number.txt1234564638511449 command12345678910# 將 number.txt 文件的內容作為 sort 命令的輸入,並對內容進行排序sort -n < number.txt# 終端顯示4911446385 健忘筆記 sort -n < number.txt ,-n 選項是指定對數字進行排序 << 多行輸入重定向將多行文字作為命令的輸入,直到遇到指定的結束標記 範例 command123456789# 將多行文字作為 cat 命令的輸入,並將這些文字輸出到終端cat << EOFHelloWorldEOF# 終端顯示HelloWorld 健忘筆記 EOF 是一個告訴 linux 開始與結束的標記,用於長文本段落或多行命令的輸入。 EOF 本身並沒有特別的含義,可以用其他任意的字串來代替,只要確保開始標記和結束標記一致即可 動手做做看 標準輸出 stdout,代號:1 實例搶先看 標準輸出 (stdout,代號:1) > 輸出重定向:將命令的標準輸出重定向到文件,會覆蓋文件的原有內容 >> 附加重定向:將命令的標準輸出附加到文件末尾 實例搶先看 > 輸出重定向將命令的標準輸出重定向到文件,會覆蓋文件的原有內容 範例 command12345678# echo 命令的輸出寫入到 output.txt 文件中,如果文件已經存在,會覆蓋原有內容。echo hello world > output.txt# 查看 output.txt 的內容cat output.txt# 終端顯示hello world >> 附加重定向將命令的標準輸出附加到文件末尾,不會覆蓋文件的原有內容 範例 command123456789# 將 echo 命令的輸出附加到 output.txt 文件的末尾 (延續上一個範例)echo hello world >> output.txt# 查看 output.txt 的內容cat output.txt# 終端顯示hello worldhello world 動手做做看 錯誤輸出 stderr,代號:2 實例搶先看 錯誤輸出 (stderr,代號:2) 2> 錯誤輸出重定向:將命令的錯誤輸出重定向到文件,會覆蓋文件的原有內容 2>> 錯誤輸出附加重定向:將命令的錯誤輸出附加到文件末尾,不會覆蓋文件的原有內容 實例搶先看 2> 錯誤輸出重定向將命令的錯誤輸出重定向到文件,會覆蓋文件的原有內容 範例 command12345678910# non_existing_file 是一個不存在的檔案# 嘗試列出檔案資訊,並將錯誤訊息寫入到 error.logls non_existing_file 2> error.log# 查看 error.log 的內容cat error.log# 因為 non_existing_file 檔案不存在,系統給予錯誤訊息,並錯誤輸出重定向到 error.log# 終端顯示ls: cannot access 'non_existing_file': No such file or directory 2>> 錯誤輸出附加重定向將命令的錯誤輸出附加到文件末尾,不會覆蓋文件的原有內容 範例 command1234567891011# non_existing_file 是一個不存在的檔案# 嘗試列出檔案資訊,並將錯誤訊息附加到 error.log 的末尾(延續上一個範例)ls non_existing_file 2>> error.log# 查看 error.log 的內容cat error.log# 因為 non_existing_file 檔案不存在,系統給予錯誤訊息,並錯誤輸出重定向到 error.log 的末尾# 終端顯示ls: cannot access 'non_existing_file': No such file or directoryls: cannot access 'non_existing_file': No such file or directory 動手做做看 綜合應用標準輸入結合標準輸出command1234567891011121314151617181920212223# 使用多行輸入重定向搭配輸出重定向# 製作 input.txtcat << EOF > input.txthellotest 123EOFcat input.txt# 終端顯示hellotest 123# 將 input.txt 的內容作為 cat 命令的輸入,在輸出到 output.txtcat < input.txt > output.txt# 查看 output.txt 的內容cat output.txt# 得到跟 input.txt 一模一樣的 output.txt# 終端顯示hellotest 123 標準輸出結合錯誤輸出command1234567891011121314# non_existing_file 是一個不存在的檔案# 嘗試列出檔案資訊,並標準輸出到 output.log,錯誤輸出到 error.logcat non_existing_file > output.log 2> error.log# 查看 output.log 的內容cat output.log# 終端無顯示任何東西,output.log 是空的# 查看 error.log 的內容cat error.log# 終端顯示cat: non_existing_file: No such file or directory 動手做做看 重定向的判讀方式[重定向符號] + [文件或字串] 根據重定向符號和文件或字串來判斷,因此符號的前後順序不影響命令的結果 健忘筆記 Shell 在執行命令之前會先解析所有的重定向符號,再執行命令。 Shell 是用來和操作系統進行溝通的命令行界面(CLI),允許用戶通過輸入命令來控制系統執行程序、管理文件系統等 cat < input.txt > output.txt 可以分解為: < input.txt:這部分將 input.txt 的內容重定向到 cat 命令的標準輸入 > output.txt:這部分將 cat 命令的標準輸出重定向到 output.txt Shell 會先解析重定向符號,再執行 cat 命令,從 input.txt 讀取內容並將其寫入 output.txt 因此不管是 cat < input.txt > output.txt 或是 cat > output.txt < input.txt 結果都是一樣的!符號的前後順序不影響命令的結果。 特殊重定向用法/dev/null可以視為垃圾桶,任何資料重定向給它就會丟棄 範例 command12345# non_existing_file 是一個不存在的檔案# 嘗試列出檔案資訊,並將錯誤訊息重定向到 /dev/nullls non_existing_file 2> /dev/null# 終端不顯示訊息,錯誤訊息直接丟棄 健忘筆記 重定向到 /dev/null 表示丟棄所有寫入它的數據,因此無法復原要謹慎使用! 動手做做看 &>將命令的標準輸出和錯誤輸出都重定向到同一個文件 範例 command12345678910111213141516171819202122# non_existing_file 是不存在的檔案# 嘗試列出檔案資訊,並將標準輸出和錯誤輸出都重定向到 output.txtcat non_existing_file &> output.txt# 查看 output.txt 的內容cat output.txt# 終端顯示cat: cannot access 'non_existing_file': No such file or directory# 建立 test.txtecho test > test.txt# test.txt 是已存在的檔案# 嘗試列出檔案資訊,並將標準輸出和錯誤輸出都重定向到 output.txtcat test.txt &> output.txt# 查看 output.txt 的內容cat output.txt# 終端顯示test 健忘筆記 需要重複輸出到同一個檔案時,可以使用 &>>,將輸出附加到檔案末尾 動手做做看 2>&1、1>&2 2>&1 表示將標準錯誤輸出重定向到標準輸出 1>&2 表示將標準輸出輸出重定向到錯誤輸出 範例 test.txt12hellotest 123 2>&1 command123456789101112131415161718# non_existing_file 是不存在的檔案# 列出 test.txt 和 non_existing_file 檔案資訊,並標準輸出重定向到 output.txt,最後要求標準錯誤輸出重定向到標準輸出ls test.txt non_existing_file > output.txt 2>&1# 查看 output.txt 的內容cat output.txt# 終端顯示ls: cannot access 'non_existing_file': No such file or directorytest.txt# 如果使用 2> 會導致訊息消失,因為錯誤輸出已經重定向到標準輸出了ls test.txt non_existing_file 2> output.txt 2>&1# 查看 output.txt 的內容cat output.txt# 終端無顯示任何東西,output.txt 是空的 1>&2 command123456789101112131415161718# non_existing_file 是不存在的檔案# 列出 test.txt 和 non_existing_file 檔案資訊,並錯誤輸出重定向到 output.txt,最後要求標準輸出輸出重定向到錯誤輸出ls test.txt non_existing_file 2> output.txt 1>&2# 查看 output.txt 的內容cat output.txt# 終端顯示ls: cannot access 'non_existing_file': No such file or directorytest.txt# 如果使用 > 會導致訊息消失,因為標準輸出已經重定向到錯誤輸出了ls test.txt non_existing_file > output.txt 1>&2# 查看 output.txt 的內容cat output.txt# 終端無顯示任何東西,output.txt 是空的 健忘筆記 同時重定向標準輸出和標準錯誤輸出,可以使用 command &> output.log command > output.log 2>&1 command 2> output.log 1>&2 三種方法都有一樣的效果 動手做做看 結論了解並熟悉資料輸出重定向的用法,能夠讓我們更靈活地處理和管理命令的輸入輸出。以下是一些需要注意的地方: 依不同的需求,使用不同的輸出方式 > 和 2> 會覆蓋輸出檔案原本的內容。 >> 和 2>> 會將輸出附加到檔案原本的內容末尾。 重定向符號的前後順序不影響命令的結果 如果你有其他有趣的用法或技巧,歡迎在下方留言分享! 動手做做看 Linux 線上模擬器","link":"/Backend/Linux/Understanding-Data-Redirection/"},{"title":"【MySQL】解析資料庫語言類型 DDL、DML、DCL、DQL","text":"本篇重點 了解 DML、DDL、DCL 和 DQL 分別是資料庫裡的哪些功能 以下說明會以 MySQL 的指令做說明 在資料庫管理中,DML、DDL、DCL 和 DQL 是資料庫領域中的四種類型,它們各自負責著不同的任務。 舉例的中括號 [ ] 為替換字串 DDL (Data Definition Language) 數據定義語言DDL用於定義和管理資料庫結構。 包括創建、修改和刪除資料庫、資料表、索引等對象的操作。 常見指令 CREATE:建立資料庫的物件 (資料表、索引等) DESCRIBE:查詢資料表的結構資訊 ALTER:修改現有資料庫對象的結構 (新增欄位、修改資料型別等) TRUNCATE:刪除資料表中的所有資料,但保留資料表的結構 DROP:刪除資料庫的物件 (資料表、索引等) 實例搶先看 DDL 數據定義語言 CREATE:建立資料庫的物件 (資料表、索引等)DESCRIBE:查詢資料表的結構資訊ALTER:修改現有資料庫對象的結構 (新增欄位、修改資料型別等)DROP:刪除資料庫的物件 (資料表、索引等) 實例搶先看 舉例創建資料庫 mysql1234CREATE DATABASE [資料庫名稱];// 創建 "mydatabase" 資料庫CREATE DATABASE mydatabase; 創建資料表 mysql12345678CREATE TABLE [資料表名稱];// 創建 "customers" 資料表CREATE TABLE customers (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50),email VARCHAR(100)); 查詢資料表的結構資訊 mysql1234DESCRIBE [資料表名稱];// 查看 "customers" 資料表結構資訊DESCRIBE customers; 修改資料表結構 mysql1234567ALTER TABLE [資料表名稱] [修改事項];// "customers" 資料表新增一個欄位 "phone"ALTER TABLE customers ADD phone VARCHAR(20);// 刪除 "customers" 資料表的 "phone" 欄位ALTER TABLE customers DROP COLUMN phone; 清空資料表所有資料 mysql1234TRUNCATE TABLE [資料表名稱];// 清空 "customers" 資料表內所有內容TRUNCATE TABLE customers; 刪除資料表 mysql1234DROP TABLE [資料表名稱];// 刪除 "customers" 資料表DROP TABLE customers; 健忘筆記 刪除資料功能 (TRUNCATE 指令或刪除資料表的欄位等) 無法回滾(Rollback),一旦執行就無法還原被刪除的資料。在使用刪除功能時,請再三確認要刪除的資料。 動手做做看 動手做做看 DML (Data Manipulation Language) 數據操作語言DML 是用於操作和處理資料。 包括對資料進行插入、更新和刪除等操作。 常見指令 INSERT INTO:新增資料到資料表中 UPDATE:更改資料表中的資料 DELETE:刪除資料表中的資料 健忘筆記 在一些資料庫系統中,SELECT 指令也可能被視為 DML 指令的一部分,這取決於特定資料庫的標準。但在 MySQL 中,通常將 SELECT 指令歸類為 DQL 指令。 實例搶先看 DML 數據操作語言 INSERT INTO:新增資料到資料表中SELECT:查詢資料庫中的資料UPDATE:更改資料表中的資料DELETE:刪除資料表中的資料 實例搶先看 舉例新增資料 mysql1234INSERT INTO [資料庫名稱] ([欄位]) VALUES ([值]);// 在 "customers" 資料表新增一筆客戶資料INSERT INTO customers (name, email) VALUES ('John', '[email protected]'); 更新資料 mysql1234UPDATE [資料庫名稱] SET [修改值] WHERE [條件];// 在 "customers" 資料表更新一筆客戶資料UPDATE customers SET email = '[email protected]' WHERE name = 'John'; 刪除資料 mysql1234DELETE FROM [資料庫名稱] WHERE [條件];// 在 "customers" 資料表刪除一筆客戶資料DELETE FROM customers WHERE name = 'John'; 動手做做看 動手做做看 DQL (Data Query Language) 數據查詢語言DQL 用於查詢資料庫的資料。 主要目的是檢索所需的數據,而不涉及對數據進行修改。 常見指令 SELECT:查詢資料庫中的資料 WHERE:條件篩選資料 DISTINCT:檢索唯一的資料值 ORDER BY:依指定的欄位排序資料 GROUP BY:依指定的欄位分組 實例搶先看 DQL 數據查詢語言 SELECT:查詢資料庫中的資料WHERE:條件篩選資料DISTINCT:檢索唯一的資料值ORDER BY:按照指定的欄位排序資料GROUP BY:依指定的欄位分組 實例搶先看 舉例查詢資料 mysql1234SELECT [欄位名稱] FROM [資料表名稱];// 搜索 table_name 資料表內所有欄位的資料SELECT * FROM table_name; 篩選條件 mysql1234SELECT [欄位名稱] FROM [資料表名稱] WHERE [篩選條件];// 搜索 table_name 資料表內 uid = 123 的資料SELECT * FROM table_name WHERE uid = 123; 搜索唯一值 mysql1234SELECT DISTINCT [欄位名稱] FROM [資料表名稱];// 搜索 order_list 資料表內 uid 唯一值的資料SELECT DISTINCT uid FROM order_list; 依指定欄位排序資料 mysql1234567SELECT [欄位名稱] FROM [資料表名稱] ORDER BY [欄位名稱] (ASC/DESC);// 搜索 order_list 資料表內所有資料並以uid做排序SELECT * FROM order_list ORDER BY uid;// 設定順序由大排到小SELECT * FROM order_list ORDER BY uid DESC; 健忘筆記 ORDER BY 未指定排序,預設使用 ASC (升冪),順序由小排到大,如果想要由大排到小,可以設定 ORDER BY [欄位名稱] DESC; 依指定的欄位分組 mysql1234SELECT [欄位名稱] FROM [資料表名稱] GROUP BY [欄位名稱];// 依 team 去分組,計算每組的人數SELECT team, COUNT(*) FROM table_name GROUP BY team; 動手做做看 動手做做看 DCL (Data Control Language) 數據控制語言DCL 用於控制資料庫的使用權限和訪問權限。 包括授予、撤銷用戶的權限,以及確保資料庫的安全性和完整性。 常見指令 CREATE USER:創建新的使用者 DROP USER:刪除現有的使用者 GRANT:授予使用者特定的權限和許可權 REVOKE:撤銷使用者的特定權限和許可權 舉例創建新的使用者 mysql1234CREATE USER [使用者名稱]@[IP位置或主機名] IDENTIFIED BY 'password';// 創建新使用者 "mary",並設定密碼CREATE USER 'mary'@'localhost' IDENTIFIED BY 'password'; 健忘筆記 IDENTIFIED BY 是用於設定使用者密碼的指令,可以省略這個指令讓使用者直接進入資料庫,但這樣就有安全性的問題 刪除現有的使用者 mysql1234DROP USER [使用者名稱]@[IP位置或主機名];// 刪除資料庫使用者 "mary"DROP USER 'mary'@'localhost'; 授予權限 mysql1234GRANT [權限] ON [資料庫名稱].* TO [使用者名稱]@[IP位置或主機名];// 授予 "john" 在 my_database 搜尋和寫入和刪除的權限GRANT SELECT, INSERT, DELETE ON my_database.* TO 'john'@'localhost'; 健忘筆記 ‘john‘@’localhost’ 是用來指定使用者帳號和使用者連接的 IP,指定連接 IP 確保資料庫的安全性my_database.* 是指定 my_database 資料庫的所有資料表,也可以指定特定資料表的權限,例如 my_database.my_table 收回權限 mysql1234REVOKE [權限] ON [資料庫名稱].* FROM [使用者名稱]@[IP位置或主機名];// 收回 "john" 在 my_database 刪除的權限REVOKE DELETE ON my_database.* FROM 'john'@'localhost'; 結論有一次在看 MySQL 文件的時候裡面提到 DQL,但也沒有特別解釋什麼是 DQL,後來去查才知道這是資料庫語言類型,感覺很容易忘記所以有了這篇😆 DDL:定義和管理資料庫結構 DML:操作和處理資料 DQL:查詢資料庫的資料 DCL:控制資料庫的使用權限和訪問權限。 動手做做看 mysql 線上編輯器","link":"/Backend/MySQL/Analyzing-4-Types-of-Database-Language/"},{"title":"【Git、Hexo】deploy github 檔名大小寫問題","text":"本篇重點 hexo deploy 檔名大小寫不同,導致網頁404 git 忽略檔名大小寫的原因 解決 hexo deploy github 檔名大小寫問題 hexo deploy github page 檔名大小寫不同,導致網頁404有一次無意間發現網站中的某幾個頁面會404 error,但是在本地 hexo s 測試卻是正常的,重新 deploy 還是沒有修正這個問題,仔細比對檔案和網址後發現 github 上的檔名和網址路徑不同 造成錯誤的原因是剛開始設計的 tag 名稱是大寫,但後來修改為小寫命名,deploy 到 github 並沒有更新為小寫,導致 github page 404 錯誤,也就是說 git 並未追蹤檔名的大小寫。 健忘筆記 404 錯誤是 HTTP 的其中一種「標準回應訊息」(HTTP狀態碼),表示網頁不存在 git 忽略檔名大小寫的原因git 預設是忽略追蹤檔名大小寫,所以檔名做大小寫變更時並不會記錄。原因是許多作業系統(例如 Windows 和 macOS)的檔案系統,檔名大小寫是不敏感的。例如:建立 test 資料夾後,再建立 TEST 資料夾,系統會詢問是否要取代檔案,認為兩個檔案名稱是相同的 解決 hexo deploy github 檔名大小寫問題修改檔名的當下,git 設定是忽略檔名大小寫的,因此之後的更新沒辦法改變 github 上的檔名,解決這個問題必須清空 github 上的檔案並且重新上傳。 1. 設定 git 追蹤檔名大小寫執行 hexo d 的時候,會從 .deploy_git 資料夾將檔案更新至設定好的 github,所以需要修改 .deploy_git 的 git 設定,讓 git 追蹤檔名的大小寫,以便之後修改檔名能正確更新。 command12345// 進入 .deploy_git 資料夾cd .deploy_git// 設定追蹤檔名大小寫git config --local core.ignorecase false 查看更多 git 設定 2. 清空 github 上的檔案command12345678// 移除當前目錄及其子目錄中的所有文件和文件夾,新增至暫存區git rm -rf *// 提交變更git commit -m 'clean all file'// 更新至 githubgit push https://github.com/forgetfulengineer/forgetfulengineer.github.io.git HEAD:main 健忘筆記 git push https://github.com/forgetfulengineer/forgetfulengineer.github.io.git HEAD:main https://github.com/forgetfulengineer/forgetfulengineer.github.io.git 為遠端名稱 HEAD 為當前所在的分支 main 為 github 上要更新的分支 意思是把當前所在的分支更新到遠端的 main 分支。遠端名稱可以透過 git config --local -l 查詢 3. hexo 重新生成檔案並佈署command12345678// 回到 hexo 資料夾cd ..// 清除 hexo 生成的所有檔案hexo clean// 生成檔案並佈署hexo d -g 結論無意間發現的錯誤讓我更了解 git ,原來 git 預設是忽略追蹤檔名大小寫的。檔名修正更新後 php 標籤頁就恢復正常啦😁~ 快回想看看你的 github page 有沒有曾經更改過檔名大小,如果有,可能也會遇到 404 的問題,趕快清空 github 上的檔案重新佈署吧! 延伸閱讀 【官方文件】 Hexo 是甚麼 【官方文件】 github page 是甚麼","link":"/Other/Hexo/Handling-Case-Sensitivity-Issues-in-GitHub-Deployment/"},{"title":"【Hexo】多台電腦佈署 GitHub page 的問題","text":"本篇重點 了解 Hexo 佈署的流程 多台電腦佈署網站,導致 git 紀錄被覆蓋 使用腳本解決 git 紀錄被覆蓋的問題 Hexo 佈署的流程演示佈署網站的流程 command12345# 先移除原本已生成的檔案hexo clean# 生成檔案並且佈署到 githubhexo d -g 使用 hexo d 前要先到 _config.yml 中配置 GitHub 的設定 hexo d 的時候會將 public 目錄下的檔案複製到 .deploy_git 中,再從這個目錄強制推送 git push -f 到 repository,接著 github page 服務會自動偵測到推送的更新,並在一段時間內更新佈署到網站上 多台電腦佈署網站,導致 git 紀錄被覆蓋當使用 Hexo 在多台電腦上進行佈署時,可能會遇到 git 紀錄被覆蓋的問題。這是因為 hexo d 會從 .deploy_git 強制推送更新到 github,而不會先拉取最新的紀錄回 .deploy_git。因此,如果在不同的電腦上進行佈署,git 紀錄就可能會被覆蓋。 舉例來說,如果 A 電腦在 7 月 1 日更新了網站,隨後 B 電腦在 7 月 3 日也進行了更新,但由於 B 電腦的 .deploy_git 資料夾沒有拉取最新的記錄,因此 GitHub 上的記錄不會包含 7 月 1 日的更新。 雖然這對網站內容本身沒有任何影響,但版本控制的主要目的是記錄每一次的更改。因此,保留每次更新的記錄是必要的! 解決 git 紀錄被覆蓋的問題Hexo 官方沒有針對多台電腦佈署的具體方案,因此每次佈署網站時,都需要先進入 .deploy_git 更新進度再執行 hexo d,這樣非常不方便。為了解決這個問題,我編寫了一個腳本來自動化更新進度並佈署網站。 1. 製作自動化腳本 deploy.sh在每次佈署前先檢查 .deploy_git 資料夾是否存在,並拉取最新的進度。這樣可以確保佈署過程中的進度同步,避免覆蓋提交記錄的問題。 以下是完整的腳本示例: deploy.sh12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#!/bin/bash# GitHub Pages repository 的 URLREPO_URL="https://github.com/forgetfulengineer/forgetfulengineer.github.io.git"USER_NAME="forgetfulengineer"USER_EMAIL="[email protected]"FIRST_DEPLOY=0# 檢查 .deploy_git 資料夾是否存在echo -e "\\n檢查 .deploy_git 資料夾是否存在..."if [ -d ".deploy_git" ]; then # 切換到 .deploy_git 資料夾並拉取最新進度 cd .deploy_git || { echo -e "\\n切換到 .deploy_git 資料夾失敗"; exit 1; } echo -e "\\n拉取 github page 最新進度..." git pull || { echo -e "\\n拉取進度失敗"; exit 1; } cd .. || { echo -e "\\n返回 Hexo 資料夾失敗"; exit 1; }else # 檢查 GitHub Pages repository 是否已有 commit echo -e "\\n檢查 GitHub Pages repository 是否已有 commit..." if git ls-remote --exit-code "$REPO_URL" HEAD > /dev/null 2>&1; then echo -e "\\nClone repository 到 .deploy_git 資料夾..." git clone "$REPO_URL" .deploy_git || { echo -e "\\nClone repository 失敗"; exit 1; } # 設置 git config cd .deploy_git || { echo -e "\\n切換到 .deploy_git 資料夾失敗"; exit 1; } git config --local user.name "$USER_NAME" git config --local user.email "$USER_EMAIL" git config --local core.ignorecase false cd .. || { echo -e "\\n返回 Hexo 資料夾失敗"; exit 1; } else echo -e "\\nGitHub Pages repository 尚無 commit,進行首次佈署" FIRST_DEPLOY=1 fifi# 清理舊的生成文件echo -e "\\n清理舊的生成文件..."hexo clean || { echo -e "\\nHexo 清理失敗"; exit 1; }# 生成新的靜態文件並佈署網站echo -e "\\n生成新的靜態文件並佈署網站..."hexo d -g || { echo -e "\\nHexo 佈署失敗"; exit 1; }# 如果是首次部署,進入 .deploy_git 設置 git configif [ "$FIRST_DEPLOY" -eq 1 ]; then echo -e "\\n首次佈署,設置 git config --local core.ignorecase false" cd .deploy_git || { echo -e "\\n切換到 .deploy_git 資料夾失敗"; exit 1; } git config --local core.ignorecase false cd .. || { echo -e "\\n返回 Hexo 資料夾失敗"; exit 1; }fiecho -e "\\n佈署完成" 2. 執行 deploy.sh 腳本完成 deploy.sh 腳本後,將其放在執行 Hexo 的資料夾中。佈署網站時,只需執行 deploy.sh,神奇的事情就會發生囉~😝 command12# 在 hexo 資料夾的路徑執行 deploy.sh./deploy.sh 補充說明檢查 .deploy_git 資料夾是否存在使用 if [ -d ".deploy_git" ] 檢查 .deploy_git 資料夾是否存在。在 Shell 中,-d 選項常用來檢查資料夾是否存在。如果要檢查檔案是否存在,可以使用 -f 選項。若要檢查資料夾或是檔案是否存在,則可以使用 -e 選項。 使用 || 和 {} 處理命令執行失敗的情況|| 是邏輯 OR 操作符。它表示當前面的命令執行失敗(返回非零退出狀態碼)時,執行後面的命令。例如: command1command1 || command2 如果 command1 執行成功,那麼 command2 不會被執行。如果 command1 執行失敗,那麼 command2 會被執行。 {} 用於將多條命令組合成一個命令塊。命令塊中的命令會按順序執行。通常與邏輯操作符(如 || 或 &&)結合使用。例如: command1command1 || { command2; command3; } 如果 command1 執行失敗,則執行命令塊 { command2; command3; } 中的命令。 使用 echo -e 啟用反斜杠特殊字符轉義告訴 echo 啟用反斜杠特殊字符轉義,例如 \\n、\\t、\\r 。如果沒有使用 -e ,字串會直接顯示不會有特殊符號的效果。 檢查 GitHub Pages repository 是否已有 commit使用 git ls-remote --exit-code "$REPO_URL" HEAD 檢查 repository 。 ls-remote 用於檢查遠端儲存庫是否存在特定分支的命令,執行後終端顯示該分支最新的進度。 command1234git ls-remote --exit-code https://github.com/forgetfulengineer/forgetfulengineer.github.io.git# 終端顯示4w727c14a1260cf59a65e34de3b643d3f3bee83f HEAD --exit-code 選項 如果找到指定的引用(例如 HEAD),命令會成功執行並返回退出碼 0。 如果未找到指定的引用,命令會返回退出碼 2 不使用 -exit-code 的情況 無論是否找到指定的引用,命令都會成功執行並返回退出碼 0 > /dev/null 2>&1; 表示不顯示 command 的輸出結果將標準輸出和錯誤輸出重定向到垃圾桶 (/dev/null),這樣執行的結果就不會顯示在終端。 想了解更多重定向符號的使用方法,可以到【Linux】解析資料重定向 查看 if [ -d ".deploy_git" ]; then 和 if git ls-remote --exit-code "$REPO_URL" HEAD > /dev/null 2>&1; then 兩種判斷式的差異[ ... ] 是 POSIX 標準中的測試命令,又稱 test 命令,用來檢查條件表達式是否為真,根據條件的結果返回不同的退出狀態碼。退出狀態碼為 0 表示條件為 true,非 0 表示條件為fasle,通常用於檔案或目錄的存在性、字串比較等操作。 if COMMAND; then 是基於命令執行後的退出狀態碼判斷。退出狀態碼為 0 表示 true,非 0 表示 false,通常用於判斷一個命令是否成功執行。 git config --local core.ignorecase false 設定 git 追蹤檔名大小寫有兩種情況會首次建立 .deploy_git 首次佈署,執行 hexo d 後建立 .deploy_git GitHub Pages repository 已有 commit,使用 git clone 建立 .deploy_git 建立後建議進入 .deploy_git 設定 git 追蹤檔名大小寫,不然有機會遇到 git 忽略檔名大小寫導致 github page 404 的錯誤 想了解更多 git config 的設定,可以到【Git】了解 git config 設定 查看 結論透過上述腳本,我們可以確保在多台電腦上進行 Hexo 佈署時,不會覆蓋 GitHub 上的提交記錄。這樣的解決方案不僅簡單且有效,同時也考慮到首次佈署的情況,確保每次佈署順利進行。 另外也可以使用 GitHub Actions 解決,GitHub Actions 可以設定自動化工作流程,將 Hexo 生成的靜態網站自動佈署到 GitHub Pages,但跟我的佈署習慣不同,所以就沒有使用了,使用方式可以看這篇教學。 希望這篇文章對遇到相同問題的你有所幫助~😁","link":"/Other/Hexo/Multi-Computer-Deployment-Issues-on-GitHub-Page/"},{"title":"【Git】了解 git config 設定","text":"本篇重點 了解設定區域:--system, --global, --local git config 常見設定 查詢 git config 設定 刪除 git config 設定 設定的區域依需求做不同範圍的設定,在不同區域的設定影響 git 操作的範圍 當前儲存庫設定 --local在資料夾建立 git 環境後,這個資料夾就是當前儲存庫的設定區域 設定檔文件通常位於當前資料夾的 .git/config 用戶級別設定 --global系統用戶的設定區域,會影響當前用戶所建立的所有儲存庫區域。 設定檔文件通常位於用戶家目錄下的 .gitconfig 或 .config/git/config 系統級別設定 --system系統管理員的設定區域,會影響所有用戶所建立的所有儲存庫區域。 設定檔文件通常位於 /etc/gitconfig 健忘筆記 如果想查詢各個區域的設定檔,可以使用 git config --list --show-origin [區域],例如 git config --list --show-origin --global 設定區域優先級git config 會依照固定的優先順序進行覆蓋。優先順序如下: --local:對當前資料夾的 Git 儲存庫有效,優先級最高,會覆蓋 --global 和 --system 的相同設定。 --global:對當前用戶的所有 Git 儲存庫有效,優先級次於 --local ,會覆蓋 --system 的相同設定,但不會覆蓋 --local 的。 --system:對系統上所有 Git 的儲存庫有效,優先級最低,會被 --global 和 --local 覆蓋相同的設定。 健忘筆記 優先級順序: --local > --global > --system git config 常見設定各個設定都可以依據需求來做不同區域的設定 舉例的中括號 [ ] 為替換字串 git1234567git config [要設定的區域] [甚麼設定] [設定值]// 設定用戶級別的區域git config --global user.name "forgetfulengineer"// 設定當前儲存庫的區域git config --local user.email "[email protected]" 健忘筆記 如果沒有指定設定位置,例如:git config user.name "forgetfulengineer"git config 的預設位置為 -- local 設定使用者名稱和郵件地址git123456789// 設定使用者的名稱git config --global user.name "[名字]"git config --global user.name "forgetfulengineer"// 設定使用者信箱git config --local user.email "[信箱]"git config --local user.email "[email protected]" 設定 Git 指令縮寫git1234567891011git config --global alias.[縮寫] [指令]// 設定 st 等於 statusgit config --global alias.st status// 設定完後使用 git st 等於 git status 的效果// 設定 br 等於 branchgit config --global alias.br branch// 設定完後使用 git br 等於 git branch 的效果 設定 Git 使用的編輯器git config –global core.editor “vim” git1234git config --global core.editor "[編輯器]"// 設定 vim 為 git 的編輯器git config --global core.editor "vim" 設定 git log 顯示各分支進度git12345// 開啟顯示各分支進度git config --global log.decorate auto// 關閉顯示各分支進度git config --global log.decorate no log.decorate 設置有幾個選項: auto:根據終端檢測決定是否顯示各分支進度。 short:顯示簡短的各分支進度。 full:顯示完整的各分支進度。 no:不顯示各分支進度。 健忘筆記 HEAD -> dev 表示當前 branch 的進度,當前在 dev 這個 branch 上origin/dev 表示遠端 branch 的進度,當前 github 上的 dev branch 在 “無障礙功能優化” 這個 commit 上 當前本地 branch 還沒跟遠端 branch 的進度同步 設定 git 追蹤檔案權限預設情況下修改檔案的權限(chmod) 會影響 git 的紀錄 git12345// 開啟追蹤檔案權限git config --global core.filemode true// 關閉追蹤檔案權限git config --global core.filemode false 範例 command12345678910111213141516// chmod_test.txt 檔案權限是 644touch chmod_test.txt// 用 chmod 修改檔案權限chmod 755 chmod_test.txt// git diff 查看檔案更動紀錄git diff chmod_test.txt// git diff 結果diff --git a/chmod_test.txt b/chmod_test.txtold mode 100644new mode 100755// 不想記錄檔權限,關閉追蹤檔案權限git config --global core.filemode false 健忘筆記 三位數的檔案權限數字用來說明三種身分user(自己)、group(組別)、other(其它人)的權限,每一位數是三種權限read(4)、write(2)、execute(1)的加總。詳細說明看這裡! 設定 git 是否忽略檔名大小寫預設情況下 git 是忽略檔名大小寫的,所以修改檔名大小寫 git 不會紀錄 git12345// 設定忽略檔名大小寫 (預設)git config core.ignorecase true// 設定追蹤檔名大小寫git config core.ignorecase false git 忽略檔名大小寫引發 github page 404 錯誤 查詢 git config 設定值及刪除設定查詢單一設定git12345// 查詢 --global 的使用者名稱git config --get --global user.name// 查詢 --local 的 log 設定git config --get --local log.decorate 查詢所有設定git12345// 查詢 --global 的所有設定git config --global --list// 也可以用縮寫 -lgit config --global -l 健忘筆記 如果沒有指定設定位置,例如:git config --list,會列出當前存儲庫的 Git 配置 --local 和當前用戶級別的 Git 配置 --global,但不包括系統級別的 Git 配置 --system 刪除設定使用以下命令來刪除 Git 的現有設定: git12345// 刪除 --global 的使用者名稱git config --unset --global user.name// 刪除 --local 的 log 設定git config --unset --local log.decorate 結論我認為 git config 中最基本也最重要的兩種設定是 user.name 和 user.email,因為使用 git commit 時會記錄名字和信箱,如果沒有設定且嘗試使用 git commit,Git 通常會給出錯誤提示。如果仍然嘗試進行提交,Git 可能會使用空值或電腦的使用者名稱作為提交者資訊,獨自開發的情況下影響不大,但多人開發專案時提交資訊就非常重要了。(才有辦法追朔誰開發出 bug 🤣) 增加一些設定也可以讓我們更加便利,像是設定快捷鍵簡短指令長度,加快打指令的速度,或是讓 git log 顯示分支進度,讓資訊更一目了然。 可能還有很多方便的設定,如果你知道就分享一下吧~ 延伸閱讀 【官方文件】git init 創建 git 倉儲環境 【官方文件】git config 介紹 【官方文件】git commit 介紹","link":"/Other/Git/Understanding-Git-Config-Settings/"},{"title":"【HTML】button 在 form 裡和在 form 以外的差別","text":"本篇重點 了解 <button> 在 <form> 裡與 <form> 以外的差別 了解 <form> 的預設 method 和預設 action <button> 在 <form> 裡與 <form> 以外的差別<button> 在 <form> 裡 當 <button> 放在 <form> 裡且沒有指定 type 屬性時,它的預設 type 是 submit,會提交整個表單到指定的 action URL 如果指定了 type="button",按鈕就不會觸發表單提交,只是單純的按鈕,可以透過 JavaScript 綁定其他行為 html12345<!-- 按下提交按鈕會觸發表單提交,並將資料發送到 "example.php" --><form method="post" action="example.php"> <input type="text" name="username"> <button>提交</button> <!-- 相當於 <button type="submit">提交</button> --></form> <button> 在 <form> 以外 在 <form> 以外的 <button> 元素,預設 type="button",按下時不會觸發表單提交 這種 <button> 通常用於執行與表單提交無關的操作,例如觸發 JavaScript 函數等 html12345<!-- 按下提交按鈕甚麼事都不會發生 --><form method="post" action="example.php"> <input type="text" name="username"></form><button>提交</button> <!-- 相當於 <button type="button">提交</button> --> 案例說明在處理表單返回按鈕的功能時,發現一個問題,當 <button> 沒有設定 type 屬性時,點擊按鈕會自動送出表單,這和原本預設的行為不符。 以下範例的樣式使用 bulma html1234567891011121314151617181920212223<!-- 建立一個表單,底部有兩個按鈕,一個是返回指定頁面,一個是提交表單 --><form> <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label">Name</label> </div> <div class="field-body"> <div class="field"> <div class="control"> <input class="input" type="text" name="username" placeholder="Text input"> </div> </div> </div> </div> <div class="field is-grouped is-grouped-centered"> <a href="/" class="control"> <button class="button is-link">返回</button> <!-- 預期是返回首頁 --> </a> <div class="control"> <button class="button is-link">提交</button> <!-- 預期是提交表單 --> </div> </div></form> 實例 Name 返回 提交 範例中,<button> 位於 <form> 內部,當按鈕沒有設定 type 屬性時,瀏覽器會將其視為 type="submit"。所以點擊「返回」按鈕時,會觸發表單的提交操作,而不是前往 href 指定的首頁。 為了正確的前往指定連結,就要將「返回」按鈕的 type 設定為 button html1234<!-- <button> 的 type 設定為 button --><a href="/" class="control"> <button type="button" class="button is-link">返回</button></a> 實例 Name 返回 提交 設定後,點擊「返回」按鈕會前往首頁,而不會提交表單。 健忘筆記 <button> 位於 <form> 內且未設置 type 時,默認為 type="submit",會提交表單。 <form> 的預設 method 和預設 action 預設 method:沒有設定 method 屬性,<form> 元素的預設提交方法是 GET。表單數據會被附加到 URL 中進行提交。 預設 action:沒有設定 action 屬性,表單數據會提交到當前頁面本身的 URL。 html12345678910111213141516171819202122<form> <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label">Name</label> </div> <div class="field-body"> <div class="field"> <div class="control"> <input class="input" type="text" name="username" placeholder="Text input"> </div> </div> </div> </div> <div class="field is-grouped is-grouped-centered"> <a href="/" class="control"> <button type="button" class="button is-link">返回</button> </a> <div class="control"> <button class="button is-link">提交</button> </div> </div></form> 實例 Name 返回 提交 提交表單後會以 GET 的方式送到原網址,因此可以看到網址列最後面會加上 ?username=[填入的字串] 動手做做看 html 線上編輯器 結論這個 <button> 小細節是在我製作表單時不小心踩到的坑。當時因為沒有指定屬性,結果 <button> 在不同情境下的預設值竟然不一樣,讓我花了不少時間才找到問題。標籤的預設屬性在不同情境下可能會有很大的差異,還有甚麼在不同情境下有不同預設屬性的標籤嗎?歡迎分享給我~ 延伸閱讀 【MDN】<button> 介紹 【MDN】<form> 介紹 【medium】HTML5 新增的表單元件 & 屬性","link":"/Frontend/Html/Difference-Between-button-Inside-and-Outside-of-a-form/"},{"title":"【jQuery】click 事件綁定方式比較","text":"本篇重點 $('選擇器').click() 的應用和使用時機 $(document).on('click', '選擇器', function(){}) 的應用和使用時機 .on('click', function() {}) 不是委派給 document 就無法適用在動態生成的元素 先了解這些會幫助你更快理解唷😁 【jQuery、css】解析六種組合選擇器:相連、+、~、>、,、空格 在前端開發中,經常需要偵測使用者對於網頁上元素的點擊事件,jQuery 中,可以使用 .click() 或 .on('click') 事件來偵測元素的點擊事件,雖然都是偵測點擊事件,但兩者有些差異。 $(選擇器).click()應用重點 直接綁定點擊事件到指定的元素 只適用於當前 DOM 中已存在的元素 當指定元素被刪除,綁定的事件也會被刪除 使用時機 用於靜態元素,這些元素在 DOM 加載時已經存在且不會動態變更 適合簡單的事件綁定,不需要過多處理 健忘筆記 DOM(Document Object Model)是瀏覽器用來解讀和操作 HTML 或 XML 文件的結構化模型,它將 HTML 文件中的各種元素(如標籤、屬性、文本等)轉換為 JavaScript 可以操作的物件,讓開發者可以動態修改、刪除或新增內容,並控制網頁的行為。 範例 實例搶先看 $(選擇器).click() 直接綁定點擊事件到指定的元素 只適用於當前 DOM 中已存在的元素 當指定元素被刪除,綁定的事件也會被刪除 html123<button class="button is-link add_button"> 新增按鈕</button> js12345678let num = 1;$('.add_button').click(function() { let new_button = `<button class="button is-success add_button"> 新增按鈕 ${num} </button>`; $(this).after(new_button); num ++;}); 點擊 “新增按鈕” 產生新按鈕,新的按鈕雖然 class 也有 .add_button,但無法產生新的按鈕 $(document).on(‘click’, ‘選擇器’, function(){})應用重點 委派事件處理給 document,再綁定點擊事件到指定的元素 適用於當前或未來新增的元素 當指定元素被刪除,綁定的事件依然存在 使用時機 適用於動態生成的指定元素,確保事件觸發 範例 實例搶先看 $(document).on('click', '選擇器', function(){}) 委派事件處理給 document,再綁定點擊事件到指定的元素 適用於當前或未來新增的元素 當指定元素被刪除,綁定的事件依然存在 html123<button class="button is-link add_button"> 新增按鈕</button> js12345678let num = 1;$(document)on('click', '.add_button', function() { let new_button = `<button class="button is-success add_button"> 新增按鈕 ${num} </button>`; $(this).after(new_button); num ++;}); 點擊 “新增按鈕” 產生新的按鈕,新按鈕也可以產生新的按鈕 健忘筆記 早期的 jquery 是使用 .live(),但這個函數因為一些漏洞已在 jQuery 1.9 被刪除,所以請將 .live() 替換成 .on()詳情請看【geeksforgeeks】Replace live() with on() in jQuery 如果 .on('click', function() {}) 不是委派給 document 會發生甚麼事.on('click', function() {}) 不是委派給 document 就無法適用在動態生成的元素,只能綁定到當前 DOM 中已存在的元素 例如 實例搶先看 如果 .on('click', function() {}) 不是委派給 document 會發生甚麼事 不是委派給 document 就無法適用在動態生成的元素,只能綁定到當前 DOM 中已存在的元素 html123<button class="button is-link add_button"> 新增按鈕</button> js1234567891011121314151617let num = 1;$('.add_button').on('click', function() { let new_button = `<button class="button is-success add_button"> 新增按鈕 ${num} </button>`; $(this).after(new_button); num ++;});$('.add_button').click(function() { let new_button = `<button class="button is-success add_button"> 新增按鈕 ${num} </button>`; $(this).after(new_button); num ++;}); $('.add_button').on('click', function() {}) 和 $('.add_button').click(function() {}) 寫法不同,但兩者的效果是一樣的,都是綁定 click 事件到當前 DOM 中已存在的 .add_button 元素,動態生成的 .add_button 元素無法觸發事件 這兩種寫法的效果相同,但 .click(function() {}) 僅能偵測點擊事件;相比之下,使用 .on('click', function() {}) 更具彈性。除了偵測點擊事件,.on() 還能同時綁定多個事件,例如:.on('click mouseenter change', function() {}),因此在事件處理上提供了更多的靈活性。 結論 click(function() {}) 是最簡單的事件綁定方式,適合靜態元素的單一點擊事件。 $(document).on('click', function() {}) 是較複雜但更具彈性的方式,特別適合處理動態生成的元素或需要更靈活事件處理的情況。 根據具體使用場景選擇最適合的綁定方式,才能確保達到預期效果。如果你需要偵測點擊事件,不妨試試這兩種方式,看哪一種更符合你的需求! 動手做做看 codepen 線上編輯器 延伸閱讀【jQuery 官方文件】.click() 介紹【jQuery 官方文件】.on(‘click’, function() {}) 介紹【天矽科技】DOM 是什麼?","link":"/Frontend/JQuery/Comparison-of-Click-Event-Binding-Methods/"},{"title":"【jQuery】尋找父元素、同層元素和子元素的方法","text":"本篇重點 尋找父元素的常用方法:.parent() 、.parents() 、.closest() 尋找同層元素的常用方法:.siblings() 、.next() 、.prev() 尋找子元素的常用方法:.children() 、.find() 每個尋找元素方法的具體用途和應用場景 先了解這些會幫助你更快理解唷😁 【jQuery、css】解析六種組合選擇器:相連、+、~、>、,、空格 尋找父元素.parent()只尋找當前元素上一層匹配的元素,也就是尋找親身父母 範例 實例搶先看 .parent() 尋找親身父親,也就是尋找當前元素上一層元素 html123456789101112131415161718192021<div class="box"> <div class="content"> <h2>.parent() 的效果</h2> <h3>使用方式一</h3> <ul> <li class="target-1 target-2">取得所有 li 元素的直接父元素</li> <li>設定父元素的文字顏色</li> </ul> <h3>使用方式二</h3> <ul class='selected'> <li class="target-1 target-2">取得所有 li 元素的直接父元素,並且父元素的 class 有 "selected"</li> <li>設定父元素的文字顏色</li> <li class="selected">沒有 "selected" 的元素不會被設定</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').parent().css('color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').parent('.selected').css('color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('*').css('color', '');}); .parents()向上尋找所有匹配的祖先元素,直到根元素為止 範例 實例搶先看 .parents() 向上尋找所有祖先元素,直到根元素為止 html123456789101112131415161718192021<div class="box"> <div class="content selected"> <h2>.parents() 的效果</h2> <h3>使用方式一</h3> <ul> <li>取得所有 li 元素的所有匹配的祖先元素,直到根元素</li> <li class="target-1">設定所有祖先元素的背景顏色</li> </ul> <h3>使用方式二</h3> <ul class="selected"> <li>取得所有 li 元素的祖先元素,並且元素的 class 有 "selected" </li> <li>設定匹配的祖先元素背景顏色</li> <li class="target-1 target-2">只設定匹配的元素,因此使用方法一的ul不會被設定背景顏色</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').parents().css('background-color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').parents('.selected').css('background-color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('*').css('background-color', '');}); .closest() 向上尋找所有祖先元素,直到第一個匹配的元素停止 .closest() 方法必須代入參數 (選擇器) 範例 實例搶先看 .closest() 向上尋找所有祖先元素,直到第一個匹配的元素停止 .closest() 方法必須代入參數 (選擇器) html123456789101112131415<div class="box"> <div class="content selected"> <h2>.closest() 的效果</h2> <h3>使用方式</h3> <ul class="selected"> <li>取得所有 li 元素向上尋找祖先元素,直到第一個 class 有 "selected" 的元素停止</li> <li class="target-1">設定匹配元素的邊框</li> <li>只設定第一個匹配的元素,因此上層的 div class 有 "selected",但沒有被設定邊框</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式</button> <button class="button reset">reset</button> </div></div> js123456789// 使用方式一$('.example-1').on('click', function() { $('.target-1').closest('.selected').css('border', '1px solid red');});// reset$('.reset').on('click', function() { $('*').css('border', '');}); 尋找同層元素.siblings()尋找當前元素的所有同層元素 (排除自己),也就是元素的兄弟姐妹 範例 實例搶先看 .siblings() 尋找當前元素的所有同層元素,也就是元素的兄弟姐妹 html12345678910111213141516171819202122<div class="box"> <div class="content selected"> <h2 class="selected">.siblings() 的效果</h2> <h3>使用方式一</h3> <ul class="target-1 selected"> <li>取得 class 有 "target-1" 的元素再匹配所有同層元素</li> <li>設定所有同層元素的文字顏色</li> <li>設定除了自己的同層元素</li> </ul> <h3 class="target-2">使用方式二</h3> <ul class="selected"> <li>取得 class 有 "target-2" 的元素再匹配所有同層 class 有 "selected" 元素</li> <li>設定所有匹配同層元素的文字顏色</li> <li>設定除了自己的同層元素</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').siblings().css('color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').siblings('.selected').css('color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('ul').siblings().css('color', '');}); .next()尋找當前元素同層的下一個元素,也就是元素最大的弟弟或妹妹 範例 實例搶先看 .next() 尋找當前元素同層的下一個元素,也就是元素最大的弟弟或妹妹 html123456789101112131415161718192021<div class="box"> <div class="content selected"> <h2>.next() 的效果</h2> <h3 class="target-1">使用方式一</h3> <ul> <li>取得 class 有 "target-1" 的元素再匹配同層的下一個元素</li> <li>設定同層的下一個元素的文字顏色</li> </ul> <h3 class="target-2">使用方式二</h3> <ul class="selected"> <li>取得 class 有 "target-2" 的元素再匹配同層下一個 class 有 "selected" 的元素</li> <li>設定同層下一個匹配元素的文字顏色</li> <li>如果同層下一個元素 class 沒有 "selected" 就無法設定文字顏色</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').next().css('color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').next('.selected').css('color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('*').css('color', '');}); .prev()尋找當前元素同層的上一個元素,也就是元素最小的哥哥或姐姐 範例 實例搶先看 .prev() 尋找當前元素同層的上一個元素,也就是元素最小的哥哥或姐姐 js123456789101112131415161718192021<div class="box"> <div class="content selected"> <h2>.prev() 的效果</h2> <h3 class="target-1">使用方式一</h3> <ul> <li>取得 class 有 "target-1" 的元素再匹配同層的上一個元素</li> <li>設定同層的上一個元素的文字顏色</li> </ul> <h3 class="selected">使用方式二</h3> <ul class="target-2"> <li>取得 class 有 "target-2" 的元素再匹配同層上一個 class 有 "selected" 的元素</li> <li>設定同層上一個匹配元素的文字顏色</li> <li>如果同層上一個元素 class 沒有 "selected" 就無法設定文字顏色</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').prev().css('color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').prev('.selected').css('color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('*').css('color', '');}); 這段代碼會將類別為 .current 的元素的上一個同層元素字體加粗。 尋找子元素.children()只尋找當前元素下一層匹配的元素,也就是尋找元素的親生小孩 範例 實例搶先看 .children() 只尋找當前元素下一層匹配的元素,也就是尋找元素的親生小孩 html123456789101112131415161718192021<div class="box"> <div class="content"> <h2>.children() 的效果</h2> <h3>使用方式一</h3> <ul class="target-1"> <li>取得 class 有 "target-1" 的元素再匹配所有下一層的元素</li> <li>設定所有下一層元素的文字顏色</li> </ul> <h3>使用方式二</h3> <ul class="target-2"> <li>取得 class 有 "target-2" 的元素再匹配所有下一層 class 有 "selected" 的元素</li> <li class="selected">設定所有下一層元素的文字顏色</li> <li class="selected">沒有 "selected" 的元素不會被設定</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式一</button> <button class="button is-info example-2">使用方式二</button> <button class="button reset">reset</button> </div></div> js1234567891011121314// 使用方式一$('.example-1').on('click', function() { $('.target-1').children().css('color', 'DodgerBlue');});// 使用方式二$('.example-2').on('click', function() { $('.target-2').children('.selected').css('color', 'LightSkyBlue');});// reset$('.reset').on('click', function() { $('*').css('color', '');}); .find() 向下尋找所有匹配的後代元素 .find() 方法必須代入參數 (選擇器) 範例 實例搶先看 .find() 向下尋找所有匹配的後代元素 .find() 方法必須代入參數 (選擇器) html123456789101112131415<div class="box"> <div class="content target-1"> <h2 class="selected">.find() 的效果</h2> <h3>使用方式</h3> <ul> <li class="selected">取得 class 有 "target-1" 的元素再向下匹配所有 class 有 "selected" 的元素</li> <li class="selected">設定匹配元素的文字顏色</li> <li>如果元素的 class 沒有 "selected" 就無法設定文字顏色</li> </ul> </div> <div class="field is-grouped"> <button class="button is-link example-1">使用方式</button> <button class="button reset">reset</button> </div></div> js123456789// 使用方式一$('.example-1').on('click', function() { $('.target-1').find('.selected').css('color', 'DodgerBlue');});// reset$('.reset').on('click', function() { $('*').css('color', '');}); 結論jQuery 提供了強大的工具,能快速尋找父元素、同層元素與子元素,讓操作 DOM 結構更加靈活且高效。 尋找父元素 .parent():尋找最近的父元素 .parents():尋找所有祖先元素 .closest():尋找最近且符合條件的祖先元素 尋找同層元素 .siblings():尋找所有同層元素(不包括自身) .next():尋找下一個同層元素 .prev():尋找上一個同層元素 尋找子元素 .children():尋找所有直接子元素 .find():尋找所有符合條件的子元素 除了這些常用方法外,還有一些進階方法,如 .parentsUntil() 和 .offsetParent() 等,可以根據需求選擇最適合的方法~ 動手做做看 html 線上編輯器 延伸閱讀【天矽科技】DOM 是什麼?【jQuery 官方文件】tree-traversal 介紹","link":"/Frontend/JQuery/Methods-for-Finding-Parent-and-Sibling-and-Child-Elements/"},{"title":"【HTML】解析 <a> 的 rel 屬性","text":"本篇重點 了解 <a> 的 rel 屬性 <a> 常見的 rel 屬性值和用途 不同情境下 <a> rel 屬性的使用方式 現代瀏覽器在大部分情況下已經自動為帶有 target="_blank" 的連結加上 rel="noopener" 調用 window.opener 的方法 了解 <a> 的 rel 屬性<a> 元素常用於創建超連結,連結其他頁面或網站。而 rel 全名 “relationship” 用來定義當前文件和連結資源之間的關係,這個屬性不僅能夠影響 SEO,還能提升網站的安全性。 <a> 常見的 rel 屬性值和用途noopener當使用 target="_blank" 開啟新頁面時,使用此屬性可以防止新視窗操作原本的網站,避免潛在的安全風險。noopener 和 Javascript 有關,新視窗可以使用 window.opener 來控制原視窗,藉此執行惡意行為。 健忘筆記 現代瀏覽器在大部分情況下已經自動為帶有 target="_blank" 的連結加上 rel="noopener",所以有沒有設定 noopener 屬性,在新視窗使用 window.opener 都會得到 null,但為了確保相容性和覆蓋到所有情況,依然建議明確地設定 rel="noopener"。【Chrome Platform Status】自動為所有使用 target=”_blank” 的連結加上 rel=”noopener” 例如js12345678// 原視窗重新導向到首頁window.opener.location.href = "https://forgetfulengineer.github.io/";// 開啟原視窗的 alertwindow.opener.alert('你點到惡意連結了');// 操作原視窗的 DOMwindow.opener.document.querySelector('body').innerHTML='<b style="color: red; font-size: 100px; margin: auto;">你點到惡意連結了</b>'; noreferrer阻止瀏覽器在新頁面中傳送 Referer 標頭,從而保護當前頁面 URL 不被暴露給目標網站。這個屬性也會自動包含 noopener 的效果。 健忘筆記 網站內部連結時,千萬別加上 noreferrer 這個屬性值,否則會影響 SEO! nofollow告訴搜尋引擎忽視兩個網站間的關聯,不要追蹤此連結,對於原視窗沒有影響,但會影響新視窗的流量分析和 SEO。這個屬性通常應用在廣告或不信任的外部連結上,以防止影響網站的 SEO 排名。 健忘筆記 backlink 是 SEO 計算排名的指標之一,如果某知名網站推廣了健忘工程師網站,並且沒有使用 nofollow,就可能提高網站的 SEO 分數。 external告訴瀏覽器或一些輔助工具(如 SEO 工具或網頁分析工具),這個連結指向的是一個外部網站。 ugc(User Generated Content)用於標示用戶生成的內容,常見於評論、留言等。 sponsored表示該連結為付費推廣或廣告內容,這有助於透明地告知搜尋引擎該連結的性質。 不同情境下 <a> rel 屬性的使用方式 rel 屬性可以疊加使用 外部連結針對外部連結可以使用 rel="noopener noreferrer nofollow external" html1<a href="<https://www.google.com>" target="_blank" rel="noopener noreferrer nofollow external">google</a> 提升 SEO 針對付費推廣連結時可以使用rel="sponsored" 針對用戶自行提交的連結可以使用 rel="ugc nofollow" html123<a href="<https://ads.com>" rel="sponsored">Ads</a><a href="<https://user-content.com>" rel="ugc nofollow">User Content</a> 調用 window.opener 的方法隨著瀏覽器安全性的提升,現代瀏覽器已經自動為所有帶有 target="_blank" 的連結加上 rel="noopener",這是為了防止新視窗通過 window.opener 對原視窗進行操作,避免可能的安全漏洞(如釣魚攻擊)。 如果在某些情境下需要測試或使用 window.opener,這邊提供兩種方法~ 設置 rel="opener" 使用 window.open() 開啟新連結 需要注意的是,這只能在原視窗與新視窗位於相同域名的情況下使用,如果是跨域情況,則無法操作 window.opener。 html12345<!-- 設置 rel="opener" --><a href="https://example.com" target="_blank" rel="opener">測試 window.opener</a><!-- 使用 window.open() 開啟新連結 --><button onclick="javascript:window.open('https://example.com');">測試 window.opener</button> 😈 惡意連結實例 原視窗重新導向到首頁 開啟原視窗的 alert 操作原視窗的 DOM 結論rel 屬性雖然簡單,但在網站的安全性、SEO 扮演著重要角色。 noopener:阻擋新視窗操作原視窗 (現代瀏覽器已經自動為所有帶有 target="_blank" 的連結加上 rel="noopener") noreferrer:阻止瀏覽器在新頁面中傳送 Referer 標頭,影響新視窗的 SEO nofollow:告訴搜尋引擎忽視兩個網站間的關聯,影響新視窗的 SEO external:告訴瀏覽器此連結是外部連結 ugc:標示用戶生成的內容 sponsored:標示此連結為付費推廣或廣告內容 延伸閱讀【MDN】rel 屬性介紹【MDN】Window: opener 屬性介紹【Chrome Platform Status】自動為所有使用 target=”_blank” 的連結添加 rel=”noopener”","link":"/Frontend/Html/Understanding-the-rel-Attribute-of-the-a-Tag/"},{"title":"【PHP】陣列合併應用:array + array、array_merge()、array_replace()","text":"本篇重點 陣列的自定義鍵值和流水號鍵值 array + array、array_merge()、array_replace() 的使用方式和差異 陣列的自定義鍵值和流水號鍵值陣列的鍵值可以是自定義的字符串或整數,也可以是預設的流水號鍵值 實例搶先看 陣列的自定義鍵值和流水號鍵值 自定義鍵值:使用有意義的鍵來標識陣列中的元素 流水號鍵值:從 0 開始遞增的整數鍵值,沒有指定鍵時,PHP 會自動生成預設的流水號鍵值 實例搶先看 自定義鍵值使用有意義的鍵來標識陣列中的元素 12345$customArray = [ 'name' => 'Alice', 'age' => 25, 'city' => 'New York']; 流水號鍵值從 0 開始遞增的整數鍵值。沒有指定鍵時,PHP 會自動生成預設的流水號鍵值 1$defaultArray = ['Apple', 'Banana', 'Cherry']; 同時使用自定義鍵值和流水號鍵值1234567$mixedArray = [ 'name' => 'Bob', 'age' => 30, 'colors' => ['Red', 'Green', 'Blue'], '2' => 'two', 1 => 1]; 鍵值重複同一個陣列中使用相同的鍵值,後面定義的值會覆蓋前面的值。 12345$duplicateArray = [ 'name' => 'Bob', 'name' => 'Tom', 'age' => 30,]; 動手做做看 動手做做看 陣列合併應用array + array 保留第一組陣列的所有鍵值對 添加第二組陣列中不在第一組陣列的鍵值對 如果兩個陣列有相同的鍵值(不管字串或數字的鍵值),則保留第一組陣列的鍵值對 如果合併的時候有流水號鍵值,則保持原順序,不會重新排序 範例 實例搶先看 array + array 保留第一組陣列的所有鍵值對 添加第二組陣列中不在第一組陣列的鍵值對 如果兩個陣列有相同的鍵值,則保留第一組陣列的鍵值對 流水號鍵值保持原順序,不會重新排序 實例搶先看 12345678910111213141516171819202122232425262728293031323334353637383940414243// 自定義鍵值$array1 = ['a' => 1, 'b' => 2];$array2 = ['b' => 3, 'c' => 4];$result1 = $array1 + $array2;// 輸出結果print_r($result1);Array( [a] => 1 [b] => 2 [c] => 4)// 流水號鍵值$array3 = [0 => 'Apple', 3 => 'Banana'];$array4 = [0 => 'Cherry', 2 => 'Grap'];$result2 = $array3 + $array4;// 輸出結果print_r($result2);Array( [0] => Apple [3] => Banana [2] => Grap)// 同時使用自定義鍵值和流水號鍵值$array5 = [0 => 'Apple', 'b' => 23, 3 => 'Banana'];$array6 = ['e' => 66, 'Cherry', 'Grap'];$result3 = $array5 + $array6;// 輸出結果print_r($result3);Array( [0] => Apple ['b'] => 23 [3] => Banana ['e'] => 66 [1] => Grap) 動手做做看 動手做做看 array_merge() 合併一組或多組陣列 保留所有參與合併陣列的鍵值對 如果有相同的鍵值 (不是數字的鍵值),後面陣列的鍵值對會覆蓋前面的鍵值對 如果合併的時候有數字或流水號鍵值,則重新排序 (從0開始遞增) 範例 實例搶先看 array_merge() 合併一個或多個陣列 保留所有參與合併陣列的鍵值對 如果有相同的鍵值 (不是數字的鍵值),後面陣列的鍵值對會覆蓋前面的鍵值對 如果合併的時候有數字或流水號鍵值,則重新排序 (從0開始遞增) 實例搶先看 12345678910111213141516171819202122232425262728293031323334353637383940414243444546// 自定義鍵值$array1 = ['a' => 1, 'b' => 2];$array2 = ['b' => 3, 'c' => 4];$result1 = array_merge($array1, $array2);// 輸出結果print_r($result1);Array( [a] => 1 [b] => 3 [c] => 4)// 流水號鍵值$array3 = [0 => 'Apple', 3 => 'Banana'];$array4 = [0 => 'Cherry', 2 => 'Grap'];$result2 = array_merge($array3, $array4);// 輸出結果// 陣列都是數字鍵值,合併後鍵值重新排序print_r($result2);Array( [0] => Apple [1] => Banana [2] => Cherry [3] => Grap)// 同時使用自定義鍵值和流水號鍵值$array5 = [0 => 'Apple', 'b' => 23, 3 => 'Banana'];$array6 = ['e' => 66, 'Cherry', 'Grap'];$result3 = array_merge($array5, $array6);// 輸出結果print_r($result3);Array( [0] => Apple [b] => 23 [1] => Banana [e] => 66 [2] => Cherry [3] => Grap) 動手做做看 動手做做看 array_replace() 合併一組或多組陣列 添加後面陣列中不在第一組陣列的鍵值對 如果有相同的鍵值 (不管字串或數字的鍵值),後面陣列的鍵值對會覆蓋前面的鍵值對 如果合併的時候有流水號鍵值,則保持原順序,不會重新排序 範例 實例搶先看 array_replace() 合併一個或多個陣列 添加後面陣列中不在第一組陣列的鍵值對 如果有相同的鍵值 (不管字串或數字的鍵值),後面陣列的鍵值對會覆蓋前面的鍵值對 如果合併的時候有流水號鍵值,則保持原順序,不會重新排序 實例搶先看 12345678910111213141516171819202122232425262728293031323334353637383940414243// 自定義鍵值$array1 = ['a' => 1, 'b' => 2];$array2 = ['b' => 3, 'c' => 4];$result1 = array_replace($array1, $array2);// 輸出結果print_r($result1);Array( [a] => 1 [b] => 3 [c] => 4)// 流水號鍵值$array3 = [0 => 'Apple', 3 => 'Banana'];$array4 = [0 => 'Cherry', 2 => 'Grap'];$result2 = array_replace($array3, $array4);// 輸出結果print_r($result2);Array( [0] => Cherry [3] => Banana [2] => Grap)// 同時使用自定義鍵值和流水號鍵值$array5 = [0 => 'Apple', 'b' => 23, 3 => 'Banana'];$array6 = ['e' => 66, 'Cherry', 'Grap'];$result3 = array_replace($array5, $array6);// 輸出結果print_r($result3);Array( [0] => Cherry [b] => 23 [3] => Banana [e] => 66 [1] => Grap) 動手做做看 動手做做看 array + array、array_merge()、array_replace() 相互比較合併組數 array + array:只能合併兩組陣列 1$result = $array1 + $array2; array_merge():可合併多組陣列 1$result = array_merge($array1, $array2, $array3, ...); array_replace():可合併多組陣列 1$result = array_replace($array1, $array2, $array3, ...); 相同鍵值時,鍵值對的覆蓋方式 array + array: 不論是字符串鍵值還是數字鍵值,保留第一組陣列的鍵值對,不會被後面的鍵值對覆蓋 array_merge(): 字符串鍵值:後面陣列的鍵值對會覆蓋前面的鍵值對 數字鍵值:後面陣列的值會追加到結果陣列中,不覆蓋前面的鍵值對 array_replace(): 不論是字符串鍵值還是數字鍵值,後面陣列的鍵值對都會覆蓋前面的鍵值對 合併數字鍵值時,鍵值排序方式 array + array:保持數字鍵值的原順序,不會重新排序 123456789101112$array1 = [0 => 'Apple', 2 => 'Banana'];$array2 = [2 => 'Cherry', 4 => 'Grap'];$result = $array1 + $array2;// 輸出結果:print_r($result);Array( [0] => Apple [2] => Banana [4] => Grap) array_merge():數字鍵值會重新索引,從0開始遞增 12345678910111213$array1 = [0 => 'Apple', 2 => 'Banana'];$array2 = [2 => 'Cherry', 4 => 'Grap'];$result = array_merge($array1, $array2);// 輸出結果:print_r($result);Array( [0] => Apple [1] => Banana [2] => Cherry [3] => Grap) array_replace():保持數字鍵值的原順序,不會重新排序 123456789101112$array1 = [0 => 'Apple', 2 => 'Banana'];$array2 = [2 => 'Cherry', 4 => 'Grap'];$result = array_replace($array1, $array2);// 輸出結果:print_r($result);Array( [0] => Apple [2] => Cherry [4] => Grap) 動手做做看 PHP 線上編輯器 總結 array + array array_merge() array_replace() 合併陣列組數 兩組 多組 多組 相同鍵值的覆蓋方式 不論字符串鍵值還是數字鍵值,保留第一組陣列的鍵值對,不覆蓋 字符串鍵值:後者覆蓋前者數字鍵值:追加不覆蓋 不論字符串鍵值還是數字鍵值,後者覆蓋前者 合併數字鍵值時的排序方式 保持原順序,不重新排序 重新排序,從0開始遞增 保持原順序,不重新排序 array + array、array_merge()、array_replace() 三種合併陣列的方式,各自有相似的地方,但是執行結果有些許差異。 我很常會忘記它們各自的差異,所以需要陣列合併的時候會不知道要使用哪個方式,希望透過這篇整理可以幫助到我跟有同樣困擾的人😂","link":"/Backend/PHP/Analyzing-Three-Methods-of-Merging-Array/"},{"title":"【linux】使用 less 查看檔案","text":"本篇重點 less 基本使用方法 less 的實用選項:-N、-S、+F、-p、-i、-m less 檢視模式內的快捷鍵:/pattern、?pattern、&pattern、n、N、g、G、F、q、h 比較 less 和 more 的差異 在 Linux 中,經常需要查看文字檔案的內容,例如系統日誌、設定檔等。當查看大檔案時,使用 cat 會一次顯示全部內容,這不僅會造成閱讀困難,也可能因為資料龐大而影響載入速度。這時,less 就是一個非常實用的工具,能夠讓使用者輕鬆瀏覽檔案內容,不會一次性載入全部資料,並按需求檢視,接下來介紹 less 命令的使用方法。 less 基本使用方法在終端輸入 less 加上檔案名稱即可檢視檔案 command123# less [檔案名稱]less example.txt less 的實用選項當使用 less 查看檔案時,可以透過不同的選項來提升檢視效率 動手做做看 -N:顯示行號讓每一行都顯示行號,方便定位具體行數。 command123# less -N [檔案名稱]less -N example.txt -S:長行單行顯示預設情況下,超過螢幕寬度的長行會自動換行,使用此選項可以保持單行顯示。 command123# less -S [檔案名稱]less -S example.txt +F:追蹤檔案最後一行的變動類似 tail -f,適合查看動態更新的日誌文件,會自動顯示新增的內容。 command123# less +F [檔案名稱]less +F example.txt 健忘筆記 less +F 是追蹤檔案最後一行的變動,如果透過編輯器修改文件的中間部分或重寫文件的某些區塊,可能會導致 less +F 無法正確解析或錯誤更新,因為它只關注尾端的變化。 -p "pattern": 直接搜尋特定字串打開檔案的同時,直接搜尋特定字串,並跳轉到該字串的位置。 command123# less -p "pattern" [檔案名稱]less -p "test" example.txt -i:搜尋時忽略大小寫查看文件時,搜尋關鍵字忽略大小寫。 command123# less -i [檔案名稱]less -i example.txt -m:顯示查看進度查看文件時,底部顯示當前進度。 command123# less -m [檔案名稱]less -m example.txt 選項疊加使用各選項可以疊加使用,增加靈活度 command12# 查看文件時,顯示行號、長行單行顯示、顯示查看進度less -NSm example.txt 檢視模式內的快捷鍵進入 less 的檢視模式後,可以使用一些快捷鍵來操作檔案。 動手做做看 /pattern:向下搜尋字串,輸入 / 後跟著填入要搜尋的字串,less 會跳轉到該字串第一次出現的地方,按 n 可以跳到下一個匹配 ?pattern:向上搜尋字串,? 會向上搜尋,跟 / 搜尋相反 &pattern:只顯示匹配的字串行 n:跳轉到下一個匹配結果 N (shift + n):跳轉到上一個匹配結果 g:跳轉到檔案開頭 G (shift + g):跳轉到檔案結尾 F (shift + f):追蹤檔案最後一行的變動,和 less +F 的效果相同 q:退出 less h:顯示幫助頁面,列出所有快捷鍵 比較 less 和 more 的差異more 較早的工具,功能相對簡單 一次性加載整個檔案,當檔案很大時,可能會花較長時間加載 關閉 more 後,終端會保留顯示過的檔案內容 less more 的增強版本,具備更靈活的操作功能 分段加載檔案,僅顯示需要的部分 關閉 less 後,終端不會顯示檔案內容,回到執行 less 前的狀態 結論less 透過選項與快捷鍵可以靈活地檢視大檔案、日誌文件或程式碼,如果有其他有趣的選項或快捷鍵,歡迎在下方留言分享! 動手做做看 Linux 線上模擬器","link":"/Backend/Linux/Using-less-to-View-Files/"},{"title":"【Css】解析五種常見的相對單位","text":"本篇重點 常見的相對單位:%、em、rem、vh、vw 相對單位的使用方式和時機 在 CSS 中,除了固定的像素單位(px)之外,還有許多相對單位可以根據父元素比例或視窗大小或元素字體自動調整,是現代響應式設計(RWD)不可或缺的工具。 %:父元素的相對比例最基本的相對單位,常用來設定元素尺寸(例如 width、height、margin、padding 等),其值是相對於父元素對應屬性的比例,表示當父元素的尺寸改變時,使用百分比的子元素會隨之縮放。 範例利用百分比設計圖片區塊,讓圖片隨著不同的螢幕寬度自適應 實例搶先看 %:父元素的相對比例 相對於父元素對應屬性的比例 html123<div class="responsive-wrapper"> <img src="https://forgetfulengineer.github.io/gallery/covers/Understanding-five-Common-Relative-Units.png"></div> css123456789/* 寬度預設為 width: 100%,寬度隨螢幕寬度改變 */.responsive-wrapper { background-color: blue;}.responsive-wrapper img { width: 80%; /* 圖片佔父容器 80% */ height: auto; /* 維持圖片比例 */} em:字體大小的相對單位相對於當前元素或父元素字體大小的單位,常用於需要隨字體大小變化調整元素大小的排版,例如調整字體和內邊距,讓內、外邊距跟隨字體大小調整,保持整體視覺一致,或是設置多層次樣式,呈現層級關係時使用。 假設一個父容器的字體大小為 20px,子元素的 padding 設為 1.5em,則子元素實際的 padding 值為 30px,因為 1.5em * 20px = 30px。 健忘筆記 em 的參照順序: 當前元素有設置 font-size,則 em 以當前元素的字體大小為基準。 若當前元素沒有設定 font-size,會沿著 DOM 樹逐層向上找,直到找到最近一個有 font-size 的父元素。 如果沒有找到設置的字體大小,則最終會參照根元素 <html> 的 font-size。根元素默認值通常是 16px(但可透過 CSS 調整,例如 html { font-size: 10px; })。 範例 實例搶先看 em:字體大小的相對單位 相對於當前元素或父元素字體大小的單位 html1234<div class="parent"> 測試內容 <button class="child">我是按鈕</button></div> css12345678.parent { font-size: 30px;}button { font-size: 0.5em; padding: 0.5em 1em;} 健忘筆記 em 是相對於當前元素或父元素字體大小的單位,如果父元素和當前元素同時使用 em,則當前元素屬性的大小會隨著層級增加而累積 rem:根元素字體大小的相對單位rem(root em)是相對於根元素(通常是 <html>)字體大小的單位,統一的相對大小能確保在頁面中一致性設計。 假設根元素的字體大小為 20px,其子元素的 padding 設為 1.5rem,則子元素實際的 padding 值為 30px,因為 1.5rem * 20px = 30px。 範例 實例搶先看 rem:根元素字體大小的相對單位 相對於根元素(通常是 <html>)字體大小的單位 html1234<div class="container"> 容器文字大小為 24px <div class="child">子元素文字大小為 32px</div></div> css1234567/* 根元素 font-size 預設 16px */.container { font-size: 1.5rem; /* 1.5 * 16px = 24px */}.child { font-size: 2rem; /* 2 * 16px = 32px */} vh 和 vw:用戶視窗高和寬的比例相對於用戶視窗高度和寬度的單位,適合設計需要相對於視窗尺寸而調整的布局,讓元素能隨著不同裝置和瀏覽器窗口大小動態縮放,常用於設置全螢幕背景或全螢幕容器,例如:lightbox。 1vh 表示視窗高度的 1% 20vw 表示視窗寬度的 20% 範例 實例搶先看 vh 和 vw:用戶視窗高和寬的比例 相對於用戶視窗高度和寬度的單位 html1<img src="https://forgetfulengineer.github.io/gallery/covers/Understanding-five-Common-Relative-Units.png"> css1234img { height: 30vh; /* 視窗高度的 30% */ width: 50vw; /* 視窗寬度的 50% */} 健忘筆記 裝置旋轉的影響:vh 和 vw 會根據視窗實際顯示區的高度和寬度來計算,因此旋轉裝置時,元素可能會突然變大或縮小。 捲軸條影響:若瀏覽器視窗出現垂直或水平捲軸條,會佔據一定的寬度或高度,影響到 vw 和 vh 的實際計算結果。 本網站的 lightbox 使用 vw 來控制寬度,可以點擊 實例搶先看 或 文章圖片 查看元素的寬度~ 結論這些相對單位可以更靈活得設計響應式佈局,並確保網頁在不同設備和視窗大小上都能有適當的呈現。 %:父元素的相對比例 em:當前元素或父元素字體大小的相對單位 rem:根元素字體大小的相對單位 vh 和 vw:用戶視窗高和寬的比例 動手做做看 codepen 線上編輯器 延伸閱讀【W3Schools】單位大全【愛貝斯網路】RWD是甚麼?","link":"/Frontend/Css/Understanding-five-Common-Relative-Units/"},{"title":"【GitHub】追蹤檔案修改紀錄","text":"本篇重點 查看檔案的 commit 紀錄 依作者或時間查詢 commit 紀錄 使用 blame 查看檔案的逐行修改紀錄 blame 模式下,還原檔案至指定 commit 前的狀態,查看修改前的內容 Git 的 git blame 查看檔案的逐行修改紀錄 在軟體開發中,版本控制是用來追蹤檔案修改紀錄的重要工具,不僅能掌握專案的歷史變更,還能快速查找特定的修改。GitHub 提供了多種實用工具來幫助開發者追蹤檔案變更,blame 功能就是其中一個非常實用的功能,可以逐行檢視修改詳情,接下來來了解 GitHub 上幾種查看檔案修改紀錄的方法。 查看檔案的 commit 紀錄每當檔案修改並提交 commit 後,會記錄修改人、修改時間以及提交內容說明。 1. 查找檔案透過目錄尋找檔案 透過路徑或檔名尋找檔案 2. 點擊檔案右上方的 History 顯示檔案的所有 commit 歷程(新到舊) 此頁面顯示所有與該檔案相關的提交紀錄,包括每次提交的 SHA 值、提交者、提交時間及提交說明,並且可以點擊 commit,進一步檢視 commit 的修改內容。 依作者或時間查詢 commit 紀錄在 commit 歷史頁面,GitHub 提供了篩選功能,可以依據作者、日期查詢 commit 紀錄。 依作者查詢因為這個專案只有我在維護,所以能查詢的作者只有 forgetfulengineer 依日期查詢 查詢功能能快速找到特定修改者或在特定時間範圍內更動紀錄,特別適合用於大型專案或長期維護的專案。 使用 blame 查看檔案的逐行修改紀錄blame 是 GitHub 上一項強大的功能,用於查看檔案每一行的修改紀錄,能精確地了解每一行的最新修改者及其修改時間,對於排查問題和追溯修改原因很有幫助。 1. 查找檔案 2. 點擊檔案左方的 Blame 3. 查看檔案的逐行修改紀錄可以看到每一行左側顯示了最新修改此行的 commit 記錄、作者和時間 在 blame 模式下,可以直接點擊每行的 commit 說明來檢視該提交的詳細內容,進一步追蹤更動的原因和細節。 還原檔案至指定 commit 前的狀態,查看修改前的內容有時可能想查看檔案某一行或某一個 commit 前的檔案內容,例如確認修改前的檔案狀況或排查錯誤。在 blame 模式下,可以點擊每行 commit ID 旁邊的按鈕達到還原的效果。 1. 點擊檔案左方的 Blame 2. 點擊 commit ID 旁邊的按鈕 點擊後,檔案將會還原到指定 commit 前的狀態! Git 的 git blame 查看檔案的逐行修改紀錄Git 提供 git blame 指令,追蹤檔案每一行的修改紀錄,這個指令會顯示出每行程式碼的最新修改資訊,包括提交的作者、日期和 commit ID。 123git blame [檔案名稱]git blame example.txt 結論blame 功能非常實用,尤其在排查問題和追溯修改原因時效果顯著。我個人在追蹤檔案的修改紀錄時經常使用 blame,不僅更清晰地了解修改細節,也提升了整體追蹤效率。如果 GitHub 有其他方便的功能,歡迎在下方留言分享! 延伸閱讀 【GitHub 官方文件】Viewing a file 【git 官方文件】git blame 說明","link":"/Other/GitHub/Tracking-File-Modification-History/"},{"title":"【Git】強制更新遠端分支進度到本地分支","text":"本篇重點 強制更新遠端分支進度到本地分支的方法 git checkout -B 強制更新本地分支 刪除並重新建立本地分支 git reset --hard 強制更新本地分支 強制更新本地分支進度到遠端分支的方法 git push -f 強制更新遠端分支 在版本控制的過程中,有時會遇到本地分支的進度與遠端分支不同步的情況,而當遠端分支的進度才是正確版本時,需要強制更新本地分支來與遠端保持同步。以下提供三種方法來完成本地分支的強制更新! 強制更新遠端分支進度到本地分支方法一:git checkout -B(推薦)git12git fetch origingit checkout -B local-branch origin/remote-branch 使用 git fetch 更新遠端分支的資訊。 接著執行 git checkout -B,該指令會執行以下操作: 切換到指定的本地分支(若不存在,會自動建立)。 強制將本地分支重置為遠端分支的最新進度。 不管當前位於哪個分支,都可以直接使用 git checkout -B 來切換並更新指定分支 範例 遠端分支為 origin/develop,本地分支為 develop git12git fetch origingit checkout -B develop origin/develop 方法二:刪除並重新建立分支git123git fetch origingit branch -D local-branchgit checkout -b local-branch origin/remote-branch 使用 git fetch 更新遠端分支的資訊。 使用 git branch -D 刪除本地分支。 透過 git checkout -b 重新建立一個與遠端分支同步的本地分支。 範例遠端分支為 origin/develop,本地分支為 develop git1234git fetch origingit checkout mastergit branch -D developgit checkout -b develop origin/develop 健忘筆記 使用 git branch -D 刪除分支時,要先離開欲刪除的分支 git checkout -b 只能建立當前不存在的分支 方法三:git reset --hardgit123git fetch origingit checkout local-branchgit reset --hard origin/remote-branch 使用 git fetch 更新遠端分支的資訊。 使用 git checkout -b 切換到欲更新的分支。 使用 git reset --hard 將當前的本地分支強制重置為遠端分支的最新進度。 範例遠端分支為 origin/develop,本地分支為 develop git123git fetch origingit checkout developgit reset --hard origin/develop 健忘筆記 git reset --hard 會丟失本地的變更,本地未提交的更改將會消失 強制更新本地分支進度到遠端分支git push -fgit12git checkout local-branchgit push -f origin remote-branch 使用 git checkout -b 切換到要推送的分支。 使用 git push -f 強制更新遠端分支進度。 範例遠端分支為 origin/develop,本地分支為 develop git12git checkout developgit push -f origin develop 健忘筆記 如果遠端分支的名稱和本地分支的名稱不同(遠端分支為 origin/develop,本地分支為 dev),可以使用 git push -f origin dev:develop 做更新 結論我認為使用 git checkout -B 是最方便且直觀的方式,能快速完成本地分支與遠端分支的同步,且無需額外刪除或重建分支,適合大多數情況。不過,選擇哪種方式還是取決於當前分支的狀況與需求。需要特別注意的是,強制更新可能會無法復原,所以執行時要特別注意,確認無誤再更新,避免重要紀錄遺失。 延伸閱讀【Git 官方文件】git checkout -B 介紹【Git 官方文件】git push -f 介紹【Git 官方文件】git reset –hard 介紹【Git 官方文件】git fetch 介紹","link":"/Other/Git/Force-Update-Local-Branch-with-Remote-Branch-Progress/"},{"title":"【Git】使用 git commit 修改提交(commit)的資訊或是內容","text":"本篇重點 git commit --amend 修改最新一次提交的資訊或是內容 git commit --amend --author 修改提交的作者和信箱 git commit --amend --reset-author 重置提交的作者和信箱 git commit --amend -m 修改提交訊息 git commit --amend --no-editor 提交修改但不修改提交訊息 每次修改提交 git commit --amend 都會變更提交 ID 在使用 Git 時,提交(commit)後才發現需要修改提交的資訊或內容。Git 提供了 git commit --amend 指令,能夠修改最新一次提交的內容或資訊,這樣能夠避免新增額外的提交,保持乾淨的提交歷史。 修改提交資訊修改提交的作者和信箱提交的作者和信箱是透過 git config 指令來設定的 git git12git config --global user.name "你的名稱"git config --global user.email "你的信箱" 詳細設定方式可查看【Git】了解 git config 設定 修改最新一次提交的作者名稱和信箱方法一,git commit --amend --reset-author 設定正確的作者名稱和信箱資訊 git12git config --global user.name "forgetfulengineer"git config --local user.email "[email protected]" 重置作者名稱和信箱資訊 git1git commit --amend --reset-author 方法二,git commit --amend --author git1234git commit --amend --author="新作者名稱 <新信箱>"# 修改最新一次提交的作者名稱和信箱git commit --amend --author="forgetfulengineer <[email protected]>" 健忘筆記 信箱的 <> 一定要加上 修改提交訊息修改最新一次提交的訊息 git1git commit --amend -m "修改後的提交訊息" 範例原本的提交訊息為「修正錯誤」,修改改成「修正登入功能錯誤」 git1git commit --amend -m "修正登入功能錯誤" 修改提交內容使用 Git 時,我的提交習慣是根據遠端分支的狀態來決定處理方式。如果提交尚未推送到無法強制修改的遠端分支(例如 master 或 main),我會保持每個提交精簡且整潔,避免有修正型的提交。例如,在設計網站的樣式並進行提交時,如果尚未更新到這些重要的遠端分支,仍處於自己的開發分支中,發現有需要修正的部分時,我不會新增一個修正提交,而是直接修正後再合併到原提交中,確保分支保持整潔。 但是當提交已經推送到無法強制修改的遠端分支時,為了避免影響該分支的穩定性,我會選擇透過提交一個新的修正分支,保留修改記錄的完整性。 新增內容到最新一次的提交在最新一次提交中加入新的修改,並使用 git commit --amend --no-edit 更新提交,這樣會將新添加的內容更新到最新一次的提交中,並保留原提交訊息跟資訊(作者、信箱) git12git add example.jsgit commit --amend --no-edit 不更改提交訊息如果不需要修改提交訊息,可以加上 --no-edit 選項,保持原提交訊息不變: git12345# 提交當前檔案git commit --amend --no-edit# 提交當前檔案並且修改作者名稱和信箱git commit --amend --no-edit --author="forgetfulengineer <[email protected]>" 結論git commit --amend 是非常靈活的指令,用於修正最新一次提交的錯誤資訊或內容。然而需要注意的是,每次執行 git commit --amend 都會產生一個新的提交 ID,因此在使用時務必確認不會影響遠端分支的進度,尤其是在多人開發的專案中更需謹慎,以免造成分支衝突或其他協作問題。 延伸閱讀 【Git 官方文件】git commit --amend 介紹 【Git 官方文件】git commit --amend --no-edit 介紹 【Git 官方文件】git config 介紹","link":"/Other/Git/Using-git-commit-to-Modify-Commit-Data-or-Content/"},{"title":"【NPM、GitHub】解決 npm 版本落後 GitHub 版本的問題","text":"本篇重點 如果發現 npm 套件的版本有 bug,但 GitHub 上的版本已修正,應該如何安裝修正版套件? 怎麼處理 npm 版本落後於 GitHub 版本的狀況 怎麼使用 npm 安裝 GitHub 套件的指定版本? 怎麼使用 npm 更新 GitHub 套件? hexo-generator-sitemap 的 3.0.1 版本存在 bug,導致沒有指定 sitemap 檔案,影響網站 seo 本網站使用 hexo-generator-sitemap 自動生成站點地圖(sitemap.xml),但透過 npm 安裝後,套件沒有正常運作,檢查後發現 npm 套件的版本存在 bug,而套件的 GitHub 儲存庫已修正問題,但修正版尚未發佈至 npm。 本篇文章將以 hexo-generator-sitemap 為例,分享如何處理 npm 版本落後於 GitHub 版本的狀況。 使用 npm 安裝 GitHub 套件指定版本在 GitHub 找到相對應的套件,查找正確的版本(特定分支或 commit id 或 tag 版號) 方法一:使用 npm 指令安裝套件npm12345678# 安裝指定 branch 版本npm install <github-username>/<repository-name>#<branch># 安裝指定 commit 版本npm install <github-username>/<repository-name>#<commit-hash># 安裝指定 tag 版本npm install <github-username>/<repository-name>#<tag> 健忘筆記 也可以使用 npm install git+https://github.com/<github-username>/<repository-name>.git,這同等於 npm install <github-username>/<repository-name>。會使用 git+https://... 的情境可能是如果儲存庫在自建 Git 伺服器上或非 GitHub 平台,需要更高的靈活性或精確指定完整 URL。 範例npm12345678# 安裝最新的 master 分支版本npm install hexojs/hexo-generator-sitemap#master# 安裝指定 commit 版本npm install hexojs/hexo-generator-sitemap#3ac80ce7a3c2506e99b7bf69010ac00b363e6222# 安裝指定 tag 版本npm install hexojs/hexo-generator-sitemap#v3.1.0 健忘筆記 如果沒有指定版本 npm install hexojs/hexo-generator-sitemap,預設安裝該 GitHub 儲存庫 default branch 的最新提交(通常是 main 或 master 分支) 方法二:修改 package.json 檔案並安裝將套件的寫入 package.json 並指定版本1234// 安裝指定 branch 或 tag 或 commit 版本"dependencies": { "<package-name>": "github:<username>/<repository>#<tag-or-commit>"} 執行 npm install 安裝套件npm1npm install 範例1234// 安裝指定 branch 或 tag 或 commit 版本"dependencies": { "hexo-generator-sitemap": "github:hexojs/hexo-generator-sitemap#master"} npm1npm install 健忘筆記 如果沒有指定版本 "hexo-generator-sitemap": "github:hexojs/hexo-generator-sitemap#master",預設安裝該 GitHub 儲存庫的 default branch 的最新提交(通常是 main 或 master 分支) 使用 npm 更新 GitHub 套件重新安裝覆蓋原本的版本npm12# 安裝儲存庫預設分支的最新版本npm install <github-username>/<repository-name> 範例npm12# 安裝 hexojs/hexo-generator-sitemap 的最新版本npm install hexojs/hexo-generator-sitemap 如果 package.json 的設定是 "hexo-generator-sitemap": "github:hexojs/hexo-generator-sitemap",可以直接使用 npm install 就會安裝套件的最新版本! 健忘筆記 npm update 只針對 package.json 中指向 NPM 註冊表的套件進行檢查與更新,所以無法使用 npm update 來更新 GitHub 安裝的套件。 hexo-generator-sitemap 3.0.1 版本的 bug 【NPM】hexo-generator-sitemap 3.0.1 套件 錯誤說明套件的 lib/rel.js 負責將 <link rel="sitemap" href="..." /> 插入到 HTML 檔案的 <head> 標籤內。 lib/rel.jsnpm套件123// 將 sitemap 設定插到 <head> 的最後面const relSitemap = `<link rel="sitemap" type="application/xml" title="Sitemap" href="${url_for.call(this, path)}">`;data.replace(/<head>(?!<\\/head>).+?<\\/head>/, str => str.replace('</head>', `${relSitemap}</head>`)); 當前正規表達式只能匹配到 <head> 標籤單行存在的狀況 html1<head>...</head> 如果 <head> 標籤是多行排列時,正規表達式無法正確匹配,導致 sitemap 設定未寫入,影響網站 seo html1234// 正規表達式無法匹配<head> <meta charset="utf-8"></head> 修正錯誤hexo-generator-sitemap 的 GitHub 儲存庫已修正 <head> 標籤多行排列,正規表達式無法正確匹配的錯誤。 lib/rel.jsGitHub修改紀錄12- return data.replace(/<head>(?!<\\/head>).+?<\\/head>/, str => str.replace('</head>', `${relSitemap}</head>`));+ return data.replace(/<head>(?!<\\/head>).+?<\\/head>/s, str => str.replace('</head>', `${relSitemap}</head>`)); 啟用修飾詞 s 讓特殊字元 . 可以匹配所有字元,包括換行符(\\n 或 \\r\\n)。 結論在開發過程中發現 hexo-generator-sitemap 的錯誤,進一步了解到 NPM 套件版本有時無法完全跟上 GitHub 上的最新版本。為了解決這個問題,可以直接從 GitHub 安裝最新修正的版本,讓套件正常運行。但需要注意的是這種方法只是暫時性的解決方案,未來還是需要關注 NPM 的正式版本更新,確保專案的長期穩定性和可維護性。如果你有其他解決方法或建議,也歡迎在下方留言分享~ 延伸閱讀【NPM 官方文件】npm install 介紹【NPM】hexo-generator-sitemap 套件【GitHub】hexo-generator-sitemap 套件【Fooish 程式技術】Regex 正規表示法 - 修飾詞","link":"/Other/NPM/Resolving-the-Issue-of-npm-Version-Lagging-Behind-the-GitHub-Version/"},{"title":"【PHP、JavaScript】陣列自定義排序","text":"本篇重點 PHP 的 usort() 陣列自定義排序 JavaScript 的 .sort() 陣列自定義排序 自定義排序比較函數的規則 PHP usort() 和 JavaScript .sort() 的反向排序 陣列自定義排序應用範例 PHP 的 usort()根據自定義的邏輯對陣列進行排序,不保留鍵名,僅針對值進行排序,並且直接修改原陣列 usort($array, $callback); php123usort($array, function($a, $b) { return $a <=> $b;}); $array 為欲排序的陣列 $callback 為比較函數 比較函數的規則 return < 0:$a 排在 $b 前 return > 0:$a 排在 $b 後 return === 0:$a 和 $b 順序保持不變 <=> 介紹<=> 是 PHP 7 引入的「太空船運算子」(Spaceship Operator),用來比較兩個值的大小,返回三種結果 返回 -1:左邊的值小於右邊的值 返回 0:左邊的值等於右邊的值 返回 1:左邊的值大於右邊的值 範例 情境一,對一組隨機亂數的陣列,依小到大做排序 (升序) php1234567891011121314151617$array = [5, 2, 9, 1, 3];// 方法一usort($array, function($a, $b) { return $a - $b; // 差值決定排序順序});// 方法二usort($array, function($a, $b) { return $a <=> $b;});// 方法三 (單層的陣列可以直接使用 sort() 排序,預設排序是小到大)sort($array);print_r($array);// 輸出: [1, 2, 3, 5, 9] 動手做做看 對一組隨機亂數的陣列,依小到大做排序 動手做做看 情境二,假設得到一組陣列資料,裡面有各個活動的資訊,依需求對陣列排序。 整體順序是 1.未到期活動 2.已到期活動,且皆以最新到最舊活動排序,執行方式為判斷活動結束時間 end_date 是否小於現在時間 (是否到期),未到期活動排在已到期活動前面,再以活動開始時間 start_date 大到小排序 實例搶先看 假設得到一組陣列資料,裡面有各個活動的資訊,對陣列做排序 整體順序是 1. 未到期活動 2.已到期活動,且皆以最新到最舊活動排序 php1234567891011121314151617181920212223242526272829303132333435363738394041424344454647// 活動資訊陣列$array = [ [ "id" => 1, "event_time" => [ "start_date" => 1730084400, // 2024-10-28 11:00:00 "end_date" => 1731513659 // 2024-11-14 00:00:59 ] ], [ "id" => 2, "event_time" => [ "start_date" => 1729512000, // 2024-10-21 20:00:00 "end_date" => 1731254400 // 2024-11-11 00:00:00 ] ], [ "id" => 3, "event_time" => [ "start_date" => 1730102400, // 2024-10-28 16:00:00 "end_date" => 1731686400 // 2024-11-16 00:00:00 ] ]];// 排序函數usort($array, function ($a, $b) { $current_time = time(); $a_end_date = $a['event_time']['end_date']; $b_end_date = $b['event_time']['end_date']; $a_start_date = $a['event_time']['start_date']; $b_start_date = $b['event_time']['start_date']; // 首先判斷是否過期 $a_is_expired = $a_end_date < $current_time; $b_is_expired = $b_end_date < $current_time; // 如果一個過期一個未過期,將未過期的排前面 if ($a_is_expired !== $b_is_expired) { return $a_is_expired <=> $b_is_expired; } // 否則依據 start_date 從大到小排序 return $b_start_date <=> $a_start_date;});print_r($array); 動手做做看 動手做做看 JavaScript 的 .sort().sort() 是 JavaScript 提供的陣列排序方法,與 PHP 的 usort() 規則非常相似,允許傳入自定義的比較函數,並且直接修改原陣列。 array.sort([compareFunction]) js123array.sort(function (a, b) { return a - b;}); array 為欲排序的陣列 compareFunction 為比較函數 比較函數的規則: return < 0:a 排在 b 前 return > 0:a 排在 b 後 return === 0:順序保持不變 健忘筆記 JavaScript 沒有 <=> 運算子 範例 情境一,對一組隨機亂數的陣列,依小到大做排序 (升序) js123456789101112let array = [5, 2, 9, 1, 3];// 方法一,.sort() 預設就是以小排到大array.sort();// 方法二,差值決定排序順序array.sort(function (a, b) { return a - b;});console.log(array);// 輸出: [1, 2, 3, 5, 9] 情境二,假設需要依照指定順序照片排序 陣列內是指定順序的照片編號 實例搶先看 假設需要依照指定順序照片排序 陣列內是指定順序的照片編號 html12345<div class="images_container"> <img data-id="1" src="https://forgetfulengineer.github.io/gallery/covers/Tracking-File-Modification-History.png"></img> <img data-id="2" src="https://forgetfulengineer.github.io/gallery/covers/Understanding-five-Common-Relative-Units.png"></img> <img data-id="3" src="https://forgetfulengineer.github.io/gallery/covers/Using-less-to-View-Files.png"></img></div> js1234567891011let images_sorting_arr = [3, 1, 2];let images_container = $(".images_container");let images = $(".images_container [data-id]").toArray();category_news.sort(function (a, b) { return ( images_sorting_arr.indexOf($(a).data("id")) - images_sorting_arr.indexOf($(b).data("id")) );});images_container.empty();$(images).appendTo(images_container); PHP usort() 的反向排序php12345678910111213141516171819202122$array = [5, 2, 9, 1, 3];// 方法一usort($array, function($a, $b) { return $b - $a;});// 方法二usort($array, function($a, $b) { return $b <=> $a;});// 方法三 (使用負號來反轉比較結果)usort($array, function($a, $b) { return -($a <=> $b);});// 方法四 (單層的陣列可以直接使用 rsort() 排序)rsort($array);print_r($array);// 輸出: [9, 5, 3, 2, 1] 動手做做看 得到一組隨機亂數的陣列,依小到大做排序 動手做做看 JavaScript .sort() 的反向排序js12345678910111213let array = [5, 2, 9, 1, 3];// 方法一,先用 .sort() 小排到大,再用 .reverse() 把陣列順序反轉array.sort();array.reverse();// 方法二,差值決定排序順序array.sort(function (a, b) { return b - a;});console.log(array);// 輸出: [9, 5, 3, 2, 1] 結論PHP 的 usort() 和 JavaScript 的 .sort() 是功能非常相似的自定義排序工具,並遵循相同的比較函數邏輯判斷 return < 0:$a 排在 $b 前 return > 0:$a 排在 $b 後 return === 0:$a 和 $b 順序保持不變 自定義排序可以更靈活的依照需求得到想要的陣列,在開發上很有幫助! 延伸閱讀 【PHP 官方文件】usort 介紹 【w3schools】PHP Sorting Arrays 【w3schools】PHP Operators (邏輯運算子) 【w3schools】JavaScript Sorting Arrays","link":"/Backend/PHP/Custom-Sorting-an-Array/"}],"tags":[{"name":"vscode","slug":"vscode","link":"/tags/vscode/"},{"name":"git bash","slug":"git-bash","link":"/tags/git-bash/"},{"name":"terminal","slug":"terminal","link":"/tags/terminal/"},{"name":"php","slug":"php","link":"/tags/php/"},{"name":"backend","slug":"backend","link":"/tags/backend/"},{"name":"css","slug":"css","link":"/tags/css/"},{"name":"jquery","slug":"jquery","link":"/tags/jquery/"},{"name":"frontend","slug":"frontend","link":"/tags/frontend/"},{"name":"linux","slug":"linux","link":"/tags/linux/"},{"name":"system","slug":"system","link":"/tags/system/"},{"name":"mysql","slug":"mysql","link":"/tags/mysql/"},{"name":"database","slug":"database","link":"/tags/database/"},{"name":"db","slug":"db","link":"/tags/db/"},{"name":"hexo","slug":"hexo","link":"/tags/hexo/"},{"name":"git","slug":"git","link":"/tags/git/"},{"name":"github","slug":"github","link":"/tags/github/"},{"name":"html","slug":"html","link":"/tags/html/"},{"name":"seo","slug":"seo","link":"/tags/seo/"},{"name":"security","slug":"security","link":"/tags/security/"},{"name":"npm","slug":"npm","link":"/tags/npm/"},{"name":"javascript","slug":"javascript","link":"/tags/javascript/"},{"name":"js","slug":"js","link":"/tags/js/"}],"categories":[{"name":"Other","slug":"Other","link":"/categories/Other/"},{"name":"Backend","slug":"Backend","link":"/categories/Backend/"},{"name":"Frontend","slug":"Frontend","link":"/categories/Frontend/"},{"name":"VSCode","slug":"Other/VSCode","link":"/categories/Other/VSCode/"},{"name":"MySQL","slug":"Backend/MySQL","link":"/categories/Backend/MySQL/"},{"name":"PHP","slug":"Backend/PHP","link":"/categories/Backend/PHP/"},{"name":"Git","slug":"Other/Git","link":"/categories/Other/Git/"},{"name":"Hexo","slug":"Other/Hexo","link":"/categories/Other/Hexo/"},{"name":"Html","slug":"Frontend/Html","link":"/categories/Frontend/Html/"},{"name":"Css","slug":"Frontend/Css","link":"/categories/Frontend/Css/"},{"name":"JQuery","slug":"Frontend/JQuery","link":"/categories/Frontend/JQuery/"},{"name":"Linux","slug":"Backend/Linux","link":"/categories/Backend/Linux/"},{"name":"GitHub","slug":"Other/GitHub","link":"/categories/Other/GitHub/"},{"name":"NPM","slug":"Other/NPM","link":"/categories/Other/NPM/"},{"name":"JavaScript","slug":"Frontend/JavaScript","link":"/categories/Frontend/JavaScript/"}],"pages":[{"title":"404 - 網頁不存在","text":"var redirects = { \"/PHP/4-Ways-to-Check-If-a-Variable-or-Array-Exists/\": \"/Backend/PHP/4-Ways-to-Check-If-a-Variable-or-Array-Exists/\", \"/VSCode/Using-Git-Bash-in-VSCode/\": \"/Other/VSCode/Using-Git-Bash-in-VSCode/\", }; var path = window.location.pathname; if (redirects[path]) { window.location.replace(redirects[path]); } 這是一個不存在的頁面 抱歉,找不到你要的頁面 😢將在 5 秒後返回首頁。 let countTime = 5; function count() { document.getElementById('timeout').textContent = countTime; countTime -= 1; if (countTime === 0) { location.href = 'https://forgetfulengineer.github.io'; } setTimeout(() => { count(); }, 1000); } count();","link":"/404.html"},{"title":"Cookie Policy","text":"甚麼是 cookie?Cookie 是由網站儲存在使用者瀏覽器中的小型文字檔案,用於在不同的頁面或訪問之間存儲數據。它們主要用來保存使用者資訊,以便在使用者再次訪問網站時提供個性化的體驗。 更詳細的說明可查看 【資安趨勢部落格】cookie 介紹 在哪裡使用 cookie本網站使用了一些第三方服務 Google Analytics : 用來紀錄訪客數據 Twikoo 評論系統 : 用來讓訪客回覆,紀錄訪客資訊 (名稱、信箱等) 禁用 cookie您可以經由瀏覽器的設定,取消或限制 cookie (操作方式請至瀏覽器幫助查詢),但我並不建議您禁用 cookie,禁用可能會導致您喪失網站的一些功能。","link":"/cookie-policy/index.html"},{"title":"【HTML】解析 <a> 的 rel 屬性 - window.opener 惡意連結實例","text":"原視窗重新導向到首頁如果帶有 target="_blank" 的連結沒有加上 rel 的 noopener 屬性,新視窗可以使用 window.opener 控制原視窗重新導向指定網址。 js12// 原視窗重新導向到首頁window.opener.location.href = "https://forgetfulengineer.github.io/"; 開啟原視窗的 alert如果帶有 target="_blank" 的連結沒有加上 rel 的 noopener 屬性,新視窗可以使用 window.opener 開啟原視窗的 alert。 js12// 開啟原視窗的 alertwindow.opener.alert('你點到惡意連結了'); 操作原視窗的 DOM如果帶有 target="_blank" 的連結沒有加上 rel 的 noopener 屬性,新視窗可以使用 window.opener 操作原視窗的 DOM。 js12// 操作原視窗的 DOMwindow.opener.document.querySelector('body').innerHTML='<b style="color: red; font-size: 100px; margin: auto;">你點到惡意連結了</b>'; 健忘筆記 現代瀏覽器在大部分情況下已經自動為帶有 target="_blank" 的連結加上 rel="noopener",所以有沒有設定 noopener 使用 window.opener 都會得到 null,但為了確保相容性和覆蓋到所有情況,依然建議明確地設定 rel="noopener"。 😈 惡意連結實例 原視窗重新導向到首頁 開啟原視窗的 alert 操作原視窗的 DOM 回到原文章 let urlParams = new URLSearchParams(window.location.search); let example = (['1', '2', '3'].includes(urlParams.get('example'))) ? urlParams.get('example') : 1; let element = document.querySelector(\".example-\" + example); element.classList.remove(\"is-hidden\"); switch (example) { case '1': default: window.opener.location.href = \"https://forgetfulengineer.github.io/\"; break; case '2': window.opener.alert('你點到惡意連結了'); break; case '3': window.opener.document.querySelector('body').innerHTML='你點到惡意連結了'; break; }","link":"/example/Malicious-Links-Using-window-opener.html"}]}