🔍 搜尋結果:todo

🔍 搜尋結果:todo

後端 JS 訓練一:第3課 ── 用 node 寫入檔案內容

## 課程目標 - 用 node 寫入檔案內容 ## 課程內容 來學習一下用 node 寫入檔案的方法 學會這方法,可以用 node 寫腳本處理工作上的文書瑣事 --- 建立 `write-my-name.js` 程式,裡面輸入 ``` var fs = require('fs'); const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); readline.question('請問您的大名?\n', function (answer) { fs.writeFile('my-name.txt', answer, function (err) { console.log('儲存成功。'); process.exit(0); }); }); ``` 然後去終端機輸入 ``` node write-my-name.js ``` 你會看到終端機要求你輸入內容,接著會去更新文字檔內容! --- 第一段的 `readline` 模組,是處理 `輸入/輸出` 資訊的模組,後面要呼叫 `createInterface` 並且用全域變數 `process` 來設定輸入、輸出來源 照做就好,背後意義不用細究,能用就好,有興趣自行 google `readline.question` 從終端機請求用戶輸入內容,`\n` 是換行字元,讓畫面更好看而已 注意 `readline.question` 後面還是把函式當參數傳,也就是依然採用「非同步程式設計」 很怪、很醜,對嗎?我同意,這語法設計實在意義不明 又不是在等待 AJAX 回應的同時,用戶可以先做別的事情 這邊就是要等用戶輸入完內容,程式往下走才有意義呀! 後面會教你如何改寫成「同步程式設計」,先照做就好 ## 課後作業 接續前一課的作業,現在來寫「新增」功能 請建立一個 `create.js` 檔案 使用者輸入 `node create.js` 之後,終端機會詢問 ``` 您要新增什麼待辦事項? ``` 使用者可以輸入內容,接著終端機會顯示 ``` 新增事項:XXXXXX ``` 打開 `todos.json` 查看,會看到剛剛輸入的項目出現在裡面 完成以上任務,你就完成這次的課程目標了!

後端 JS 訓練一:第2課 ── 用 node 讀取檔案內容

## 課程目標 - 用 node 讀取檔案內容 ## 課程內容 來學習一下用 node 讀取檔案的方法 學會這方法,可以用 node 寫出簡易的檔案內容分析程式 --- 建立一個 `my-name.txt` 文字檔,在裡面輸入你的名字 然後建立 `read-my-name.js` 程式,裡面輸入 ``` var fs = require('fs'); fs.readFile('my-name.txt', function(err, data) { console.log("您好," + data); process.exit(0); }); ``` 然後去終端機輸入 ``` node read-my-name.js ``` 你會看到一段打招呼的訊息! --- 讓我們逐行說明一下 ``` var fs = require('fs'); ``` 這是載入「檔案系統模組」的意思,`fs` 是 `file system` 的縮寫 `readFile` 函式,第一個參數是檔案名稱,第二個參數是「一個函式定義」 看起來有點怪,其實是「非同步程式設計」的關係 之前在學網頁元素的事件處理時,就是用「非同步」程式設計處理 也就是我不確定「點擊」事件何時會發生,但我先「綁定」好事件發生時要做的任務 還有在網頁呼叫 AJAX 時也是,我不確定「主機回應」何時會拿到,但我先「綁定」好拿到之後要做的任務 這邊 `fs` 的意思就是:我不確定何時會「檔案讀取完畢」,但我先「綁定」好讀取完畢之後,要做的任務 看起來很怪、很醜,這種設計的意義不明,對嗎?我也覺得!後面會教你如何改寫成「同步程式設計」,先照做就好 -- `console.log` 是印出訊息到終端機(語法就跟在瀏覽器環境一樣!) `process.exit(0);` 是結束程式的意思。那個 `process` 是代表當前 node 程式的全域變數 --- 在瀏覽器裡面,無法去操作「檔案系統模組」,否則也太可怕,每個人上網時,都能用 js 亂改電腦上的檔案,資安大問題! 在瀏覽器裡面,也沒有 `process` 這個全域變數 用 node 跑完這段程式,你應該會發現,這段程式拿到網頁環境,是無法執行的! 在瀏覽器、node 跑 js 程式,有很多相似,也有很多相異之處,希望你慢慢抓到兩者的感覺! ## 課後作業 讓我們嘗試開發一個 CLI 版本的待辦管理工具 請建立一個檔案 `todos.json` 並放入以下內容 ``` [ { "title": "去操場跑步" }, { "title": "去市場採購" }, { "title": "找朋友吃飯" } ] ``` 然後建立一個 `read.js` 檔案 使用者輸入 `node read.js` 之後,終端機會去讀取 `todos.json` 並且顯示 ``` 您的待辦事項: #0 去操場跑步 #1 去市場採購 #2 找朋友吃飯 ``` 完成以上任務,你就完成這次的課程目標了! --- 交作業的方法: **方法一** 直接截圖視窗內容,上傳到留言區 **方法二** 開一個新資料夾,用 git 初始化這個資料夾 接下來的作業,都放在這個資料夾,然後上傳 github 然後把 github 專案連結,貼到留言區即可

[好文分享] 太屌了吧!?用Class(類)製作Jquery的效果!

## 目錄 ##### [【前端動手玩創意】等待的轉圈圈效果 (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) ## 前情提要 各位知道jquery,這個JS的函式庫提供我們非常多實用的方法,包裝好給我們用。 其中底層邏輯都還是跑不出js原生的概念, 今天就讓我們用原生JS的類來創造一些Jquery幫我們打包好的方法吧! 來掀開它的奧秘底牌。 ## 程式碼內容 假設我們要創造一個叫做Dquery的東西,該怎麼做呢: ``` class Dquery { constructor(selector) { this.elements = document.querySelectorAll(selector); //噴出DOM來 } css(property, value) { for (let i = 0; i < this.elements.length; i++) { this.elements[i].style[property] = value; } return this; //修改style } addClass(className) { for (let i = 0; i < this.elements.length; i++) { this.elements[i].classList.add(className); } return this; //增加class } removeClass(className) { for (let i = 0; i < this.elements.length; i++) { this.elements[i].classList.remove(className); } return this; } on(eventType, callback) { for (let i = 0; i < this.elements.length; i++) { this.elements[i].addEventListener(eventType, callback); } return this; //監聽事件的運作 } html(htmlString) { if (typeof htmlString === 'undefined') { return this.elements[0].innerHTML; } else { for (let i = 0; i < this.elements.length; i++) { this.elements[i].innerHTML = htmlString; } return this; } } } function $(selector) { return new Dquery(selector); } ``` ## 觀念筆記 其實概念就是先把底層邏輯刷過一遍 最後return this 就達成jquery的效果了唷。 ## 心得 Jquery曾經非常流行,儘管後來式微了,卻還是有一批死忠的粉絲鍾愛著它的簡便, 事實上它就是JS,所以討人喜歡也是正常的, 這次學會了用ES6類的概念,會讓我們在前端的功力大幅提升唷!!

[好文轉載]哇操!你敢信?花式寫todo-list,body裡面一行都沒有也能搞?

[【前端動手玩創意】哇操!你敢信?花式寫todo-list,body裡面一行都沒有也能搞?](https://ithelp.ithome.com.tw/articles/10312056) ## 前情提要 如果說蟑螂怕拖鞋,老鼠愛大米,任何事物都有相生相剋的道理,那麼前端最害怕什麼呢? 恐怕就是todo-list。 這應該是前端的四大惡夢之一,並不是因為太難了,而是因為太簡單而且太無聊了, 不只無聊,還是每次教學都必須寫的一個磨難,簡直是瞬間殺死靈魂中隊前端的愛。 今天要來用不同風格寫出todo-list,把代辦事項寫出新滋味。 body裡面一行都沒有也能搞? 就是可以搞,讓我們馬上來欣賞這段有特別滋味的玩法!ε(*´・∀・`)з゙ ## 程式碼 ``` <!DOCTYPE html> <html> <head> <title>Todo List</title> </head> <body></body> <script> //渲染DOM AddHtml(); //資料內容 function AddHtml() { const Data = { h1: "Todo List", button: "Add", }; //主體的DOM const html = `<h1>${Data.h1}</h1> <input type="text" id="input" /> <button onclick="CheckNull()">${Data.button}</button> <ul id="list"></ul>`; //渲染至畫面上 document.body.innerHTML += html; } //邏輯確認:是否有輸入值 function CheckNull() { if (!input.value.trim("")) { return; } else { AddItem(); } } //新增代辦事項 function AddItem() { const li = `<li>${document.getElementById("input").value}</li>`; document.getElementById("list").innerHTML += li; input.value = ""; } </script> </html> ``` [可以貼到try it的地方執行看看效果](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_form_submit) ## 觀念筆記 所謂MVC架構就是模型、視圖、控制,背後其實有一個元素貫串任何程式,那就是:「邏輯」 每當你要下手寫一個程式卻不知道怎麼開始動手, 那就是邏輯沒有通順。 網頁不外乎就是畫面,以及資料,還有使用者的操作。 對於todo-list來說就是一個簡單的input畫面,使用者輸入的資料,點下按鈕送出的操作。 這段程式特地不寫任何一行body裡面的東西, 玩弄了一般人對於程式區分的概念。 用模板符的特性讓所有一切交給變數與函式處理,最後三個function: AddHtml、CheckNull、AddItem完美演繹了代辦清單這個網頁所需要構成的底層邏輯。 必須先加入畫面,然後確認使用者操作的條件,最後新增資料。 這樣子的流程對於新手或許不習慣,但是以邏輯面來看比一般人的寫法清晰許多。 這也是未來框架導入後,對資料流更敏感的培養練習。 ## 心得 無聊的todo-list竟然可以搞成這樣!? 真的是太有趣了(๑╹◡╹๑)! 原來前端的惡夢也可以變成寫不同風格的天堂,沒錯,寫程式就是這麼千變萬化! 重點是背後的邏輯抓到了,那麼想要怎麼寫,真的就是藝術的發揮。 請繼續關注, 跟著我們這個系列繼續動手玩創意!!未來還有更多更新鮮的花招呢(。◕∀◕。)

寫了多年 React 之後,改寫 Svelte 的心得與感想

原文出處:https://dev.to/mikenikles/why-i-moved-from-react-to-svelte-and-others-will-follow-210l # React 多年來一直是我的首選 2015 年 10 月 14 日,我主持了 [首屆 React 溫哥華聚會](https://www.meetup.com/ReactJS-Vancouver-Meetup/events/225362860/)。當時我在一年中的大部分時間裡都在使用 React,並希望將志同道合的開發人員聚集在一起。 那時的 React,我敢說,是 web 前端世界的革命性的。與 jQuery、Backbone.js 或 Angular 1.x 等替代方案相比,使用 React 進行開發感覺直觀、清新且富有成效。就個人而言,隔離建置塊(又名元件)的想法真的很吸引我,因為它自然會導致結構化、組織良好且更易於維護的程式碼庫。 在接下來的幾年裡,我一直密切關注 Angular 2.x+、Vue 等,但沒有一個是值得跳槽的選擇。 # 然後我了解了 Svelte 我第一次了解 Svelte 是在 2018 年年中,也就是 3.0 版發布前將近一年(見下文)。 “[計算機,為我建置一個應用程式。](https://www.youtube.com/watch?v=qqt6YxAZoOc)”[Rich Harris](https://twitter.com/Rich_Harris) 讓我著迷Svelte。 > 如果您不熟悉 Svelte ([https://svelte.dev/](https://svelte.dev/)),請存取網站並花 5 分鐘閱讀介紹。 閱讀了嗎?真的?優秀👍 看完影片後,我心中的主要問題是是否值得學習 Svelte 並開始將其用於新專案甚至現有專案。平心而論,Svelte 給我留下了深刻的印象,但仍然不足以讓我完全接受它。 # Svelte 3.x 2019 年 4 月 22 日 - [Svelte 3:重新思考反應性](https://svelte.dev/blog/svelte-3-rethinking-reactivity) 是我一直在等待的博文。 > 請花一些時間閱讀博文並[觀看影片](https://www.youtube.com/watch?v=AdNJ3fydeao) - 這是關於電子表格的,但我保證它很有趣😉 為什麼這是一件大事?首先,Svelte 團隊一直在談論版本 3,我想看看它的實際應用。另一方面,Svelte 及其承諾比我第一次聽說 React 時更讓我興奮。 那時我指導 Web 開發人員,並花了很多時間讓他們加快 React 的速度。為了開發 React 應用程式,需要學習、理解並在一定程度上掌握 JSX、CSS-in-JS、Redux、create-react-app、SSR 和其他概念。 > 對於 Svelte,這些都不是必需的。 ``` <script> let name = 'world'; </script> <style> h1 { color: blue; } </style> <h1>Hello {name}!</h1> ``` 夠簡單嗎?我同意。事實上,它非常簡單,我將它推薦給我的 Web 開發新手。 ## 很快,那段程式碼發生了什麼? `script` 標籤是元件邏輯所在的位置。 `style` 標籤定義了這個元件的 CSS - 這些都不會洩漏到元件之外,所以我們可以安全地使用 h1 並且它只適用於這個元件。它是真正的 CSS,而不是偽裝成 CSS 的 Javascript 對像或偽裝成 CSS 的字串文字。 底部是元件的 HTML。使用帶有 `{myVariable}` 的變數。與 React 的 JSX 相比,Svelte 允許您使用正確的 HTML 標籤,例如 `for`、`class` 而不是 `forHtml` 和 `className`。請參閱 React 文件中的“[屬性差異](https://reactjs.org/docs/dom-elements.html#differences-in-attributes)”以獲取所有非標準 HTML 屬性的列表。 # 讓我們重建 React 示例 為了讓您了解 Svelte 與 React 的對比,讓我們重新建置 [https://reactjs.org/](https://reactjs.org/) 上列出的內容。 ## 一個簡單的元件 請參閱上面的程式碼片段。 ## 一個有狀態的元件 [互動演示](https://svelte.dev/repl/6e9ef214ae774287b21f902d7e6f0e68?version=3.16.6) ``` <script> let seconds = 0; setInterval(() => seconds += 1, 1000); </script> Seconds: {seconds} ``` React:33行 Svelte:6 行 ## 一個應用程式 [互動演示](https://svelte.dev/repl/817d413fd6c344bf859f0dbf8063de2f?version=3.16.6) ``` <script> /* App.svelte */ import TodoList from './TodoList.svelte'; let items = []; let text = ''; const handleSubmit = () => { if (!text.length) { return } const newItem = { text, id: Date.now(), }; items = items.concat(newItem); } </script> <div> <h3>TODO</h3> <TodoList {items} /> <form on:submit|preventDefault={handleSubmit}> <label for="new-todo"> What needs to be done? </label> <input id="new-todo" bind:value={text} /> <button> Add #{items.length + 1} </button> </form> </div> ``` ``` <script> /* TodoList.svelte */ export let items = []; </script> <ul> {#each items as item} <li key={item.id}>{item.text}</li> {/each} </ul> ``` React:66行 Svelte:43 行 ## 使用外部插件的元件 [互動演示](https://svelte.dev/repl/28f4b2e36e4244b8b23cae3d584c4c88?version=3.16.6) ``` <script> const md = new window.remarkable.Remarkable(); let value = 'Hello, **world**!'; </script> <svelte:head> <script src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/2.0.0/remarkable.min.js"></script> </svelte:head> <div className="MarkdownEditor"> <h3>Input</h3> <label htmlFor="markdown-content"> Enter some markdown </label> <textarea id="markdown-content" bind:value={value} /> <h3>Output</h3> <div className="content"> {@html md.render(value)} </div> </div> ``` React:42行 Svelte:24 行 > 更少的程式碼 = 更少的錯誤 > 更少的程式碼 = 更好的性能 = 更好的用戶體驗 > 更少的程式碼 = 更少的維護 = 更多的時間來開發功能 # 我還喜歡 Svelte 什麼? ## 反應性 另一個強大的功能是 [反應式聲明](https://svelte.dev/tutorial/reactive-declarations)。讓我們從一個例子開始: ``` <script> let count = 0; $: doubled = count * 2; function handleClick() { count += 1; } </script> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> <p>{count} doubled is {doubled}</p> ``` 每當你有依賴於其他變數的變數時,用 `$: myVariable = [引用其他變數的程式碼]` 聲明它們。以上,每當 count 發生變化時,doubled 都會自動重新計算,並且 UI 會更新以反映新值。 ## Stores 在需要跨元件共享狀態的情況下,Svelte 提供了存儲的概念。 [教程很好地解釋了 store](https://svelte.dev/tutorial/auto-subscriptions)。無需閱讀冗長的教程 - store 就這麼簡單。 ### Derived stores 通常,一家 store 依賴於其他 store。這就是 Svelte 提供 derived() 來組合 store 的地方。 [有關詳細訊息,請參閱教程](https://svelte.dev/tutorial/derived-stores)。 ## 作為邏輯塊等待 好吧,這是一個非常優雅的。讓我們從程式碼開始([交互式演示](https://svelte.dev/repl/b9fc662a253443dc901ff189ce1cdd4b?version=3.16.7)): ``` <script> let githubRepoInfoPromise; let repoName = 'mikenikles/ghost-v3-google-cloud-storage'; const loadRepoInfo = async () => { const response = await fetch(`https://api.github.com/repos/${repoName}`); if (response.status === 200) { return await response.json(); } else { throw new Error(response.statusText); } } const handleClick = () => { githubRepoInfoPromise = loadRepoInfo(); } </script> <input type="text" placeholder="user/repo" bind:value={repoName} /> <button on:click={handleClick}> load Github repo info </button> {#await githubRepoInfoPromise} <p>...loading</p> {:then apiResponse} <p>{apiResponse ? `${apiResponse.full_name} is written in ${apiResponse.language}` : ''}</p> {:catch error} <p style="color: red">{error.message}</p> {/await} ``` 看到 HTML 中的“#await”塊了嗎?在真實世界的應用程式中,您將有一個加載元件、一個錯誤元件和在這種情況下呈現 API 響應的實際元件。嘗試在文本框中輸入無效的 repo 名稱以觸發錯誤案例。 # “等等,那……呢?” ## 開源元件? 當我向某人介紹 Svelte 時,我得到的主要回應是“但是生態系統、元件、教程、工具等呢?” 是的,開源 Svelte 元件遠不及 React 元件多。話雖如此,您多久使用一個開源 React 元件並在沒有任何問題或不必要的開銷的情況下集成它?我認為我們 Javascript 社區中的許多人已經變得過於依賴 `npm install ...` 來拼湊一個 web 應用程式。通常建置自己的元件,尤其是在 Svelte 中,可以減少整體花費的時間。我沒有資料可以證明,這是基於我個人的經驗。 不過,與此相關的是,對於任何願意重用開源元件的人來說,Svelte 元件的列表越來越多。 ## 正在找工作? 機會很多,請參閱 [https://sveltejobs.dev/](https://sveltejobs.dev/)。 Apple 的欺詐工程團隊正在[尋找 Svelte 開發人員](https://sveltejobs.dev/jobs/apple-senior-front-end-developer)(截至 2019 年 12 月)。 還要記住,與申請需要 React、Vue、Angular 等的工作相比,競爭要小得多。 # 然後,有 Sapper 來部署 Svelte 應用程式 開發應用程式只是整個蛋糕的一小部分——應用程式還需要部署。為此,Svelte 團隊提供了 [Sapper](https://sapper.svelte.dev/)。這本身就是一篇完整的帖子,所以現在請查看網站了解詳細訊息。 # 結論 每天,新的 Web 開發人員開始他們的旅程,許多人遇到的第一件事就是不確定首先要學什麼。我說未來就是簡單、快速的開發時間,我想不出比這更簡單、更快的事情了: ``` <script> let name = 'world'; </script> <style> h1 { color: blue; } </style> <h1>Hello {name}!</h1> ``` 以上分享,希望對您有幫助

適用於各種軟體開發技能:2023 推薦練習的專案開發

作為一名開發人員,了解最新的技術和工具對於在就業市場上保持競爭力至關重要。 在這篇文章中,我們整理了一份 2023 年最熱門開發專案的完整列表,以及掌握每個專案的教程和資源。 無論您是希望提高技能的初學者,還是希望擴展您的技能組合的資深開發人員,此列表都適合每個人。 - 原文出處:https://dev.to/rahul3002/2023s-top-development-projects-for-programmers-a-complete-list-of-tutorials-and-tools-for-mastering-the-latest-technologies-37o3 --- ## 專案教程列表: ### Web開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 NextJS 建置 Reddit 2.0 克隆 | React、SQL、Supabase、Next.js、GraphQL | [連結](https://projectlearn.io/learn/web-development/project/build-reddit-2.0-clone-with-nextjs-205?from=github)| |使用 React 建置 YouTube 克隆 | Express、Node、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/build-a-youtube-clone-with-react-200?from=github)| |使用 JavaScript 圖表庫建立發散條形圖 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/create-a-diverging-bar-chart-with-a-javascript-charting-library-197?from=github)| |通過建置卡片組件學習 CSS 基礎知識 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/learn-css-basics-by-building-a-card-component-196?from=github)| |建立無伺服器模因即服務 | JavaScript、Rust、CSS、HTML | [連結](https://projectlearn.io/learn/web-development/project/create-a-serverless-meme-as-a-service-194?from=github)| |天氣預報網站 | JavaScript、HTML、CSS、React | [連結](https://projectlearn.io/learn/web-development/project/weather-forecast-website-193?from=github)| |連結縮短網站 | JavaScript、Vue、HTML、CSS、React | [連結](https://projectlearn.io/learn/web-development/project/link-shortener-website-192?from=github)| |抄襲檢查器網站 | Python, 引導 | [連結](https://projectlearn.io/learn/web-development/project/plagiarism-checker-website-189?from=github)| |建置自定義 Google 地圖主題 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/build-a-custom-google-maps-theme-187?from=github)| |使用 JavaScript 建置超級馬里奧主題的 Google 地圖 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/build-a-super-mario-themed-google-map-with-javascript-180?from=github)| |建置社區驅動的交付應用程式 | Python、Django、PostgreSQL、JavaScript、Mapbox | [連結](https://projectlearn.io/learn/web-development/project/build-a-community-driven-delivery-application-176?from=github)| |建置本地商店搜尋和發現應用程式 | Python、Django、PostgreSQL、JavaScript、Mapbox | [連結](https://projectlearn.io/learn/web-development/project/build-a-local-store-search-and-discovery-application-175?from=github)| |使用 React.js 和 Node.js 的中型克隆 |React、Node、CSS3、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/medium-clone-using-react.js-and-node.js-174?from=github)| |使用 React JS 克隆 Facebook |React、Firebase、CSS3、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/facebook-clone-with-react-js-171?from=github)| | JavaScript30 - 30 天 Vanilla JS 編碼挑戰 | JavaScript | [連結](https://projectlearn.io/learn/web-development/project/javascript30---30-day-vanilla-js-coding-challenge-170?from=github)| |使用 Gatsby 和 GraphCMS 的旅行遺願清單地圖 |Gatsby、Leaflet、GraphCMS、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/travel-bucket-list-map-with-gatsby-and-graphcms-168?from=github)| |使用 Vue.js 的記憶卡遊戲 | Vue、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/memory-card-game-with-vue.js-167?from=github)| | Strapi 和 GatsbyJS 課程 - 投資組合專案 | Strapi、Gatsby、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/strapi-and-gatsbyjs-course---portfolio-project-166?from=github)| | Storybook - Node、Express、MongoDB 和 Google OAuth | MongoDB、Node、JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/storybook---node,-express,-mongodb-and-google-oauth-165?from=github)| |呼吸和放鬆應用程式 - JavaScript 和 CSS 動畫 | JavaScript、HTML、CSS | [連結](https://projectlearn.io/learn/web-development/project/breathe-and-relax-app---javascript-and-css-animations-164?from=github)| |用於加密貨幣價格的 Node.js CLI |Node,JavaScript | [連結](https://projectlearn.io/learn/web-development/project/node.js-cli-for-cryptocurrency-prices-163?from=github)| | React 和 Tailwind CSS 圖片庫 |React,順風,JavaScript,HTML,CSS | [連結](https://projectlearn.io/learn/web-development/project/react-and-tailwind-css-image-gallery-162?from=github)| |使用 React 的番茄鐘 |React,JavaScript,HTML,CSS | [連結](https://projectlearn.io/learn/web-development/project/pomodoro-clock-using-react-161?from=github)| | Laravel 從零開始的關鍵字密度工具 | Laravel、PHP、JQuery、AJAX、SEO | [連結](https://projectlearn.io/learn/web-development/project/keyword-density-tool-with-laravel-from-scratch-160?from=github)| |使用 Yii2 PHP 框架克隆 YouTube | Yii2, PHP | [連結](https://projectlearn.io/learn/web-development/project/youtube-clone-using-yii2-php-framework-159?from=github)| |使用 React、GraphQL 和 Amplify 克隆 Reddit | React、Amplify、AWS、GraphQL、Node | [連結](https://projectlearn.io/learn/web-development/project/reddit-clone-with-react,-graphql-and-amplify-157?from=github)| |使用 React 和 GraphQL 的全棧 Yelp 克隆 |React、GraphQL、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/full-stack-yelp-clone-with-react-and-graphql-155?from=github)| |帶有 React Hooks 和 Context API 的 Pokémon Web App |React、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/pokémon-web-app-with-react-hooks-and-context-api-154?from=github)| |使用 JavaScript 和 Rails 進行分水嶺監控 | Ruby、Rails、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/watershed-monitor-using-javascript-and-rails-153?from=github)| |使用 React 和 Redux 的氣候資料儀表板 | React、Redux、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/climate-data-dashboard-using-react-and-redux-152?from=github)| |僅使用 CSS 翻轉 UNO 卡片 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/flipping-uno-cards-using-only-css-151?from=github)| |使用 Redis、WebSocket 和 Go 的聊天應用程式 | Redis、Web Socket、Go、Azure | [連結](https://projectlearn.io/learn/web-development/project/chat-app-with-redis,-websocket-and-go-146?from=github)| |使用 React 導航的 Spotify 登錄動畫 |React、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/spotify-login-animation-with-react-navigation-145?from=github)| |僅使用 CSS 的動態天氣界面 | HTML, CSS | [連結](https://projectlearn.io/learn/web-development/project/dynamic-weather-interface-with-just-css-144?from=github)| |使用 Airtable 和 Vue 的簡單 CRUD 應用程式 | Airtable、Vue、Vuetify、API、HTML | [連結](https://projectlearn.io/learn/web-development/project/simple-crud-app-with-airtable-and-vue-143?from=github)| |帶有 MEVN 堆棧的全棧 RPG 角色生成器 | MongoDB、Express、Vue、Node、HTML | [連結](https://projectlearn.io/learn/web-development/project/full-stack-rpg-character-generator-with-mevn-stack-142?from=github)| |帶有 PERN 堆棧的 Todo 應用 | PostgreSQL、Express、React、Node、HTML | [連結](https://projectlearn.io/learn/web-development/project/todo-app-with-the-pern-stack-141?from=github)| |帶有 Gatsby 的夏季公路旅行地圖應用程式 |React,Gatsby,Leaflet | [連結](https://projectlearn.io/learn/web-development/project/summer-road-trip-mapping-app-with-gatsby-140?from=github)| |使用 Socket.io 的多人紙牌遊戲 | Phaser 3、Express、Socket.io、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/multiplayer-card-game-with-socket.io-139?from=github)| |帶有 Gatsby 的 COVID-19 儀表板和地圖應用程式 |React,Gatsby,Leaflet | [連結](https://projectlearn.io/learn/web-development/project/covid-19-dashboard-and-map-app-with-gatsby-138?from=github)| | React 抽認卡測驗 |React、API、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/flashcard-quiz-with-react-125?from=github)| |用純 JavaScript 打地鼠 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/whack-a-mole-with-pure-javascript-124?from=github)| |使用 JavaScript 的諾基亞 3310 貪吃蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/nokia-3310-snake-game-using-javascript-123?from=github)| |原版 JavaScript 中的石頭剪刀布 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/rock-paper-scissors-in-vanilla-javascript-122?from=github)| |純 JavaScript 的俄羅斯方塊 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/tetris-with-pure-javascript-121?from=github)| |使用 React 製作 Meme Maker |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/meme-maker-with-react-119?from=github)| |使用 React 克隆 Evernote |React、Firebase、Node、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/evernote-clone-with-react-118?from=github)| |開發者 Meetup App with Vue | Vue、Firebase、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/developer-meetup-app-with-vue-117?from=github)| | Vue 實時聊天應用 | Vue、Firebase、Vuex、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/real-time-chat-app-with-vue-116?from=github)| |使用 Vue 的加密貨幣追踪器 | Vue、Vuetify、API、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/cryptocurrency-tracker-with-vue-115?from=github)| | Vue 多人問答遊戲 | Vue、Pusher、Node、Express、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/multiplayer-quiz-game-with-vue-114?from=github)| | Vue 掃雷遊戲 | Vue、Vuex、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/minesweeper-game-with-vue-113?from=github)| |使用 Vue 克隆 Instagram | Vue、CSSGram、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/instagram-clone-with-vue-112?from=github)| |使用 Angular 克隆黑客新聞 |角度、燈塔、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/hacker-news-clone-with-angular-111?from=github)| |聊天界面 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/chat-interface-110?from=github)| |純 CSS3 工具提示 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/pure-css3-tooltip-109?from=github)| |社交媒體按鈕 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/social-media-buttons-108?from=github)| |推薦卡 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/testimonial-card-107?from=github)| |帶有 CSS3 Flexbox 的導航欄 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/navigation-bar-with-css3-flexbox-106?from=github)| |使用 CSS3 Flexbox 的移動應用程式佈局 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/mobile-app-layout-with-css3-flexbox-105?from=github)| |受 Reddit 啟發的加載微調器 | HTML5, CSS3 | [連結](https://projectlearn.io/learn/web-development/project/reddit-inspired-loading-spinner-104?from=github)| |帶 CSS3 網格的日曆 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/calendar-with-css3-grid-103?from=github)| | React 中的俄羅斯方塊遊戲 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/tetris-game-in-react-102?from=github)| | 2D 突圍遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/2d-breakout-game-101?from=github)| |精靈動畫 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/sprite-animation-100?from=github)| |蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/snake-game-99?from=github)| |記憶遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/memory-game-98?from=github)| |簡單的身份驗證和授權 | GraphQL、Apollo、Node、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/simple-authentication-and-authorization-97?from=github)| |加密貨幣追踪器 | NextJS、GraphQL、Apollo、Node、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/cryptocurrency-tracker-96?from=github)| |使用 Vanilla Javascript 進行即時搜尋 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/instant-search-with-vanilla-javascript-95?from=github)| |計算器應用 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/calculator-app-94?from=github)| |待辦事項 | Vue、JavaScript、CSS3、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/todo-app-45?from=github)| |博客應用 | Vue、GraphQL、阿波羅、JavaScript、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/blog-app-44?from=github)| |簡單的預算應用程式 | Vue、布爾瑪、JavaScript、CSS3、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/simple-budgeting-app-43?from=github)| |搜尋機器人 |Node、Twilio、Cheerio、API、自動化 | [連結](https://projectlearn.io/learn/web-development/project/search-bot-42?from=github)| |推特機器人 |Node、JavaScript、API、自動化 | [連結](https://projectlearn.io/learn/web-development/project/twitter-bot-41?from=github)| |實時 Markdown 編輯器 |Node、JavaScript、Express、Redis、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/real-time-markdown-editor-40?from=github)| |待辦事項 | Angular、TypeScript、RxJS、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/todo-app-39?from=github)| |黑客新聞客戶端 |角度、RxJS、Webpack、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/hacker-news-client-38?from=github)| |隨機報價機 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/random-quote-machine-37?from=github)| | Todoist克隆| React, Firebase, JavaScript, 測試, HTML5 | [連結](https://projectlearn.io/learn/web-development/project/todoist-clone-36?from=github)| |帶有情感分析的聊天應用 | NextJS、Pusher、Sentiment、Node、React | [連結](https://projectlearn.io/learn/web-development/project/chat-app-with-sentiment-analysis-35?from=github)| |預約安排 | React、Twilio、CosmicJS、Material-UI、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/appointment-scheduler-34?from=github)| |生命遊戲 |React、2D、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/game-of-life-33?from=github)| |新聞應用 | React Native、Node、API、React、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/news-app-32?from=github)| |聊天應用 | React、Redux、Redux Saga、Web 套接字、Node | [連結](https://projectlearn.io/learn/web-development/project/chat-app-31?from=github)| |待辦事項 | React Native、GraphQL、Apollo、API、Hasura | [連結](https://projectlearn.io/learn/web-development/project/todo-app-30?from=github)| | Chrome 擴展 |React,包裹,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/chrome-extension-29?from=github)| |電影投票應用 | React、Redux、API、不可變、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/movie-voting-app-27?from=github)| |特雷洛克隆 | React、Elixir、Phoenix、JWT、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/trello-clone-25?from=github)| | Wiki 風格的 CMS | C#、.NET、Razor 頁面 | [連結](https://projectlearn.io/learn/web-development/project/wiki-style-cms-18?from=github)| |使用 ReactJS 克隆 Spotify |React,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/spotify-clone-with-reactjs-15?from=github)| |微軟主頁克隆 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/microsoft-homepage-clone-14?from=github)| |簡單甘特圖 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/simple-gantt-chart-13?from=github)| |工作抓取應用 |Node、JavaScript、REST、API、Express | [連結](https://projectlearn.io/learn/web-development/project/job-scraping-app-12?from=github)| |電子商務應用 |React,引導程序,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/web-development/project/e-commerce-app-11?from=github)| | Netflix 著陸頁 | HTML5、CSS3、JavaScript | [連結](https://projectlearn.io/learn/web-development/project/netflix-landing-page-10?from=github)| |人工智能聊天機器人 | Web 語音 API、Node、JavaScript、Express、Socket.io | [連結](https://projectlearn.io/learn/web-development/project/ai-chatbot-9?from=github)| |社交網絡應用 |React、Node、Redux、Firebase、REST | [連結](https://projectlearn.io/learn/web-development/project/social-networking-app-8?from=github)| |在 Node.js 中建置一個簡單的加密貨幣區塊鏈 |Node、JavaScript、密碼學、區塊鏈 | [連結](https://projectlearn.io/learn/web-development/project/build-a-simple-cryptocurrency-blockchain-in-node.js-7?from=github)| | BT 客戶端 |Node、JavaScript、TCP、計算機網絡 | [連結](https://projectlearn.io/learn/web-development/project/bittorrent-client-6?from=github)| |使用 JavaScript 的待辦事項列表應用 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/web-development/project/todo-list-app-with-javascript-4?from=github)| |使用 Anime.js 的 JavaScript 動畫 | JavaScript、CSS3、庫、HTML5、API | [連結](https://projectlearn.io/learn/web-development/project/javascript-animations-with-anime.js-3?from=github)| |帶有 React 的工作板應用程式 |React、Node、Cron、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/web-development/project/job-board-app-with-react-1?from=github)| ### 移動開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 React Native 建置一個 Uber Eats 克隆 | React Native、Javascript、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/build-an-uber-eats-clone-with-react-native-204?from=github)| |使用 React Native 建置一個 Uber 克隆 | React Native、Javascript、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/build-an-uber-clone-with-react-native-203?from=github)| |使用 Flutter SDK 建置帶有故事的聊天應用程式 |顫振,飛鏢 | [連結](https://projectlearn.io/learn/mobile-development/project/build-a-chat-app-with-stories-using-the-flutter-sdk-199?from=github)| |建置 Robinhood 風格的應用程式來跟踪 COVID-19 病例 |科特林, 安卓 | [連結](https://projectlearn.io/learn/mobile-development/project/build-a-robinhood-style-app-to-track-covid-19-cases-198?from=github)| | Tinder 風格的 Swipe 移動應用程式 |科特林、Java、斯威夫特 | [連結](https://projectlearn.io/learn/mobile-development/project/tinder-style-swipe-mobile-app-186?from=github)| |加密貨幣價格列表移動應用程式 | React Native、Swift、Flutter、Dart | [連結](https://projectlearn.io/learn/mobile-development/project/cryptocurrency-price-listing-mobile-app-185?from=github)| |餐廳社交移動應用程式 | React Native、Swift、Flutter、Dart | [連結](https://projectlearn.io/learn/mobile-development/project/restaurants-social-mobile-app-184?from=github)| |休息時間提醒移動應用 | React Native、Kotlin、Java、Swift | [連結](https://projectlearn.io/learn/mobile-development/project/break-time-reminder-mobile-app-183?from=github)| |發票和付款提醒移動應用程式 | React、Node、Express、MongoDB | [連結](https://projectlearn.io/learn/mobile-development/project/invoicing-and-payment-reminder-mobile-app-182?from=github)| |倒計時移動應用 | Swift、Java、React Native | [連結](https://projectlearn.io/learn/mobile-development/project/countdown-mobile-app-181?from=github)| |使用 Swift 的 Flappy Bird iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/flappy-bird-ios-game-using-swift-130?from=github)| |使用 Swift 的 Bull's Eye iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/bull's-eye-ios-game-using-swift-129?from=github)| |使用 SwiftUI 的任務列表 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/task-list-ios-app-using-swiftui-128?from=github)| |使用 SwiftUI 的餐廳 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/restaurant-ios-app-using-swiftui-127?from=github)| |使用 Swift 的骰子 iOS 應用 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/dice-ios-app-with-swift-126?from=github)| | TrueCaller 克隆 | Java、MySQL、XAMPP、Android | [連結](https://projectlearn.io/learn/mobile-development/project/truecaller-clone-83?from=github)| |天氣應用 | Java, API, Android | [連結](https://projectlearn.io/learn/mobile-development/project/weather-app-82?from=github)| |電子商務應用 | Java、Firebase、Android | [連結](https://projectlearn.io/learn/mobile-development/project/e-commerce-app-81?from=github)| |聊天應用 | Java、Firebase、Android | [連結](https://projectlearn.io/learn/mobile-development/project/chat-app-80?from=github)| |待辦事項 | Flutter、Dart、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/todo-app-79?from=github)| |旅遊應用程式用戶界面 | Flutter、Dart、Android、iOS | [連結](https://projectlearn.io/learn/mobile-development/project/travel-app-ui-78?from=github)| | Reddit 客戶端 |安卓,科特林 | [連結](https://projectlearn.io/learn/mobile-development/project/reddit-client-46?from=github)| |待辦事項 | React Native、Android、iOS、JavaScript | [連結](https://projectlearn.io/learn/mobile-development/project/todo-app-24?from=github) |照片庫查看器 | C#、iOS、Xamarin、Visual Studio、Android | [連結](https://projectlearn.io/learn/mobile-development/project/photo-library-viewer-19?from=github)| |使用 React Native 克隆 WhatsApp | React Native、Node、GraphQL、Apollo、JavaScript | [連結](https://projectlearn.io/learn/mobile-development/project/whatsapp-clone-with-react-native-2?from=github)| ### 遊戲開發: |專案 |技術 |連結 | | :--- |:---|:---| |使用 Kaboom.js 建置超級馬里奧兄弟、塞爾達傳說和太空侵略者 | JavaScript,Kaboom | [連結](https://projectlearn.io/learn/game-development/project/build-super-mario-bros,-zelda,-and-space-invaders-with-kaboom.js-201?from=github) | |使用 TypeScript 建立打磚塊遊戲 |打字稿、HTML、CSS、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/create-an-arkanoid-game-with-typescript-195?from=github)| |簡單遊戲 | Lua、LÖVE、Python、Pygame 零 | [連結](https://projectlearn.io/learn/game-development/project/simple-games-179?from=github)| | Python在線多人遊戲|蟒蛇 | [連結](https://projectlearn.io/learn/game-development/project/python-online-multiplayer-game-173?from=github)| |打敗他們格鬥遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/beat-em-up-fight-game-172?from=github)| |使用 Godot 3.1 的簡單 3D 遊戲 |戈多,C#,3D | [連結](https://projectlearn.io/learn/game-development/project/simple-3d-game-using-godot-3.1-150?from=github)| | Godot 中的簡單益智遊戲- Box and Switch |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/simple-puzzle-game-in-godot---box-and-switch-149?from=github)| | Godot 3 中的遊戲界面從頭開始 |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/game-interface-from-scratch-in-godot-3-148?from=github)| | Godot 的 2D 遊戲:玩家與敵人 |戈多,C#,二維 | [連結](https://projectlearn.io/learn/game-development/project/2d-game-with-godot:-player-and-enemy-147?from=github)| |使用 Socket.io 的多人紙牌遊戲 | Phaser 3、Express、Socket.io、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-card-game-with-socket.io-139?from=github)| |使用 Unity 2D 和 Mirror 的多人紙牌遊戲 | C#、Unity、二維、鏡像 | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-card-game-with-unity-2d-and-mirror-137?from=github)| | Rust 中的 Roguelike 教程 |生鏽,二維 | [連結](https://projectlearn.io/learn/game-development/project/roguelike-tutorial-in-rust-136?from=github)| | Rust 歷險記 - 一款基本的 2D 遊戲 |生鏽,二維 | [連結](https://projectlearn.io/learn/game-development/project/adventures-in-rust---a-basic-2d-game-135?from=github)| |使用 Ruby 的終端貪吃蛇遊戲 |紅寶石,二維 | [連結](https://projectlearn.io/learn/game-development/project/terminal-snake-game-with-ruby-134?from=github)| |使用 OpenGL 的太空入侵者 | OpenGL、C/C++、2D | [連結](https://projectlearn.io/learn/game-development/project/space-invaders-using-opengl-133?from=github)| | C 中的數獨求解器 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/sudoku-solver-in-c-132?from=github)| | C 中的國際象棋引擎 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/chess-engine-in-c-131?from=github)| |使用 Swift 的 Flappy Bird iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/game-development/project/flappy-bird-ios-game-using-swift-130?from=github)| |使用 Swift 的 Bull's Eye iOS 遊戲 |斯威夫特、XCode、iOS | [連結](https://projectlearn.io/learn/game-development/project/bull's-eye-ios-game-using-swift-129?from=github)| |用純 JavaScript 打地鼠 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/whack-a-mole-with-pure-javascript-124?from=github)| |使用 JavaScript 的諾基亞 3310 貪吃蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/nokia-3310-snake-game-using-javascript-123?from=github)| |原版 JavaScript 中的石頭剪刀布 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/rock-paper-scissors-in-vanilla-javascript-122?from=github)| |純 JavaScript 的俄羅斯方塊 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/tetris-with-pure-javascript-121?from=github)| | Vue 多人問答遊戲 | Vue、Pusher、Node、Express、JavaScript | [連結](https://projectlearn.io/learn/game-development/project/multiplayer-quiz-game-with-vue-114?from=github)| | Vue 掃雷遊戲 | Vue、Vuex、Vuetify、JavaScript、HTML5 | [連結](https://projectlearn.io/learn/game-development/project/minesweeper-game-with-vue-113?from=github)| | React 中的俄羅斯方塊遊戲 |React,JavaScript,HTML5,CSS3 | [連結](https://projectlearn.io/learn/game-development/project/tetris-game-in-react-102?from=github)| | 2D 突圍遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/2d-breakout-game-101?from=github)| |精靈動畫 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/sprite-animation-100?from=github)| |蛇遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/snake-game-99?from=github)| |記憶遊戲 | JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/memory-game-98?from=github)| |坦克射手 | 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/tanks-shooter-93?from=github)| | 2D Roguelike |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/2d-roguelike-92?from=github)| |約翰·萊蒙鬧鬼的短途旅行 3D | 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/john-lemon's-haunted-jaunt-3d-91?from=github)| | VR 初學者:密室逃脫 |虛擬現實、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/vr-beginner:-the-escape-room-90?from=github)| |露比的冒險 |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/ruby's-adventure-89?from=github)| |角色扮演遊戲 |二維、Unity、C# | [連結](https://projectlearn.io/learn/game-development/project/rpg-game-88?from=github)| |滾球| 3D、統一、C# | [連結](https://projectlearn.io/learn/game-development/project/roll-a-ball-87?from=github)| | FPS 微型遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/fps-microgame-86?from=github)| |平台微遊戲 | Unity、C#、2D | [連結](https://projectlearn.io/learn/game-development/project/platformer-microgame-85?from=github)| |卡丁車小遊戲 |統一,C# | [連結](https://projectlearn.io/learn/game-development/project/karting-microgame-84?from=github)| |街機射擊 | Lua,愛 | [連結](https://projectlearn.io/learn/game-development/project/arcade-shooter-47?from=github)| |生命遊戲 |React、2D、JavaScript、HTML5、CSS3 | [連結](https://projectlearn.io/learn/game-development/project/game-of-life-33?from=github)| |手工英雄 | C/C++、OpenGL、2D | [連結](https://projectlearn.io/learn/game-development/project/handmade-hero-23?from=github)| |突圍 | C/C++、OpenGL、2D | [連結](https://projectlearn.io/learn/game-development/project/breakout-22?from=github)| |俄羅斯方塊 | C/C++, 二維 | [連結](https://projectlearn.io/learn/game-development/project/tetris-21?from=github)| |紅白機遊戲 | C/C++、Python、二維 | [連結](https://projectlearn.io/learn/game-development/project/nes-game-20?from=github)| | Roguelike 遊戲 | C#、.NET、RogueSharp、MonoGame、RLNet | [連結](https://projectlearn.io/learn/game-development/project/roguelike-game-17?from=github)| |簡單的角色扮演遊戲 | C#、SQL、二維 | [連結](https://projectlearn.io/learn/game-development/project/simple-rpg-game-16?from=github)| ### 機器學習與人工智能: |專案 |技術 |連結 | | :--- |:---|:---| |使用 BeautifulSoup 建置網絡爬蟲 | Python, BeautifulSoup | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/build-a-web-scraper-using-beautifulsoup-202?from=github)| |從胸部 X 光檢測肺炎的 CNN |美國有線電視新聞網,蟒蛇 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/cnn-that-detects-pneumonia-from-chest-x-rays-169?from=github)| |使用 AWS 在 Python 中自動更新資料可視化 | Python、AWS、Matplotlib | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/auto-updating-data-visualizations-in-python-with-aws-158?from=github)| |使用 GCP 和 Node 的 Twitter 情感分析工具 | API、GCP、Node、JavaScript | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-tool-using-gcp-and-node-156?from=github)| |使用 CNN 進行 Twitter 情緒分析 | Python、Matplotlib、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-using-cnn-120?from=github)| |泰勒斯威夫特歌詞生成器 | Python、Keras、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/taylor-swift-lyrics-generator-77?from=github)| | MNIST 數字辨識器 | Python、Keras、TensorFlow、Numpy、SciKit | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/mnist-digit-recognizer-76?from=github)| |訓練模型生成顏色 | Python、Keras、TensorFlow、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/train-a-model-to-generate-colors-75?from=github)| |圖片說明生成器 | Python、TensorFlow、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/image-caption-generator-74?from=github)| |使用 CNN 破解驗證碼系統 | Python、Keras、TensorFlow、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/break-a-captcha-system-using-cnn-73?from=github)| |生成一張平均臉 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/generate-an-average-face-72?from=github)| |圖像拼接 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/image-stitching-71?from=github)| |手部關鍵點檢測 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/hand-keypoint-detection-70?from=github)| |特徵臉 | Python、OpenCV、Numpy、C/C++ | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/eigenface-69?from=github)| |無人機目標檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/drone-target-detection-68?from=github)| |使用 Mask R-CNN 進行目標檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/object-detection-using-mask-r-cnn-67?from=github)| |面部地標檢測 | Python、OpenCV、DLib、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/facial-landmark-detection-66?from=github)| |文本傾斜校正 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/text-skew-correction-65?from=github)| | OCR 和文本辨識 | Python、OpenCV、Tesseract、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/ocr-and-text-recognition-64?from=github)| |人數統計 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/people-counter-63?from=github)| |文本檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/text-detection-62?from=github)| |語義分割 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/semantic-segmentation-61?from=github)| |物件跟踪 | Python、OpenCV、Numpy、CamShift | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/object-tracking-60?from=github)| |人臉聚類 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/face-clustering-59?from=github)| |條碼掃描儀 | Python、OpenCV、ZBar、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/barcode-scanner-58?from=github)| |顯著性檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/saliency-detection-57?from=github)| |人臉檢測 | Python、OpenCV、Numpy | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/face-detection-56?from=github)| |文件掃描儀 | Python、OpenCV、Numpy、SciKit | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/document-scanner-55?from=github)| |音樂推薦 | Python、SciKit、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/music-recommender-54?from=github)| |預測葡萄酒質量 | Python、Matplotlib、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/predict-quality-of-wine-53?from=github)| |遺傳算法 | Python、SciKit、Numpy、熊貓 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/genetic-algorithms-52?from=github)| |深夢 | Python、TensorFlow、可視化 | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/deepdream-51?from=github)| |股價預測| Python、SciKit、Matplotlib | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/stock-price-prediction-50?from=github)| |電影推薦系統 | Python, LightFM | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/movie-recommendation-systems-49?from=github)| | Twitter 情緒分析 | Python, API | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/twitter-sentiment-analysis-48?from=github)| |帶有情感分析的聊天應用 | NextJS、Pusher、Sentiment、Node、React | [連結](https://projectlearn.io/learn/machine-learning-and-ai/project/chat-app-with-sentiment-analysis-35?from=github)| --- **結論** 2023 年將成為令人振奮的發展年,新技術和工具層出不窮。 希望這篇文章對您有幫助。

軟體開發者推薦使用:50 個好用的 CLI 指令工具

作為開發人員,我們在終端機上花費了大量時間。有很多有用的 CLI 工具,它們可以讓您在命令行中的生活更輕鬆、更快速,而且通常更有趣。 這篇文章概述了 50 個必備的好用 CLI 工具。 原文出處:https://dev.to/lissy93/cli-tools-you-cant-live-without-57f6 --- ## 工具 ### [`thefuck`](https://github.com/nvbn/thefuck) - 自動更正錯誤輸入的命令 > `thefuck` 是您一旦嘗試過就離不開的實用程式之一。每當您輸入錯誤的命令並出現錯誤時,只需執行 `fuck`,它就會自動更正它。使用向上/向下選擇一個更正,或者只執行 `fuck --yeah` 立即執行最有可能的。 ![他媽的示例用法](https://i.ibb.co/J55hWKX/thefuck.gif) --- ### [`zoxide`](https://github.com/ajeetdsouza/zoxide) - 輕鬆導航 _(更好的 cd)_ > `z` 讓您可以跳轉到任何目錄,而無需記住或指定其完整路徑。它會記住您存取過的目錄,因此您可以快速跳轉——您甚至不需要鍵入完整的文件夾名稱。它還具有互動式選項,使用“fzf”,因此您可以即時過濾目錄結果 ![zoxide-example-usage](https://i.ibb.co/6Z960jq/zoxide.gif) --- ### [`tldr`](https://github.com/tldr-pages/tldr) - 社區維護的文件 _(更好的 `man`)_ > `tldr` 是社區維護的手冊頁的巨大集合。與傳統的手冊頁不同,它們進行了總結,包含有用的用法範例,並且配色良好,便於閱讀 ![tldr-example-usage](https://i.ibb.co/jTW9knx/tlfr.gif) --- ### [`scc`](https://github.com/boyter/scc) - 計算程式碼行數_(更好的`cloc`)_ > `scc` 為您提供了針對特定目錄以每種語言編寫的程式碼行數的細分。它還顯示了一些有趣的統計資料,例如估計的開發成本和復雜性訊息。它的速度非常快,非常準確,並且支持多種語言 ![scc-example-usage](https://i.ibb.co/NygHWXt/scc.png) --- ### [`exa`](https://github.com/ogham/exa) - 列出文件 _(更好的 `ls`)_ > `exa` 是基於 Rust 的現代替代 `ls` 命令,用於列出文件。它可以顯示文件類型圖標、顏色、文件/文件夾訊息,並有多種輸出格式——樹、網格或列表 ![exa-example-usage](https://i.ibb.co/cTs0wQ5/exa.png) --- ### [`duf`](https://github.com/muesli/duf) - 硬碟使用量 _(更好的 `df`)_ > `duf` 非常適合顯示有關已安裝硬碟的訊息和檢查可用空間。它產生清晰多彩的輸出,並包括用於排序和自定義結果的選項。 ![duf-示例用法](https://i.ibb.co/sP59DKd/duf.png) --- ### [`aria2`](https://github.com/aria2/aria2) - 下載實用程式 _(更好的 `wget`)_ > `aria2` 是一種輕量級、多協議、用於 HTTP/HTTPS、FTP、SFTP、BitTorrent 和 Metalink 的恢復下載實用程序,支持通過 RPC 接口進行控制。它的[功能豐富](https://aria2.github.io/manual/en/html/README.html)令人難以置信,並且有大量的[選項](https://aria2.github.io/manual/en/ html/aria2c.html)。還有 [ziahamza/webui-aria2](https://github.com/ziahamza/webui-aria2) - 一個不錯的網路介面搭配。 ![aria2c-example-usage](https://i.ibb.co/pJkkX6x/aria2c.png) --- ### [`bat`](https://github.com/sharkdp/bat) - 讀取文件_(更好的`cat`)_ > `bat` 是 `cat` 的複製品,但具有語法高亮顯示和 git 集成。它是用 Rust 編寫的,性能非常好,並且有多個用於自定義輸出和主題的選項。支持自動管道和文件連接 ![bat-example-usage](https://i.ibb.co/VND3Y9s/bat.png) --- ### [`diff-so-fancy`](https://github.com/so-fancy/diff-so-fancy) - 文件比較_(更好的`diff`)_ > `diff-so-fancy` 為比較字串、文件、目錄和 git 更改提供了更好看的差異。更改突出顯示使發現更改變得更加容易,並且您可以自定義輸出佈局和顏色 ![diff-so-fancy-example-usage](https://i.ibb.co/RGKLhQk/diff-so-fancy.png) --- ### [`entr`](https://github.com/eradman/entr) - 觀察變化 > `entr` 允許您在文件更改時執行任意命令。您可以傳遞一個文件、目錄、符號連結或正則表達式來指定它應該監視哪些文件。它對於自動重建專案、響應日誌、自動化測試等非常有用。與類似專案不同,它使用 kqueue(2) 或 inotify(7) 來避免輪詢,並提高性能 ![entr-example-usage](https://i.ibb.co/HHKQx2H/entr.png) --- ### [`exiftool`](https://github.com/exiftool/exiftool) - 讀取+寫入元資料 > ExifTool 是一個方便的實用程序,用於讀取、寫入、剝離和建立各種文件類型的元訊息。再次分享照片時不要不小心洩露您的位置! ![exiftool-example-usage](https://i.ibb.co/Gv5PN6v/exiftool.png) --- ### [`fdupes`](https://github.com/jbruchon/jdupes) - 重複文件查找器 > `jdupes` 用於辨識和/或刪除指定目錄中的重複文件。當您有兩個或更多相同的文件時,它對於釋放硬碟空間很有用 ![fdupes-example-usage](https://i.ibb.co/jhSY2Nn/fdupes.png) --- ### [`fzf`](https://github.com/junegunn/fzf) - 模糊文件查找器_(更好的`find`)_ > `fzf` 是一個非常強大且易於使用的模糊文件查找器和過濾工具。它允許您跨文件搜尋字串或模式。 fzf 也有可用於大多數 shell 和 IDE 的[插件](https://github.com/junegunn/fzf/wiki/Related-projects),用於在搜尋時顯示即時結果。這篇由 Alexey Samoshkin 撰寫的 [文章](https://www.freecodecamp.org/news/fzf-a-command-line-fuzzy-finder-missing-demo-a7de312403ff/) 重點介紹了它的一些用例。 ![fzf-示例用法](https://i.ibb.co/LNcwjWm/fzf.gif) --- ### [`hyperfine`](https://github.com/sharkdp/hyperfine) - 命令基準測試 > `hyperfine` 可以輕鬆準確地對任意命令或腳本進行基準測試和比較。它負責預熱執行、清除緩存以獲得準確的結果並防止來自其他程序的干擾。它還可以將結果導出為原始資料並生成圖表。 ![hyperfine-example-usage](https://i.ibb.co/tKNR5gr/hyperfine.png) --- ### [`just`](https://github.com/casey/just) - 現代命令執行器_(更好的`make`)_ > `just` 與 `make` 類似,但增加了一些不錯的功能。它讓您可以將專案命令分組到副本中,這些副本可以輕鬆列出和執行。支持別名、位置參數、不同的 shell、dot env 集成、字串插入以及幾乎所有您可能需要的東西 --- ### [`jq`](https://github.com/stedolan/jq) - JSON 處理器 > `jq` 類似於 `sed`,但對於 JSON - 您可以使用它輕鬆地切片、過濾、映射和轉換結構化資料。它可用於編寫複雜的查詢以提取或操作 JSON 資料。還有一個 [jq playground](https://jqplay.org/),您可以用來試用,或通過即時回饋制定查詢 --- ### [`most`](https://www.jedsoft.org/most/) - 多窗口滾動尋呼機_(更好的 less)_ > `most` 是一個尋呼機,用於讀取長文件或命令輸出。 `most` 支持多窗口並且可以選擇不換行 --- ### [`procs`](https://github.com/dalance/procs) - 進程查看器_(更好的 ps)_ > `procs` 是一個易於導航的流程查看器,它具有彩色突出顯示,使流程的排序和搜尋變得容易,具有樹視圖和實時更新 ![procs-example-usage](https://i.ibb.co/y6qhgDX/procs-demo.gif) --- ### [`rip`](https://github.com/nivekuil/rip) - 刪除工具_(更好的 rm)_ > `rip` 是一種安全、符合人體工程學且高性能的刪除工具。它讓您直觀地刪除文件和目錄,並輕鬆恢復已刪除的文件 ![rip-example-usage](https://i.ibb.co/10DTvT2/rip.gif) --- ### [`ripgrep`](https://github.com/BurntSushi/ripgrep) - 在文件中搜尋 _(更好的 `grep`)_ > `ripgrep` 是一種面向行的搜尋工具,可遞歸地在當前目錄中搜尋正則表達式模式。它可以忽略 .gitignore 的內容並跳過二進製文件。它能夠在壓縮檔案中搜尋,或只搜尋特定的擴展名,並使用各種編碼方法理解文件 ![ripgrep-example-usage](https://i.ibb.co/qkMgQm9/ripgrep.png) --- ### [`rsync`](https://rsync.samba.org/) - 快速、增量文件傳輸 > `rsync` 讓您可以在本地複制大文件,或將大文件複製到遠程主機或外部驅動器或從遠程主機或外部驅動器複製。它可用於保持多個位置的文件同步,非常適合建立、更新和恢復備份 --- ### [`sd`](https://github.com/chmln/sd) - 查找並替換_(更好的`sed`)_ > `sd` 是一種簡單、快速且直觀的查找和替換工具,基於字串文字。它可以在文件、整個目錄或任何管道文本上執行 ![sd-示例用法](https://i.ibb.co/G9CfcGS/sd.png) --- ### [`tre`](https://github.com/dduan/tre) - 目錄層次結構_(更好的`tree`)_ > `tre` 輸出當前目錄或指定目錄的樹形文件列表,並帶有顏色。使用“-e”選項執行時,它會為每個專案編號,並建立一個臨時別名,您可以使用該別名快速跳轉到該位置 ![tre-example-usage](https://i.ibb.co/CmMrZLB/tre.png) --- ### [`xsel`](https://github.com/kfish/xsel) - 存取剪貼板 > `xsel` 讓您通過命令行讀取和寫入 X 選擇剪貼板。它對於將命令輸出通過管道傳輸到剪貼板或將復制的資料傳輸到命令中很有用 --- ## CLI 監控和性能應用程式 ### [`bandwhich`](https://github.com/imsnif/bandwhich) - 頻寬利用率監視器 > 即時顯示頻寬使用情況、連接訊息、傳出主機和 DNS 查詢 ![bandwhich-example-usage](https://i.ibb.co/8jHHBD3/Screenshot-from-2023-01-18-22-45-32.png) --- ### [`ctop`](https://github.com/bcicen/ctop) - 容器指標和監控 > 類似於 `top`,但用於監控正在執行的(Docker 和 runC)容器的資源使用情況。它顯示實時 CPU、內存和網絡帶寬以及每個容器的名稱、狀態和 ID。還有一個內置的日誌查看器和管理(停止、啟動、執行等)容器的選項 ![ctop-example-usage](https://i.ibb.co/xGjyzZ2/ctop.gif) --- ### [`bpytop`](https://github.com/aristocratos/bpytop) - 資源監控_(更好的`htop`)_ > `bpytop` 是一種快速、交互式、可視化的資源監視器。它顯示了最熱門的執行進程、最近的 CPU、內存、磁盤和網絡歷史記錄。您可以從界面中導航、排序和搜尋——還支持自定義顏色主題 ![bpytop-example-usage](https://i.ibb.co/nj9jrhr/bpytop.gif) --- ### [`glances`](https://github.com/nicolargo/glances) - 資源監視器 + 網絡和 API > `glances` 是另一個資源監視器,但具有不同的功能集。它包括一個完全響應的 Web 視圖、一個 REST API 和歷史監控。它易於擴展,並且可以與其他服務集成 ![掃視示例用法](https://i.ibb.co/6g65Qy4/glances.gif) --- ### [`gping`](https://github.com/orf/gping) - 交互式 ping 工具 _(更好的 `ping`)_ > `gping` 可以在多個主機上執行 ping 測試,同時以實時圖形顯示結果。當與 --cmd 標誌一起使用時,它還可以用於監視執行時間 ![gping 示例用法](https://i.ibb.co/CvG6xt0/gping.gif) --- ### [`dua-cli`](https://github.com/Byron/dua-cli) - 磁盤使用分析器和監視器 _(更好的 `du`)_ > `dua-cli` 讓您以交互方式查看每個已安裝驅動器的已用和可用磁盤空間,並輕鬆釋放存儲空間 ![dua-cli-usage-example](https://i.ibb.co/x3NbDLR/dua.gif) --- ### [`speedtest-cli`](https://github.com/sivel/speedtest-cli) - 命令行速度測試實用程序 > `speedtest-cli` 只是執行網路速度測試,通過 speedtest.net - 但直接從終端 :) ![speedtest-cli-example-usage](https://i.ibb.co/25QCbdF/speedtest-cli.gif) --- ### [`dog`](https://github.com/ogham/dog) - DNS 查找客戶端_(更好的`dig`)_ > `dog` 是一個易於使用的 DNS 查找客戶端,支持 DoT 和 DoH,漂亮的彩色輸出和發出 JSON 的選項 ![dog-example-usage](https://i.ibb.co/48n617Q/dog.png) --- ## CLI 生產力應用程式 > 上網衝浪、播放音樂、查看電子郵件、管理日曆、閱讀新聞等等,無需離開終端! ### [`browsh`](https://github.com/browsh-org/browsh) - CLI 網路瀏覽器 > `browsh` 是一個完全交互的、實時的、現代的基於文本的瀏覽器,呈現給 TTY 和瀏覽器。它同時支持鼠標和鍵盤導航,並且對於純基於終端的應用程式來說功能豐富得令人吃驚。它還緩解了困擾現代瀏覽器的電池耗盡問題,並且通過對 MoSH 的支持,由於帶寬減少,您可以體驗更快的加載時間 ![browsh-example-usage](https://i.ibb.co/S7nLFX5/browsh.gif) --- ### [`books`](https://github.com/jarun/books) - 書籤管理器 > `buku` 是一個基於終端的書籤管理器,具有大量的配置、存儲和使用選項。還有一個可選的 [web UI](https://github.com/jarun/buku/tree/master/bukuserver#screenshots) 和 [瀏覽器插件](https://github.com/samhh/bukubrow-webext#installation ), 用於在終端外存取您的書籤 ![buku-example-usage](https://i.ibb.co/CWQsf1x/buku.png) --- ### [`cmus`](https://github.com/cmus/cmus) - 音樂瀏覽器/播放器 > `cmus` 是終端音樂播放器,由鍵盤快捷鍵控制。它支持廣泛的音頻格式和編解碼器,並允許將曲目組織到播放列表中並應用播放設置 ![cmus-example-usage](https://i.ibb.co/dP6b3bd/cmus.png) --- ### [`cointop`](https://github.com/cointop-sh/cointop) - 跟踪加密價格 > `cointop` 顯示當前的加密貨幣價格,並跟踪您的投資組合的價格歷史。支持價格提醒、歷史圖表、貨幣換算、模糊搜尋等。您可以通過網絡 [cointop.sh](https://cointop.sh/) 或執行 `ssh cointop.sh` 來嘗試演示 ![cointop-example-usage](https://i.ibb.co/JBf9y4y/cointop.png) --- ### [`ddgr`](https://github.com/jarun/ddgr) - 從終端搜尋網頁 > `ddgr` 類似於 [googler](https://github.com/jarun/googler),但適用於 DuckDuckGo。它快速、乾淨、簡單,支持即時回答、搜尋完成、搜尋 bangs 和高級搜尋。它默認尊重您的隱私,也有 HTTPS 代理支持,並與 Tor 一起工作 ![dggr-example-usage](https://i.ibb.co/S0H21QH/dggr.png) --- ### [`micro`](https://github.com/zyedidia/micro) - 程式碼編輯器_(更好的`nano`)_ > `micro` 是一款易於使用、快速且可擴展的程式碼編輯器,支持鼠標。由於它被打包成一個二進製文件,安裝就像`curl https://getmic.ro | 安裝一樣簡單。慶典` --- ### [`khal`](https://github.com/pimutils/khal) - 日曆客戶端 > `khal` 是一個終端日曆應用程式,它顯示即將發生的事件、月份和議程視圖。您可以將它與任何 CalDAV 日曆同步,並直接加入、編輯和刪除事件 ![khal-example-usage](https://i.ibb.co/hLCdjZW/khal.png) --- ### [`mutt`](https://gitlab.com/muttmua/mutt) - 電子郵件客戶端 > `mut` 是一個經典的、基於終端的郵件客戶端,用於發送、閱讀和管理電子郵件。它支持所有主流電子郵件協議和郵箱格式,允許附件、密件抄送/抄送、線程、郵件列表和傳遞狀態通知 ![mutt-example-usage](https://i.ibb.co/zVVsG3s/mutt.webp) --- ### [`newsboat`](https://github.com/newsboat/newsboat) - RSS / ATOM 新聞閱讀器 > `newsboat` 是一個 RSS 提要閱讀器和聚合器,用於直接從終端閱讀新聞、博客和後續更新 ![newsboat-example-usage](https://i.ibb.co/fvT4YzD/newsboat.png) --- ### [`rclone`](https://github.com/rclone/rclone) - 管理雲存儲 > `rclone` 是一個方便的實用程序,用於將文件和文件夾同步到各種雲存儲提供商。它可以直接從命令行呼叫,也可以輕鬆集成到腳本中以替代繁重的桌面同步應用程式 --- ### [`taskwarrior`](https://github.com/GothenburgBitFactory/taskwarrior) - Todo + 任務管理 > `task` 是一個 CLI 任務管理/待辦事項應用程式。它既簡單又不引人注目,但也非常強大和可擴展,內置高級組織和查詢功能。還有很多(700+!)額外的[插件](https://taskwarrior.org/tools/) 用於擴展它的功能和與第三方服務的集成 ![任務戰士示例用法](https://i.ibb.co/7k6M37g/taskwarrior.jpg) --- ### [`tuir`](https://gitlab.com/ajak/tuir) - Reddit 的終端用戶界面 > `tuir` 是一個很好的選擇,如果你想看起來像在工作,同時實際瀏覽 Reddit!它具有直觀的鍵綁定、自定義主題,還可以呈現圖像和多媒體內容。還有 [haxor](https://github.com/donnemartin/haxor-news) 用於黑客新聞 ![tuir-example-usage](https://i.ibb.co/vzSw7s5/tuir.png) --- ## CLI 開發套件 ### [`httpie`](https://github.com/httpie/httpie) - HTTP/API測試測試客戶端 > `httpie` 是一個 HTTP 客戶端,用於測試、除錯和使用 API。它支持您所期望的一切——HTTPS、代理、身份驗證、自定義標頭、持久會話、JSON 解析。具有表達語法和彩色輸出的用法很簡單。與其他 HTTP 客戶端(Postman、Hopscotch、Insomnia 等)一樣,HTTPie 也包含一個 Web UI ![httpie-示例用法](https://i.ibb.co/Wk5S19g/httpie.png) --- ### [`lazydocker`](https://github.com/jesseduffield/lazydocker) - 完整的 Docker 管理應用程式 > `lazydocker` 是一個 Docker 管理應用程式,可讓您查看所有容器和圖像、管理它們的狀態、讀取日誌、檢查資源使用情況、重新啟動/重建、分析層、修剪未使用的容器、圖像和卷等等。它使您無需記住、鍵入和連結多個 Docker 命令。 ![lazy-docker-example-usage](https://i.ibb.co/MD8MWNH/lazydocker.png) --- ### [`lazygit`](https://github.com/jesseduffield/lazygit) - 完整的 Git 管理應用程式 > `lazygit` 是一個可視化的 git 客戶端,在命令行上。輕鬆加入、提交和推送文件、解決衝突、比較差異、管理日誌以及執行壓縮和倒帶等複雜操作。一切都有鍵綁定,顏色,而且很容易配置和擴展 ![lazy-git-example-usage](https://i.ibb.co/KLF3C6s/lazygit.png) --- ### [`kdash`](https://github.com/kdash-rs/kdash/) - Kubernetes 儀表板應用程式 > `kdash` 是一個一體化的 Kubernetes 管理工具。查看節點指標、觀察資源、流容器日誌、分析上下文和管理節點、pod 和命名空間 --- ### [`gdp-dashboard`](https://github.com/cyrus-and/gdb-dashboard) - 可視化 GDP 除錯器 > `gdp-dashboard` 向 GNU 除錯器加入了一個可視元素,用於除錯 C 和 C++ 程序。輕鬆分析內存、單步執行斷點和查看寄存器 ![gdp-dashboard-example-usage](https://i.ibb.co/2g2hVLh/gdp-dashboard.png) --- ## CLI 外部服務 ### [`ngrok`](https://ngrok.com/) - 共享本地主機的反向代理 > `ngrok` 安全* 將您的本地主機暴露在唯一 URL 後面的網路上。這使您可以與遠程同事實時共享您的工作。使用[非常簡單](https://notes.aliciasykes.com/p/RUi22QSyWe),但它也有很多高級功能,例如身份驗證、webhooks、防火牆、流量檢查、自定義/通配符域等等 ![ngrok-示例用法](https://i.ibb.co/4WPZNGx/ngrok.png) --- ### [`tmate`](https://tmate.io/) - 通過網路共享終端會話 > `tmate` 讓您立即與世界其他地方的人分享實時終端會話。跨系統工作,支持存取控制/授權,可自託管,具備Tmux的所有特性 --- ### [`asciinema`](https://asciinema.org/) - 錄製+分享終端會話 > `asciinema` 對於輕鬆記錄、共享和嵌入終端會話非常有用。非常適合展示您建置的內容,或展示教程的命令行步驟。與屏幕錄製視頻不同,用戶可以復制粘貼內容、動態更改主題和控製播放 --- ### [`navi`](https://github.com/denisidoro/navi) - 交互式備忘單 > `navi` 允許您瀏覽備忘單並執行命令。參數的建議值動態顯示在列表中。減少輸入,減少錯誤,讓自己不必記住數千條命令。它集成了 [tldr](https://github.com/tldr-pages/tldr) 和 [cheat.sh](https://github.com/chubin/cheat.sh) 以獲取內容,但您也可以導入其他備忘單,甚至編寫自己的備忘單 --- ### [`transfer.sh`](https://github.com/dutchcoders/transfer.sh/) - 快速文件共享 > `transfer` 使上傳和共享文件變得非常簡單,直接從命令行即可。它是免費的,支持加密,為您提供唯一的 URL,也可以自行託管。 > 我寫了一個 Bash 輔助函數來讓使用更容易一些,你可以[在這裡找到它](https://github.com/Lissy93/dotfiles/blob/master/utils/transfer.sh) 或嘗試一下通過執行`bash <(curl -L -s https://alicia.url.lol/transfer)` ![transfer-sh-example-usage](https://i.ibb.co/cCqDb1k/transfer-sh.png) --- ### [`surge`](https://surge.sh/) - 在幾秒鐘內部署一個站點 > `surge` 是一個免費的靜態託管服務提供商,您可以通過一個命令直接從終端部署到它,只需在您的 `dist` 目錄中執行 `surge`!它支持自定義域、自動 SSL 憑證、pushState 支持、跨域資源支持——而且是免費的! ![surge-sh-example-usage](https://i.ibb.co/NynprxZ/surge-sh.png) --- ### [`wttr.in`](https://github.com/chubin/wttr.in) - 查看天氣 > `wttr.in` 是一項以命令行中易於理解的格式顯示天氣的服務。只需執行“curl wttr.in”或“curl wttr.in/London”來嘗試一下。有 URL 參數來自定義返回的資料以及格式 ![wrrt-in-example-usage](https://i.ibb.co/J2JWnYT/Screenshot-from-2023-01-18-21-10-54.png) --- ## CLI 樂趣 ### [`cowsay`](https://en.wikipedia.org/wiki/Cowsay) - 讓 ASCII 牛說出你的訊息 > `cowsay` 是一個可配置的會說話的奶牛。它基於 Tony Monroe 的[原創](https://github.com/tnalpgge/rank-amateur-cowsay) ![cowsay-example-usage](https://i.ibb.co/TRqW3jD/cowsay.png) --- ### [`figlet`](http://www.figlet.org/) - 將文本輸出為大型 ASCII 藝術文本 > `figlet` 將文本輸出為 ASCII 藝術 ![figlet-example-usage](https://i.ibb.co/fk4T7D0/figlet.png) --- ### [`lolcat`](https://github.com/busyloop/lolcat) - 使控制台輸出彩虹色 > `lolcat` 使任何傳遞給它的文本變成彩虹色 ![lolcat-example-usage](https://i.ibb.co/nfp9Ycx/lolcat.png) --- ### [`neofetch`](https://github.com/dylanaraps/neofetch) - 顯示系統資料和 ditstro 訊息 > `neofetch` 打印發行版和系統訊息(這樣你就可以靈活地在 r/unixporn 上使用 Arch btw) ![neofetch-example-usage](https://i.ibb.co/x1PHpFC/Screenshot-from-2023-01-18-22-44-28.png) 例如,我使用 `cowsay`、`figlet`、`lolcat` 和 `neofetch` 來建立一個自定義的基於時間的 MOTD,在用戶首次登錄時顯示給他們。它以他們的名字問候他們,顯示伺服器訊息和時間、日期、天氣和 IP。 [這裡是源程式碼](https://github.com/Lissy93/dotfiles/blob/master/utils/welcome-banner.sh)。 ![歡迎](https://i.ibb.co/cTg0jyn/Screenshot-from-2023-01-18-22-59-28.png) --- ## 安裝和管理 我們大多數人都有一套核心的 CLI 應用程式和我們所依賴的實用程序。設置一台新機器並單獨安裝每個程序很快就會讓人厭煩。因此,安裝和更新終端應用程式的任務非常適合自動化。 [此處](https://github.com/Lissy93/dotfiles/tree/master/scripts/installs) 是我編寫的一些示例腳本,可以輕鬆將其放入您的點文件或獨立執行以確保您永遠不會錯過一個應用程式。 對於 MacOS 用戶,最簡單的方法是使用 [Homebrew](https://brew.sh/)。只需建立一個 Brewfile(使用 `touch ~/.Brewfile`),然後列出您的每個應用程式,然後執行 `brew bundle`。您可以通過將其放入 Git 存儲庫來備份您的包列表。這是一個示例,讓您入門:https://github.com/Lissy93/Brewfile 在 Linux 上,您通常希望使用本機包管理器(例如 `pacman`、`apt`)。例如,[這裡有一個腳本](https://github.com/Lissy93/dotfiles/blob/master/scripts/installs/arch-pacman.sh) 用於在 Arch Linux 系統上安裝上述應用程式 Linux 上的桌面應用程式可以通過 Flatpak 以類似的方式進行管理。同樣,[這是一個示例腳本](https://github.com/Lissy93/dotfiles/blob/master/scripts/installs/flatpak.sh) :) --- ## 結論 ...就是這樣 - 一個方便的 CLI 應用程式列表,以及一種在您的系統中安裝和保持它們最新的方法。 希望其中一些對你們中的一些人有用:)

JavaScript 系列六:第5課 ── 熟悉匿名函式

## 課程目標 能夠在陣列更新元素 繼續熟悉 anonymous function 的觀念 ## 課程內容 這課先介紹一種資料型態:布林(boolean) 這種資料型態,幾乎所有程式語言都有,是一種寫程式必備的基本資料型態 ``` var x = true; var y = false; if (x) { alert('hello x'); } if (y) { alert('hello y'); } ``` 布林值只有 `true` 跟 `false` 兩種,在 if/else 條件流程控制中,會影響程式流程 這種型態,也是建造 data model 時一定會用到的型態 --- 在 JavaScript 更新陣列元素的方法,一樣有非常多種 這邊介紹一種根據索引更新的方法 ``` var fruits = ['apple', 'banana', 'orange']; fruits[2] = 'lemon'; console.log(fruits) ``` 老話一句,就是實務上,你就根據情況,隨便找一個能用的方式,來操作陣列就對了 ## 課後作業 接續上一課作業,這次來實作「已完成」按鈕 data model 的結構請更新成這樣 ``` var todos = [ { title: "倒垃圾", category: "normal", isCompleted: false }, { title: "繳電話費", category: "important", isCompleted: false }, { title: "採買本週食材", category: "urgent", isCompleted: false }, ]; ``` 請更新 `render` 函式,讓 UI 看起來像這樣 ``` - 倒垃圾 [標示為已完成][刪除] - 繳電話費 [標示為已完成][刪除] - 採買本週食材 [標示為已完成][刪除] ``` 如果倒完垃圾了,就可以點擊按鈕,來備註已完成,這時才顯示 (已完成) 文字 ``` - 倒垃圾(已完成)[標示為未完成][刪除] - 繳電話費 [標示為已完成][刪除] - 採買本週食材 [標示為已完成][刪除] ``` 然後在 render 過程中,動態產生 button 的時候,將 `.onclick` 屬性設定為一個 arrow function 這個 arrow function 不能直接更新 DOM,而是先去更新 data model,接著 render,用這種方式間接更新 DOM ``` toggleBtn.onclick = () => { // 請寫出此 arrow function 內容(更新 todos 陣列) render(); }; ``` 做出以上功能,你就完成這次的課程目標了!

JavaScript 系列六:第4課 ── 熟悉 render function

## 課程目標 繼續熟悉 render function 的觀念 ## 課程內容 render function 雖然只是將 data model 轉換成 UI 呈現在 root 裡面 但是根據資料內容的不同,render function 當然也可以有各種條件判斷、巢狀結構等等,較複雜的邏輯 ``` <div id="root"> </div> ``` ``` var products = [ { name: "冬季外套", category: "women", }, { name: "男士大衣", category: "men", }, ] render(); function render() { var root = document.querySelector('#root'); root.textContent = ""; for (product of products) { var name = document.createElement('div'); name.textContent = '商品名稱:' + product.name; if (product.category == 'men') { name.style.color = 'blue'; } else if (product.category == 'women') { name.style.color = 'red'; } root.append(name); } } ``` 別忘了 render function 肩負呈現 UI 的重責大任 所以 `render` 會看起來比較複雜 但是,除了 `render` 以外的函式,通通都變簡單了 ## 課後作業 接續上一課作業,這次來實作「急迫性分類」 data model 的結構請更新成這樣 ``` var todos = [ { title: "倒垃圾", category: "normal" }, { title: "繳電話費", category: "important" }, { title: "採買本週食材", category: "urgent" }, ]; ``` 然後 html 的部份會變成像這樣 ``` <input type="text"> <button onclick="add()">新增</button> <select> <option value="normal">一般</option> <option value="important">重要</option> <option value="urgent">緊急</option> </select> <div id="root"> </div> ``` 請更新 `render` 函式,將重要事項顯示為「橘色」,緊急事項顯示為「紅色」 做出以上功能,你就完成這次的課程目標了!

JavaScript 系列六:第3課 ── 認識匿名函式

## 課程目標 能夠從陣列刪除元素 認識 for in 迴圈寫法 認識匿名函式(anonymous function) ## 課程內容 在 JavaScript 中,刪除陣列元素的方法,有超多種 這邊介紹一種根據索引刪除的方法 ``` var fruits = ["apple", "banana", "orange"]; var index = 1; var num = 1; fruits.splice(index, num) console.log(fruits) ``` `.splice()` 函式第一個傳索引,第二個傳要刪的數量,通常就傳 1 就好了(一次刪一個即可) 實務上,你就根據情況,隨便找一個能用的方式,來操作陣列就對了 --- 之前我們介紹過 for of 的寫法,很簡單好用 ``` var fruits = ["apple", "banana", "orange"]; for (const fruit of fruits) { console.log(fruit) } ``` 這邊多介紹一個 for in 的寫法,需要索引時可以用 ``` var fruits = ["apple", "banana", "orange"]; for (const index in fruits) { const fruit = fruits[index]; console.log(index); console.log(fruit); } ``` --- 最後來介紹匿名函式(anonymous function) 聽起來很玄,但其實就只是沒有名字的函式而已 以下是有名字的函式 ``` function hello1() { alert("hello1"); } var hello2 = () => { alert("hello2"); } ``` 以下是沒有名字的函式 ``` <button> hello </button> ``` ``` var button = document.querySelector('button'); button.onclick = () => { alert(123) }; ``` 動態宣告一個函式,然後直接指派、使用,就是匿名函式 在 JavaScript 中,很多時候,有些小任務,需要宣告新函式來用,但又懶得去設計命名那些的 這時候就可以用匿名函式來節省時間 雖然看起來有點不習慣、有點奇怪 但在實務上,非常多地方,其實都會用到匿名函式,算是 JavaScript 非常好用的一個功能、特性 ## 課後作業 接續上一課作業,這次來實作「刪除事項」 請更新 `render` 函式,讓 UI 看起來像這樣 ``` <ul> <li> <span>倒垃圾</span> <button>刪除</button> </li> <li> <span>繳電話費</span> <button>刪除</button> </li> <li> <span>採買本週食材</span> <button>刪除</button> </li> </ul> ``` 然後在過程中,動態產生 button 的時候,將 `.onclick` 屬性設定為一個 arrow function 這個 arrow function 不能直接更新 DOM,而是先去更新 data model,接著 render,用這種方式間接更新 DOM ``` deleteBtn.onclick = () => { // 請寫出此 arrow function 內容(更新 todos 陣列) render(); }; ``` --- 提示:由於 javascript 中 hoisting 的特性,for loop 拿到的索引,在裡面的 arrow function 中使用,很容易抓錯 關於索引一直拿不到的問題,請參閱這邊我跟 birdie 同學的討論 https://codelove.tw/@birdie2019/post/2anbka --- 做出以上功能,你就完成這次的課程目標了!

JavaScript 系列六:第1課 ── 認識 data model 與 render function

## 課程目標 認識 data model 的觀念 認識 render function 的觀念 ## 課程內容 如果電商網站上有這樣的內容 ``` <div> 商品名稱:<span id="name">冬季外套</span> 價格:<span id="price">$1,990</span> 分類:<span id="category">女裝</span> 剩餘數量:<span id="remain">5</span> </div> ``` 在網站上的任何操作,菜鳥工程師會覺得就直接去更新 DOM 就好了 在程式還小的時候,這樣開發沒問題 但是當專案變大之後,這樣的開發會遇到問題,程式碼會越來越難維護 這種很難維護的寫法,我稱之為「在各處胡亂更新各處 DOM」的寫法 --- 有經驗的工程師在開發的時候,會習慣將應用程式的「狀態」與程式的其他部份分開來 這個「狀態」我們叫 state 或者 model 或者 data model 實務上,這三種名詞都很常看到,我在文章中也會混雜著交互使用 同樣的電商頁面,資深工程師會覺得看到了以下 data model ``` var product = { name: "冬季外套", price: 1990, category: "women", remain: 5 } ``` 而在開發各種功能的時候,資深工程師會覺得,一律先更新 data model,再接著拿 data model 來呈現出 UI 比較好 這樣在開發複雜應用程式的時候,相關函式一律只要關心 data model 就好,不用管 UI 在思考的時候,腦子的負擔會小很多,因為你變得只要想著應用程式的「狀態」就好 --- 那麽只更新 data model,那何時更新 UI 呢? 這邊介紹一個簡單的方法,叫做 render function 就是放一個 root 元素,作為程式 UI 的容器 接著寫一個 render 函式,來根據 data model,畫出全部 UI 到 root 裡面 這個 render 函式有三個注意事項 - 第一行要先清空 UI - 在所有跟「狀態」有關操作的最後一行,都要呼叫這個函式 - 所有 DOM 操作一律由 render 函式處理(其他全部函式,通通禁止更新 DOM) 請在 jsfiddle 嘗試以下範例 ``` <div id="root"> </div> <button onclick="decrease()">decrese</button> <button onclick="increase()">increase</button> ``` ``` var product = { name: "冬季外套", price: 1990, category: "women", remain: 5 }; render(); function render() { var root = document.querySelector('#root'); root.textContent = ""; var name = document.createElement('div'); name.textContent = '商品名稱:' + product.name; var price = document.createElement('div'); price.textContent = '價格:' + product.price; var category = document.createElement('div'); category.textContent = '分類:' + product.category; var remain = document.createElement('div'); remain.textContent = '剩餘數量:' + product.remain; root.append(name); root.append(price); root.append(category); root.append(remain); } function decrease() { product.remain = product.remain - 1; render(); } function increase() { product.remain = product.remain + 1; render(); } ``` 這樣的寫法,很神奇地,關於 DOM 的操作通通放在 `render` 即可 雖然 `render` 函式變得很多行、很大、寫起來比較麻煩 但是除了 `render` 以外的函式,通通都變簡單了 這是「短期麻煩,長期方便」的一個明顯例子 ## 課後作業 在之前的課程,你開發過一個「待辦事項小工具」,甚至還加上了 local storage 儲存功能 在開發的過程中,我相信你有感覺到,程式碼越來越大團了,新功能雖然寫得出來,但越來越難寫了 回頭看看當初的程式碼,你會發現讀起來不容易,要再維護、擴充功能,也都不太容易 讓我們使用新方法,重新開發一次這個小工具 請使用 https://jsfiddle.net 並且建立一份新的 fiddle --- 這一課,不開發任何功能,先實作把 data model 給 render 出來的效果 請使用以下 html 作為 root 元素 ``` <div id="root"> </div> ``` 然後複製以下 js 使用,將 `render` 函式完成 ``` var todos = [ { title: "倒垃圾" }, { title: "繳電話費" }, { title: "採買本週食材" }, ]; function render() { // 請寫出此函式內容 } render(); ``` 在這段 js 中,`todos` 陣列,就是我們的 data model 最後,在畫面上,應該會出現以下內容 ``` <div id="root"> <ul> <li> <span>倒垃圾</span> </li> <li> <span>繳電話費</span> </li> <li> <span>採買本週食材</span> </li> </ul> </div> ``` 做出以上功能,你就完成這次的課程目標了!

現代前端框架的背後觀念:新手必讀基本功

框架背後有什麼必學觀念的?這篇文章簡單整理如下 原文出處:https://dev.to/lexlohr/concepts-behind-modern-frameworks-4m1g --- 很多初學者會問“我應該學哪個框架?”和“學一個框架之前需要學多少JS或TS?” - 無數自以為是的文章都在宣傳作者首選框架或庫的優勢,而不是向讀者展示其背後的概念、教他們如何做出明智的決定。讓我們先解決第二個問題: ## “在學習框架之前要學多少 JS/TS?” 盡可能多地理解它們的基本概念。您將需要了解基本資料類型、函數、基本運算符和文檔對像模型 (DOM),這是 HTML 和 CSS 在 JS 中的基礎。雖然先學一點當然沒關係,但沒必要先精通框架或庫。 如果您是一個完全的初學者,[JS for cats](http://jsforcats.com/) 可能是您第一步的好資源。繼續前進,直到您感到自信為止,然後繼續前進,直到您開始感到自信不足。那就是你了解足夠的 JS/TS 並可以開始學框架的時間。其餘的你可以邊走邊學。 ## “你指的是什麼概念?” - 狀態 - 效果 - 記憶化 - 模板和渲染 所有現代框架都從這些概念中衍伸出它們的功能。 ### 狀態 狀態只是讓您的應用程式跑起來的資料。它可能在全局級別上,適用於應用程式的較大部分,或適用於單個元件。讓我們以一個簡單的計數器為例。它保留的計數是狀態。我們可以讀取狀態並寫入狀態以增加計數。 最簡單的表示通常是一個變數,其中包含我們的狀態所包含的資料: ``` let count = 0; const increment = () => { count++; }; const button = document.createElement('button'); button.textContent = count; button.addEventListener('click', increment); document.body.appendChild(button); ``` 但是這段程式碼有一個問題:對 count 的更改,就像對 increment 所做的更改一樣,不會更新按鈕的文本內容。我們可以手動更新所有內容,但這對於更複雜的用例來說並不能很好地擴展。 `count` 更新其用戶的能力稱為*反應性*。這是通過訂閱並重新執行應用程式的訂閱部分來更新的。 幾乎每個現代前端框架和庫都有一種響應式管理狀態的方法。解決方案分為三部分,至少採用其中之一或混合使用: - Observables / Signals - Reconciliation of immutable updates - Transpilation #### Observables / Signals Observables 基本上是允許藉由訂閱閱讀器的函數來進行讀取的結構。然後訂閱者在更新時重新執行: ``` const state = (initialValue) => ({ _value: initialValue, get: function() { /* subscribe */; return this._value; }, set: function(value) { this._value = value; /* re-run subscribers */; } }); ``` 這個概念的第一個用途之一是在 [knockout](https://knockoutjs.com/) 中,它使用相同的函數,帶和不帶參數進行寫/讀存取。 這種模式目前正在以「信號」的形式復興,例如在 [Solid.js](https://www.solidjs.com/docs/latest/api#createsignal) 和 [preact signals](https://preactjs.com /guide/v10/signals/),但在 [Vue](https://vuejs.org/) 和 [Svelte](https://svelte.dev/) 的底層使用了相同的模式。 [RxJS](https://rxjs.dev/) 為 [Angular](https://angular.io/) 的反應層提供動力,是這一原則的延伸,超越了簡單狀態,但有人可能會爭辯說它模擬複雜性的能力可能反而綁手綁腳。 [Solid.js](https://www.solidjs.com/) 還以儲存(可以通過 setter 操作的物件)和可變(可以像平常一樣使用的物件)的形式進一步抽象這些信號 JS 物件或 [Vue](https://vuejs.org/) 中的狀態來處理巢狀狀態物件。 #### Reconciliation of immutable states 不變性意味著如果一個物件的屬性發生變化,整個物件引用必須改變,所以簡單的引用比較可以很容易地檢測到是否有變化,這就是協調器所做的。 ``` const state1 = { todos: [{ text: 'understand immutability', complete: false }], currentText: '' }; // updating the current text: const state2 = { todos: state1.todos, currentText: 'understand reconciliation' }; // adding a to-do: const state3 = { todos: [ state.todos[0], { text: 'understand reconciliation', complete: true } ], currentText: '' }; // this breaks immutability: state3.currentText = 'I am not immutable!'; ``` 如您所見,未更改專案的引用被重新使用。如果協調器檢測到不同的物件引用,它會再次使用狀態(props, memos, effects, context)來重跑所有元件。由於讀取存取是被動的,這需要手動指定對反應值的依賴性。 顯然,您不是以這種方式定義狀態。您可以從現有屬性建置它,也可以使用所謂的 reducer。reducer 是一個函數,它接受一個狀態並返回另一個狀態。 [react](https://reactjs.org/) 和 [preact](https://preactjs.com/) 使用此模式。它適合與 vDOM 一起使用,我們將在稍後描述模板時探討它。 並非每個框架都使用其 vDOM 來使狀態完全響應。 例如 [Mithril.JS](https://mithril.js.org/components.html#state),元件會在設置的事件後變化後更新狀態;否則你必須手動觸發 `m.redraw()`。 #### Transpilation Transpilation 是一個建置步驟,它重寫我們的程式碼以使其在舊瀏覽器上執行或賦予它額外的能力;在這種情況下,該技術用於將簡單變數更改為反應系統的一部分。 [Svelte](https://svelte.dev/) 基於一個轉譯器,該轉譯器還通過看似簡單的變數宣告和存取為其反應式系統提供動力。 順便說一句,[Solid.js](https://solidjs.com) 使用轉譯,但不是針對它的狀態,只是針對模板。 ### 效果 在大多數情況下,我們需要對反應狀態做更多的事情,而不是從中衍伸並渲染到 DOM 中。我們必須管理副作用,這些都是由於視圖更新之外的狀態更改而發生的所有事情(儘管 [Solid.js](https://solidjs.com) 等一些框架也將視圖更改視為效果)。 還記得第一個例子中,訂閱處理被故意遺漏的狀態嗎?讓我們完成這個處理效果,來作為對更新的反應: ``` const context = []; const state = (initialValue) => ({ _subscribers: new Set(), _value: initialValue, get: function() { const current = context.at(-1); if (current) { this._subscribers.add(current); } return this._value; }, set: function(value) { if (this._value === value) { return; } this._value = value; this._subscribers.forEach(sub => sub()); } }); const effect = (fn) => { const execute = () => { context.push(execute); try { fn(); } finally { context.pop(); } }; execute(); }; ``` 這基本上是 [preact signals](https://preactjs.com/guide/v10/signals/) 或 [Solid.js](https://solidjs.com) 中反應狀態的簡化,沒有錯誤處理和狀態突變模式(使用接收前一個值並返回下一個值的函數),但這很容易加入。 它允許我們使前面的範例具有反應性: ``` const count = state(0); const increment = () => count.set(count.get() + 1); const button = document.createElement('button'); effect(() => { button.textContent = count.get(); }); button.addEventListener('click', increment); document.body.appendChild(button); ``` > ☝ 使用您的開發人員工具在 [空白頁面](about:blank) 中嘗試上述兩個程式碼塊。 在大多數情況下,框架允許不同的時間安排,讓效果在渲染 DOM 之前、期間或之後執行。 ### 記憶化 Memoization 意味著緩存從狀態計算的值,它會從狀態衍伸的變化更新時更新。它基本上是一種回傳衍伸狀態的效果。 在重新執行元件功能的框架中,例如 [react](https://reactjs.org/) 和 [preact](https://preactjs.com/),這讓某些複雜計算不需要每次都重複計算。 對於其他框架,情況恰恰相反:它允許您選擇部分組件進行響應式更新,同時緩存之前的計算。 對於我們簡單的反應式系統,memo 看起來像這樣: ``` const memo = (fn) => { let memoized; effect(() => { if (memoized) { memoized.set(fn()); } else { memoized = state(fn()); } }); return memoized.get; }; ``` ### 模板化和渲染 現在我們有了純的、衍伸的和緩存形式的狀態,我們想把它展示給用戶。在我們的範例中,我們直接使用 DOM 來加入按鈕並更新其文本內容。 為了對開發人員更加友好,幾乎所有現代框架都支持一些特定領域的語言來編寫類似於程式碼中所需輸出的內容。儘管有不同的風格,比如 `.jsx`、`.vue` 或 `.svelte` 文件,但它們都歸結為用類似於 HTML 的程式碼表示 DOM,因此基本上 ``` <div>Hello, World</div> // in your JS // becomes in your HTML: <div>Hello, World</div> ``` 你可能會問“我要把狀態放在哪裡?”。很好的問題。在大多數情況下,`{}` 用於表示屬性和節點周圍的動態內容。 最常用的 JS 模板語言擴展無疑是 JSX。對於 [react](https://reactjs.org),它被編譯為純 JavaScript,其方式允許它建立 DOM 的虛擬表示,一種稱為虛擬文檔對像模型或簡稱 vDOM 的內部視圖狀態。 這樣設計的原因是:建立物件比存取 DOM 快得多,所以如果你能用當前的替換後者,你可以節省時間。但是,如果您在任何情況下都有大量 DOM 更改或建立無數物件而沒有更改,則此解決方案的優點就變成必須通過「記憶化」來規避的缺點。 ``` // original code <div>Hello, {name}</div> // transpiled to js createElement("div", null, "Hello, ", name); // executed js { "$$typeof": Symbol(react.element), "type": "div", "key": null, "ref": null, "props": { "children": "Hello, World" }, "_owner": null } // rendered vdom /* HTMLDivElement */<div>Hello, World</div> ``` 不過,JSX 不僅限於 react。例如,Solid 使用其轉譯器更徹底地更改程式碼: ``` // 1. original code <div>Hello, {name()}</div> // 2. transpiled to js const _tmpl$ = /*#__PURE__*/_$template(`<div>Hello, </div>`, 2); (() => { const _el$ = _tmpl$.cloneNode(true), _el$2 = _el$.firstChild; _$insert(_el$, name, null); return _el$; })(); // 3. executed js code /* HTMLDivElement */<div>Hello, World</div> ``` 雖然轉譯後的程式碼乍看可能令人望而生畏,但解釋這裡發生的事情卻相當簡單。首先,建立包含所有靜態部分的模板,然後複製它以建立其內容的新實體,並加入動態部分並連接以根據狀態更改進行更新。 Svelte 走得更遠,不僅可以轉換模板,還可以轉換狀態。 ``` // 1. original code <script> let name = 'World'; setTimeout(() => { name = 'you'; }, 1000); </script> <div>Hello, {name}</div> // 2. transpiled to js /* generated by Svelte v3.55.0 */ import { SvelteComponent, append, detach, element, init, insert, noop, safe_not_equal, set_data, text } from "svelte/internal"; function create_fragment(ctx) { let div; let t0; let t1; return { c() { div = element("div"); t0 = text("Hello, "); t1 = text(/*name*/ ctx[0]); }, m(target, anchor) { insert(target, div, anchor); append(div, t0); append(div, t1); }, p(ctx, [dirty]) { if (dirty & /*name*/ 1) set_data(t1, /*name*/ ctx[0]); }, i: noop, o: noop, d(detaching) { if (detaching) detach(div); } }; } function instance($$self, $$props, $$invalidate) { let name = 'World'; setTimeout( () => { $$invalidate(0, name = 'you'); }, 1000 ); return [name]; } class Component extends SvelteComponent { constructor(options) { super(); init(this, options, instance, create_fragment, safe_not_equal, {}); } } export default Component; // 3. executed JS code /* HTMLDivElement */<div>Hello, World</div> ``` 也有例外。例如,在 [Mithril.js](https://mithril.js.org/) 中,雖然可以使用 JSX,但我們鼓勵您編寫 JS: ``` // 1. original JS code const Hello = { name: 'World', oninit: () => setTimeout(() => { Hello.name = 'you'; m.redraw(); }, 1000), view: () => m('div', 'Hello, ' + Hello.name + '!') }; // 2. executed JS code /* HTMLDivElement */<div>Hello, World</div> ``` 雖然大多數人會發現開發人員缺乏經驗,但其他人更喜歡完全控制他們的程式碼。根據他們主要想解決的問題,缺少轉譯步驟甚至可能是有益的。 儘管很少有人這樣推薦,許多其他框架都允許在不進行轉譯的情況下使用。 ## “我現在應該學習什麼框架或庫?” 我有一些好訊息和一些壞訊息要告訴你。 壞訊息是:沒有萬靈丹。沒有哪個框架在每個方面都比其他框架好得多。他們每個人都有自己的優勢和妥協。 [React](https://reactjs.org/) 有它的鉤子規則,[Angular](https://angular.io/) 缺乏簡單的信號,[Vue](https://vuejs.org/)缺乏向後兼容性,[Svelte](https://svelte.dev/) 不能很好地擴展,[Solid.js](https://www.solidjs.com/) 禁止解構,[Mithril.js]( https://mithril.js.org/) 並不是真正的反應式,僅舉幾例。 好訊息是:沒有錯誤的選擇——至少,除非專案的要求真的很有限,無論是在 bundle 大小還是性能方面。每個框架都會完成它的工作。有些人可能需要配合團隊的設計決策,這可能會使您的速度變慢,但無論如何您都應該能夠獲得可行的結果。 話雖這麼說,沒有框架也可能是一個可行的選擇。許多專案都被過度使用 JavaScript 破壞了。其實帶有一些互動性的靜態頁面就可以完成這項工作。 現在您已經了解了這些框架和庫應用的概念,請選擇最適合您當前任務的概念。不要害怕在下一個專案中切換框架。沒有必要學習所有這些。 如果你嘗試一個新的框架,我發現最有幫助的事情之一就是跟它的社群有所連結,無論是在社群媒體、discord、github 還是其他地方。他們可以告訴您哪些方法適合他們的框架,這將幫助您更快地獲得更好的解決方案。 ## “拜託,你*總是*有個人喜好吧!” 如果你的主要目標是就業,我建議學習 [react](https://reactjs.org/)。如果您想要輕鬆的性能和控制體驗,請嘗試 [Solid.js](https://solidjs.com);你可能會在 Solid 的 [Discord](https://discord.com/invite/solidjs) 上見到我。 但請記住,所有其他選擇都同樣有效。你不應該因為我這麼說就選擇一個框架,而應該使用最適合你的框架。

初次轉職寫程式:作品集有用嗎?要做什麼作品?面試官會看嗎?

很多朋友轉職寫程式,在補習班或者線上課程,告一段落之後,開始找工作之前,會整理作品集 關於作品集,簡單給大家一些建議 ## 作品集有用嗎? 公司在徵人的時候,其實來應徵的人五花八門 滿多人看起來,根本不會寫程式,連最基本的小網頁或者小程式都寫不出來 連基本技能都沒有準備好,感覺是到處碰碰運氣、履歷亂誇大就到處丟。公司面試時,最怕遇到這種狀況 作品集,至少代表,你寫得出基本東西。很多人根本寫都不會寫,就去應徵了,作品集至少可以讓公司避免踩雷 話說回來,如果你的作品集,只是補習班的幾個分組專案,糊裡糊塗地完成了,就跟在學校敷衍交報告一樣,你對細節其實不了解,那這種作品集,當然幫助不大,對你的信心也沒有多少幫助 ## 要做什麼作品? 所以該做什麼作品呢? 最好做一些你真的需要的「應用程式」,寫起來才有動力、才好玩,內容也才扎實 簡單舉例,如果你在受訓的過程是這些: ### 前端工程師 做個待辦事項清單工具吧!按照自己的喜好設計,做完之後找地方上線 在找工作的這幾個星期,實際拿這個工具來做紀錄,投履歷時、面試時,很自然可以分享你的心得跟小熱情 對面試官來說,看到面試者有即戰力(即便是有一點點)、對自己的程式有熱情(即便只有一點點),都會加分不少 請參考 https://todomvc.com/ 這是各種前端工具寫的 todo list 應用程式,你還可以比較自己的程式碼,與社群所寫的差異 ### 後端工程師 我鼓勵後端的入行者,寫一個「個人專屬部落格」 這個部落格要有以下功能 - 首頁列出文章清單 - 能簡單單篇文章瀏覽 - 自己可以登入後台 - 在後台可以新增、編輯、刪除文章 有餘力的話,還可以加個留言功能 這種部落格,會實際做完資料的 CRUD 基本功能,還有簡易的註冊、登入、驗證 找地方把這個部落格上線,或者買網址、租主機,實際上線 在找工作的這幾個星期,實際拿這個部落格,來寫文章、技術筆記、經驗分享 面試官絕對會覺得你是積極的人、有備而來 (錄取之後就停止寫網誌的習慣也沒關係) ### 全端工程師 我鼓勵全端的入行者,寫一個「個人行事曆工具」並且是 single page application (SPA) 這個行事曆要有以下功能 - 有一個行事曆頁面 - 有個按鈕可以新增活動 - 點擊行事曆內的活動,可以編輯、刪除 - 有一個清單業面,可以用條列式顯示全部活動 - 全程使用 ajax,不能整個刷新頁面 這種行事曆,會實際做完資料的 CRUD 基本功能,還有基本的 SPA routing 在找工作的這幾個星期,實際拿這個行事曆,紀錄生活是像、活動 面試時分享,面試官絕對會覺得你是積極的人、是個即戰力 ## 結論 除此之外,做個人履歷表的網頁也不錯 可以搜尋 'Portfolio website examples' 看看各種漂亮設計 實際把履歷做成網頁,也可稍微證明自己能力 在工程師生涯,不斷地做自己的 side project 是一個有趣、進步的好習慣 甚至有一天,你做的某個 side project 大受歡迎,還可能變成一個獨立的小產品呢 有空可以逛逛 https://www.producthunt.com/ 看看大家都在做什麼 side project 或許模仿其中一些,做個簡易版本,你會學到很多的~! --- 您有沒有什麼好的點子、推薦的 side project 點子給初心者呢? 歡迎留言分享!

快速複習 React 基本觀念&實務範例:推薦新手參考

React 作為一個強大的前端工具,有很多需要熟悉的基本觀念&語法。 這篇文章做一個快速的全面整理,方便工作時,可以隨時翻閱,希望您喜歡。 - 原文出處:https://dev.to/reedbarger/the-react-cheatsheet-for-2020-real-world-examples-4hgg ## 核心概念 ### 元素和 JSX - React 元素的基本語法 ``` // In a nutshell, JSX allows us to write HTML in our JS // JSX can use any valid html tags (i.e. div/span, h1-h6, form/input, etc) <div>Hello React</div> ``` - JSX 元素就是一段表達式 ``` // as an expression, JSX can be assigned to variables... const greeting = <div>Hello React</div>; const isNewToReact = true; // ... or can be displayed conditionally function sayGreeting() { if (isNewToReact) { // ... or returned from functions, etc. return greeting; // displays: Hello React } else { return <div>Hi again, React</div>; } } ``` - JSX 允許我們嵌套表達式 ``` const year = 2020; // we can insert primitive JS values in curly braces: {} const greeting = <div>Hello React in {year}</div>; // trying to insert objects will result in an error ``` - JSX 允許我們嵌套元素 ``` // to write JSX on multiple lines, wrap in parentheses: () const greeting = ( // div is the parent element <div> {/* h1 and p are child elements */} <h1>Hello!</h1> <p>Welcome to React</p> </div> ); // 'parents' and 'children' are how we describe JSX elements in relation // to one another, like we would talk about HTML elements ``` - HTML 和 JSX 的語法略有不同 ``` // Empty div is not <div></div> (HTML), but <div/> (JSX) <div/> // A single tag element like input is not <input> (HTML), but <input/> (JSX) <input name="email" /> // Attributes are written in camelcase for JSX (like JS variables <button className="submit-button">Submit</button> // not 'class' (HTML) ``` - 最基本的 React 應用程式需要三樣東西: - 1. ReactDOM.render() 渲染我們的應用程序 - 2. 一個 JSX 元素(在此情況下,稱為根節點) - 3. 一個用於掛載應用程式的 DOM 元素(通常是 index.html 文件中 id 為 root 的 div) ``` // imports needed if using NPM package; not if from CDN links import React from "react"; import ReactDOM from "react-dom"; const greeting = <h1>Hello React</h1>; // ReactDOM.render(root node, mounting point) ReactDOM.render(greeting, document.getElementById("root")); ``` ### 元件和 Props - 基本 React 元件的語法 ``` import React from "react"; // 1st component type: function component function Header() { // function components must be capitalized unlike normal JS functions // note the capitalized name here: 'Header' return <h1>Hello React</h1>; } // function components with arrow functions are also valid const Header = () => <h1>Hello React</h1>; // 2nd component type: class component // (classes are another type of function) class Header extends React.Component { // class components have more boilerplate (with extends and render method) render() { return <h1>Hello React</h1>; } } ``` - 如何使用元件 ``` // do we call these function components like normal functions? // No, to execute them and display the JSX they return... const Header = () => <h1>Hello React</h1>; // ...we use them as 'custom' JSX elements ReactDOM.render(<Header />, document.getElementById("root")); // renders: <h1>Hello React</h1> ``` - 元件可以在我們的應用程式中重複使用 ``` // for example, this Header component can be reused in any app page // this component shown for the '/' route function IndexPage() { return ( <div> <Header /> <Hero /> <Footer /> </div> ); } // shown for the '/about' route function AboutPage() { return ( <div> <Header /> <About /> <Testimonials /> <Footer /> </div> ); } ``` - 資料可以通過 props 動態傳遞給元件 ``` // What if we want to pass data to our component from a parent? // I.e. to pass a user's name to display in our Header? const username = "John"; // we add custom 'attributes' called props ReactDOM.render( <Header username={username} />, document.getElementById("root") ); // we called this prop 'username', but can use any valid JS identifier // props is the object that every component receives as an argument function Header(props) { // the props we make on the component (i.e. username) // become properties on the props object return <h1>Hello {props.username}</h1>; } ``` - Props 不可直接改變(mutate) ``` // Components must ideally be 'pure' functions. // That is, for every input, we be able to expect the same output // we cannot do the following with props: function Header(props) { // we cannot mutate the props object, we can only read from it props.username = "Doug"; return <h1>Hello {props.username}</h1>; } // But what if we want to modify a prop value that comes in? // That's where we would use state (see the useState section) ``` - 如果我們想將元素/元件作為 props 傳遞給其它元件,可以用 children props ``` // Can we accept React elements (or components) as props? // Yes, through a special property on the props object called 'children' function Layout(props) { return <div className="container">{props.children}</div>; } // The children prop is very useful for when you want the same // component (such as a Layout component) to wrap all other components: function IndexPage() { return ( <Layout> <Header /> <Hero /> <Footer /> </Layout> ); } // different page, but uses same Layout component (thanks to children prop) function AboutPage() { return ( <Layout> <About /> <Footer /> </Layout> ); } ``` - 可以用三元運算子來條件顯示元件 ``` // if-statements are fine to conditionally show , however... // ...only ternaries (seen below) allow us to insert these conditionals // in JSX, however function Header() { const isAuthenticated = checkAuth(); return ( <nav> <Logo /> {/* if isAuth is true, show AuthLinks. If false, Login */} {isAuthenticated ? <AuthLinks /> : <Login />} {/* if isAuth is true, show Greeting. If false, nothing. */} {isAuthenticated && <Greeting />} </nav> ); } ``` - Fragments 是用來顯示多個元件的特殊元件,無需向 DOM 添加額外的元素 - Fragments 適合用在條件邏輯 ``` // we can improve the logic in the previous example // if isAuthenticated is true, how do we display both AuthLinks and Greeting? function Header() { const isAuthenticated = checkAuth(); return ( <nav> <Logo /> {/* we can render both components with a fragment */} {/* fragments are very concise: <> </> */} {isAuthenticated ? ( <> <AuthLinks /> <Greeting /> </> ) : ( <Login /> )} </nav> ); } ``` ### 列表和 keys - 使用 .map() 將資料列表(陣列)轉換為元素列表 ``` const people = ["John", "Bob", "Fred"]; const peopleList = people.map(person => <p>{person}</p>); ``` - .map() 也可用來轉換為元件列表 ``` function App() { const people = ['John', 'Bob', 'Fred']; // can interpolate returned list of elements in {} return ( <ul> {/* we're passing each array element as props */} {people.map(person => <Person name={person} />} </ul> ); } function Person({ name }) { // gets 'name' prop using object destructuring return <p>this person's name is: {name}</p>; } ``` - 迭代的每個 React 元素都需要一個特殊的 `key` prop - key 對於 React 來說是必須的,以便能夠追蹤每個正在用 map 迭代的元素 - 沒有 key,當資料改變時,React 較難弄清楚元素應該如何更新 - key 應該是唯一值,才能讓 React 知道如何分辨 ``` function App() { const people = ['John', 'Bob', 'Fred']; return ( <ul> {/* keys need to be primitive values, ideally a generated id */} {people.map(person => <Person key={person} name={person} />)} </ul> ); } // If you don't have ids with your set of data or unique primitive values, // you can use the second parameter of .map() to get each elements index function App() { const people = ['John', 'Bob', 'Fred']; return ( <ul> {/* use array element index for key */} {people.map((person, i) => <Person key={i} name={person} />)} </ul> ); } ``` ### 事件和事件處理器 - React 和 HTML 中的事件略有不同 ``` // Note: most event handler functions start with 'handle' function handleToggleTheme() { // code to toggle app theme } // in html, onclick is all lowercase <button onclick="handleToggleTheme()"> Submit </button> // in JSX, onClick is camelcase, like attributes / props // we also pass a reference to the function with curly braces <button onClick={handleToggleTheme}> Submit </button> ``` - 最該先學的 React 事件是 onClick 和 onChange - onClick 處理 JSX 元素上的點擊事件(也就是按鈕動作) - onChange 處理鍵盤事件(也就是打字動作) ``` function App() { function handleChange(event) { // when passing the function to an event handler, like onChange // we get access to data about the event (an object) const inputText = event.target.value; const inputName = event.target.name; // myInput // we get the text typed in and other data from event.target } function handleSubmit() { // on click doesn't usually need event data } return ( <div> <input type="text" name="myInput" onChange={handleChange} /> <button onClick={handleSubmit}>Submit</button> </div> ); } ``` ## React Hooks ### State and useState - useState 為我們提供 function component 中的本地狀態 ``` import React from 'react'; // create state variable // syntax: const [stateVariable] = React.useState(defaultValue); function App() { const [language] = React.useState('javascript'); // we use array destructuring to declare state variable return <div>I am learning {language}</div>; } ``` - 注意:此段文章中的任何 hook 都來自 React 套件,且可以單獨導入 ``` import React, { useState } from "react"; function App() { const [language] = useState("javascript"); return <div>I am learning {language}</div>; } ``` - useState 還為我們提供了一個 `setter` 函數來更新它的狀態 ``` function App() { // the setter function is always the second destructured value const [language, setLanguage] = React.useState("python"); // the convention for the setter name is 'setStateVariable' return ( <div> {/* why use an arrow function here instead onClick={setterFn()} ? */} <button onClick={() => setLanguage("javascript")}> Change language to JS </button> {/* if not, setLanguage would be called immediately and not on click */} <p>I am now learning {language}</p> </div> ); } // note that whenever the setter function is called, the state updates, // and the App component re-renders to display the new state ``` - useState 可以在單個元件中使用一次或多次 ``` function App() { const [language, setLanguage] = React.useState("python"); const [yearsExperience, setYearsExperience] = React.useState(0); return ( <div> <button onClick={() => setLanguage("javascript")}> Change language to JS </button> <input type="number" value={yearsExperience} onChange={event => setYearsExperience(event.target.value)} /> <p>I am now learning {language}</p> <p>I have {yearsExperience} years of experience</p> </div> ); } ``` - useState 可以接受 primitive value 或物件 ``` // we have the option to organize state using whatever is the // most appropriate data type, according to the data we're tracking function App() { const [developer, setDeveloper] = React.useState({ language: "", yearsExperience: 0 }); function handleChangeYearsExperience(event) { const years = event.target.value; // we must pass in the previous state object we had with the spread operator setDeveloper({ ...developer, yearsExperience: years }); } return ( <div> {/* no need to get prev state here; we are replacing the entire object */} <button onClick={() => setDeveloper({ language: "javascript", yearsExperience: 0 }) } > Change language to JS </button> {/* we can also pass a reference to the function */} <input type="number" value={developer.yearsExperience} onChange={handleChangeYearsExperience} /> <p>I am now learning {developer.language}</p> <p>I have {developer.yearsExperience} years of experience</p> </div> ); } ``` - 如果新狀態依賴於之前的狀態,我們可以在 setter 函數中使用一個函數來為我們提供之前狀態的值 ``` function App() { const [developer, setDeveloper] = React.useState({ language: "", yearsExperience: 0, isEmployed: false }); function handleToggleEmployment(event) { // we get the previous state variable's value in the parameters // we can name 'prevState' however we like setDeveloper(prevState => { return { ...prevState, isEmployed: !prevState.isEmployed }; // it is essential to return the new state from this function }); } return ( <button onClick={handleToggleEmployment}>Toggle Employment Status</button> ); } ``` ### side effects 和 useEffect - useEffect 讓我們在 function component 中執行副作用。什麼是副作用? - 副作用是我們需要接觸外部世界的地方。例如,從 API 獲取資料或操作 DOM。 - 副作用是可能以不可預測的方式,改變我們元件狀態的操作(導致「副作用」)。 - useEffect 接受 callback function(稱為 effect 函數),預設情況下,每次重新渲染時都會運行 - useEffect 在我們的元件載入後運行,可以準確在元件的各個生命週期觸發 ``` // what does our code do? Picks a color from the colors array // and makes it the background color function App() { const [colorIndex, setColorIndex] = React.useState(0); const colors = ["blue", "green", "red", "orange"]; // we are performing a 'side effect' since we are working with an API // we are working with the DOM, a browser API outside of React useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; }); // whenever state is updated, App re-renders and useEffect runs function handleChangeIndex() { const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1; setColorIndex(next); } return <button onClick={handleChangeIndex}>Change background color</button>; } ``` - 如果不想在每次渲染後都執行 callback function,可以在第二個參數傳一個空陣列 ``` function App() { ... // now our button doesn't work no matter how many times we click it... useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; }, []); // the background color is only set once, upon mount // how do we not have the effect function run for every state update... // but still have it work whenever the button is clicked? return ( <button onClick={handleChangeIndex}> Change background color </button> ); } ``` - useEffect 讓我們能夠在 dependencies 陣列的內容改變時,才執行 - dependencies 陣列是第二個參數,如果陣列中的任何一個值發生變化,effect function 將再次運行 ``` function App() { const [colorIndex, setColorIndex] = React.useState(0); const colors = ["blue", "green", "red", "orange"]; // we add colorIndex to our dependencies array // when colorIndex changes, useEffect will execute the effect fn again useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; // when we use useEffect, we must think about what state values // we want our side effect to sync with }, [colorIndex]); function handleChangeIndex() { const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1; setColorIndex(next); } return <button onClick={handleChangeIndex}>Change background color</button>; } ``` - 可以在 useEffect 最後回傳一個函數,來取消訂閱某些效果 ``` function MouseTracker() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); React.useEffect(() => { // .addEventListener() sets up an active listener... window.addEventListener("mousemove", handleMouseMove); // ...so when we navigate away from this page, it needs to be // removed to stop listening. Otherwise, it will try to set // state in a component that doesn't exist (causing an error) // We unsubscribe any subscriptions / listeners w/ this 'cleanup function' return () => { window.removeEventListener("mousemove", handleMouseMove); }; }, []); function handleMouseMove(event) { setMousePosition({ x: event.pageX, y: event.pageY }); } return ( <div> <h1>The current mouse position is:</h1> <p> X: {mousePosition.x}, Y: {mousePosition.y} </p> </div> ); } // Note: we could extract the reused logic in the callbacks to // their own function, but I believe this is more readable ``` - 使用 useEffect 撈取資料 - 請注意,如果要使用更簡潔的 async/awit 語法處理 promise,則需要建立一個單獨的函數(因為 effect callback function 不能是 async) ``` const endpoint = "https://api.github.com/users/codeartistryio"; // with promises: function App() { const [user, setUser] = React.useState(null); React.useEffect(() => { // promises work in callback fetch(endpoint) .then(response => response.json()) .then(data => setUser(data)); }, []); } // with async / await syntax for promise: function App() { const [user, setUser] = React.useState(null); // cannot make useEffect callback function async React.useEffect(() => { getUser(); }, []); // instead, use async / await in separate function, then call // function back in useEffect async function getUser() { const response = await fetch("https://api.github.com/codeartistryio"); const data = await response.json(); setUser(data); } } ``` ### 效能和 useCallback - useCallback 是一個用來提高元件性能的 hook - 如果你有一個經常重新渲染的元件,useCallback 可以防止元件內的 callback function 在每次元件重新渲染時都重新創建(導致元件重新運行) - useCallback 僅在其依賴項之一改變時重新運行 ``` // in Timer, we are calculating the date and putting it in state a lot // this results in a re-render for every state update // we had a function handleIncrementCount to increment the state 'count'... function Timer() { const [time, setTime] = React.useState(); const [count, setCount] = React.useState(0); // ... but unless we wrap it in useCallback, the function is // recreated for every single re-render (bad performance hit) // useCallback hook returns a callback that isn't recreated every time const inc = React.useCallback( function handleIncrementCount() { setCount(prevCount => prevCount + 1); }, // useCallback accepts a second arg of a dependencies array like useEffect // useCallback will only run if any dependency changes (here it's 'setCount') [setCount] ); React.useEffect(() => { const timeout = setTimeout(() => { const currentTime = JSON.stringify(new Date(Date.now())); setTime(currentTime); }, 300); return () => { clearTimeout(timeout); }; }, [time]); return ( <div> <p>The current time is: {time}</p> <p>Count: {count}</p> <button onClick={inc}>+</button> </div> ); } ``` ### Memoization 和 useMemo - useMemo 和 useCallback 非常相似,都是為了提高效能。但就不是為了暫存 callback function,而是為了暫存耗費效能的運算結果 - useMemo 允許我們「記憶」已經為某些輸入進行了昂貴計算的結果(之後就不用重新計算了) - useMemo 從計算中回傳一個值,而不是 callback 函數(但可以是一個函數) ``` // useMemo is useful when we need a lot of computing resources // to perform an operation, but don't want to repeat it on each re-render function App() { // state to select a word in 'words' array below const [wordIndex, setWordIndex] = useState(0); // state for counter const [count, setCount] = useState(0); // words we'll use to calculate letter count const words = ["i", "am", "learning", "react"]; const word = words[wordIndex]; function getLetterCount(word) { // we mimic expensive calculation with a very long (unnecessary) loop let i = 0; while (i < 1000000) i++; return word.length; } // Memoize expensive function to return previous value if input was the same // only perform calculation if new word without a cached value const letterCount = React.useMemo(() => getLetterCount(word), [word]); // if calculation was done without useMemo, like so: // const letterCount = getLetterCount(word); // there would be a delay in updating the counter // we would have to wait for the expensive function to finish function handleChangeIndex() { // flip from one word in the array to the next const next = wordIndex + 1 === words.length ? 0 : wordIndex + 1; setWordIndex(next); } return ( <div> <p> {word} has {letterCount} letters </p> <button onClick={handleChangeIndex}>Next word</button> <p>Counter: {count}</p> <button onClick={() => setCount(count + 1)}>+</button> </div> ); } ``` ### Refs 和 useRef - Refs 是所有 React 組件都可用的特殊屬性。允許我們在元件安裝時,創建針對特定元素/元件的引用 - useRef 允許我們輕鬆使用 React refs - 我們在元件開頭呼叫 useRef,並將回傳值附加到元素的 ref 屬性來引用它 - 一旦我們創建了一個引用,就可以用它來改變元素的屬性,或者可以呼叫該元素上的任何可用方法(比如用 .focus() 來聚焦) ``` function App() { const [query, setQuery] = React.useState("react hooks"); // we can pass useRef a default value // we don't need it here, so we pass in null to ref an empty object const searchInput = useRef(null); function handleClearSearch() { // current references the text input once App mounts searchInput.current.value = ""; // useRef can store basically any value in its .current property searchInput.current.focus(); } return ( <form> <input type="text" onChange={event => setQuery(event.target.value)} ref={searchInput} /> <button type="submit">Search</button> <button type="button" onClick={handleClearSearch}> Clear </button> </form> ); } ``` ## 進階 Hook ### Context 和 useContext - 在 React 中,盡量避免創建多個 props 來將資料從父元件向下傳遞兩個或多個層級 ``` // Context helps us avoid creating multiple duplicate props // This pattern is also called props drilling: function App() { // we want to pass user data down to Header const [user] = React.useState({ name: "Fred" }); return ( // first 'user' prop <Main user={user} /> ); } const Main = ({ user }) => ( <> {/* second 'user' prop */} <Header user={user} /> <div>Main app content...</div> </> ); const Header = ({ user }) => <header>Welcome, {user.name}!</header>; ``` - Context 有助於將 props 從父組件向下傳遞到多個層級的子元件 ``` // Here is the previous example rewritten with Context // First we create context, where we can pass in default values const UserContext = React.createContext(); // we call this 'UserContext' because that's what data we're passing down function App() { // we want to pass user data down to Header const [user] = React.useState({ name: "Fred" }); return ( {/* we wrap the parent component with the provider property */} {/* we pass data down the computer tree w/ value prop */} <UserContext.Provider value={user}> <Main /> </UserContext.Provider> ); } const Main = () => ( <> <Header /> <div>Main app content...</div> </> ); // we can remove the two 'user' props, we can just use consumer // to consume the data where we need it const Header = () => ( {/* we use this pattern called render props to get access to the data*/} <UserContext.Consumer> {user => <header>Welcome, {user.name}!</header>} </UserContext.Consumer> ); ``` - useContext hook 可以移除這種看起來很怪的 props 渲染模式,同時又能在各種 function component 中隨意使用 ``` const Header = () => { // we pass in the entire context object to consume it const user = React.useContext(UserContext); // and we can remove the Consumer tags return <header>Welcome, {user.name}!</header>; }; ``` ### Reducers 和 useReducer - Reducers 是簡單、可預測的(純)函數,它接受一個先前的狀態物件和一個動作物件,並回傳一個新的狀態物件。例如: ``` // let's say this reducer manages user state in our app: function reducer(state, action) { // reducers often use a switch statement to update state // in one way or another based on the action's type property switch (action.type) { // if action.type has the string 'LOGIN' on it case "LOGIN": // we get data from the payload object on action return { username: action.payload.username, isAuth: true }; case "SIGNOUT": return { username: "", isAuth: false }; default: // if no case matches, return previous state return state; } } ``` - Reducers 是一種強大的狀態管理模式,用於流行的 Redux 狀態管理套件(這套很常與 React 一起使用) - 與 useState(用於本地元件狀態)相比,Reducers 可以通過 useReducer hook 在 React 中使用,以便管理我們應用程序的狀態 - useReducer 可以與 useContext 配對來管理資料並輕鬆地將資料傳遞給元件 - useReducer + useContext 可以當成應用程式的整套狀態管理系統 ``` const initialState = { username: "", isAuth: false }; function reducer(state, action) { switch (action.type) { case "LOGIN": return { username: action.payload.username, isAuth: true }; case "SIGNOUT": // could also spread in initialState here return { username: "", isAuth: false }; default: return state; } } function App() { // useReducer requires a reducer function to use and an initialState const [state, dispatch] = useReducer(reducer, initialState); // we get the current result of the reducer on 'state' // we use dispatch to 'dispatch' actions, to run our reducer // with the data it needs (the action object) function handleLogin() { dispatch({ type: "LOGIN", payload: { username: "Ted" } }); } function handleSignout() { dispatch({ type: "SIGNOUT" }); } return ( <> Current user: {state.username}, isAuthenticated: {state.isAuth} <button onClick={handleLogin}>Login</button> <button onClick={handleSignout}>Signout</button> </> ); } ``` ### 編寫 custom hooks - 創建 hook 就能輕鬆在元件之間重用某些行為 - hook 是一種比以前的 class component 更容易理解的模式,例如 higher-order components 或者 render props - 根據需要,隨時可以自創一些 hook ``` // here's a custom hook that is used to fetch data from an API function useAPI(endpoint) { const [value, setValue] = React.useState([]); React.useEffect(() => { getData(); }, []); async function getData() { const response = await fetch(endpoint); const data = await response.json(); setValue(data); }; return value; }; // this is a working example! try it yourself (i.e. in codesandbox.io) function App() { const todos = useAPI("https://todos-dsequjaojf.now.sh/todos"); return ( <ul> {todos.map(todo => <li key={todo.id}>{todo.text}</li>)} </ul> ); } ``` ### Hooks 規則 - 使用 React hooks 有兩個核心規則,要遵守才能正常運作: - 1. Hooks 只能在元件開頭呼叫 - Hooks 不能放在條件、迴圈或嵌套函數中 - 2. Hooks只能在 function component 內部使用 - Hooks 不能放在普通的 JavaScript 函數或 class component 中 ``` function checkAuth() { // Rule 2 Violated! Hooks cannot be used in normal functions, only components React.useEffect(() => { getUser(); }, []); } function App() { // this is the only validly executed hook in this component const [user, setUser] = React.useState(null); // Rule 1 violated! Hooks cannot be used within conditionals (or loops) if (!user) { React.useEffect(() => { setUser({ isAuth: false }); // if you want to conditionally execute an effect, use the // dependencies array for useEffect }, []); } checkAuth(); // Rule 1 violated! Hooks cannot be used in nested functions return <div onClick={() => React.useMemo(() => doStuff(), [])}>Our app</div>; } ``` --- 以上是快速整理,希望對您有幫助!