成品連結:https://codingdark.github.io/program/2023/09/18/API-Test.html ##第一步 架部落格 最初看到站長的貼文,提供了本站的API 並且鼓勵大家自架部落格,來嘗試串API 看到文章的當下,覺得有點難度(沒用過github page,API也不熟) 不過看到站長提供的關鍵字`setup a personal blog with github pages` 最終還是決定先google看看 查了之後,發現近年的gitbub簡化了很多 都可以自動部署,根本就是一鍵架站 外加原始碼開源,很多東西都能自己改 所以光是部落格就玩了一天XD 因為本站為CodeLove 愛寫扣 我就創了一個CodingDark 闇寫扣 表示致敬本站 & 本人的中二風格 ##第二步 串API 因為不熟的關係,所以決定先隨便串 呼叫API之後,把data印在console.log 大致上看了一下資料格式 使用上其實就類似陣列,非常方便 沒有想像中的難 確認API可以正常呼叫後 陸續加入一些功能 比方說,用Table把文章列表排整齊、加上[Read more]按鈕 先讓json資料,轉換成網頁能呈現出來的[資訊] ##第三步 程式碼優化 到這邊為止,網頁的畫面已經差不多定型了 剩下的就是回頭檢視程式碼 考量到後續維護 盡可能把重複的程式碼,包裝成function 或是把一群散亂的變數,包裝成object 最後,為了方便擴充文章列表 將原本是寫死的HTML Dom 改成動態產生 目前的部落格頁面 點進去會撈出站長、Tony,以及我的文章列表 後續若想要列出其他使用者的文章 只需新增`setTable(userAccount)`即可 ##結尾 感謝站長提供有趣的API 讓大家可以有練習的機會 雖然目前我在工作上,沒接觸過API 但經過這次的練習,以後若是真的有需要用到 可以更快上手
您是否想過當您**執行 Rust 程式**時**RAM**會發生什麼情況**?您編寫程式碼的**方式會如何干擾系統中的許多其他事物? 這篇文章將幫助您了解更多關於 *管理記憶體* 和 **RUST 如何運作** 的資訊。 原文出處:https://dev.to/canhassi/how-rust-memory-management-work-to-beginners-622 ## 1. Stack and Heap 在了解 rust 的作用之前,您必須先了解一些概念。一般來說,我們有兩種類型的內存,稱為:**堆疊和堆**。現在我們來介紹一下他們。 ### 1.1 記憶體:Stack 堆疊,顧名思義,**工作原理就像堆疊**,遵循**“後進先出”(LIFO)的原則。**也許分步驟解釋會更容易: *想像一下**一堆盤子**; *您放入的**第一道菜**是**最後取出的**; * 當**函數被呼叫**時,一塊記憶體被**「堆疊」在棧頂; * 當**函數結束**時,該區塊**“unstacked”**,釋放該記憶體。 通常,**編譯器**(在編譯時)知道將儲存在堆疊上的**值**,因為它知道需要儲存多少記憶體。此過程**自動**發生,所有值都會從記憶體中刪除。 下面是一個例子: ``` fn main() { let number = 12; // at this moment the variable has created println!("{}", number); // 12 } // When the owner (main function) goes out of scope, the value will be dropped ``` 在 Rust 中,我們只需使用「{}」即可建立一些作用域,這會在堆疊中加入具有有限生命週期的層。當您離開該特定*範圍*後,記憶體將被清除,您將遺失相關資訊。一個很好且簡單的例子是: ``` fn main() { { let number = 12; println!("{}", number); // 12 } println!("{}", number); // Cannot find value `number` in this scope } ``` ### 1.2 記憶體:Heap 簡而言之:**堆**記憶體是一個空閒記憶體空間,用於分配可能更改的資料。 想像一下,您需要在啟動程式後**儲存一些變數**,該變數在編譯時沒有已知的固定大小,因為它可能有大小變化或是記憶體中的直接分配。 如果上述可能性之一匹配,我們就知道我們有 **堆** 內存,而不是 **堆疊**。堆擁有更**靈活的記憶體**和更大的空間。看一看: ``` let number = Box::new(12); // alocate a integer in heap let name = String::from("Canhassi"); // alocate a String in heap ``` 在 Rust 中,我們有兩種字串「類型」:「&str」和「String」。 * **&str**:根據所寫的文字有固定的大小; * **字串**:具有可以增加、減少和刪除的大小。 ……這就是為什麼 `String` 儲存在堆上,而 `&str` 儲存在堆疊上。 釋放堆記憶體的一種方法是:當儲存堆上某些內容的**變數離開函數的作用域(到達函數末端)時,它將以相同的方式釋放作為堆疊。 好了,現在我們對這兩種記憶體類型有了一個清晰的認識,但是堆疊和堆在管理記憶體方面有什麼區別呢?讓我們看看這些差異吧! ## 2. 借用檢查器 借用檢查器是 Rust 編譯器的**部分**,它**檢查並確保**所有權、借用和生命週期**規則得到尊重**。 老實說:一開始我在理解它是如何運作的方面遇到了一些問題,我發現這在新的 Rustaceans 中很常見。但別擔心,我的朋友。我會用最好的方式教你。但首先,讓我們先來看看下面的程式碼: ``` fn main() { let name = String::from("Canhassi"); // Creating a string variable print_name(name); // calling the print_name function passing the variable println!("{}", name); // Error: name borrowed to print_name() } fn print_name(name: String) { println!("{}", name); // print "Canhassi" } ``` 如果您使用該程式碼執行編譯器,您將看到以下錯誤: ``` borrow of moved value: name ``` 當我們呼叫“print_name”函數時,“name”變數將被**移動到另一個作用域**,並且該作用域將成為它的**新所有者**。並且所有者的規則超出範圍將再次應用。借用檢查器確保**一旦所有權轉移**,原始變數**不能再用於**來存取該值。這發生在上面的程式碼中。 使用原始變數的另一種方法是使用類似的引用。 ``` fn main() { let name = String::from("Canhassi"); // Creating a string variable print_name(&name); // calling the print_name function passing the variable println!("{}", name); // print "Canhassi" } fn print_name(name: &String) { println!("{}", name); // print "Canhassi" } ``` PS:這些**借用檢查器的規則僅適用於**堆中指派的物件**。 ## 3. 錯誤預防 借用檢查器對於確保 Rust 記憶體安全而無需[垃圾收集器](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) 至關重要。 在 C 和 C++ 等其他語言中,我們(作為開發人員)必須使用某些函數手動釋放記憶體。 C++ 以允許記憶體管理錯誤而聞名,包括[記憶體洩漏](https://en.wikipedia.org/wiki/Memory_leak)。 C++本身不會導致記憶體洩漏。相反,**C++ 為程式設計師提供了大量的靈活性**和控制力,如果使用不當,這種**自由可能會導致錯誤**。 一個著名的錯誤是**未定義的行為**,例如,想像一個函數傳回這樣的變數的引用 ``` fn main() { let number = foo(); // calling foo function } fn foo() -> &i32 { let number = 12; // creating a var number &number // try return a reference of var number } ``` 程式碼不起作用,因為 Rust 編譯器對記憶體管理有限制規則。我們不能回傳 var `number` 的引用,因為這個函數的作用域將會消失,而 var `number` 將會消失,所以 Rust 不會讓這種情況發生。在 C++ 中我們可以做到這一點,並且它允許臭名昭著的記憶體洩漏。 我認為知道 Rust 編譯器避免了這種類型的錯誤真是太酷了...如果這個主題對您來說是新的,我可以說內存洩漏可能會花費很多錢並且確實很難修復它,因為絕不只有一次內存洩漏。 其他範例是,**雙重釋放**,當您嘗試釋放相同物件兩次(例如在 C 程式碼中)時,就會發生這種情況。 ``` char* ptr = malloc(sizeof(char)); *ptr = 'a'; free(ptr); free(ptr); ``` 這個主題非常廣泛,當您使用其他語言時,很可能會產生類似的錯誤。但是,我會讓您自己進行研究,並確保在這篇文章的評論中告訴我更多! ## 4。結論 我寫這篇文章的目的是以更一般的方式展示記憶體管理如何與 Rust 配合使用。但我建議您閱讀《Rust 程式語言》一書的第 4 章( https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html )來獲得更完整的知識。在那裡您將獲得更多示例和更多關於此內容的解釋。 希望這篇文章有幫助! 🦀🦀
阿川收到網友提問如下: > 阿川你好: > 我的背景是雲科碩畢業,算是混上去的,現在打算轉職軟工,由於有在工作,所以打算先以自學為主3-6個月,看情況後決定是否報名資策會。 > 想請問一下,目前比較希望能夠走後端(網頁開發類),查了一些相關資訊,網頁似乎比較友善,未來有機會再往其他產業前進! > 搜尋了一下職務,網頁類的後端其實也需要html css js 前端三本柱。 > 我想問的是: > 1.是否直接開始學三本柱比較好?(反正前面的作品、入職也會需要)且 有了js基礎還能繼續學習node.js(後端)。 不過又礙於可能比較沒方向,會變成說學一學越來越往前端過去? > 2.先以門檻較低的前端入門、入職以後再好好思考想專精哪一端之類的 or 以c#為主學習,再慢慢學三本柱,資料庫等等 > 3.前端的切版技術等等,是否真的必要? 本人美感很差.. 兩個問題的考量的都是想說是否先以java,c#等後端去建立程式概念或許比較好。 > 文有點長,再麻煩您給我一些建議了,也想順便問一下,有看到您有提供免費html css 以及付費js課程,能在跟您要這方面的資訊嗎? 這些問題很好,我一樣公開回答,給類似狀況的人參考。 --- 簡單回答如下: 1、不論前後端 html 跟 css 都要會,所以這兩個可以先學。js 的話後端不用學精,稍微會寫就好,除非你是寫 node 至於最後會去前端或後端的職缺,都可以,先不用擔心這個,不然你就找全端的職缺也可以 2、後端需要學資料庫、基本伺服器管理,語言的話 C# 或 java 或 php 或 python 或 node 之類的都可以 3、前端做久了,因為常常跟設計師合作,會慢慢具備一點設計素養。如果對「UI 設計」有興趣是最好,沒有的話,倒也沒關係。美感可以慢慢訓練,先不用畫地自限 --- 總結來說,我建議你就先學 html 與 css,之後再看你用 html css 把網頁寫漂亮有沒有興趣,如果喜歡把畫面弄漂亮,就多學一點前端。如果只想做工程,就專心在後端吧。這些問題學了 html css 之後會更清楚,先不用太糾結。不然你就以全端為方向也可以,前後端都寫!你就先挑一個免費 or 便宜的線上課程,先開始寫寫看再說 先開始行動,會更清楚自己在做什麼,之後需要花大錢去報名補習班時,也會比較有把握 就算你一開始只寫前 or 後端,很多人上班之後,因為工作需求,還是慢慢有具備全端的技能 其實不用太排斥全端,都寫的話,一來在公司能做的事情變多、能應徵的機會變多,二來還可以自己用業餘時間寫 side project,因為一個人就能做完全部事情,所以會很好玩,也對職業生涯很有幫助 關於我設計的免費 html css 教材,請參考:https://codelove.tw/courses/frontend-beginner 另外,轉職過程會有諸多問題,可以加我們 LINE 群多跟大家討論:https://line.me/ti/g2/nipkjq2WoZPKX5dTn9tE9266aEOt6EOICFGa1g --- 以上,簡單分享,希望對大家有幫助!
## 課程目標 - 認識 async/await 語法與收尾處理 ## 課程內容 接著來學 async/await 的收尾處理吧! 說起來也神奇,只要加上 `finally` 區塊就可以了! ``` try { const data1 = await $.get(url, params); // do something with data to get params2 const data2 = await $.get(url2, params2); // do something with data to get params3 const data3 = await $.get(url3, params3); // do the final task with data } catch (err) { alert('Something went wrong.'); } finally { // hide the loading icon } ``` 因為 `try/catch/finally` 本來就是一般同步程式設計語言會用到的錯誤處理語法 所以這整段程式碼,看起來跟一般的同步程式設計,幾乎一模一樣! 就是這麼奇妙!應該不用我多解釋什麼了! --- 多補充一句,我個人開發比較複雜的前端應用時,最常用的語法就是這種! 我認為 `async/await` 加上 `try/catch/finally` 是最簡潔有力的! 錯誤訊息提示、忙碌狀態提示,通通都有了,很輕易就做出 UX 很棒的應用程式! ## 課後作業 請拿出第三課的作業,我們來改善這個頁面的 UX(使用者體驗),明確提示「忙碌中」這個狀態 --- - 請用 html 元素,在頁面中加入一段 `讀取中,請稍等...` 的訊息,這個元素預設不顯示 - 在開始呼叫 API 的地方,用 js 操作來讓那個 html 元素顯示 - 在結束呼叫 API 的地方,使用 `finally` 語法,用 js 操作來讓那個 html 元素隱藏 做出以上功能,你就完成這次的課程目標了!
## 課程目標 - 認識 promise chain 鏈接與收尾處理 ## 課程內容 接著來學 promise chain 的收尾處理吧! 繼續拿 jquery 當範例,只要在上次的 promise chain 最後,加上 `.always()` 就可以了! ``` $.get(url, params).then((data) => { // do something with data to get params2 return $.get(url2, params2); }).then((data) => { // do something with data to get params3 return $.get(url3, params3); }).then((data) => { // do the final task with data }).catch((err) => { alert('Something went wrong.'); }).always(() => { // hide the loading icon }); ``` 很簡潔有力吧! ### ⚠️特別注意事項⚠️ 因為某些歷史因素,jquery 包裝的 promise 跟現在瀏覽器原生的 promise 有點不太一樣! 原生的 promise 是 `.finally()`,而不像 jquery 是 `.always()`! 為了教學方便,本課&作業都用 jquery 示範,實務上如果看到 `.finally()` 請不要意外! 都是類似東西,知道這樣就好! ## 課後作業 請拿出第二課的作業,我們來改善這個頁面的 UX(使用者體驗),明確提示「忙碌中」這個狀態 --- - 請用 html 元素,在頁面中加入一段 `讀取中,請稍等...` 的訊息,這個元素預設不顯示 - 在開始呼叫 API 的地方,用 js 操作來讓那個 html 元素顯示 - 在結束呼叫 API 的地方,使用 `always()`,用 js 操作來讓那個 html 元素隱藏 寫完之後,你應該會發現不但 callback hell 改善了、錯誤處理有了、連 UX 都改善了! 做出以上功能,你就完成這次的課程目標了!
## 課程目標 - 認識 callback hell 與收尾處理 ## 課程內容 研究完 callback hell、promise chain、async/await 的錯誤處理 接著來用三課的時間,分別研究收尾處理吧! 讓我們先從 callback hell 的寫法開始! --- 什麼是收尾處理? 其實就是,有些事情,不論任務執行成功 or 失敗,都固定要執行 這種事情,可以在 success callback 跟 error callback 最後都寫,但這樣就重複寫了,很煩! 所以就有所謂的收尾處理,讓你寫一次就好了 如果繼續拿 jquery 做範例,看起來會像這樣: ``` $.ajax({ url: url, data: params, success: (res) => {}, error: (res) => {}, complete: () => {}, }); ``` 其實,就是再多一個 callback function 而已!很單純吧! 在連續多個 ajax call 的時候,錯誤處理機制,再加上收尾處理機制,想想看 callback hell 會有多嚴重! --- 看到這邊,你可能會想,到底什麼事情需要在收尾機制處理呀? 其實,以我個人經驗來說,需要放進收尾處理的東西,其實很少 最常見的就是處理畫面上的「載入中,請稍等...」的文字,或者是畫面上「用來代表忙碌中的一個旋轉的圖示」 不論任務執行結果,都需要把這些文字、圖示隱藏 老實說,很多人根本連「忙碌中」這個狀態也沒做,導致 UX 不太好 所以實務上,如果你發現專案中不太會寫收尾處理,那也算正常,你就知道有這功能可以用即可 ## 課後作業 在第一課的作業,你已經體驗到了 callback hell 與錯誤處理的悲劇 忍耐一下,這一課要再體驗一下當年工程師的痛苦:加上收尾處理吧! 請拿出第一課的作業,我們來改善這個頁面的 UX(使用者體驗),明確提示「忙碌中」這個狀態 --- - 請用 html 元素,在頁面中加入一段 `讀取中,請稍等...` 的訊息,這個元素預設不顯示 - 在開始呼叫 API 的地方,用 js 操作來讓那個 html 元素顯示 - 在結束呼叫 API 的地方,使用 `$.ajax()` 的 `complete` 參數,用 js 操作來讓那個 html 元素隱藏 寫完之後,你應該會發現,有點難寫,而且顯示/隱藏的時機,有點奇怪! 如果想要讓顯示/隱藏的時機,完全正確,那就會重複很多一樣的 code! 別懷疑,就是這麼難寫、這麼奇怪!這就是當年前端開發的為難之處! 做出以上功能,你就完成這次的課程目標了!
大家好,我是站長阿川 我留意到 LINE 群組的討論非常踴躍 很多迷惘、想轉職的新手,各種發問,都有業界工程師幫忙回答,非常熱心! 各位很多的回答「非常詳細」,完整到我覺得:只有群組內的新手看到,也太可惜! 應該讓網路上更多人都能看到,這樣更造福眾生、未來有人 google 搜尋也能夠找到! 繁體中文社群,需要知識不斷累積。如果一直在 FB 等等聊天室討論,然後被洗掉,有點可惜! 這也是我建立 CodeLove 網站的初衷!所以我設計了一個新計畫,跟大家分享一下! # CodeLove 前輩分享寫作計畫:VIP 審核限定 我鼓勵大家,在回答新手之餘,如果覺得 LINE 訊息文字篇幅不夠,或是 LINE 程式碼排版不易 請直接在 CodeLove 寫一篇完整文章,然後再貼到 LINE 群組內! 舉例來說,我自己就有這樣回答 LINE 群組新手的習慣: [轉職軟體工程師的方法很多,到底該如何選擇:實體補習班、線上補習班、不花錢自學?](https://codelove.tw/@howtomakeaturn/post/NxN2Kx) [回答網友提問:如果前端要銜接後端的話,是不是學 node.js 比較快?](https://codelove.tw/@howtomakeaturn/post/2anP0x) [回應網友提問:我是新手前端,公司叫我學一點 php + laravel 串 API,該從哪邊學起呢?](https://codelove.tw/@howtomakeaturn/post/Zq4Ona) # 如何成為這個計畫的 VIP? 原則上只接受「業界工程師」加入,也就是有工作經驗者加入! 就算只有一年工作經驗,也是正在轉職的新手的前輩,所以也歡迎! 越資深的話越好,因為您有大量的知識&經驗可以分享!真的是大前輩! **請在 CodeLove 網站上,任意發表一篇技術文章 or 工作心得,完成之後,點擊下方 LINE 群組加入:** https://line.me/ti/g2/9V19e5igoaUts-hrn1Vr3nNHMcGLLa1hJiaFRg 經過我審核之後,您就加入這個 VIP 群組了! (例外情況:您是學生,但明顯有極大分享熱情&知識,也會允許加入) # 身為這個群組的 VIP,可以幹嘛? 首先,我希望您寶貴的文章,能被儘量多的讀者看到! 您只要負責寫作就好,我會幫您「製造精美封面圖片」以及「行銷宣傳您的文章」! 凡是 VIP 前輩發文,我都會在有超過三百人的群組「愛寫扣論壇:發問&交流&討論群」轉貼,並且「設定為公告置頂至少24小時」! 再來,VIP 群組內都是「樂於分享、經驗豐富、寫作能力出色」的業界人士,大家可以在小群組內交流,我認為互相交換情報,也很有價值! 最後,如果我覺得您的文章實在應該被「成千上萬的更多讀者看到」,我會直接到各大論壇,到處轉貼宣傳您的文章,類似下面這樣: - https://www.dcard.tw/f/softwareengineer/p/252600314 - https://www.dcard.tw/f/f2e/p/252598230 - https://forum.gamer.com.tw/C.php?bsn=60076&snA=7835159 - https://forum.gamer.com.tw/C.php?bsn=60292&snA=8421 我會確保您的文章被數千、數萬人閱讀!身為寫作者,通常文章四處發表,會到處被不同工程師嘴砲、開嗆,沒關係,這很正常,我會擋在砲火最前面!您不用被這些負面訊息轟炸,我只會回報有意義的正面留言給您! 如果有很棒的留言或 feedback,我會貼回 VIP 群組內通知您! # 我想加入,但我沒什麼寫作靈感,怎麼辦? 首先,如果您有想發表的技術文章,當然可以直接當成寫技術部落格,寫一篇發表! 再來,您可以在 LINE 群組,看看新手們都在問些什麼,然後就當作在回答他們,直接公開寫一篇完整回答! 最後,也可以是您近期的一些技術筆記、工作隨筆,稍微整理之後發表,這種筆記也常常對後人很有價值! # 結論 我真的覺得繁體中文世界,需要有一個優質的討論區、寫作園區,知識才能有效累積,這個國家的軟體產業才能進步、發達 另外,這個 CodeLove 論壇是有 [文章 API](https://codelove.tw/@howtomakeaturn/post/jqeDka) 功能的 您可以在這邊大量寫作,之後呼叫 API 串接到自己的部落格,markdown 格式與 html 格式的轉換我都已經幫您做好了 以上,各位熱心的工程師,誠摯歡迎您加入「CodeLove 前輩分享寫作計畫」!一起造福眾生吧! https://line.me/ti/g2/9V19e5igoaUts-hrn1Vr3nNHMcGLLa1hJiaFRg 有問題歡迎直接留言與我討論!
## 目錄 ##### [【前端動手玩創意】等待的轉圈圈效果 (1)](https://ithelp.ithome.com.tw/articles/10311621) ##### [【前端動手玩創意】google五星評分的星星(2)](https://ithelp.ithome.com.tw/articles/10311643) ##### [【前端動手玩創意】CSS-3D卡片翻轉效果(3) (今天難度頗高,想挑戰再進來!)](https://ithelp.ithome.com.tw/articles/10311672) ##### [【前端動手玩創意】一句CSS做出好看的hero section!(4)](https://ithelp.ithome.com.tw/articles/10311691) ##### [【前端動手玩創意】創造一個Skill bar(5)](https://ithelp.ithome.com.tw/articles/10311756) ##### [【前端動手玩創意】遮蔽廣告(D卡未登入)腳本、自定義新增名單(6)](https://ithelp.ithome.com.tw/articles/10311999) ##### [【前端動手玩創意】前端canvas截圖的招式!竟然有三招,可存成SVG或PNG (7)](https://ithelp.ithome.com.tw/articles/10312001) ##### [【前端動手玩創意】讓你的PDF檔案更難被抓取(8)](https://ithelp.ithome.com.tw/articles/10312046) ##### [【前端動手玩創意】哇操!你敢信?花式寫todo-list,body裡面一行都沒有也能搞?(9)](https://ithelp.ithome.com.tw/articles/10312056) ##### [【前端動手玩創意】卡片製作,才不是!是卡片製作器!(10)](https://ithelp.ithome.com.tw/articles/10312066) ##### [【前端動手玩創意】太屌了吧!?用Class(類)製作Jquery的效果!(11)](https://ithelp.ithome.com.tw/articles/10312114) ##### [ 【前端動手玩創意】置頂按鈕,老梗經典|帶你的網頁搭電梯(12)](https://ithelp.ithome.com.tw/articles/10312922) ## 前情提要 一陣子沒寫前端動手玩創意了 今天要來點好料的 我們談談關於藝術 對 就算是寫程式我們也是可以有藝術氣息的 別這麼驚訝XD 假設我有一組資料 一般人來說 最直覺的就是把html裡面的元素寫出來寫死 直覺菜鳥就是寫出來啊 ``` <div id="items_list"> <li class="buy_item">1.紅茶 <div class="price">10</div> <div class="del_btn">X</div> </li> <li class="buy_item">2.奶茶 <div class="price">15</div> <div class="del_btn">X </div> </li> <li class="buy_item">3.綠茶 <div class="price">30</div> <div class="del_btn">X</div> </li> </div> ``` 要更新則是就去更改DOM就好了 反正我都學會JS了 有什麼大不了(? 但是現在已經進入大前端時代了就算你寫原生 也會有data model的概念 這部分可以參考站長阿川寫過的好文 裡面的文筆跟邏輯 不誇張 是我見過「華文圈寫得最好的前端教學」 尤其就是這篇 關於data model的介紹 切入點非常的有趣也很有道理 有興趣的自己去花心思讀看看 [認識 data model 與 render function](https://codelove.tw/@howtomakeaturn/post/9xLo5q) 稍微有點料的前端學習者 本身就會寫一寫 想說:既然有一隻API是createElement 那是不是我可以整個html都用js寫出來(? 這是個超級有趣的觀點 ## 關於data render的概念: 「是不是我可以整個html都用js寫出來」 相傳牛頓提出三大定律以後 認為地球和八大行星一開始的慣性力叫「上帝的第一推動力」 實際上這個: 「整個html都用js寫出來」 也是推動前端往框架邁進的思考第一步 可以說是前端慣性的上帝推力了 當然如果你有打籃球 也可以比喻成上籃的第零步XD ## 觀念筆記 ### html程式碼 ``` <div id="buylist"> <h1>myBuylist 購物清單</h1> <div class="buyitem"> <label>產品名</label> <input/> <label>價錢</label> <input/><span class="addbtn">+新增</span> </div> <div id="items_list">這邊準備用JS插入東西所以這段只是說明文字</div> </div> ``` 把整個頁面的元素寫出來 但是資料的區塊保留著 因為等等我們要用JS的API去動態生成 未來直接data render 方便更新與管理 ### JS程式碼 ``` var shoplist = {}; shoplist.name = "購物清單"; shoplist.list = [ { name: "吹風機", price: "300" }, { name: "麥克筆", price: "20" }, { name: "筆記型電腦", price: "29300" }, { name: "Iphone 9", price: "5200" }, { name: "神奇海螺", price: "1000" }, ]; var item_html = "<li id={{id}} class='buy_item'>{{name}}<div class='price'>{{price}}</div><div class='del_btn'>X</div></li>"; var total_html = "<li class='buy_item total'>總價<div class='price'>{{price}}</div><div class='del_btn'>X</div></li>"; var total_price = 0; for (var i=0; i < shoplist.list.length; i++) { var item = shoplist.list[i]; total_price += item.price; var current_item_html = item_html.replace("{{num}}", i + 1) .replace("{{name}}", item.name) .replace("{{id}}", "buyitem_" + i) .replace("{{price}}", item.price); $("#items_list").append(current_item_html); } ``` 這邊值得關注的一點是資料的處理 也就是數據結構上使用物件與陣列去儲存資料 為什麼要學 陣列 為什麼要學物件 這兩個都是抽象的名詞 他們都是為了來處理資料所規劃的兩種不同內容 ## 關於物件與陣列 物件就像是RPG角色 會有很多的屬性 魔法 敏捷 力量 血量 這些屬性都是被附加在person上面 所以person.blood是一個資料 person.power是一個資料 person.magic是一個資料 最後都存在person裡面 這個person就是一個含有很多屬性的物件 感覺就是有血有肉很3D 而陣列就比較平面化 就是很多數字排成一列而已 其實沒什麼特別需要關注的 這兩個也不會不好區分 只要稍微做個比喻 都很好理解 以我們的code來講解 shoplist就是一個物件 含有一些屬性 包含名字與清單 因為清單很多 所以清單用一個陣列儲存 陣列裡面放很多個物件 這些物件就是每一個清單包含的那些購買項目 其實不用太在意誰是誰因為用看的就很清楚 最後我們用迴圈去把shoplist裡面的每一筆資料都丟進去 中途replace是文字處理 把我們設置的{{name}}這種花括號的東西換成真實資料 這部分有點樣板語言的感覺XD 其實非常有趣 很值得玩味 ## 心得 這次比較多實在的JS程式碼 就不只是玩玩切版了 算是有點靠近框架的部分(◉3◉) 動手玩創意這個系列其實靈魂之處就在於「有趣」兩個字 坊間把前端描繪成為了找工作的銅臭味 以及把切版講成無聊的工匠苦力活 我認為都是錯誤的解讀 我認為 只要是有趣的地方就是前端最有價值的地方 而不是誰學了那個框架 誰又認為哪個東西比較厲害 哪個語言比較屌 那都是很無聊的文字遊戲罷了 如果你喜歡這樣子的前端 請跟著這個系列繼續走(→ܫ←) 我們才只是在桃花源外的小溪旁玩水而已呢! 未來會往天空飛翔哦XD
除了幾間知名的人力銀行網站之外 有些FB社團也常常有職缺資訊,可以逛一下 https://www.facebook.com/groups/javascript.tw https://www.facebook.com/groups/javascript.html.css.node https://www.facebook.com/groups/f2e.tw 還有像這種 github 頁面也有職缺 https://github.com/f2etw/jobs/issues 加油囉各位!
阿川收到網友提問如下: ``` 我最近有在看前端的一些基礎課程,想問問如果32歲想轉職工程師是不是不吃香😅畢竟我也不是本科的 ``` 看過很多人提出類似問題,寫一篇公開回答跟大家分享,給類似狀況的人參考。 --- 首先我自己親自指導過轉職的,年齡最大的是31歲、非本科、私立科大夜間部,原本在餐飲業 在網路上搜尋「30歲轉職工程師」、「40歲轉職工程師」、「50歲轉職工程師」 會發現30歲相關文章很多,大家議論紛紛 40歲相關文章比較少,持鼓勵、正面意見的佔少數 50歲相關文章,一篇心得分享都沒有 我建議把幾歲轉職當成是一個「漸層問題」,不是非黑即白的「二元問題」 也就是年紀越大越難,但沒有過了幾歲就一定不行這種事 --- 再來我認為要務實一點,不論自學或上課,半路出家至少也需要2個月~6個月的時間 請減少生活開銷,然後原本工作可以的話,先別辭掉,利用晚上&週末的時間進修,壓力也小一點 不然壓力大到睡不著覺的話,精神不佳,學習效果怎麼會好呢? 然後建議多找幾種學習方法試試看,如果一種不行,就換另一種方法試試 別太快覺得「自己不行」,說不定是「老師不行」,或只是方法不適合你 我建議先大量找免費或便宜的教材,先吸收,多試幾份,真的卡關了,再開始挑補習班 先直接找一些作業跟專案寫寫看,從免費 -> 便宜的 -> 稍貴的,這樣一點一點花錢,風險比較小 更認識自身需求之後,再去比較市面上的各種補習班,最後再把這錢花下去,比較保險 --- 最後我必須說,2023 全球軟體業狀況比較嚴峻,目前職缺好像比較緊縮,不知道何時會恢復 這跟 2008 年金融海嘯出社會的新鮮人狀況一樣,就是比較倒霉 反正轉職過程中,記得早點開人力銀行等等網站,看看職缺狀況,心裡有個底,知道一下要面臨多少競爭 順帶一提,我也有設計免費的 html&css 教材,還有優惠的 javascript 教材,內含「大量練習專案」,不論你最後選擇哪種學習方式,我都推薦搭配拿去學習、練習,稍有難度,但不少人全做完之後就順利面試上班了 以上,祝各位轉職順利!
資深開發者 Jatin Sharma 在國外論壇分享了個人使用的 VSCode 設定,內容豐富,跟大家分享! 原文出處:https://dev.to/j471n/my-vs-code-setup-971 ## 🎨主題 我使用 [**Andromeda**](https://marketplace.visualstudio.com/items?itemName=EliverLara.andromeda) 作為我的 VS Code 的主要主題  ## 🪟圖標 對於圖標,我會在 [**材質圖標主題**](https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme) 和 [**材質主題圖標**]( https://marketplace.visualstudio.com/items?itemName=Equinusocio.vsc-material-theme-icons) **找找看。** ### 材質圖標主題  ### 材質主題圖標  ## ⚒️外掛 最讚的部分來了,有很多擴展我只提到了我最喜歡的或我每天主要使用的擴展。 ### 自動重命名標籤 自動重命名配對的 HTML/XML 標記,與 Visual Studio IDE 的操作相同。 **下載:** [**自動重命名標籤**](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag)  ### 括號對著色切換器 VS Code 擴展,為您提供一個簡單的命令來快速切換全局“括號對著色” **下載:** [**括號對著色切換器**](https://marketplace.visualstudio.com/items?itemName=dzhavat.bracket-pair-toggler)  ### C/C++ C/C++ 擴展向 Visual Studio Code 加入了對 C/C++ 的語言支持,包括編輯 (IntelliSense) 和除錯功能。 **下載:** [**C/C++**](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)  ### 程式碼執行器 執行多種語言的程式碼片段或程式碼文件 **下載:** [**程式碼執行器**](https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner)  ### 程式碼拼寫檢查器 一個基本的拼寫檢查器,可以很好地處理程式碼和文件。 該拼寫檢查器的目標是幫助發現常見的拼寫錯誤,同時保持較低的誤報數量。 **下載:** [**程式碼拼寫檢查器**](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)  ### DotENV VSCode `.env` 語法高亮。 **下載:** [**DotENV**](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv)  ### 錯誤鏡頭 ErrorLens 通過使診斷更加突出來增強語言診斷功能,突出顯示語言生成的診斷的整行,並內聯打印訊息。 **下載:** [**錯誤鏡頭**](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens)  ### ES7+ React/Redux/React-Native 片段 ES7+ 中的 JavaScript 和 React/Redux 片段以及 [VS Code](https://code.visualstudio.com/) 的 Babel 插件功能 **下載:** [**ES7+ React/Redux/React-Native 片段**](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets)  ### ESLint 該擴展使用安裝在打開的工作區文件夾中的 ESLint 庫。如果該文件夾未提供,則擴展程序將查找全局安裝版本。如果您尚未在本地或全局安裝 ESLint,請在工作區文件夾中執行“npm install eslint”進行本地安裝,或執行“npm install -g eslint”進行全局安裝。 **下載:** [**ESLint**](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)  ### Git 圖 查看存儲庫的 Git 圖表,並從圖表中輕鬆執行 Git 操作。可配置為您想要的外觀! **下載:** [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)  ### GitLens GitLens **增強了 VS Code 中的 Git,並解鎖每個存儲庫中**未開發的知識**。它可以幫助您通過 Git Blame 註釋和 CodeLens 一目了然地**可視化程式碼作者**,**無縫導航和探索** Git 存儲庫,**通過豐富的可視化和強大的比較命令**獲得有價值的見解**,等等更多的。 **下載:** [**GitLens**](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens)  ### HTML 樣板 此擴展提供了所有 Web 應用程式中使用的標準 HTML 樣板程式碼。 **下載:** [**HTML 樣板**](https://marketplace.visualstudio.com/items?itemName=sidthesloth.html5-boilerplate)  ### Import Cost 此擴展將在編輯器中內聯顯示導入包的大小。該擴展利用 webpack 來檢測導入的大小。 **下載:** [**Import Cost**](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost)  ### Live Server 它將啟用實時更改而不保存文件。 **下載:** [**Live Server**](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)  ### Markdown 多合一 Markdown 所需的一切(鍵盤快捷鍵、目錄、自動預覽等)。 ***注意***:VS Code 具有開箱即用的基本 Markdown 支持(例如,**Markdown 預覽**),請參閱官方文件了解更多訊息。 **下載:** [**Markdown All in One**](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one)  ### Markdown 預覽增強 它顯示了 Markdown 內容的增強預覽。 **下載:** [**Markdown 預覽增強版**](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced)  ### 將 JSON 粘貼為程式碼 複製 JSON,粘貼為 Go、TypeScript、C#、C++ 等。 **下載 -** [**將 JSON 粘貼為程式碼**](https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype)  ### 更漂亮 使用 Prettier 的程式碼格式化程序 **下載 -** [**Prettier**](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)  ### Python IntelliSense (Pylance)、Linting、除錯(多線程、遠程)、Jupyter Notebooks、程式碼格式化、重構、單元測試等。 **下載 -** [**Python**](https://marketplace.visualstudio.com/items?itemName=ms-python.python)  ### 設置同步 使用 GitHub Gist 跨多台計算機同步設置、程式碼片段、主題、文件圖標、啟動、按鍵綁定、工作區和擴展。 **下載 -** [**設置同步**](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync)  ### Tailwind CSS IntelliSense 適用於 VS Code 的智能 Tailwind CSS 工具 **下載 -** [**Tailwind CSS IntelliSense**](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)  ### 所有亮點 突出顯示程式碼中的“TODO”、“FIXME”和其他註釋。 有時,在將程式碼發佈到生產環境之前,您會忘記檢查編碼時加入的 TODO。所以我長期以來一直想要一個擴展來突出顯示它們並提醒我還有註釋或尚未完成的事情。 希望這個擴展也能幫助您。 **下載 -** [**TODO 突出顯示**](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight)  ### Turbo 控制台日誌 自動編寫有意義的日誌訊息的過程。 **下載 -** [**Turbo 控制台日誌**](https://marketplace.visualstudio.com/items?itemName=ChakrounAnas.turbo-console-log)  ### 塔布寧人工智能 Tabnine 是一款 AI 程式碼助手,可讓您成為更好的開發人員。 Tabnine 將通過所有最流行的編碼語言和 IDE 中的實時程式碼完成來提高您的開發速度。 **下載 -** [**Tabnine AI**](https://marketplace.visualstudio.com/items?itemName=TabNine.tabnine-vscode)  ## ⚙️設置 以下“JSON”程式碼顯示了我的 VS Code 設置: ``` // user/settings.json { "files.autoSave": "afterDelay", "editor.mouseWheelZoom": true, "code-runner.clearPreviousOutput": true, "code-runner.ignoreSelection": true, "code-runner.runInTerminal": true, "code-runner.saveAllFilesBeforeRun": true, "code-runner.saveFileBeforeRun": true, "editor.wordWrap": "on", "C_Cpp.updateChannel": "Insiders", "editor.suggestSelection": "first", "python.jediEnabled": false, "editor.fontSize": 17, "emmet.includeLanguages": { "javascript": "javascriptreact" }, "editor.minimap.size": "fit", "editor.fontFamily": "Consolas, DejaVu Sans Mono, monospace", "editor.fontLigatures": false, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "python.formatting.provider": "yapf", "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "git.autofetch": true, "git.enableSmartCommit": true, "html-css-class-completion.enableEmmetSupport": true, "editor.formatOnPaste": true, "liveServer.settings.donotShowInfoMsg": true, "[python]": { "editor.defaultFormatter": "ms-python.python" }, "diffEditor.ignoreTrimWhitespace": false, "[json]": { "editor.defaultFormatter": "vscode.json-language-features" }, "[c]": { "editor.defaultFormatter": "ms-vscode.cpptools" }, "editor.fontWeight": "300", "editor.fastScrollSensitivity": 6, "explorer.confirmDragAndDrop": false, "vsicons.dontShowNewVersionMessage": true, "workbench.iconTheme": "material-icon-theme", "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.renderWhitespace": "none", "workbench.startupEditor": "newUntitledFile", "liveServer.settings.multiRootWorkspaceName": "", "liveServer.settings.port": 5000, "liveServer.settings.donotVerifyTags": true, "editor.formatOnSave": true, "html.format.indentInnerHtml": true, "editor.formatOnType": true, "printcode.tabSize": 4, "terminal.integrated.confirmOnExit": "hasChildProcesses", "terminal.integrated.cursorBlinking": true, "terminal.integrated.rightClickBehavior": "default", "tailwindCSS.emmetCompletions": true, "sync.gist": "527c3e29660c53c3f17c32260188d66d", "gitlens.hovers.currentLine.over": "line", "terminal.integrated.profiles.windows": { "PowerShell": { "source": "PowerShell", "icon": "terminal-powershell" }, "Command Prompt": { "path": [ "${env:windir}\\Sysnative\\cmd.exe", "${env:windir}\\System32\\cmd.exe" ], "args": [], "icon": "terminal-cmd" }, "Git Bash": { "source": "Git Bash" }, "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe (migrated)": { "path": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "args": [] }, "Windows PowerShell": { "path": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" }, "Ubuntu (WSL)": { "path": "C:\\WINDOWS\\System32\\wsl.exe", "args": [ "-d", "Ubuntu" ] } }, "javascript.updateImportsOnFileMove.enabled": "always", "[dotenv]": { "editor.defaultFormatter": "foxundermoon.shell-format" }, "editor.tabSize": 2, "cSpell.customDictionaries": { "custom-dictionary-user": { "name": "custom-dictionary-user", "path": "~/.cspell/custom-dictionary-user.txt", "addWords": true, "scope": "user" } }, "window.restoreFullscreen": true, "tabnine.experimentalAutoImports": true, "files.defaultLanguage": "${activeEditorLanguage}", "bracket-pair-colorizer-2.depreciation-notice": false, "workbench.editor.wrapTabs": true, "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[ignore]": { "editor.defaultFormatter": "foxundermoon.shell-format" }, "terminal.integrated.fontFamily": "courier new", "terminal.integrated.defaultProfile.windows": "pwsh.exe -nologo", "terminal.integrated.shellIntegration.enabled": true, "terminal.integrated.shellIntegration.showWelcome": false, "editor.accessibilitySupport": "off", "editor.bracketPairColorization.enabled": true, "todohighlight.isEnable": true, "terminal.integrated.shellIntegration.history": 1000, "turboConsoleLog.insertEnclosingClass": false, "turboConsoleLog.insertEnclosingFunction": false, "files.autoSaveDelay": 500, "liveServer.settings.CustomBrowser": "chrome", "liveServer.settings.host": "localhost", "liveServer.settings.fullReload": true, "workbench.editor.enablePreview": false, "workbench.colorTheme": "Andromeda Bordered" } ``` ## 總結 以上簡單分享,希望對您有幫助!
## 課程目標 - 使用 node 與 express 提供靜態檔案 ## 課程內容 目前為止的網頁,都是純 html,太陽春了! 這一課來學習,如何用 node 來提供 css 或圖片之類的「靜態檔案」! 替這課建立 lesson4 資料夾,內容跟 lesson3 同樣之外,再建立一個 public 資料夾,裡面新增 style.css 檔案 ``` /repo /lesson4 /index.js /hello.ejs /users.json /public /style.css ``` 在 index.js 裡面多加一行程式碼 ``` app.use(express.static('./lesson4/public')); ``` 在 style.css 裡面加入一些樣式 ``` p { color: green; } ``` 接著在 hello.ejs 加入樣式連結 ``` <link rel="stylesheet" href="/style.css"> ``` 然後去終端機輸入 ``` node lesson4/index.js ``` 接著打開瀏覽器,在網址輸入 ``` http://localhost:3000/ ``` 你會看到原本的打招呼訊息,文字變成了綠色! --- 後端程式設計,不論何種程式語言,在提供圖片、css 這種靜態檔案的時候,通常會開一個獨立的 public 資料夾來放檔案 所以本課使用的 `app.use(express.static('./lesson4/public'));` 程式碼 就只是設定一下,請 express 從某個資料夾提供靜態檔案,就這樣而已! ## 課後作業 這次要練習用 node 回應靜態檔案 請把 hw3 的內容複製到 hw4,然後增加 public 資料夾與 style.css 檔案 ``` /repo /hw4 /index.js /homepage.ejs /posts.json /public /style.css ``` 請在 style.css 中,稍微替你的日記首頁加一些樣式,弄得漂亮一點! 完成以上任務,你就完成這次的課程目標了!
## 課程目標 - 使用 ejs 模板並讀取變數 ## 課程內容 這一課來學習如何讀取變數之後,放進 ejs 模板呈現! 先來安裝之前用過的 readline-sync 套件 ``` npm install readline-sync ``` 替這課建立一個資料夾,然後建立 `index.js` `hello.ejs` `users.json` 這幾個檔案 此時資料夾會長類似這樣 ``` repo ├── package.json ├── package-lock.json ├── node_modules ├── lesson1 │ └── index.js ├── lesson2 │ ├── hello.ejs │ └── index.js └── lesson3 ├── users.json ├── hello.ejs └── index.js ``` 在 users.json 放入以下內容 ``` [ { "name": "小明", }, { "name": "小華", }, { "name": "小王", } ] ``` 在 hello.ejs 放入以下內容 ``` <div> <% for(var i = 0; i < users.length; i++) { %> <p> <%= users[i].name %>同學,你好! </p> <% } %> </div> ``` 在 index.js 放入以下內容 ``` const express = require('express'); const app = express(); const engine = require('ejs-locals'); const fs = require('fs'); app.engine('ejs', engine); app.set('views', './lesson3'); app.set('view engine', 'ejs'); app.get('/', function(req, res){ const data = fs.readFileSync('./lesson3/users.json'); const users = JSON.parse(data); res.render('hello', { users: users }); }); app.listen(3000); ``` 然後去終端機輸入 ``` node lesson3/index.js ``` 接著打開瀏覽器,在網址輸入 ``` http://localhost:3000/ ``` 你會看到很多則訊息,分別跟多位同學打招呼! --- 這段程式不用我多加說明了吧!檔案讀取也是之前教過的內容! 這邊唯一多學的東西,就是 ejs 關於 for 迴圈的語法,反正就是 `<%` 跟 `%>` 之類的東西包起來而已 ejs 還有支援很多豐富的語法&功能,有興趣的話,自行研究一下吧! ## 課後作業 這次要練習匯入資料到 ejs 模板 請新建立 hw3 資料夾,採用以下結構 ``` /repo /hw3 /index.js /homepage.ejs /posts.json ``` 請修改 homepage.ejs 內容,將文章內容移出來,放在 posts.json 裡面 ``` [ { "title": "第一篇日記", "content": "今天天氣很好,夏天太陽很大,讓我心情很好" }, { "title": "第二篇日記", "content": "早起出門運動,回家沖個澡,整天心情很好" }, { "title": "第三篇日記", "content": "下大雨一整天,整天在家追劇,滿舒服的" } ] ``` 這樣 homepage.ejs 內就不會只是 html 了,你會練習到 ejs 獨有的模板語法! 完成以上任務,你就完成這次的課程目標了! --- 請更新你的 github 專案內容,此時應該變成這樣 ``` /repo /hw1 /index.js /hw2 /index.js /homepage.ejs /hw3 /index.js /homepage.ejs /posts.json ``` 依此類推,之後就這樣交作業!
## 課程目標 - 使用 ejs 模板渲染出 html ## 課程內容 上一課我們成功讓後端回應 html 給瀏覽器了,很棒 可是每次都讓 res.send 回應一大串 html,就太奇怪了 至少要讓 html 內容放在單獨一個檔案,才有寫網頁的感覺吧! 這課來學習如何做到這點吧! --- 來安裝一款新套件,請在終端機輸入 ``` npm install ejs-locals ``` 替這課建立一個資料夾,然後建立一個 index.js 檔案與一個 hello.ejs 檔案 此時資料夾會長類似這樣 ``` repo ├── package.json ├── package-lock.json ├── node_modules ├── lesson1 │ └── index.js └── lesson2 ├── hello.ejs └── index.js ``` 在 hello.ejs 放入以下內容 ``` <h1>恭喜您,成功囉!</h1> <h2>您真的做得很棒!</h2> <p>繼續學習,不斷進步吧!</p> ``` 然後在 index.js 放入以下內容 ``` const express = require('express'); const app = express(); const engine = require('ejs-locals'); app.engine('ejs', engine); app.set('views', './lesson2'); app.set('view engine', 'ejs'); app.get('/', function(req, res){ res.render('hello') }); app.listen(3000); ``` 然後去終端機輸入 ``` node lesson2/index.js ``` 接著打開瀏覽器,在網址輸入 ``` http://localhost:3000/ ``` 你會看到一段打招呼訊息! --- ejs 是 javascript 社群常用的一款「模板引擎」套件 我們不是直接安裝 ejs 套件,而是安裝 ejs-locals 套件,這是一款把 ejs 整合進 express 的方便套件! 在載入 ejs-locals 之後,接著用 app.engine 告訴 express 我們要設定模板引擎 然後用 app.set 告訴 express 要去哪邊找到 `模板檔案` 最後,處理 http 請求的地方,把原本的 res.send 改成 res.render 並放進模板檔案名稱,就可以囉! 多看幾眼這段程式,這就是後端開發,用 node、express 來讀取一段 html,並且回應給瀏覽器的方式,不難吧! ## 課後作業 這次要練習使用 ejs 模板 請新建立 hw2 資料夾,採用以下結構 ``` /repo /hw2 /index.js /homepage.ejs ``` 並開發一個 app,打開首頁 `http://localhost:3000/` 會顯示 homepage.ejs 的內容作為部落格首頁,homepage.ejs 的內容先放這些 html 就好: ``` <h1>我的個人日記 APP</h1> <div> <h2>第一篇日記</h2> <div>今天天氣很好,夏天太陽很大,讓我心情很好</div> </div> <div> <h2>第二篇日記</h2> <div>早起出門運動,回家沖個澡,整天心情很好</div> </div> <div> <h2>第三篇日記</h2> <div>下大雨一整天,整天在家追劇,滿舒服的</div> </div> ``` 完成以上任務,你就完成這次的課程目標了! --- 請更新你的 github 專案內容,此時應該變成這樣 ``` /repo /hw1 /index.js /hw2 /index.js /homepage.ejs ``` 依此類推,之後就這樣交作業!
## 課程目標 - 使用 node 與 express 回應 http get request ## 課程內容 在 node 中開發後端程式,通常會使用一款叫做 express 的套件 雖然不用 express 也能夠開發後端應用,但 express 提供很多現成好用功能 所以先來安裝 express 吧! ``` npm install express ``` 建立一個資料夾,放我們每課的練習內容,這一課就叫 lesson1 吧 然後建立一個 index.js 檔案 此時資料夾會長類似這樣 ``` repo ├── package.json ├── package-lock.json ├── node_modules └── lesson1 └── index.js ``` 在 index.js 檔案放入以下內容 ``` const express = require('express'); const app = express(); app.get('/', function(req, res){ res.send('<h1>恭喜您,成功囉!</h1>'); }); app.listen(3000); ``` 然後去終端機輸入 ``` node lesson1/index.js ``` 接著打開瀏覽器,在網址輸入 ``` http://localhost:3000/ ``` 你會看到一段大大的打招呼訊息! --- 讓我們逐行說明一下 前面兩句是載入 express 套件,然後建立主程式物件 `app.get()` 是註冊登記一個處理 `HTTP GET 請求` 第一個參數是 `要處理的網址` 第二個參數是放進一段「函式定義」代表要如何處理 函式定義通常會用 `(req, res)` 當參數,有人會寫 `(request, response)`,都可以,分別是代表 `請求` 與` 回應` 的物件 這段看不太懂沒關係,需要稍微研究一下「HTTP 協定」才會知道定義 反正就先用 `res.send` 來回應一段 html 就對了! 最後用 `app.listen(3000);` 來在 port 3000 跑這段後端程式 --- 在一台電腦上,多個程式之間彼此溝通,通常會在電腦上各自使用一個 port 號碼 在瀏覽器中,通常只會輸入網址,例如 `https://www.google.com.tw` 之類的 只輸入網址,代表使用 443 當作 port,舉例來說,你可以在網址輸入 `https://www.google.com.tw:443` 看看,結果一模一樣 一個 port 只能同時給一個程式使用,為了避免用到別的程式在用的 port,我們請 node 在這邊使用 3000 這個冷門的 port,方便我們測試 然後 `localhost` 不是真的網址,是請瀏覽器直接在本機電腦上尋找網站開啟的意思! 以上通通看不懂沒關係,需要對 `網際網路協定` 稍微研讀才比較懂,先照做即可! ## 課後作業 這次的系列作業,要練習開發一個「個人日記 APP」 首先來練習如何用 node 回應 http get request 請開發一個 app,打開首頁 `http://localhost:3000/` 會顯示 `<h1>我的個人日記 APP</h1>`,先做到這樣就好 完成以上任務,你就完成這次的課程目標了! --- 交作業的方法: 請建立一個 repo 上傳到 github 這個 repo 的檔案結構應該會是這樣: ``` repo ├── package.json ├── package-lock.json ├── node_modules └── hw1 └── index.js ``` 接下來的每次作業,都新開一個小資料夾 然後把 github 專案連結,貼到留言區即可
上一次的課程,我們學會如何用 Node 開發老派 CLI 應用程式,很好玩吧! 再次提醒,上次的開發過程,可是跟 `網站` `瀏覽器` `web 伺服器` 完全沒關係的喔! 之所以這樣課程設計,是為了先幫大家脫離 `js 一定是網頁相關、一定是 html/css 相關` 的刻板印象 現在,我們回頭來碰 backend programming 開發,銜接回來 web 領域看看! 這樣的學習順序,吸收才順暢,不會各種觀念一直搞混在一起 雖然之前的教材一直是以前端開發為主,但是我認為稍微教一點 Node.js 後端開發,對於前端工程師的能力會有很大幫助! 上完之後,會更清楚前後端的分工,以及網頁背後的基本概念! 別擔心,本課只會深入淺出,學習一點基本的後端觀念,不會是艱難、完整的後端課程! 準備好的話,讓我們馬上開始吧!
因為一直找不到工作(...汗)所以來整理作品 [成果展示](https://superyngo.github.io/to_do_list/) 基本上是參考[Let's Write](https://www.letswrite.tw/)做的[Demo](https://letswritetw.github.io/letswrite-food-check/) 在頁面下方有作品導覽以及Github連結 使用工具: 1.Github Page 2.[Google Tag Manager](https://tagmanager.google.com/#/home) 步驟: 1.申請GTM並取得GTM代碼 2.將GTM代碼插入所有專案的index.html中,並將所有專案上傳github,開啟page頁面 3.另外做一個myNavbat的github page,將所有專案連結放進去,可參考[我做的](https://github.com/superyngo/myNavbar) 4.用GTM的「自訂HTML」功能將myNavbar和github連結塞進所有專案中,參考代碼如下: ``` <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" /> <div class="myNav"></div> <div class="github"> <a class="githubHerf"> <i class="fa fa-github" aria-hidden="true"></i> </a> </div> <script> var githubHerf=document.querySelector(".githubHerf") githubHerf.setAttribute("href","https://github.com/superyngo"+{{Page Path}}) var myNav2 = document.querySelector(".myNav"); var iframe2 = document.createElement("iframe"); iframe2.setAttribute("src", "https://superyngo.github.io/myNavbar/"); iframe2.setAttribute("width", "100%"); iframe2.setAttribute("frameborder", "0"); myNav2.appendChild(iframe2) </script> <style> body{ background-color: #fff0df; } .github { position: fixed; left: 0; bottom: 0; display: flex; width: 100px; height: 100px; cursor: pointer; z-index: 2; :hover { position: absolute; left: 10px; bottom: 5px; font-size: 3rem; color: #fff; scale: 0.9; } } .github::before { content: ""; width: 0; height: 0; border-style: solid; border-width: 100px 0 0 100px; border-color: transparent transparent transparent #6e5494; } .github .fa { position: absolute; left: 10px; bottom: 5px; font-size: 3rem; color: #fff; } @media screen and (max-width: 600px) { :root { font-size: 12px; } .github { width: 70px; height: 70px; } .github::before { border-width: 70px 0 0 70px; } .github .fa { left: 8px; bottom: 4px; font-size: 2rem; } } </style> ``` 注意事項; 1.不知為何我GTM塞iframe一直不給過,所以用append的。 2.iframe內的超連結預設會在iframe內開啟,要避免只要在myNavbar的head裡加上<base target="_parent" />就可以了。 3當初做這些作業時完全沒考慮theme和RWD,花了一些時間但又不想花太多時間結果就勉勉強強用手機也都能開。 閒聊: 前陣子都在codeSignal上刷題,看別人解法真的很神,學很多... 有沒有北部公司缺人啊...投履歷都沒人回..中年轉行真的不行嗎...
上次的(十)是純 CLI 應用 先幫大家脫離 ` js 一定是網頁、一定是 html/css 相關` 的刻板印象 接著再回來碰 backend programming 開發,銜接回來 web 領域 這樣才順暢,才不會一直搞混在一起 教材研發中,近期上線,敬請期待~
本文將分為三個部分: 1. 通用設計模式 2. 我的建議 3. 進一步閱讀 享受並且讓我知道您在專案中使用的模式和實踐🚀 原文出處:https://dev.to/jacobandrewsky/good-practices-and-design-patterns-for-vue-composables-24lk ## 通用設計模式 我認為了解建置可組合項模式的最佳來源實際上是 Vue.js 文件,您可以在[此處](https://vuejs.org/guide/reusability/composables.html)查看 ### 基本可組合項 Vue 文件顯示了以下 useMouse 可組合項的示例: ``` // mouse.js import { ref, onMounted, onUnmounted } from 'vue' // by convention, composable function names start with "use" export function useMouse() { // state encapsulated and managed by the composable const x = ref(0) const y = ref(0) // a composable can update its managed state over time. function update(event) { x.value = event.pageX y.value = event.pageY } // a composable can also hook into its owner component's // lifecycle to setup and teardown side effects. onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update)) // expose managed state as return value return { x, y } } ``` 稍後可以在元件中使用它,如下所示: ``` <script setup> import { useMouse } from './mouse.js' const { x, y } = useMouse() </script> <template>Mouse position is at: {{ x }}, {{ y }}</template> ``` ### 異步可組合項 為了獲取資料,Vue 建議使用以下可組合結構: ``` import { ref, watchEffect, toValue } from 'vue' export function useFetch(url) { const data = ref(null) const error = ref(null) watchEffect(() => { // reset state before fetching.. data.value = null error.value = null // toValue() unwraps potential refs or getters fetch(toValue(url)) .then((res) => res.json()) .then((json) => (data.value = json)) .catch((err) => (error.value = err)) }) return { data, error } } ``` 然後可以在元件中使用它,如下所示: ``` <script setup> import { useFetch } from './fetch.js' const { data, error } = useFetch('...') </script> ``` ### 可組合合約 根據上面的示例,以下是所有可組合項都應遵循的約定: 1. 可組合文件名應以 use 開頭,例如 `useSomeAmazingFeature.ts` 2. 它可以接受輸入參數,這些參數可以是字串等基本類型,也可以接受 refs 和 getter,但需要使用 toValue 幫助器 3. Composable 應該返回一個 ref 值,該值可以在解構可組合項後存取,例如 `const { x, y } = useMouse()` 4. 可組合項可以保存可以在整個應用程式中存取和修改的全局狀態。 5. 可組合性可能會產生副作用,例如加入窗口事件偵聽器,但在卸載元件時應清除它們。 6. 可組合項只能在 `<script setup>` 或 `setup()` 掛鉤中呼叫。它們也應該在這些上下文中同步呼叫。在某些情況下,您還可以在生命週期掛鉤中呼叫它們,例如“onMounted()”。 7. 可組合項可以呼叫內部的其他可組合項。 8. 可組合項應在內部包裝某些邏輯,當過於復雜時,應將它們提取到單獨的可組合項中以便於測試。 ## 我的建議 我已經為我的工作專案和開源專案建置了多個可組合項 - NuxtAlgolia、NuxtCloudinary、NuxtMedusa,因此基於這些,我想根據我的經驗在上面的合同中加入一些要點。 ### 有狀態或/和純函數可組合項 在程式碼標準化的某個時刻,您可能會得出這樣的結論:您希望對可組合項中的狀態保留做出決定。 最容易測試的函數是那些不存儲任何狀態的函數(即它們是簡單的輸入/輸出函數),例如負責將字節轉換為人類可讀值的可組合函數。它接受一個值並返回一個不同的值 - 它不存儲任何狀態。 不要誤會我的意思,你不必做出“或”的決定。您可以完全保留有狀態和無狀態可組合項。但這應該是一個書面決定,以便以後更容易與他們合作 🙂 ### 可組合項的單元測試 我們希望使用 Vitest 為我們的前端應用程式實施單元測試。在後端工作時,進行單元測試程式碼覆蓋率非常有用,因為您主要關注邏輯。然而,在前端,您通常使用視覺效果。 因此,我們認為對整個元件進行單元測試可能不是最好的主意,因為我們基本上將對框架本身進行單元測試(如果按下按鈕,檢查狀態是否更改或模式是否打開)。 由於我們已將所有業務邏輯移至可組合項(基本上是 TypeScript 函數)內,因此它們很容易使用 Vitest 進行測試,並且允許我們擁有更穩定的系統。 ### 可組合項的範圍 不久前,在 VueStorefront 中,我們開發了自己的可組合方法(早在它們實際上像這樣被呼叫之前)。在我們的方法中,我們使用可組合項來映射電子商務的業務領域,如下所示: ``` const { cart, load, addItem, removeItem, remove, ... } = useCart() ``` 這種方法絕對有用,因為它允許將域包裝在一個函數中。在“useProduct”或“useCategory”等更簡單的示例中,實現和維護相對簡單。然而,正如您在此處的“useCart”示例中看到的那樣,當包裝一個包含更多邏輯而不僅僅是資料獲取的域時,這個可組合項正在發展成為一種非常難以開發和維護的形狀。 此時,我開始為 Nuxt 生態系統做出貢獻,其中引入了不同的方法。在這種新方法中,每個可組合項僅負責一件事。因此,我們的想法不是建置一個巨大的“useCart”可組合項,而是為每個功能建置可組合項,即“useAddToCart”、“useFetchCart”、“useRemovefromCart”等。 因此,維護和測試這些可組合項應該更容易 🙂 ## 進一步閱讀 這將是我的研究的全部內容。如果您想了解有關此主題的更多訊息,請務必查看以下文章: * https://vuejs.org/guide/reusability/composables.html * https://www.youtube.com/watch?v=bcZM3EogPJE * https://vueschool.io/articles/vuejs-tutorials/what-is-a-vue-js-composable/ * https://blog.logrocket.com/getting-started-vue-composables/ * https://macopedia.com/blog/news/how-can-vue-3-composables-make-your-life-easier
我曾經不同意淺色和深色模式切換。 “切換開關是用戶系統偏好設置!”我會天真地感嘆,選擇讓 [prefers-color-scheme CSS 媒體查詢](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) 控制我個人網站上的主題。沒有切換。沒有選擇。 🫠 自從黑暗模式出現以來,我一直是它的用戶。但最近,我更喜歡在輕型模式下使用_**一些**_網站和工具 - 包括我的個人網站 - 同時將我的系統設置牢牢地保留在黑暗中。我需要一個開關。我需要一個選擇!其他人也是如此。 在這篇文章中,我將向您展示如何使用 JavaScript 為我的網站建置終極主題 Toggle™️: 1. 在本地瀏覽器存儲中存儲和檢索主題首選項, 1. 退回到用戶系統首選項, 1. 如果未檢測到上述情況,則回退到默認主題。 TL;DR:[這是 CodePen 上的程式碼](https://codepen.io/whitep4nth3r/pen/VwEqrQL)。 原文出處:https://dev.to/whitep4nth3r/the-best-lightdark-mode-theme-toggle-in-javascript-368f ## 將資料屬性加入到 HTML 標記中 在 HTML 標記上,加入一個資料屬性,例如“data-theme”,並為其指定默認值“淺色”或“深色”。過去我使用自定義屬性“color-mode”而不是資料屬性(例如“color-mode=”light“”)。雖然這可行,但它沒有被歸類為有效的 HTML,而且我找不到任何相關文件!對此的任何見解都非常感激。 😅 ``` <html lang="en" data-theme="light"> <!-- all other HTML --> </html> ``` ## 通過 CSS 自定義屬性配置主題 在 CSS 中,通過“data-theme”每個值下的 [CSS 自定義屬性](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)(或變數)配置主題顏色` 屬性。請注意,您不一定需要將 `:root` 與 `data-theme` 結合使用,但它對於不隨主題變化的全局屬性很有用(如下例所示)。 [在 MDN 上了解有關 :root CSS 偽類的更多訊息。](https://developer.mozilla.org/en-US/docs/Web/CSS/:root) ``` :root { --grid-unit: 1rem; --border-radius-base: 0.5rem; } [data-theme="light"] { --color-bg: #ffffff; --color-fg: #000000; } [data-theme="dark"] { --color-bg: #000000; --color-fg: #ffffff; } /* example use of CSS custom properties */ body { background-color: var(--color-bg); color: var(--color-fg); } ``` 在 HTML 標籤上手動切換“data-theme”屬性,您就會看到主題已經發生變化(只要您使用這些 CSS 屬性來設置元素的樣式)! ## 在 HTML 中建置一個切換按鈕 將 HTML 按鈕加入到您的網站標題或任何需要主題切換的位置。加入一個 `data-theme-toggle` 屬性(稍後我們將使用它來定位 JavaScript 中的按鈕)和一個 [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)如果您計劃在按鈕上使用圖標(例如太陽和月亮分別代表淺色和深色模式),以便螢幕閱讀器和輔助技術可以理解按鈕的用途互動按鈕。 ``` <button type="button" data-theme-toggle aria-label="Change to light theme" >Change to light theme (or icon here)</button> ``` ## 計算頁面加載時的主題設置 在這裡,我們將根據我所說的“_**偏好級聯**_”來計算主題設置。 ### 從本地存儲獲取主題首選項 我們可以使用 [JavaScript 中的 localStorage 屬性](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) 將用戶首選項保存在瀏覽器中,該首選項在會話之間持續存在(或直到它手動清除)。在 The Ultimate Theme Toggle™️ 中,存儲的用戶首選項是最重要的設置,因此我們將首先查找它。 頁面加載時,使用 localStorage.getItem("theme") 檢查之前存儲的首選項。在本文後面,我們將在每次按下切換按鈕時更新主題值。如果沒有本地存儲值,則該值為“null”。 ``` // get theme on page load localStorage.getItem("theme"); // set theme on button press localStorage.setItem("theme", newTheme); ``` ### 在 JavaScript 中檢測用戶系統設置 如果“localStorage”中沒有存儲的主題首選項,我們將使用 [window.matchMedia() 方法](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)通過傳入媒體查詢字串。您只需計算一項設置即可實現首選項級聯,但下面的程式碼顯示瞭如何檢測淺色或深色系統設置。 ``` const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)"); // or const systemSettingLight = window.matchMedia("(prefers-color-scheme: light)"); ``` `window.matchMedia()` 返回一個 `MediaQueryList`,其中包含您請求的媒體查詢字串,以及它是否與用戶系統設置“匹配”(true/false)。 ``` { matches: true, media: "(prefers-color-scheme: dark)", onchange: null } ``` ### 回退到默認主題 現在您可以通過“window.matchMedia()”存取“localStorage”值和系統設置,您可以使用首選項級聯(本地存儲,然後系統設置)計算首選主題設置,並回退到默認主題您的選擇(這應該是您之前在 HTML 標記上指定的默認主題)。 我們將在頁面加載時執行此程式碼來計算當前的主題設置。 ``` function calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }) { if (localStorageTheme !== null) { return localStorageTheme; } if (systemSettingDark.matches) { return "dark"; } return "light"; } const localStorageTheme = localStorage.getItem("theme"); const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)"); let currentThemeSetting = calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }); ``` ## 加入事件監聽器到切換按鈕 接下來,我們將設置一個事件監聽器,以便在按下按鈕時切換主題。使用我們之前加入的資料屬性(`data-theme-toggle`)定位 DOM 中的按鈕,並加入一個[事件監聽器](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) 加入到單擊按鈕。 - 將新主題計算為字串 - 計算並更新按鈕文本(如果您在按鈕上使用圖標,則可以在此處進行切換) - 更新按鈕上的aria標籤 - 切換HTML標籤上的data-theme屬性 - 將新的主題首選項保存在本地存儲中 - 更新內存中的currentThemeSetting ``` // target the button using the data attribute we added earlier const button = document.querySelector("[data-theme-toggle]"); button.addEventListener("click", () => { const newTheme = currentThemeSetting === "dark" ? "light" : "dark"; // update the button text const newCta = newTheme === "dark" ? "Change to light theme" : "Change to dark theme"; button.innerText = newCta; // use an aria-label if you are omitting text on the button // and using sun/moon icons, for example button.setAttribute("aria-label", newCta); // update theme attribute on HTML to switch theme in CSS document.querySelector("html").setAttribute("data-theme", newTheme); // update in local storage localStorage.setItem("theme", newTheme); // update the currentThemeSetting in memory currentThemeSetting = newTheme; }); ``` 要確認“localStorage”正在更新,請打開開發工具,導航到“Application”選項卡,展開“Local Storage”並選擇您的站點。你會看到一個鍵:值列表;查找“主題”並單擊按鈕即可觀看其實時更新。重新加載您的頁面,您將看到保留的主題首選項!  ## 把它們放在一起! 您現在可以通過以下方式建置您自己的終極主題切換™️: - 使用CSS自定義屬性來指定不同的主題顏色,通過HTML標籤上的資料屬性進行切換 - 使用 HTML 按鈕來啟動切換 - 使用首選項級聯計算頁面加載時的首選主題(本地存儲 > 系統設置 > 後備默認主題) - 單擊切換按鈕即可切換主題,並將用戶首選項存儲在瀏覽器中以供將來存取 這是完整的 CodePen,您可以在我的個人網站上查看工作版本。快樂切換! https://codepen.io/whitep4nth3r/pen/VwEqrQL
你的轉職路上,還缺少一份練功作業包!寫完這九包,直接拿作品去面試上班!
本學院另有附設一個 LINE 新手發問&交流群組!歡迎加入討論!