🔍 搜尋結果:app

🔍 搜尋結果:app

JavaScript 系列二:第1課 ── 認識 DOM 樹、新增元素

## 課程目標 認識 DOM 樹基本觀念 能夠在 DOM 樹進行「新增」 學會基本的除錯技巧 ## 課程內容 請打開這個網站,用這個網站來練習&寫作業: https://jsfiddle.net 在學 JavaScript 的時候,你會聽到很多人在講「DOM 樹」這個名詞 什麼是「DOM 樹」? 其實只是,你在網頁上看到的東西,瀏覽器會在背後的 JavaScript 環境,維持一個對應的「DOM 樹」 比如說,當你寫這樣的 html(這邊先省略內容,只留結構) ``` <html> <head> <script></script> </head> <body> <div> <h1></h1> <p></p> </div> </body> </html ``` 瀏覽器會在背後創造一個這樣的資料結構 ``` document └── html ├── head │   └── script └── body └── div ├── h1 └── p ``` 很像是樹吧?這就是「DOM 樹」 記得之前用過的 `document.getElementById` 嗎? 這就是 DOM 最上面的 document 物件 所謂的「DOM 樹」其實就是一個「巢狀物件」。 「巢狀物件」的意思是,物件的屬性,又是另一個物件,然後這物件的屬性,又可以是另一個物件 用 JavaScript 來表示的話,類似這樣(只是概念喔,真實的物件不只是這樣,而是有一堆內建函式與屬性可以用) ``` var document = { name: 'document', children: [ { name: 'html', children: [ { name: 'head', children: [ { name: 'script', children: [] } ] }, { name: 'body', children: [ { name: 'div', children: [ { name: 'h1', children: [] }, { name: 'p', children: [] } ] } ] } ] } ] } ``` 在 DOM 中,被包起來的元素,稱為子元素;把別人包起來的元素,稱為父元素。就跟學 html 時的稱呼一樣 瀏覽器會確保用戶介面(User Interface,簡稱 UI)上看到的,跟環境中實際運行的 DOM 長得一模一樣 也就是說,你修改 UI 的內容,DOM 物件就會自動更新;你用 JavaScript 修改 DOM 物件的內容,UI 就會自動更新 --- 來學學怎麼用 JavaScript 操作 DOM 樹吧! 如果原本 html 長這樣 ``` <div id="app"></div> ``` 只要加入這段程式碼 ``` var heading = document.createElement('h1'); heading.textContent = '這是標題'; var para = document.createElement('p'); para.textContent = '這是段落文字'; var app = document.getElementById('app'); app.append(heading); app.append(para); ``` 利用 document 的內建函數 `createElement` 來動態創造新的元素 修改元素的屬性 `.textContent` 來設定文字內容 接著用 `.append()` 函數來讓元素吃下別的元素,也就是「把另一個元素收為子元素」,就跟收養子女一樣! 最後 html 就會變成這樣 ``` <div id="app"> <h1>這是標題</h1> <p>這是段落文字</p> </div> ``` 馬上貼到 jsfiddle 試試看,實驗一下、玩玩看! --- 在寫 html 的時候,出現巢狀結構是很常見的 操作 DOM 時,當然也可以自由創造巢狀結構 ``` var elem1 = document.createElement('div'); elem1.textContent = 'level 1'; var elem2 = document.createElement('div'); elem2.textContent = 'level 2'; var elem3 = document.createElement('div'); elem3.textContent = 'level 3'; var app = document.getElementById('app'); app.append(elem1); elem1.append(elem2); elem2.append(elem3); ``` 到 jsfiddle 試試看,就會清楚實際效果囉! --- 在開發的過程中,基本上會不斷打錯字、寫錯用法。程式跑不出結果,很正常 這種時候,有兩個常用的除錯方法,我們叫「debug 的方法」 第一個方法是 `alert`,你就把不確定的內容,給 alert 出來看看就對了,到處寫 alert 看一下變數內容,確定內容跟預期一樣,再接著繼續寫 第二個方法是 `console.log()`,把參數傳進去,接著打開瀏覽器的「開發者工具」,就會看到結果,通常會比 alert 內容更詳細、更方便除錯 除此之外,JavaScript 相關的各種錯誤訊息,都會在「開發者工具」出現。請去研究你所使用的瀏覽器,如何打開這個工具 ``` var x = 123; var y = 'hello'; var z = document.createElement('div'); console.log(x) console.log(y) console.log(z) ``` 請打開瀏覽器的開發者工具,實際看一下上述範例的結果。 ## 課後作業 假設你是一個健忘的人,你決定寫一個「待辦事項管理」應用程式,來幫助自己 這一課,先實作「新增事項」的功能 --- 在上面,做一個文字輸入框,旁邊有一個「新增」按鈕 在下面,做一個展示待辦事項的清單,請使用這樣的結構,id 跟 css 之類的你可以自由決定 ``` <ul> <li> <span>倒垃圾</span> </li> <li> <span>繳電話費</span> </li> <li> <span>採買本週食材</span> </li> </ul> ``` 點擊「新增」按鈕,會將新事項插入到清單最底部 請稍微替這個清單工具加一點 css 屬性,弄得漂亮一點,這樣的工具才讓人想用 --- 除此之外,請練習一下 `console.log` 的用法,不然之後遇到錯誤,幾乎沒辦法除錯 請把作業內容中,出現的變數,隨便挑三個,用 `console.log` 印到開發者工具中,然後用瀏覽器看一下內容 --- 做出以上功能,你就完成這次的課程目標了!

給網站開發者:7 個值得在 2023 年用看看的免費工具

想要在 2023 年的 **Web 開發** 旅程中一帆風順嗎?參考看看這些免費工具吧! 原文出處:https://dev.to/ruppysuppy/7-free-tools-for-the-modern-web-developers-of-2023-4lhh ## 1. [Omatsuri](https://omatsuri.app/) 一個**開源 Web 應用程式**,有 **12 個令人難以置信的前端工具**,供日常開發使用。包含的工具有: 1. 三角形生成器 2. 顏色陰影生成器 3. 梯度產生器 4. 分頁器 5. SVG壓縮器 6. SVG → JSX 轉換器 7. base64編碼 8. 假資料生成器 9. 符號收錄 10. 假文字生成器 11. CSS 游標 12. 鍵盤事件程式碼 ![omatsuri](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ubhgroj9j4butoto73r.png) ## 2. [Coolers](https://coolors.co/) **Coolers** 是為您的網站生成 **調色板** 的最佳工具。 ![Coolers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q40qayjwocnseojux08a.png) ## 3. [Keyframes](https://keyframes.app/) 就跟名字一樣,它是: > 基於瀏覽器的、適合手機的、可以讓 **CSS** 變得不那麼糟糕的工具。 它有幾個工具,例如**動畫**、**陰影**和**顏色生成器**。 ![Keyframes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6f1h2a0caeb0yzx1hsg.png) ## 4. [Roadmap.sh](https://roadmap.sh/) **Roadmap**是一系列職涯路線圖,涵蓋了**前端**、**後端**、**區塊鏈**、**網路安全**等多個路徑。 他們也有**相關資源的連結**可供學習! ![Roadmap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppbw4ej1fvsbc8mzpjrr.png) ## 5. [FreeCodeCamp](https://www.freecodecamp.org/) **FreeCodeCamp** 是一個**非營利組織**,由**互動式學習網路平台**、**線上社群論壇**、**聊天室**、**線上出版物**、 **本地組織**組成,旨在讓任何人都可以學習 Web 開發。 ![FreeCodeCamp](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qh7mlh9jxlui5kq6755t.png) ## 6. [Postman](https://www.postman.com/) **Postman** 是一個用於建置和使用 **API** 的 **API 平台**。它是**後端工程師**工具庫中的必備工具,對**前端開發人員**也非常有用 ![Postman](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2q0c4046o2rrux6534y.png) ## 7. [CSS Layout](https://csslayout.io/) 它是**數百個元件**的集合,您可以將其複製貼上到您的專案中,並根據您的需要進行客製化! ![css-layout](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owuoadb9p06wqnvg7136.png) --- **以上供您參考!**

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

很多朋友轉職寫程式,在補習班或者線上課程,告一段落之後,開始找工作之前,會整理作品集 關於作品集,簡單給大家一些建議 ## 作品集有用嗎? 公司在徵人的時候,其實來應徵的人五花八門 滿多人看起來,根本不會寫程式,連最基本的小網頁或者小程式都寫不出來 連基本技能都沒有準備好,感覺是到處碰碰運氣、履歷亂誇大就到處丟。公司面試時,最怕遇到這種狀況 作品集,至少代表,你寫得出基本東西。很多人根本寫都不會寫,就去應徵了,作品集至少可以讓公司避免踩雷 話說回來,如果你的作品集,只是補習班的幾個分組專案,糊裡糊塗地完成了,就跟在學校敷衍交報告一樣,你對細節其實不了解,那這種作品集,當然幫助不大,對你的信心也沒有多少幫助 ## 要做什麼作品? 所以該做什麼作品呢? 最好做一些你真的需要的「應用程式」,寫起來才有動力、才好玩,內容也才扎實 簡單舉例,如果你在受訓的過程是這些: ### 前端工程師 做個待辦事項清單工具吧!按照自己的喜好設計,做完之後找地方上線 在找工作的這幾個星期,實際拿這個工具來做紀錄,投履歷時、面試時,很自然可以分享你的心得跟小熱情 對面試官來說,看到面試者有即戰力(即便是有一點點)、對自己的程式有熱情(即便只有一點點),都會加分不少 請參考 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 點子給初心者呢? 歡迎留言分享!

給軟體工程師的各類好用工具清單

向您介紹這個開發人員工具列表。它是一個開源專案,由社群整理。 讓我們開始吧! 🚀 原文出處:https://dev.to/dostonnabotov/ultimate-tools-for-developers-2aj2 --- ## 程式碼編輯器和 IDE 💻 - [Visual Studio Code](https://code.visualstudio.com/) 作為免費的開源程式碼編輯器,Visual Studio Code 是開發人員的絕佳工具。它帶有許多功能和外掛,使其成為開發人員的絕佳選擇。 - [CodeSandbox](https://codesandbox.io/) 簡單來說,CodeSandbox 就是 Visual Studio Code 的在線版本。 - [Dev - Visual Studio Code](https://github.dev/) github.dev 基於網絡的編輯器是一種輕量級的編輯體驗,完全在您的瀏覽器中執行。 有兩種方法可以打開基於 Web 的編輯器 1. 在任何存儲庫或拉取請求上按 `.` 鍵 2. 將 URL 中的 .com 替換為 .dev。例如。 `https://github.dev/username/repo` - [CodePen](http://codepen.io/) CodePen 是網絡前端的遊樂場。這是一個試驗、測試和展示您的前端工作的地方。此外,您還可以從其他開發人員那裡找到許多靈感。 - [Replit](https://repl.it/) Replit 是一個簡單、強大且協作的在線 IDE。這是編碼、協作和託管專案的好地方。 - [StackBlitz](https://stackblitz.com/) 面向前端和全棧開發人員的 Web IDE。 - [TypeScript Playground](https://www.typescriptlang.org/play/) 想玩玩看 TypeScript 嗎? TypeScript Playground 是一個適合你的地方。 ## 圖片 🖼 - [Unsplash](https://unsplash.com/) 為您的下一個專案輕鬆找到精美、高質量的照片。所有照片均可免費用於商業和個人用途。 - [Pexels](https://www.pexels.com/) Pexels 是免費庫存照片的重要來源。所有照片均可免費用於商業和個人用途。 - [Carbon](https://carbon.now.sh/) Carbon 是一個很棒的平台,可以建立和共享程式碼的精美圖像,允許您使用語法突出顯示、主題、字體等自定義圖像。 ## 顏色 🎨 - [Color Space](https://mycolor.space/) 再也不會浪費時間尋找完美的調色板!只需輸入顏色!並生成漂亮的調色板 - [Coolors](https://coolors.co/) 建立完美的調色板或從數千種美麗的配色方案中汲取靈感。 - [Color Wheel](https://www.canva.com/colors/color-wheel/) 想知道什麼顏色搭配起來好看嗎? Canva 的色輪讓色彩組合變得簡單。 ## 排版 📝 - [Google Fonts](https://fonts.google.com/) Google Fonts 是一個包含免費授權字體系列的庫。只需選擇您想要的字體,將它們下載到您的計算機或使用提供的 CSS 或 HTML 鏈接將它們嵌入您的網頁。 - [Fontsource](https://fontsource.org/) 如果您不想從 CDN 獲取字體,則可以使用整齊打包的 NPM 包中的自託管開源字體。 - [Nerd Fonts](https://www.nerdfonts.com/) Nerd Fonts 使用大量字形(圖標)修補針對開發人員的字體。 ## 設計 🎨 - [Figma](https://www.figma.com/) 一個免費的線上協作界面設計工具和原型製作工具。 - [Pinterest](https://www.pinterest.com/) Pinterest 是一種視覺發現工具,可用於為您的所有專案和興趣尋找創意。 ## 文檔 📚 - [MDN 網絡文檔](https://developer.mozilla.org/en-US/) 學習Web開發的最佳平台。每當您對 HTML、CSS、JavaScript 或任何其他網絡技術有疑問時,請務必先查看 MDN。 - [W3Schools](https://www.w3schools.com/) 幾乎所有您能想到的程式語言的參考。 - [CSS 技巧](https://css-tricks.com/) 提供使用 CSS(層疊樣式表)的提示、技巧和技術的最佳平台之一。 ## 工具 🛠 等一會兒!工具中的工具?是的,你沒有聽錯。這裡有一些工具可以幫助您找到更多工具。 😃 - [Stack Overflow](https://stackoverflow.com/) Stack Overflow 是一個面向專業和狂熱工程師的問答網站。這是提出問題和獲得答案的好地方。 - [Micro Digital Tools](https://mdigi.tools/) 一組對開發人員有用的工具。 - [Small Dev Tools](https://smalldev.tools/) 一組對開發人員有用的工具。 - [Can I Use](https://caniuse.com/) Can I Use 提供了最新的瀏覽器支持表,以支持桌面和移動 Web 瀏覽器上的前端 Web 技術。 - [網站圖標生成器](https://favicon.io/) 您是否曾經為了替自己的網站建立網站圖標而苦惱?不同的尺寸,不同的格式,不同的平台。 從文本、圖像或從數百個表情符號中選擇快速生成您的網站圖標。 - [Font Awesome](https://fontawesome.com/) 免費和高級圖標庫。 - [OverAPI.com](https://overapi.com/) 以有組織的格式查找大量不同技術的備忘單。 - [Transform](https://transform.tools/) 多語言網絡轉換器。輕鬆將 HTML 轉換為 Pug、將 TypeScript 轉換為 JavaScript、將 Markdown 轉換為 HTML 等等... - [Frontend Tools](https://murtazajoo.github.io/tools/) 一個網站,您可以在其中找到具有更好用戶體驗的所有工具。 - [GitProtect](https://gitprotect.io/) 適用於所有 GitHub、GitLab、Bitbucket 和 Jira 資料的 DevOps 備份和災難恢復軟體。 - [Linear](https://linear.app/) 在團隊中組織問題和拉取請求的好工具。 ## 結論 🎉 希望您覺得這個列表有用。

20 個冷門、但很實用的 git 指令:值得你稍微認識一下

如果您曾經瀏覽過 [git 手冊](https://git-scm.com/docs)(或執行 `man git`),那麼您會發現 git 指令比我們每天在用的多很多。很多指令非常強大,可以讓你的生活更輕鬆(有些比較小眾,但知道一下還是不錯)。 > 這篇文章整理了我最喜歡的 20 個冷門 git 功能,您可以使用來改善您的開發流程、給您的同事留下深刻印象、幫助您回答 git 面試問題,最重要的是 - 可以玩得很開心! 原文出處:https://dev.to/lissy93/20-git-commands-you-probably-didnt-know-about-4j4o --- ## Git Web > 執行 [`git instaweb`](https://git-scm.com/docs/git-instaweb) 可以立即瀏覽 gitweb 中的工作存儲庫 Git 有一個內建的[基於網路可視化工具](https://git-scm.com/docs/gitweb) 可以瀏覽本地存儲庫,它允許您通過瀏覽器中的 GUI 查看和管理您的存儲庫。它包含許多有用的功能,包括: - 瀏覽和單步執行修訂並檢查差異、文件內容和元資料 - 可視化查看提交日誌、分支、目錄、文件歷史和附加資料 - 生成提交和存儲庫活動日誌的 RSS 或 Atom 提要 - 搜尋提交、文件、更改和差異 要打開它,只需從您的存儲庫中執行 `git instaweb`。您的瀏覽器應該會彈出並讀取 http://localhost:1234 。如果您沒有安裝 Lighttpd,您可以使用“-d”標誌指定一個備用 Web 伺服器。其他選項可以通過標誌配置(例如 `-p` 用於端口,`-b` 用於打開瀏覽器等),或在 git 配置中的 `[instaweb]` 塊下配置。 還有 `git gui` 命令,它可以打開一個基於 GUI 的 git 應用程式 ![](https://i.ibb.co/0DrmcWG/Screenshot-from-2022-12-17-20-26-30.png) --- ## Git Notes > 使用 [`git notes`](https://git-scm.com/docs/git-notes) 向提交加入額外訊息 有時您需要將其他資料附加到 git 提交(除了更改、訊息、日期時間和作者訊息之外)。 註釋存儲在 .git/refs/notes 中,由於它與提交對像資料是分開的,因此您可以隨時修改與提交關聯的註釋,而無需更改 SHA-1 哈希。 您可以使用 `git log`、使用大多數 git GUI 應用程式或使用 `git notes show` 命令查看筆記。一些 git 主機還在提交視圖中顯示註釋(儘管 [GH 不再顯示註釋](https://github.blog/2010-08-25-git-notes-display/))。 --- ## Git Bisect > 使用 [`git bisect`](https://git-scm.com/docs/git-bisect) 你可以使用二進制搜尋找到引入錯誤的提交 這是最強大又好用的 git 命令之一 - bisect 在除錯時絕對是救命稻草。開始對分後,它會為您檢查提交,然後您告訴它提交是“好”(沒有錯誤)還是“壞”(引入錯誤),這可以讓您縮小最早提交的錯誤。 請執行 `git bisect start`,然後使用 `git bisect good <commit-hash>` 向其傳遞一個已知的良好提交,並使用 `git bisect bad <optional-hash>` 傳遞一個已知的錯誤提交(預設為當前)。然後它會檢查好提交和壞提交之間的提交,然後你用 `git bisect good` 或 `git bisect bad` 指定錯誤存在與否。然後它會重複這個過程,在好與壞的中心檢查一個提交,一直到你找到引入錯誤的確切提交。隨時使用 `git bisect reset` 取消。 bisect 命令還有更多功能,包括回放、查看提交、跳過,因此下次除錯時值得查看文檔。 --- ## Git Grep > 使用 [`git grep`](https://git-scm.com/docs/git-grep) 在您的存儲庫中搜尋程式碼、文件、提交或任何其他內容 有沒有發現自己需要在 git 專案中的任何地方搜尋字串?使用 git grep,您可以輕鬆地在整個專案中和跨分支搜尋任何字串或 RegEx(例如更強大的 <kbd>Ctrl</kbd> + <kbd>F</kbd>!)。 `git grep <regexp> <ref>` 它包括大量 [選項](https://git-scm.com/docs/git-grep#_options) 來縮小搜尋範圍,或指定結果格式。例如,使用 `-l` 僅返回文件名,`-c` 指定每個文件返回的匹配數,`-e` 排除匹配條件的結果,`--and` 指定多個條件,` -n` 以行號搜尋。 由於 git grep 與正則表達式兼容,因此您可以使用搜尋的字串獲得更多進階訊息。 您還可以使用它來指定文件擴展名,例如 `git grep 'console.log' *.js`,它將顯示 JavaScript 文件中的所有 console.logs 第二個參數是一個 ref,可以是分支名稱、提交、提交範圍或其他任何內容。例如。 `git grep "foo" HEAD~1` 將搜尋之前的提交。 --- ## Git Archive > 使用 [`git archive`](https://git-scm.com/docs/git-archive) 將整個 repo 合併到一個文件中 共享或備份存儲庫時,通常首選將其存儲為單個文件。使用 git archive 將包括所有 repo 歷史記錄,因此可以輕鬆將其提取回其原始形式。該命令還包括許多附加選項,因此您可以準確自定義存檔中包含和不包含的文件。 ``` git archive --format=tar --output=./my-archive HEAD ``` --- ## Git Submodules > 使用 [`git submodule`](https://git-scm.com/docs/git-submodule) 將任何其他存儲庫拉入您的存儲庫 在 git 中,[submodules](https://git-scm.com/docs/gitsubmodules) 讓您可以將一個存儲庫掛載到另一個存儲庫中,通常用於核心依賴項或將組件拆分到單獨的存儲庫中。有關詳細訊息,請參閱[這篇文章](https://notes.aliciasykes.com/17996/quick-tip-git-submodules)。 執行以下命令會將模塊拉到指定位置,並建立一個 .gitmodules 文件,以便在複製 repo 時始終下載它。複製 repo 時使用 `--recursive` 標誌來包含子模塊。 ``` git submodule add https://github.com/<user>/<repo> <path/to/save/at> ``` 還有 [`git subtree`](https://www.atlassian.com/git/tutorials/git-subtree),它做類似的事情,但不需要元資料文件。 --- ## Git Bug Report > 使用 [`git bugreport`](https://git-scm.com/docs/git-bugreport) 編寫錯誤票,包括 git 和系統訊息 此命令將捕獲系統訊息,然後打開一個標準錯誤模板(重現步驟、實際 + 預期輸出等)。完成的文件應該是一個非常完整的錯誤報告,包含所有必要的訊息。 如果您是開源包的維護者並要求用戶(開發人員)提出錯誤報告,這將非常方便,因為它確保包含所有必要的資料。 如果您向核心 git 系統提交錯誤報告,您還可以執行 [`git diagnostic`](https://git-scm.com/docs/git-diagnose) 命令,然後提出您的問題 [這裡](https://github.com/git/git)。 --- ## Git Fsck > 使用 [`git fsck`](https://git-scm.com/docs/git-fsck) 檢查所有物件,或恢復無法存取的物件 雖然不常需要,但有時您可能必須驗證 git 存儲的物件。這就是 fsck(或文件系統檢查)發揮作用的地方,它測試對像資料庫並驗證所有物件的 SHA-1 ID 及其建立的連接。 它還可以與 `--unreachable` 標誌一起使用,以查找不再可以從任何命名引用存取的物件(因為與其他命令不同,它包括 `.git/objects` 中的所有內容)。 --- ## Git Stripspace > 使用 [`git stripspace`](https://git-scm.com/docs/git-stripspace) 格式化給定文件中的空格 最佳做法是避免在行尾尾隨空格,避免有多個連續的空行,避免輸入的開頭和結尾出現空行,並以新行結束每個文件。有很多特定於語言的工具可以自動為您執行此操作(例如 prettier),但 Git 也內置了此功能。 它用於元資料(提交訊息、標籤、分支描述等),但如果您將文件通過管道傳輸給它,然後將響應通過管道傳輸回文件,它也可以工作。例如。 `cat ./path-to-file.txt | git stripspace` 或 `git stripspace < dirty-file.txt > clean-file.txt` 您還可以使用它來刪除註釋(使用 `--strip-comments`),甚至註釋掉行(使用 `--comment-lines`)。 --- ## Git Diff > 使用 [`git diff`](https://git-scm.com/docs/git-diff) 你可以比較 2 組程式碼之間的差異 您可能知道您可以執行 `git diff` 來顯示自上次提交以來的所有更改,或者使用 `git diff <commit-sha>` 來比較 2 次提交或 1 次提交到 HEAD。但是您可以使用 diff 命令做更多的事情。 您還可以使用它來比較任意兩個任意文件,使用 `diff file-1.txt file-2.txt`(不再存取 [diffchecker.com](https://www.diffchecker.com/compare/)! ) 或者使用 `git diff branch1..branch2` 相互比較 2 個分支或引用 請注意,雙點 (`..`) 與空格相同,表示 diff 輸入應該是分支的尖端,但您也可以使用三點 (`...`) 來轉換第一個參數進入兩個差異輸入之間共享的共同祖先提交的引用 - 非常有用!如果只想跨分支比較單個文件,只需將文件名作為第三個參數傳遞。 您可能希望查看在給定日期範圍內所做的所有更改,為此使用 `git diff HEAD@{7.day.ago} HEAD@{0}`(上週),同樣可以將其與文件名、分支名稱、特定提交或任何其他參考。 還有 [`git range-diff`](https://www.git-scm.com/docs/git-range-diff) 命令,它提供了一個用於比較提交範圍的簡單界面。 git diff 工具還有更多功能(以及使用您自己的差異檢查器的選項),因此我建議查看 [文檔](https://git-scm.com/docs/git-diff#_description) . --- ## Git Hooks > 使用 [`hooks`](https://git-scm.com/docs/githooks) 在給定的 get 操作發生時執行命令或執行腳本 Hooks 可以讓你自動化幾乎所有的事情。例如:確保滿足標準(提交訊息、分支名稱、補丁大小)、程式碼質量(測試、lint)、將附加訊息附加到提交(用戶、設備、票證 ID)、呼叫 webhook 來記錄事件或執行管道等 對於大多數 git 事件,如 commit, rebase, merge, push, update, applypatch 等,都有前後 [hooks available](https://git-scm.com/docs/githooks)。 鉤子存儲在 `.git/hooks` 中(除非您使用 `git config core.hooksPath` 在其他地方配置它們),並且可以使用 [`git hook`](https://git-scm.com/docs) 進行測試/git-hook) 命令。由於它們只是 shell 文件,因此可用於執行任何命令。 掛鉤不會推送到遠程存儲庫,因此要在您的團隊中共享和管理它們,您需要使用 [掛鉤管理器](https://github.com/aitemr/awesome-git-hooks#tools) ,例如 [lefthook](https://github.com/evilmartians/lefthook) 或 [husky](https://github.com/typicode/husky)。還有幾個[3rd-party tools](https://githooks.com/#projects),這使得管理鉤子更容易,我推薦[overcommit](https://github.com/sds/overcommit)。 請記住,掛鉤總是可以跳過(使用 `--no-verify` 標誌),所以永遠不要純粹依賴掛鉤,尤其是對於任何與安全相關的事情。 --- ## Git Blame > 使用 [`git blame`](https://git-scm.com/docs/git-blame) 顯示特定修訂版和行的作者訊息 一個經典的,快速找出誰寫了特定程式碼行(也就是你的哪個同事應該為這個錯誤負責!)。但它也有助於確定在哪個時間點發生了某些更改並檢查該提交和關聯的元資料。 例如,要查看 index.rs 第 400 到 420 行的作者和提交訊息,您可以執行: ``` git blame -L 400,420 index.rs ``` --- ## Git LFS > 使用 [`git lfs`](https://git-lfs.github.com/) 存儲大文件,以免拖慢您的存儲庫 您的專案通常會包含較大的文件(例如資料庫、二進制資產、檔案或媒體文件),這會減慢 git 工作流程並使使用限制達到最大。這就是 [大型文件存儲](https://git-lfs.github.com/) 的用武之地 - 它使您能夠將這些大型資產存儲在其他地方,同時使它們可以通過 git 進行跟踪並保持相同的存取控制/權限。 LFS 的工作原理是將這些較大的文件替換為在 git 中跟踪的文本指針。 要使用它,只需執行 `git lfs track <file glob>`,這將更新您的 `.gitattributes` 文件。您可以通過擴展名(例如“*.psd”)、目錄或單獨指定文件。執行 git lfs ls-files 以查看跟踪的 LFS 文件列表。 --- ## Git GC > 使用 [`git gc`](https://git-scm.com/docs/git-gc) 優化您的存儲庫 隨著時間的推移,git repos 會積累各種類型的垃圾,這些垃圾會佔用磁盤空間並減慢操作速度。這就是內置垃圾收集器的用武之地。執行 `git gc` 將刪除孤立的和不可存取的提交(使用 [`git prune`](https://git-scm.com/docs/git-prune)),壓縮文件修訂和存儲的 git 物件,以及一些其他一般的內務管理任務,如打包引用、修剪引用日誌、尊重元資料或陳舊的工作樹和更新索引。 加入 `--aggressive` 標誌將 [積極優化](https://git-scm.com/docs/git-gc#_aggressive) 存儲庫,丟棄任何現有的增量並重新計算它們,這需要更長的時間執行但如果你有一個大型存儲庫可能需要。 --- ## Git Show > 使用 [`git show`](https://git-scm.com/docs/git-show) 輕鬆檢查任何 git 物件 以易於閱讀的形式輸出物件(blob、樹、標籤或提交)。要使用,只需執行 `git show <object>`。您可能還想附加 `--pretty` 標誌,以獲得更清晰的輸出,但還有許多其他選項可用於自定義輸出(使用 `--format`),因此此命令對於準確顯示非常強大你需要什麼。 這非常有用的一個實例是在另一個分支中預覽文件,而無需切換分支。只需執行 `git show branch:file` --- ## Git Describe > 使用 [`git describe`](https://git-scm.com/docs/git-describe) 查找可從提交中存取的最新標記,並為其指定一個人類可讀的名稱 執行 `git describe`,您將看到一個人類可讀的字串,該字串由最後一個標籤名稱與當前提交組合而成,以生成一個字串。您還可以將特定標籤傳遞給它, 請注意,您必須已建立標籤才能使其正常工作,除非您附加了 `--all` 標誌。默認情況下,Git describe 也只會使用帶註釋的標籤,因此您必須指定 `--tags` 標誌以使其也使用輕量級標籤。 --- ## Git Tag > 使用 [`git tag`](https://git-scm.com/docs/git-tag) 在你的 repo 歷史中標記一個特定點 能夠[標記](https://git-scm.com/book/en/v2/Git-Basics-Tagging) 存儲庫歷史記錄中最常用於表示發布版本的特定重要點通常很有用。建立標籤就像 `git tag <tagname>` 一樣簡單,或者您可以使用 `git tag -a v4.2.0 <commit sha>` 標記歷史提交。與提交一樣,您可以使用“-m”在標籤旁邊包含一條訊息。 不要忘記使用 `git push origin <tagname>` 將您的標籤推送到遠程。 要列出所有標籤,只需執行 `git tag`,並可選擇使用 `-l` 進行通配符搜尋。 然後,您將能夠使用 `git checkout <tagname>` 檢出特定標籤 --- ## Git Reflog > 使用 [`git reflog`](https://git-scm.com/docs/git-reflog) 列出對您的存儲庫所做的所有更新 Git 使用稱為參考日誌或“reflogs”的機制跟踪分支尖端的更新。跟踪各種事件,包括:克隆、拉取、推送、提交、檢出和合併。能夠找到事件引用通常很有用,因為許多命令都接受引用作為參數。只需執行 `git reflog` 即可查看 `HEAD` 上的最近事件。 reflog 真正有用的一件事是恢復丟失的提交。 Git 永遠不會真正丟失任何東西,即使是在重寫歷史時(比如變基或提交修改)。 Reflog 允許您返回提交,即使它們沒有被任何分支或標記引用。 默認情況下,reflog 使用 `HEAD`(您當前的分支),但您可以在任何 ref 上執行 reflog。例如 `git reflog show <branch name>`,或者使用 `git reflog stash` 查看隱藏的更改。或者使用 `git reflog show --all` 顯示所有引用 --- ## Git Log > 使用 [`git log`](https://git-scm.com/docs/git-log) 查看提交列表 您可能已經熟悉執行 `git log` 來查看當前分支上最近提交的列表。但是您可以使用 git log 做更多的事情。 使用 `git log --graph --decorate --oneline` 將顯示一個漂亮整潔的提交圖以及 ref 指針。 ![示例 git 日誌輸出](https://i.ibb.co/c1WByg8/Screenshot-from-2022-12-17-20-43-56.png) 您還經常需要能夠根據各種參數過濾日誌,其中最有用的是: - `git log --search="<anything>"` - 搜尋特定程式碼更改的日誌 - `git log --author="<pattern>"` - 只顯示特定作者的日誌 - `git log --grep="<pattern>"` - 使用搜尋詞或正則表達式過濾日誌 - `git log <since>..<until>` - 顯示兩個引用之間的所有提交 - `git log -- <file>` - 顯示僅對特定文件進行的所有提交 或者,只需執行 `git shortlog` 以獲得匯總的提交列表。 --- ## Git Cherry Pick > 使用 [`git cherry-pick`](https://git-scm.com/docs/git-cherry-pick) 通過引用選擇指定的提交並將它們附加到工作 HEAD 有時你需要從其他地方拉一個特定的提交到你當前的分支。這對於應用熱修復、撤消更改、恢復丟失的提交以及在某些團隊協作設置中非常有用。請注意,通常傳統的合併是更好的做法,因為挑選提交會導致日誌中出現重複提交。 用法很簡單,只需執行 `git cherry-pick <commit-hash>`。這會將指定的提交拉入當前分支。 --- ## Git Switch > 使用 [`git switch`](https://git-scm.com/docs/git-switch) 在分支之間移動是我們經常做的事情,`switch` 命令就像是`git checkout` 的簡化版本,它可以用來建立和在分支之間導航,但不像 checkout 在分支之間移動時不會復制修改的文件. 類似於 `checkout -b`,使用 switch 命令你可以附加 `-c` 標誌來建立一個新分支,然後直接跳入其中,例如`git switch -c <新分支>`。執行 `git switch -` 將放棄您所做的任何實驗性更改,並返回到您之前的分支。 --- ## Git Standup > 使用 [`git standup`](https://github.com/kamranahmedse/git-standup) 回憶你在最後一個工作日做了什麼,基於 git 提交 我把它放在最後,因為它不包含在大多數 git 客戶端中,但是您可以使用系統包管理器[輕鬆安裝](https://github.com/kamranahmedse/git-standup#install) ,使用 1 行 curl 腳本,或從源程式碼建置。 如果您的老闆要求您每天站立一次,以更新昨天的工作,但您永遠記不起自己到底做了什麼——這個適合您!它將顯示一個格式良好的列表,列出在給定時間範圍內完成的所有事情。用法很簡單,只需執行 `git standup`,或使用 [這些選項](https://github.com/kamranahmedse/git-standup#options) 指定應顯示哪些資料(作者、時間範圍、分支機構等)。 --- ## 結論 希望對您有幫助!

寫文件基本技巧:如何替專案寫一份優質 README 文件

為您的開源專案提供良好的文檔是一項重要(且經常被忽視)的功能,可以促進採用並展示您的軟體的全部潛力。 不幸的是,文檔的增長速度通常比程式碼慢得多,主要是因為一些看起來相當簡單的實現,會產生大量可能的用例和變化。不可能涵蓋所有可能的場景,這就是為什麼技術作家的首要工作是確定範圍和確定優先級。關注基本知識非常重要,必須首先記錄以支持最常見的用例。 在這篇文章,我將分享一些技巧,為您的專案打造一個好的 README 文件。 原文出處:https://dev.to/erikaheidi/documentation-101-creating-a-good-readme-for-your-software-project-cf8 ## README 檔案 專案的 README 文件通常是用戶與您的專案的第一次接觸,因為這是他們在訪問您的專案時首先看到的內容。這就是為什麼優先考慮將好的 README 作為專案文檔的起點很重要。 自然地,不同的專案在 README 中有不同的東西要展示,但這些技巧應該作為大多數軟體專案的良好起點。 ## 1. 少即是多 你可能想把所有東西都放在你的 README 中,比如如何安裝和使用項目,如何部署,如何調試......更詳細地涵蓋這些主題的更完整文檔的鏈接。 當您開始時,只有一個 README 就可以了。很長的 README 沒有吸引力,因為沒有目錄或菜單可供導航,因此更難找到訊息,這最終不利於良好的用戶體驗。鏈接到相關資源的較短的自述文件使專案看起來更有條理且不那麼複雜。 如果我不想為這個專案創建一個專門的文檔網站怎麼辦?那麼,在這種情況下,您可以考慮在根目錄中創建一個 `docs` 文件夾,您可以在其中保存額外的 markdown 文檔,這些文檔可以直接從您的代碼託管平台(假設是 GitHub)瀏覽。 ## 2. 將 README 拆分為其他文檔 對於存儲庫中的文檔,您可以在應用程式的根目錄中創建一個“/docs”目錄,並使用“/docs/README.md”文件作為文檔的入口點或索引。 此文件夾的內容大概就像: - installation.md - 詳細顯示如何安裝項目的文檔。 - usage.md - 項目使用情況和主要命令的更詳細視圖。 - advanced.md - 包含一些進階使用選項和用例的文檔。 這些只是一些可以作為起點的想法。如果您覺得需要創建一個包含子文件夾的更複雜的結構,您應該認真考慮為您的項目創建一個專門的文檔網站(我們將在本系列的後續文章中介紹)。 ## 3. README 文件要點 以下是您的 README 文件中絕對應該包含的一些內容: - 項目的大致概述,包括編寫它的語言、它的作用、它為什麼有用; - 安裝要求; - 安裝文檔的鏈接; - 使用概述,讓用戶簡要了解如何執行它; - 故障排除或測試提示(可以是指向單獨文檔的鏈接); - 連接到其他資源以了解更多訊息。 理想情況下,這些應該是簡短的說明,可在必要時鏈接到更全面的文檔。 根據項目的規模和目標,您應該考慮將其他內容放在那裡: - 指向 CONTRIBUTING.md 文檔的鏈接,其中包含有關用戶如何為您的專案做出貢獻的詳細訊息 - 指向包含項目行為準則的 CODE_OF_CONDUCT.md 文檔的鏈接。 如果您的項目託管在 GitHub 上,這些將顯著顯示在右側欄的項目頁面中,就在“關於”部分的正下方。 ### 示例結構 以下是 markdown 的一般結構,您可以將其用作構建專案自述文件的基礎: ``` # Project Name A paragraph containing a high-level description of the project, main features and remarks. ## Requirements Here you should give a general idea of what a user will need in order to use your library or application. List requirements and then link to another resource with detailed installation or setup instructions. - Requirement one - Another requirement Check the [installation notes]() for more details on how to install the project. ## Usage Include here a few examples of commands you can run and what they do. Finally link out to a resource to learn more (next paragraph). For more details, check the [getting started guide](). ## Useful Resources Include here any other links that are relevant for the project, such as more docs, tutorials, and demos. ``` ## 4. 使用徽章 您可以使用徽章通過自動從專案中提取的快速訊息來豐富您的 README,例如最新構建的狀態、最新的穩定版本、專案許可證等。 有不同的服務可以為開源專案提供徽章。正如@mohsin 在這篇文章的評論部分所指出的,您可以直接從 GitHub Actions 中提取徽章,方法是轉到您的工作流程頁面,單擊右上角顯示的三個點,然後從中選擇“創建狀態徽章”菜單: ![屏幕截圖顯示在哪裡可以找到菜單以從 github 操作創建狀態徽章](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpb6g6xofhwm8vctwcem.png) 這將向您顯示一個帶有降價代碼的對話框,您可以將其複製並貼上到您的 README 文件中。 另一個不錯的選擇是使用網站 [Shields.io](https://shields.io/),它提供了幾種不同的徽章,您可以在您的開源項目中免費使用。 例如,這是顯示最新版本 [yamldocs](https://github.com/erikaheidi/yamldocs) 的圖像 URL: ``` https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge ``` 這會生成以下徽章,顯示最新版本: ![yamldocs 的最新穩定版本](https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge) 這是帶有多個徽章的 README 示例: ![顯示來自 yamldocs 項目自述文件的徽章](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5frlxoex4fyke8ra1avf.png) ## 結論 文檔是任何軟體專案的重要組成部分,應該從一開始就認真對待。最好的開始方式是創建一個好的自述文件,向用戶顯示基本信息,而不是用他們可能不需要的內容來淹沒他們,以便開始使用您的專案。

2023 前端框架比較:Svelte vs React,該學哪一個呢?

在 Web 開發世界中,有時感覺就像每天都有新的前端框架問世!大多數來去匆匆,但有一件事是肯定的:Svelte 將繼續存在。 不過,這並不意味著您應該放下一切並在今天學習!追逐最新潮流會讓您分心和不知所措。 這篇文章將一勞永逸地回答:**我應該學習 React 還是 Svelte?**。 您將看到一些程式碼範例,這些範例解釋了為什麼 React 開發人員會為 Svelte 瘋狂,但我們也必須實際一點。 React 已經存在了很長時間。有更多的套件、支援、職缺。 Svelte 還能取代 React 嗎?讓我們找出答案! - 原文出處:https://dev.to/mikehtmlallthethings/svelte-vs-react-which-framework-to-learn-in-2023-50gf --- * 📍 什麼是 React? * 📍 什麼是 Svelte? * 📍 React 和 Svelte 的 5 個區別 * Svelte 的捆綁包尺寸更小 * Svelte 更容易學習 * Svelte 使用純 HTML、CSS 和 JavaScript 進行編譯 * React 有更多的套件 * React 有 React Native * 📍 React 是庫還是框架? * 📍逐行比較 React 和 Svelte 專案 * 📍 Svelte 比 React 快嗎? * 📍 何時從 React 切換到 Svelte * 📍 結論 ### **What is React?** 讓我們從 React 開始。 React 是一個漸進式 JavaScript 前端框架(或函式庫,具體取決於您詢問的對象),可幫助您構建複雜的 Web UI。 它由 Facebook(現為 Meta)於 2013 年創建,能夠很快在前端 Web 開發領域站穩腳跟。 React 的核心是狀態和渲染狀態,這意味著要使用它,您必須添加其他庫來處理客戶端功能和路由。 ### **What is Svelte?** Svelte 也是一個前端 JavaScript 框架,但採用了更加一體化的方法。 Svelte 具有內建的狀態管理、路由和客戶端 (DOM) 功能。 ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-vs-Svelte-functionalities.png) React 需要第三方庫和工具,如 Redux、React Router、JSX,而 Svelte 內建了很多這樣的功能。它不太靈活,但更方便和一致。 它採用更幕後(魔術)風格的方法,它直譯非常基本的 JavaScript 程式碼並為您處理 UI 和狀態管理: ``` <script> let count = 0; function handleClick() { count += 1; } </script> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> ``` Svelte 由紐約時報的開發人員 Rich Harris 於 2016 年創建,用於以高效的方式處理複雜的圖表和圖形。它從那裡成長為 React 和 Vue 之類的備受喜愛的競爭對手。 ### **React 和 Svelte 之間的 5 個區別** ### **1。 Svelte 的構建包大小要小得多** 我們在下面構建的相同(功能)應用程序。部署包大小在 React 是 41.2 kB,在 Svelte 是 2.1 kB。這幾乎減少了 **20x** 🤯 為了獲得這些數字,我構建了一個在 Svelte 和 React 中具有相同功能的應用程序。我們將在 React 與 Svelte 代碼分解部分深入研究這些應用程序。 ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-vs-Svelte-bundle-size-2.png) 我用 React 和 Svelte 構建了一個相同的應用程序。看看 Svelte 包小了多少! ### **2。 Svelte 更容易學習,因為它的語法簡單** Svelte 採用更幕後的魔術方法,允許您編寫非常少量的樣板或語法糖來完成複雜的綁定。模板語法只是帶有一些額外內容的 HTML,這與 JSX(React 等價物)有很大不同並且更容易學習。 React 變數宣告: ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/React-_-React-vs-svelte_-reactive-variable-declaration.png) Svelte 變數宣告: ![](https://scrimba.com/articles/content/images/size/w1600/2022/12/Svelte-_-React-vs-svelte_-reactive-variable-declaration.png) Svelte 看起來像純 JavaScript,但它具有與 React 完全相同的功能。更新 Svelte 變數將自動更新它所在的 UI 元素。 ### **3。 Svelte 符合純 HTML、CSS 和 JavaScript** Svelte 將您編寫的程式碼編譯成基本的 HTML、CSS 和 JavaScript。它不需要像 React 那樣與你的代碼捆綁在一起! React.js 需要存在於一個 bundle 中以完成所有正確的虛擬 DOM 比較和創建,Svelte 不使用虛擬 DOM 來處理 UI。相反,它選擇了基本的 JavaScript 元素創建函數,例如 document.createElement。 ### **4。 React 擁有更多為它構建的庫和包** React 已經存在了 3 年多,也是目前 JavaScript 框架事實上的王者👑。正因為如此,它擁有大量用戶和公司創建的軟件包。 用戶創建的包通常只是為了使路由和狀態管理更容易,或者添加滑塊、燈箱等。這些並不重要,因為 Svelte 具有可靠的選項,並且兼容/適應大多數 JavaScript 套件。 有點困難的是,要跟任何其他框架之前創建的 React 套件整合時不容易。我在 Solana 和以太坊上從事 Web3 專案時經常遇到這個問題。 ### **5。 React 有 React Native** React Native 是使用率最高和受支持最多的跨平台框架之一。它提供了使用 React 創建 iOS 和 Android 應用程式的能力。全部來自同一個代碼庫。由於其成熟度,它擁有大量的庫、支援和學習資源。 儘管有 Svelte 的替代方案,例如稱為 Svelte-native 的 NativeScript 改編版,但它們不具有與 React-native 相同的可靠性和功能。 ### **React 是函示庫還是框架?** 儘管 React 通常被稱為框架,但可以說,由於其範圍,它更像是一個函式庫。它專門負責管理 UI 的狀態並使其與應用程式中的資料狀態保持同步。 因此,它需要第 3 方函式庫來處理應用程式路由 (React Router)、UI 創建 (JSX) 和元件之間的狀態管理 (Redux)。 另一方面,Svelte 內建了上述所有功能,因此更像是一個完整的 UI 管理解決方案。 你可以看到大多數人都同意這是一個函式庫,但仍有一些爭論👇 https://twitter.com/htmleverything/status/1597574223148765185 ### **逐行比較 React 和 Svelte 專案** 比較兩種 Web 技術的最佳方法是深入研究並使用它們進行構建。構建完全相同的應用程序有助於了解每個庫/框架如何處理不同的功能。 讓我們看看: * 條件渲染 * 模板循環 * 更新狀態 * 事件掛鉤 ### **我們在建造什麼?** 編碼是一項口渴的工作,因此我們將構建一個簡單的網絡應用程序,允許用戶跟踪他們全天喝了多少杯水(或🍺)。 額外的好處是顯示每杯喝醉的歷史和時間。 我們將保持 UI 簡單,以更多地關注底層框架。 (見下面的用戶界面) https://codesandbox.io/embed/react-water-example-scrimba-ny5q0m?fontsize=14&hidenavigation=1&theme=dark ### **React** 為了分解代碼,首先讓我們深入了解一些 React 概念和術語👇 React 有幾種類型的語法你需要學習。鉤子、狀態和模板 (JSX) 是主要的。 鉤子 - 允許您進入應用程序的生命週期 State - 允許您根據數據的變化更新 UI 元素。它將“狀態”(或更簡單的變量)更改與 UI 更新聯繫起來 模板 - 允許您直接在 HTML 中使用變量和 JavaScript React 組件的樣式通常由單獨的 .css(或 .scss)文件處理。 ### **React 代碼分解** https://codesandbox.io/embed/react-water-example-scrimba-ny5q0m?fontsize=14&hidenavigation=1&theme=dark&view=editor 變數是使用 useState 掛鉤設置的,它允許更新變量並讓 UI 動態呈現這些更新。 `useEffect` 用於在加載應用程序時設置今天的日期。 JSX 模板使用基本的“{}”符號以及 HTML 中的標準 JavaScript 函數,允許顯示變量和循環數組(使用“.map”)。 ### **Svelte** Svelte 採用不同的方法,採用更“幕後魔術”的風格。邏輯看起來很像純 JavaScript。在後台,代碼做的事情幾乎與 React 代碼做的一樣。 Svelte 仍然有像 `onMount` 和 `onDestroy` 這樣的鉤子,但是簡單地分配一個變量並讓它完全響應並在模板 (HTML) 中可訪問不需要任何特殊的語法糖。 另一個很大的區別是您可以直接在 Svelte 組件中編寫 CSS/SCSS。這只是一個選項,因為您仍然可以像在 React 中一樣導入樣式,但我注意到大多數 Svelte 項目都使用樣式內組件。 ### **Svelte 代碼分解** https://codesandbox.io/embed/svelte-water-example-scrimba-2vsoid?fontsize=14&hidenavigation=1&module=%2FApp.svelte&theme=dark&view=editor 上面的代碼實例化了一個 cupsOfWater 數組,將新的日期變量設置為當前日期。 聲明一個函數來創建一個新日期並將其存儲在一個名為 cup 的變量中,然後將其添加到 cupsOfWater 數組中。 模板部分更接近 HTML 並增加了一些功能。再次使用“{}”表示法,您可以從“<script>”部分引用任何聲明的變量。您還可以使用事件偵聽器(如 `on:click`)、條件(如 `{#if}`)和使用 `{#each}` 循環。 ### **Svelte 比 React 快嗎?** 是的,從快速的 HTML 生成到更快的構建和開發環境,Svelte 的性能都大大優於 React。 * 生成 HTML * 根據狀態更新 UI * 第一次內容豐富的渲染 * 互動時間 * 速度指數 所有這些都看到了可衡量的差異,而 Svelte 具有優勢。您的應用程序越大越複雜,差異就越明顯。 在 Zeitspace 的一篇文章中可以看到性能比較 https://www.zeitspace.com/blog/we-built-an-app-with-svelte.-heres-what-we-learned ### **Svelte 比 React 好嗎?** 當開始一個新專案時,Svelte 有足夠的優勢,它應該始終是一個考慮因素。 話雖如此,React 在使用率方面仍然絕對勝過 Svelte。這可能會導致專案的第 3 方插件支持、僱用和壽命問題。 不過,為了應對這一點,Svelte 語法的易用性使其非常容易上手,尤其是對於 React 開發人員而言。這是公司在招聘 Svelte 項目時可以藉鑑的東西(不要將自己局限於 Svelte 開發人員)。 ### **何時從 React 切換到 Svelte** Svelte 是構建複雜網站或 Web 應用程序的絕佳選擇。許多老牌公司已經開始將 Svelte 用於內部和外部應用程序: * 1Password * Avast * Chess.com * Alaska Airlines * Fusion Charts * Rakuten * GoDaddy * IBM * Square * 紐約時報 * 飛利浦 但這並不意味著您必須將當前的 React 應用程序放入垃圾桶! 那麼什麼時候是接觸 Svelte 的合適時機? 如果您的應用/網站: * 由於頻寬限制,需要較小的包大小 * 需要盡可能快 * 需要快速建造 When is not the right time to reach for Svelte? 什麼時候不適合使用 Svelte? 如果您的應用/網站: * 嚴重依賴第 3 方集成/工具 * 需要轉換為移動應用程序 這些很快就不會成為問題,但在投入之前確實需要進行一些研究和盡職調查。 ### **結論** 建議投入其中並嘗試在 Svelte 中構建一些東西。如果你來自 React,我幾乎可以向你保證你會喜歡它的簡單性和速度。

在 React 中使用 Design Patterns:以 Strategy Pattern 舉例

在 React 前端開發時,常常會需要在不同的元件、hook、utils 中寫一些邏輯。 有些時候,使用策略模式會很有幫助,這篇文章給您參考。 - 原文出處:https://dev.to/itshugo/applying-design-patterns-in-react-strategy-pattern-enn ## 出問題了:霰彈槍手術(Shotgun Surgery) Shotgun Surgery 是一種程式寫很爛的信號。想對程式規格做一點小修改,需要改一大堆地方。 ![](https://refactoring.guru/images/refactoring/content/smells/shotgun-surgery-01-2x.png) 在專案中通常如何發生?假設我們需要為產品寫一個報價卡片,我們根據客戶所在國家,調整價格、貨幣、折扣方式和文字說明: ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5iz9oso7ozaqm0qibd76.png) 大多數工程師可能會這樣寫: - 元件:`PricingCard`、`PricingHeader`、`PricingBody`。 - Utility functions:`getDiscountMessage`(在 **utils/discount.ts** 中),`formatPriceByCurrency`(在 **utils/price.ts** 中)。 - `PricingBody` 元件會計算最終價格。 完整程式碼範例:https://codesandbox.io/s/react-strategy-pattern-problem-h59r02?from-embed 現在假設我們需要更改一個國家/地區的定價計劃,或為另一個國家/地區添加新的定價計劃。您將如何處理這段修改?您必須至少修改 3 個地方,並向已經滿亂的 `if-else` 區塊添加更多條件: - 修改 `PricingBody` 組件。 - 修改 `getDiscountMessage` 函數。 - 修改 `formatPriceByCurrency` 函數。 如果您聽說過 S.O.L.I.D 原則,我們已經違反了前 2 條原則:單一職責原則和開閉原則。 ## 解決方法:策略模式 策略模式非常簡單。我們可以簡單的理解為,每個國家的定價方案都是一個策略。在那個策略類別中,會實現該策略的所有相關邏輯。 假設您熟悉 OOP,我們可以有一個實現共享/公共邏輯的抽像類別(`PriceStrategy`),然後具有不同邏輯的策略將繼承該抽像類別。 `PriceStrategy` 抽像類別如下所示: ``` import { Country, Currency } from '../../types'; abstract class PriceStrategy { protected country: Country = Country.AMERICA; protected currency: Currency = Currency.USD; protected discountRatio = 0; getCountry(): Country { return this.country; } formatPrice(price: number): string { return [this.currency, price.toLocaleString()].join(''); } getDiscountAmount(price: number): number { return price * this.discountRatio; } getFinalPrice(price: number): number { return price - this.getDiscountAmount(price); } shouldDiscount(): boolean { return this.discountRatio > 0; } getDiscountMessage(price: number): string { const formattedDiscountAmount = this.formatPrice( this.getDiscountAmount(price) ); return `It's lucky that you come from ${this.country}, because we're running a program that discounts the price by ${formattedDiscountAmount}.`; } } export default PriceStrategy; ``` 我們只需將實例化的策略作為 prop 傳遞給 PricingCard 元件: ``` <PricingCard price={7669} strategy={new JapanPriceStrategy()} /> ``` `PricingCard` 的 props 定義為: ``` interface PricingCardProps { price: number; strategy: PriceStrategy; } ``` 同樣,如果您了解 OOP,那麼我們不僅在使用繼承,而且還在此處使用多態性(Polymorphism)。 完整程式碼範例:https://codesandbox.io/s/react-strategy-pattern-solution-mm0cvm?from-embed 使用這個解決方案,我們只需要添加一個新的策略類別,而不需要修改任何現有程式碼。這樣,我們也滿足了 S.O.L.I.D 原則。 ## 結論 因為我們在 React 程式碼中檢測到程式碼發臭:Shotgun Surgery,所以我們使用了策略模式來解決它。 ### Before ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wn31uolfo6xfy3mh8fo.png) ### After ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xheeb2splcwj2kkqwsfo.png) 現在邏輯都存在一個地方,不再分佈在許多地方。 --- 以上是 Strategy Pattern 的簡單說明,希望對您有幫助。

36 個免費、漂亮的 React UI 模板與主題套件

網路上免費的 React 版型資源不太好找,最好有一份懶人包。 這份列表整理了各式各樣的模板與主題套件,希望對您有幫助。 - 原文出處:https://dev.to/davidepacilio/35-free-react-templates-and-themes-32ci --- ##1. Open ![](https://dev-to-uploads.s3.amazonaws.com/i/gy9nddokri1vobwrtbna.jpg) [**Live demo**](https://open.cruip.com/) / [**Download**](https://github.com/cruip/open-react-template) Open 是一個免費的 React 模板,專為開源專案、線上服務、數位產品,創建快速、專業的登陸頁面而生。為了吸引潛在客戶和電子郵件訂閱者,Open 提供了一個多功能的資源庫,其中包含時尚、簡約和可重複使用的元件和元素。 --- ##2. Atomize ![](https://dev-to-uploads.s3.amazonaws.com/i/ks2st96gb0tbu1ybuy6k.jpg) [**Live demo**](https://atomizecode.com/) / [**Download**](https://github.com/proksh/atomize) Atomize 是一個 React UI 框架,旨在幫助開發人員與設計師合作,輕鬆構建一致和諧的用戶界面。由於樣式指南和靈活網格等資源的完美結合,Atomize 適合建立任何類型的響應式網站。 --- ##3. Treact ![](https://dev-to-uploads.s3.amazonaws.com/i/3aw9a273jibs97o2l09m.jpg) [**Live demo**](https://treact.owaiskhan.me/) / [**Download**](https://gumroad.com/l/QaruQ) Treact 是使用 TailwindCSS 作為前端框架開發的現代 React 模板和 UI 組件展示庫。這個精美的檔案庫提供了 7 個內建的主頁、8 個輔助頁面以及 52 個預先設計的元素和段落。每個內容都可以針對家用電腦、平板電腦和移動設備進行擴充。 --- ##4. MatX ![](https://dev-to-uploads.s3.amazonaws.com/i/q99tvy2uvyvol2xet2et.jpg) [**Live demo**](http://matx-react.ui-lib.com/dashboard/analytics) / [**Download**](https://ui-lib.com/downloads/matx-react-dashboard/) MatX 是一個建立在 Material Design 之上的精美 React Native 模板。此模板使用 React、Redux 和 Material UI,它包含為 Web 應用程式提供新造型可能需要的所有基本功能。 MatX 的免費版本可用於輕鬆設置管理面板、用戶管理系統和專案管理系統。 --- ##5. Holly ![](https://dev-to-uploads.s3.amazonaws.com/i/dcrv1qxgo3rgq9a3j3at.jpg) [**Live demo**](https://lukemcdonald.github.io/holly-react/) / [**Download**](https://github.com/lukemcdonald/holly-react) Holly 是一個響應式 React JS 模板,適用於線上服務和數位產品的生產者,能在主要產品仍在開發中時,就開始搜集電子郵件地址。這個模板最初是由 [Cruip](https://cruip.com/) 用 HTML 設計的,然後在這個版本中用 React 撰寫。 --- ##6. OAH-Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/rteeixluj4n09a3s69ma.jpg) [**Live demo**](https://oah-admin.ahmedelywa.com/extra-components/progress/) / [**Download**](https://github.com/AhmedElywa/oah-admin) OAH-Admin 是一個基於 Gatsby 的免費 React 管理儀表板模板,帶有 oah-ui 元件和元素包。這個 React 模板有良好的 UI 元件色調,超級整潔和靈活的格式使任何人都可以輕鬆建立 SaaS 應用程式、管理面板、儀表板。 --- ##7. Gatsby Starter Ghost ![](https://dev-to-uploads.s3.amazonaws.com/i/ocey043yzsdt31f7yi9s.jpg) [**Live demo**](https://gatsby.ghost.org/) / [**Download**](https://github.com/TryGhost/gatsby-starter-ghost) 使用 Ghost 這個基於 Gatsby 的入門模板,輕鬆建立高效能網站。Gatsby Starter Ghost 是一個乾淨而現代的模板,適用於部落格、雜誌或任何新聞網站。該產品專門設計來幫助任何人在網路上建立個人空間並分享想法、創意和更新。 --- ##8. Star Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/hlbf4y4pl4a5od2c8chb.jpg) [**Live demo**](https://www.bootstrapdash.com/demo/star-admin-free/react/template/demo_1/preview/dashboard) / [**Download**](https://github.com/BootstrapDash/StarAdmin-Free-React-Admin-Template) 一個免費的 React Native 模板,提供了無窮無盡的各種基本元素,可以將任何想法變為現實。該模板具有精心製作的儀表板,包含大量整齊排列和組織的元件,它可以完美地與所有最新和現代的瀏覽器配合使用,並且能夠使資料可視化過程更易於管理。 --- ##9. Carolina Admin Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/05r7fsc1jzylez5diu6f.jpg) [**Live demo**](https://demo.uifort.com/carolina-react-admin-dashboard-material-ui-free-demo/LandingPage) / [**Download**](https://uifort.com/template/carolina-react-admin-dashboard-material-ui-free/) 如果您正在尋找一個令人驚嘆且實用的 React 儀表板模板,Carolina Admin Dashboard 擁有啟動和運行您 Web 專案所需的一切。這個漂亮的模板建立在 Material-UI 框架之上,採用乾淨清新的設計,遵循所有 Google 的 Material Design 指南。此外,核心結構是完全響應式和開源的。 --- ##10. Tabler ![](https://dev-to-uploads.s3.amazonaws.com/i/nu5vq6j5buk36iz8prsn.jpg) [**Live demo**](http://tabler-react.com/) / [**Download**](https://github.com/tabler/tabler-react) Tabler 是一個免費的 React 管理儀表板模板,非常適合任何類型的後端 Web 應用。此管理模板包含大量精心設計的範例,無需從頭開始,可為您節省大量時間,它還附帶可重複使用的元件,例如按鈕、地圖、圖表、表單等。 --- ##11. React Nice Resume ![](https://dev-to-uploads.s3.amazonaws.com/i/ci5hhvp6ki5o3mpk8zbz.jpg) [**Live demo**](https://nordicgiant2.github.io/react-nice-resume-page/#home) / [**Download**](https://github.com/nordicgiant2/react-nice-resume) React Nice Resume 是一個漂亮的主題,如果您是開發人員、設計師或一般的數位創作者,可以用來宣傳您自己和您的作品。該資源展示了一個獨特的主頁,帶有粒子背景、工作經驗時間線、技能圖表、顯示最新專案的縮略圖、一個帶有功能輸入表單的段落。 --- ##12. Boss Lite ![](https://dev-to-uploads.s3.amazonaws.com/i/zq92otm0bc9t3mwinkxb.jpg) [**Live demo**](http://boss.ux-maestro.com/app/tables/data-table) / [**Download**](https://github.com/ilhammeidi/boss-lite) Boss Lite 是一個基於 React 和 Redux 的管理儀表板模板。此模板為您帶來清新現代的設計和多種配色方案。它支援大多類型的 Web 專案,並且 Flexbox 佈局而變得很流暢。 --- ##13. Chakra UI ![](https://dev-to-uploads.s3.amazonaws.com/i/poootemj2t5caoi4lryt.jpg) [**Live demo**](https://chakra-ui.com/) / [**Download**](https://github.com/chakra-ui/chakra-ui/) Chakra UI 提供了一組好用、可重用的 React 功能元件,使建立好用網站和用戶界面變得非常簡單。 Chakra UI 中的幾乎所有元素都兼容深色模式,它們遵循 WAI-ARIA 指南規範,並構建在 React UI Primitive 之上以實現無限的可組合性。 --- ##14. Black Dashboard React ![](https://dev-to-uploads.s3.amazonaws.com/i/2r1tx4uxug6k1xlnr3pr.jpg) [**Live demo**](https://demos.creative-tim.com/black-dashboard-react/#/admin/dashboard) / [**Download**](https://www.creative-tim.com/product/black-dashboard-react) Black Dashboard React 是用於管理界面的 React 模板。該模板基於 Bootstrap 建立的設計指南,是基於企業的應用程式,是強大後端軟體可用的優秀前端選項。它具有更高等級的切分、設計套件、可重複使用的圖表,能夠不斷改善用戶和開發體驗。 --- ##15. Argon Design System ![](https://dev-to-uploads.s3.amazonaws.com/i/tvrfqzddf6kwmhiwje6x.jpg) [**Live demo**](https://demos.creative-tim.com/argon-design-system-react/) / [**Download**](https://github.com/creativetimofficial/argon-design-system-react) 使用 Bootstrap 4 和 Reactstrap 的 React 設計系統。Argon Design System 帶有 100 多個單獨的元件、內建的範例,並且每個元素都有多種樣式、懸停、焦點狀態,任何人都可以輕鬆使用。該產品是從原型設計到正式上線的完美解決方案。 --- ##16. Devias Kit - Admin Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/j7lqqfvgmujtgg1m80oi.jpg) [**Live demo**](https://react-material-dashboard.devias.io/dashboard) / [**Download**](https://github.com/devias-io/react-material-dashboard) Devias Kit 是一個響應式 Material Design 管理儀表板,專為 React 使用 Google 自己的 Material Design 框架建立。可以自定義設置、指令、圖標和樣式。該模板包含清晰直觀的目錄和文件、快速入門文件,如果您想對設計進行任何更改,甚至還有 Sketch 文件。 --- ##17. Dev Blog ![](https://dev-to-uploads.s3.amazonaws.com/i/1tym4ekzrftd6ldcflid.jpg) [**Live demo**](https://ryanfitzgerald.github.io/devblog/) / [**Download**](https://github.com/RyanFitzgerald/devblog) Dev Blog 是一個 React 網站模板,專為快速建立副專案和產品而生。該網站模板帶有一個首頁,其中顯示了部落格名稱、社交媒體圖示以及帶有文字和圖像的文章縮圖。該模板還包括單個文章頁面,有漂亮且精心策劃的排版。 --- ##18. Material PRO ![](https://dev-to-uploads.s3.amazonaws.com/i/scakf4swq5j99hln1xqx.jpg) [**Live demo**](https://wrappixel.com/demos/free-admin-templates/materialpro-reactadmin-lite/main/#/starter/starter) / [**Download**](https://www.wrappixel.com/templates/materialpro-react-admin-lite/) Material Pro 是一個免費的 React Native 模板,為任何需要管理儀表板的人精心製作。這個漂亮而清爽的產品採用模組化和現代設計理念開發,100% 免費使用和下載,並包含許多頁面,可幫助您更快、更輕鬆地建立專案。 --- ##19. Ant Design Landing ![](https://dev-to-uploads.s3.amazonaws.com/i/wnld469wyg4u9pfk31i1.jpg) [**Live demo**](https://landing.ant.design/) / [**Download**](https://github.com/ant-design/ant-design-landing) Landing 是 Ant Design System 建立的模板。內涵不同樣式的首頁和內頁模組。 --- ##20. Isomorphic ![](https://dev-to-uploads.s3.amazonaws.com/i/zy0at5stk267a06n5f95.jpg) [**Live demo**](https://isomorphic.redq.io/dashboard) / [**Download**](https://github.com/pujoey/ismorphic) Isomorphic 是一個易於管理且有吸引力的管理模板,具有大量靈活的元件。 --- ##21. Shards Dashboard Lite ![](https://dev-to-uploads.s3.amazonaws.com/i/71cn55agi3k9er11xk4o.jpg) [**Live demo**](https://designrevision.com/demo/shards-dashboard-lite-react/blog-overview) / [**Download**](https://designrevision.com/downloads/shards-dashboard-lite-react/) Shards 是一個免費的 React 儀表板模板,具有現代設計系統和許多自定義頁面和部分。 --- ##22. uiw ![](https://dev-to-uploads.s3.amazonaws.com/i/e6aakqf9m9g67mstwvi9.jpg) [**Live demo**](https://uiwjs.github.io/) / [**Download**](https://github.com/uiwjs/uiw) uiw 是用於 React 16+ 的高質量 React 元件庫和 UI 工具包。 --- ##23. React Material Admin ![](https://dev-to-uploads.s3.amazonaws.com/i/te6tezfjcp008lb4q7du.jpg) [**Live demo**](https://flatlogic.github.io/react-material-admin/#/login) / [**Download**](https://flatlogic.com/templates/react-material-admin) React Material Admin 是一個建立在 Material-UI 框架之上的 React 儀表板。 --- ##24. Material KIT React ![](https://dev-to-uploads.s3.amazonaws.com/i/cq2xlu4tci8km6p2tia7.jpg) [**Live demo**](https://demos.creative-tim.com/material-kit-react/) / [**Download**](https://www.creative-tim.com/product/material-kit-react) Material UI KIT 是一款免費的 React UI 主題,其設計靈感來自 Google 的 Material Design,設計清新整潔。 --- ##25. Airframe ![](https://dev-to-uploads.s3.amazonaws.com/i/qwt4nv73xjn14a9g09yl.jpg) [**Live demo**](http://dashboards.webkom.co/react/airframe/dashboards/projects/) / [**Download**](https://github.com/0wczar/airframe-react) Airframe 是一個基於 Bootstrap 4 和 React 16 的免費開源 React 應用程式模板。 --- ##26. Gatsby Simplefolio ![](https://dev-to-uploads.s3.amazonaws.com/i/pe3clc53zqsntgh3vw3n.jpg) [**Live demo**](https://gatsby-simplefolio.netlify.app/) / [**Download**](https://github.com/cobidev/gatsby-simplefolio) Gatsby Simplefolio 是一個乾淨、美觀且響應迅速的 React 組合模板。 --- ##27. Ant Design Pro ![](https://dev-to-uploads.s3.amazonaws.com/i/diktnddjjf630tdyyqa8.jpg) [**Live demo**](https://pro.ant.design/) / [**Download**](https://github.com/ant-design/ant-design-pro/) React --- ##28. React SaaS Template ![](https://dev-to-uploads.s3.amazonaws.com/i/yiq5ast9jw3knt8l92l0.jpg) [**Live demo**](https://reactsaastemplate.com/) / [**Download**](https://github.com/dunky11/react-saas-template) --- ##29. Shards React ![](https://dev-to-uploads.s3.amazonaws.com/i/34zfg3e4qbbzklmgr4uh.jpg) [**Live demo**](https://designrevision.com/downloads/shards-react/) / [**Download**](https://github.com/designrevision/shards-react) --- ##30. Base Web ![](https://dev-to-uploads.s3.amazonaws.com/i/8q3bxpsll7k0qrhzdlmj.jpg) [**Live demo**](https://baseweb.design/) / [**Download**](https://github.com/uber/baseweb) --- ##31. Light Blue React Dashboard ![](https://dev-to-uploads.s3.amazonaws.com/i/tfwzjgvh2sa8e5v9a0oa.jpg) [**Live demo**](https://demo.flatlogic.com/light-blue-react/#/app/main/dashboard) / [**Download**](https://github.com/flatlogic/light-blue-react-template) --- ##32. React JS Landing ![](https://dev-to-uploads.s3.amazonaws.com/i/ibuom994cxj3pzb2yzoz.jpg) [**Live demo**](https://react-landing-page-template.herokuapp.com/#page-top) / [**Download**](https://github.com/IssaafKattan/React-Landing-Page-Template) --- ##33. Admin Pro ![](https://dev-to-uploads.s3.amazonaws.com/i/0f1pjehgesa25ts39wx7.jpg) [**Live demo**](https://wrappixel.com/demos/free-admin-templates/adminpro-react-lite/main/#/dashboard) / [**Download**](https://www.wrappixel.com/templates/adminpro-react-admin-lite/#comparison) --- ##34. Blueprint ![](https://dev-to-uploads.s3.amazonaws.com/i/d1owpo8lfg3zfq1p2vpx.jpg) [**Live demo**](https://blueprintjs.com/) / [**Download**](https://github.com/palantir/blueprint) --- ##35. Datta ![](https://dev-to-uploads.s3.amazonaws.com/i/3con3tndvc7au5zg1jb0.jpg) [**Live demo**](http://lite.codedthemes.com/datta-able/react/default/dashboard/default) / [**Download**](https://codedthemes.com/item/datta-able-react-free-admin-template/) --- ##36. Flatlogic One ![](https://dev-to-uploads.s3.amazonaws.com/i/63flhvqcbh7jtfvih9do.jpg) [**Live demo**](https://flatlogic.github.io/one-react-template/#/login) / [**Download**](https://flatlogic.com/templates/one-free-react-template) --- ##結論 我希望這組免費的 React 模板和主題能夠幫助您!

都要 2023 年了還在用 console.log 嗎?來看看 10 個 console 進階用法!

寫 JavaScript 時,仍在使用 console.log 來除錯抓蟲? 是時候**升級你的技能**並學習 JavaScript console 物件的全部功能了。 從 console.table 到 console.time,這些進階方法和技巧將改善您 **debug 訊息的品質和可讀性**,讓您更輕鬆地故障排除和修復問題。 在 2023 年成為 JavaScript 除錯高手吧! - 原文出處:https://dev.to/naubit/why-using-just-consolelog-in-2023-is-a-big-no-no-2429 ## 😞 問題 僅使用 console.log 的最大問題之一是,它會使程式碼混亂且難以閱讀。此外,它本身的資訊量不是很大。它只是輸出你傳遞給它的任何內容的值,沒有任何上下文或其他資訊。 所以,這裡有十個你應該知道的 JavaScript console 物件方法和技巧,值得了解一下! ## 1️⃣ console.table 此方法以可讀且易於理解的格式,輸出資料表格。console.table 不是只顯示陣列或物件,而是以表格格式顯示,使它更易於瀏覽和理解。 ``` // Output an array of objects as a table const users = [ { id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Doe' } ]; console.table(users); ``` 這將以表格格式輸出 users 陣列,每個物件的屬性作為列,物件作為行。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hek6gxo4x73b6mvmlawr.png) ## 2️⃣console.group console.group 和 console.groupEnd。這些方法可以在控制台中,創建嵌套的可摺疊資料組。**這對於組織和構建 debug 訊息非常有用**,讓您可以輕鬆查看程式碼不同級別發生的情況。 ``` console.group('User Details'); console.log('Name: John Doe'); console.log('Age: 32'); console.groupEnd(); ``` 這將在 console 中創建一個嵌套的、可摺疊的資料組,標題為“使用者詳細資訊”。組內的日誌消息將縮進並分組在一起。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ybn1uwvyltjzxcaaytx.png) ## 3️⃣console.time console.time 和 console.timeEnd 可以測量執行程式碼所需的時間。這對於識別程式中的性能瓶頸、效能優化非常有用。 ``` console.time('Fetching data'); fetch('https://reqres.in/api/users') .then(response => response.json()) .then(data => { console.timeEnd('Fetching data'); // Process the data }); ``` 這將測量「從特定 URL 獲取資料並解析 JSON 回應」所需的時間。耗用時間會在控制台中輸出。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3hdvnz2of3an1a21j3c.png) ## 4️⃣console.assert 此方法允許您在程式碼中寫 assertions,這些是應該始終為 true 的語句。如果 assertions 失敗,console.assert 將在控制台中輸出錯誤消息。**這對於除錯抓蟲、確保程式碼正常運作非常有用。 ``` function add(a, b) { return a + b; } // Test the add function const result = add(2, 3); console.assert(result === 5, 'Expected 2 + 3 = 5'); ``` 如果 add 函數在給定輸入 2 和 3 時未返回預期結果 5,就在控制台中輸出錯誤訊息。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y25c157xwhasxnaiakd5.png) ## 5️⃣設置日誌樣式 使用 `console` 物件輸出樣式和顏色。 `console` 物件**允許您輸出不同顏色和樣式的文字**,使您的除錯輸出更具可讀性和更容易理解。 您可以在 console.log 語句中使用 %c 佔位符來指定輸出文字的 CSS 樣式。 ``` console.log('%cHello world!', 'color: red; font-weight: bold;'); ``` 這將輸出文字“Hello world!”,並使用指定的 CSS 樣式,以紅色和粗體顯示。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1p82u116icnlodu046nr.png) ## 6️⃣console.trace 使用 `console.trace` 方法輸出堆疊追踪(stack trace)。這對於理解程式碼中的執行流程、識別**特定日誌消息的來源非常有用。** ``` function foo() { console.trace(); } function bar() { foo(); } bar(); ``` 這將在控制台中輸出堆疊跟踪,顯示導致 `console.trace` 呼叫的函數呼叫序列。看起來像這樣: ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zx16nee1mp0avh04msri.png) ## 7️⃣console.dir 使用 `console.dir` 方法以分層格式輸出物件的屬性。這對於**探索物件的結構**、查看其屬性和方法非常有用。 ``` const obj = { id: 1, name: 'John Doe', address: { street: '123 Main St', city: 'New York', zip: 10001 } }; console.dir(obj); ``` 這將以分層格式輸出 `obj` 物件的屬性,允許您查看物件的結構及其所有屬性和值。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihgkg5e4wxznpaqzb8jr.png) ## 8️⃣console.count 使用 `console.count` 方法計算特定日誌消息的輸出次數。這對於**追蹤特定程式碼路徑的執行次數**以及識別程式碼中的熱點很有用。 ``` function foo(x) { console.count(x); } foo('hello'); foo('world'); foo('hello'); ``` 這將在控制台中輸出字串“hello”,然後是數字 1。然後它將在控制台中輸出字串“world”,然後是數字 1。最後,它會再次輸出字符串“hello”,然後出書數字 2(因為它被呼叫了兩次)。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cx7n8aargexpq1pvqj6n.png) ## 9️⃣console.clear 使用 `console.clear` 方法清除控制台輸出。這能保持您的除錯輸出**有條理和整潔**,讓您更容易專注於您感興趣的訊息。 ``` console.log('Hello world!'); console.clear(); console.log('This log message will appear after the console is cleared.'); ``` 這將輸出字串 “Hello world!”,接著一個空行(因為控制台已清除)。然後它會輸出字串 “This log message will appear after the console is cleared.” ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihzapi1gcin6gtqa600v.png) ## 1️⃣0️⃣console.profile 使用 `console.profile` 和 `console.profileEnd` 方法來衡量程式碼的性能。這對於**識別性能瓶頸和優化代碼**、提高速度和效率非常有用。 ``` console.profile('MyProfile'); // Run some code that you want to measure the performance of for (let i = 0; i < 100000; i++) { // Do something } console.profileEnd('MyProfile'); ``` 這將開始分析 `console.profile` 和 `console.profileEnd` 呼叫之間的程式碼,並在執行 `console.profileEnd` 時在控制台中輸出結果。輸出將包括有關執行所花費時間的詳細訊息、以及其他與性能相關的各種訊息。 ![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjw25tagjwdupmqxy1d5.png) ## 💭 最後的一些想法 在 2023 年,不要僅僅滿足於 `console.log` - JavaScript 控制台物件中有許多**更強大、更有價值的工具和技術。** 從 `console.table` 到 `console.time`,這些方法和技巧將幫助您提高除錯輸出的品質和可讀性,並使其**更容易排除和修復代碼中的問題**。 所以,為什麼不在 2023 年提高您的除錯技能並嘗試這些技術呢? 以上簡單分享,希望對您有幫助!

快速複習 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>; } ``` --- 以上是快速整理,希望對您有幫助!

簡單介紹一下 NextJS 框架

Next.js 是一個開源、輕量的 JavaScript 框架。它讓您能用 React 開發高速又好用的 Web 應用程式與靜態網站。 這篇文章簡單介紹一下這個框架! - 原文出處:https://dev.to/documatic/why-use-nextjs-mn3 # 簡介 Next.js 是用來建造 server-side rendering 的 web 應用程式的 ReactJS 框架。包含很多現成功能,例如程式碼自動拆分、基於檔案的路由、hot reloading 和通用渲染。 https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0oqlfzpvx0rkns65juxt.png Next.js 會在 React 之外處理好工具、設定,並額外提供架構、功能、與效能優化。 Next.js 由 Vercel 的軟體工程師 Guillermo Rauch 打造,並由 Vercel 的開發團隊維護。它是一個開源專案,可以在 GitHub 上找到程式碼。 # Next.js 是做什麼用的? Next.JS 常用來建造以下類型的網站: - 電子商務網站 - 部落格 - 投資組合網站 - 文件網站 - 行銷網站等等 # Next.js 和 React.js 的區別 Next.js 和 React 都是建造 Web 應用程式的常用工具。但是,它們之間有明顯差異,適用不同場景。以下分別討論幾點: # 效能 性能是 Next.js 和 React.js 之間的主要區別。 Next.js 內建許多效能優化,例如圖像優化。這些優化使 Next.js 網站跑起來非常快。 另一方面,ReactJS 是在客戶端渲染,對於高性能應用程式來說,就不太夠力。 # SEO 靜態網站比較適合 SEO 優化,使用 Next.js 很容易做出靜態網站。SEO 越好,在搜尋結果越前面。 而 React 因為是渲染 singe page application,對 SEO 來說就比較吃虧。 # Server-side rendering Next.js 提供伺服器端渲染功能 (SSR)。當您需要為不同用戶提供不同渲染方式,它可以撈資料然後回應不同請求。 雖然可以啟用,但 React 預設不支援伺服器端渲染。SSR 可以與一些伺服器軟體整合,但需要一些額外作業。 # 開發者社群 React 社群很活躍、資源很多。 Next.js 大部份討論都在 GitHub 上面。 React.JS 和 Next.JS 都有很好的開發者體驗。 # 設定檔 使用 Create React App 的話,記得要跳出來才能獨立設定各項設定檔。 使用 Next.js 的話,可以在 Next.js 模板直接自訂 `babelrc`、`jest.config` 和 `eslintrc` 等文件。 # 結論 簡單介紹一下 Next.js ,希望對您有幫助!

如何在 React 中漂亮地 render 一個列表:四點注意事項

面試的時候,常常會被問到這題。看似簡單,其實有一些進階注意事項,此篇與您分享。 - 原文出處:https://dev.to/andyrewlee/stand-out-in-a-react-interview-by-rendering-a-list-like-a-pro-1cn5 # 基本做法 以下是最基本做法。根據陣列內容,直接渲染成一個列表。 ``` import { useState, useEffect } from "react"; const App = () => { const [posts, setPosts] = useState([]); const [currentPost, setCurrentPost] = useState(undefined); useEffect(() => { const initialize = async () => { const res = await fetch("https://jsonplaceholder.typicode.com/posts"); const json = await res.json(); setPosts(json); }; initialize(); }, []); const onPostClick = (post) => { setCurrentPost(post); }; return ( <div> {currentPost && <h1>{currentPost.title}</h1>} <PostList posts={posts} onPostClick={onPostClick} /> </div> ); }; const PostList = ({ posts, onPostClick }) => { return ( <div> {posts.map((post) => ( <Post post={post} onPostClick={onPostClick} /> ))} </div> ); }; const Post = ({ post, onPostClick }) => { const onClick = () => { onPostClick(post); }; return <div onClick={onClick}>{post.title}</div>; }; export default App; ``` # 改進方法 以下是四個可以改進的方向,以及背後的原因。 ## 1. 指定 key 替每個元件提供一個 key 屬性,可以幫助後續 React 渲染時改善效能。要注意 key 屬性要是唯一值,不要直接用陣列索引當成 key。 ``` {posts.map((post) => ( <Post key={post.id} post={post} onPostClick={onPostClick} /> ))} ``` ## 2. 優化渲染 每次點擊列表項目時,都會重新渲染 `PostList` 和每個 `Post`。 ``` const Post = ({ post, onPostClick }) => { console.log("post rendered"); const onClick = () => { onPostClick(post); }; return <div onClick={onClick}>{post}</div>; }; ``` 可以使用 React 提供的 `memo` 功能來優化 `PostList` 元件。用 `memo` 包裝元件時,等於告訴 React:除非 props 改變,否則不要重新渲染這個元件。 ``` import { useState, useEffect, memo } from "react"; const PostList = memo(({ posts, onPostClick }) => { return ( <div> {posts.map((post) => ( <Post post={post} onPostClick={onPostClick} /> ))} </div> ); }); ``` 不過,實際跑下去,會發現還是重新渲染了。因為每次 currentPost 改變時,App 都會重新渲染。每次重新渲染都會重新建立 onPostClick 函數。當一個函數被重新建立時(即使函式內容一樣),都算是新的實體。所以技術上來說,props 確實發生了變化,所以 `PostList` 會重新渲染。 ``` const fn1 = () => {}; const fn2 = () => {}; fn1 === fn2; // => false ``` 這種狀況,就可以使用 useCallback hook 來告訴 React 不要重新建立函數。 ``` const onPostClick = useCallback((post) => { setCurrentPost(post); }, []); ``` 上面的例子中,使用 useCallback 沒問題,可以避免全部貼文被重新渲染。但要知道的是,並非什麼函式都適合包在 useCallback 裡面。 ``` const Post = ({ post, onPostClick }) => { const useCalllback(onClick = () => { onPostClick(post); }, []); return <div onClick={onClick}>{post.title}</div>; }; ``` 比方說,在 Post 元件使用 useCallback 就不太有意義。因為這個元件是輕量級的。應該只在有意義的情況下使用 useCallback(可以用 profiling 工具分析效能確認)。`useCallback` 有缺點:它增加了程式碼的複雜性。使用 useCallback 會在每次渲染時運行的額外程式碼。 ## 3. 元件卸載時清理乾淨 目前的元件沒有在卸載時進行清理。例如,如果在收到 URL 回應結果之前就離開頁面怎麼辦?這時應該要取消請求。 ``` useEffect(() => { const initialize = async () => { const res = await fetch("https://jsonplaceholder.typicode.com/posts"); const json = await res.json(); setPosts(json); }; initialize(); }, []); ``` `useEffect` 可以分為兩部分:掛載時運行的程式碼、卸載時運行的程式碼: ``` useEffect(() => { // When component mounts what code should I run? return () => { // When component unmounts what code should I run (clean up)? }; }, []); ``` 我們可以使用 AbortController ,並在清理時呼叫 controller.abort() 來取消請求。 ``` useEffect(() => { const controller = new AbortController(); const signal = controller.signal; const initialize = async () => { try { const res = await fetch("https://jsonplaceholder.typicode.com/posts", { signal }); const json = await res.json(); setPosts(json); } catch (err) { console.log(err); } }; initialize(); return () => { controller.abort(); }; }, []); ``` ## 4. 增加無障礙輔助功能 以上範例太過簡單,沒有太多無障礙功能可以加入。一旦應用程式變複雜,絕對應該要開始考慮這點。 有個簡單的無障礙測試:可以單獨只使用鍵盤就操作一個應用程式嗎? 關於這點,快速解法是:把每個項目都轉成按鈕,用鍵盤時就可以在元件之間切換。 ``` const Post = ({ post, onPostClick }) => { const onClick = () => { onPostClick(post); }; return <button onClick={onClick}>{post}</button>; }; ``` # 結論 在 React 中渲染列表,乍看之下,只是個簡單的面試問題。但其實可深可淺。下次面試時遇到這問題,可以思考一下此篇文章談到的各個面向。

在 JavaScript 中使用 Regex 正規表示式:懶人 Cheat Sheet 備忘單

需要字串比對、搜尋等等功能時,regex 正規表示式非常好用。以下是一份 regex 的備忘單,方便需要時可以翻閱。 - 原文出處:https://dev.to/emmabostian/regex-cheat-sheet-2j2a --- **測試正規表示式** - 使用 `.test()` 方法 ``` let testString = "My test string"; let testRegex = /string/; testRegex.test(testString); ``` **測試多種模式** - 使用 OR 運算子 (|) ``` const regex = /yes|no|maybe/; ``` **忽略大小寫** - 使用 `i` 標誌不區分大小寫 ``` const caseInsensitiveRegex = /ignore case/i; const testString = 'We use the i flag to iGnOrE CasE'; caseInsensitiveRegex.test(testString); // true ``` **將第一個符合項提取到變數** - 使用 `.match()` 函數 ``` const match = "Hello World!".match(/hello/i); // "Hello" ``` **提取所有符合項到陣列中** - 使用`g`標誌 ``` const testString = "Repeat repeat rePeAT"; const regexWithAllMatches = /Repeat/gi; testString.match(regexWithAllMatches); // ["Repeat", "repeat", "rePeAT"] ``` **匹配任意字元** - 使用通配字元`.`作為任何字元的佔位符 ``` // To match "cat", "BAT", "fAT", "mat" const regexWithWildcard = /.at/gi; const testString = "cat BAT cupcake fAT mat dog"; const allMatchingWords = testString.match(regexWithWildcard); // ["cat", "BAT", "fAT", "mat"] ``` **用多種可能性匹配單個字元** - 定義一組您希望匹配的字元 - 放在中括號內即可`[]` ``` // Match "cat" "fat" and "mat" but not "bat" const regexWithCharClass = /[cfm]at/g; const testString = "cat fat bat mat"; const allMatchingWords = testString.match(regexWithCharClass); // ["cat", "fat", "mat"] ``` **匹配字母表中的字母** - 使用字元集合 `[a-z]` ``` const regexWithCharRange = /[a-e]at/; const catString = "cat"; const batString = "bat"; const fatString = "fat"; regexWithCharRange.test(catString); // true regexWithCharRange.test(batString); // true regexWithCharRange.test(fatString); // false ``` **匹配特定的數字和字母** - 還可以使用連字符來匹配數字 ``` const regexWithLetterAndNumberRange = /[a-z0-9]/ig; const testString = "Emma19382"; testString.match(regexWithLetterAndNumberRange) // true ``` **匹配一個未知字元** - 要匹配您*不*想要的一組字元,請使用否定字元集 - 使用插入符號 `^` 即可 ``` const allCharsNotVowels = /[^aeiou]/gi; const allCharsNotVowelsOrNumbers = /[^aeiou0-9]/gi; ``` **匹配連續出現一次或多次的字元** - 使用`+`符號 ``` const oneOrMoreAsRegex = /a+/gi; const oneOrMoreSsRegex = /s+/gi; const cityInFlorida = "Tallahassee"; cityInFlorida.match(oneOrMoreAsRegex); // ['a', 'a', 'a']; cityInFlorida.match(oneOrMoreSsRegex); // ['ss']; ``` **匹配連續出現零次或多次的字元** - 使用星號`*` ``` const zeroOrMoreOsRegex = /hi*/gi; const normalHi = "hi"; const happyHi = "hiiiiii"; const twoHis = "hiihii"; const bye = "bye"; normalHi.match(zeroOrMoreOsRegex); // ["hi"] happyHi.match(zeroOrMoreOsRegex); // ["hiiiiii"] twoHis.match(zeroOrMoreOsRegex); // ["hii", "hii"] bye.match(zeroOrMoreOsRegex); // null ``` **惰性匹配** - 符合要求的字串的最短部分 - 預設情況下,正則表達式是貪婪匹配(滿足要求的字串的最長部分) - 使用 `?` 字元進行惰性匹配 ``` const testString = "catastrophe"; const greedyRexex = /c[a-z]*t/gi; const lazyRegex = /c[a-z]*?t/gi; testString.match(greedyRexex); // ["catast"] testString.match(lazyRegex); // ["cat"] ``` **匹配起始字串** - 要測試字串開頭的字元,請使用插入符 `^`,但要在字元集之外 ``` const emmaAtFrontOfString = "Emma likes cats a lot."; const emmaNotAtFrontOfString = "The cats Emma likes are fluffy."; const startingStringRegex = /^Emma/; startingStringRegex.test(emmaAtFrontOfString); // true startingStringRegex.test(emmaNotAtFrontOfString); // false ``` **匹配結尾字串** - 在正則表達式末尾使用美元符號 `$` 來檢查字串末尾是否匹配 ``` const emmaAtBackOfString = "The cats do not like Emma"; const emmaNotAtBackOfString = "Emma loves the cats"; const startingStringRegex = /Emma$/; startingStringRegex.test(emmaAtBackOfString); // true startingStringRegex.test(emmaNotAtBackOfString); // false ``` **匹配所有字母和數字** - 使用 `\w` 簡寫 ``` const longHand = /[A-Za-z0-9_]+/; const shortHand = /\w+/; const numbers = "42"; const myFavoriteColor = "magenta"; longHand.test(numbers); // true shortHand.test(numbers); // true longHand.test(myFavoriteColor); // true shortHand.test(myFavoriteColor); // true ``` **匹配除字母和數字以外的所有內容** - 你可以使用 `\w` 的反義詞也就是 `\W` ``` const noAlphaNumericCharRegex = /\W/gi; const weirdCharacters = "!_$!!"; const alphaNumericCharacters = "ab283AD"; noAlphaNumericCharRegex.test(weirdCharacters); // true noAlphaNumericCharRegex.test(alphaNumericCharacters); // false ``` **匹配所有數字** - 你可以使用字元集 `[0-9]`,或者使用簡寫形式 `\d` ``` const digitsRegex = /\d/g; const stringWithDigits = "My cat eats $20.00 worth of food a week."; stringWithDigits.match(digitsRegex); // ["2", "0", "0", "0"] ``` **匹配所有非數字** - 你可以使用 `\d` 的反義詞也就是 `\D` ``` const nonDigitsRegex = /\D/g; const stringWithLetters = "101 degrees"; stringWithLetters.match(nonDigitsRegex); // [" ", "d", "e", "g", "r", "e", "e", "s"] ``` **匹配空格** - 使用 `\s` 匹配空格和換行 ``` const sentenceWithWhitespace = "I like cats!" var spaceRegex = /\s/g; whiteSpace.match(sentenceWithWhitespace); // [" ", " "] ``` **匹配非空格** - 你可以使用 `\s` 的反義詞也就是 `\S` ``` const sentenceWithWhitespace = "C a t" const nonWhiteSpaceRegex = /\S/g; sentenceWithWhitespace.match(nonWhiteSpaceRegex); // ["C", "a", "t"] ``` **匹配字元數** - 您可以使用 `{lowerBound, upperBound}` 在一行中指定特定數量的字元 ``` const regularHi = "hi"; const mediocreHi = "hiii"; const superExcitedHey = "heeeeyyyyy!!!"; const excitedRegex = /hi{1,4}/; excitedRegex.test(regularHi); // true excitedRegex.test(mediocreHi); // true excitedRegex.test(superExcitedHey); //false ``` **匹配最少的字元數** - 您可以使用 `{lowerBound,}` 要求滿足最少數量的字元 - 這稱為數量說明符 ``` const regularHi = "hi"; const mediocreHi = "hiii"; const superExcitedHey = "heeeeyyyyy!!!"; const excitedRegex = /hi{2,}/; excitedRegex.test(regularHi); // false excitedRegex.test(mediocreHi); // true excitedRegex.test(superExcitedHey); //false ``` **匹配準確的字元數** - 您可以使用 `{requiredCount}` 指定要求字元數 ``` const regularHi = "hi"; const bestHi = "hii"; const mediocreHi = "hiii"; const excitedRegex = /hi{2}/; excitedRegex.test(regularHi); // false excitedRegex.test(bestHi); // true excitedRegex.test(mediocreHi); //false ``` **某字元可以不出現** - 要允許某字元可以不出現,請使用 `?` ``` const britishSpelling = "colour"; const americanSpelling = "Color"; const languageRegex = /colou?r/i; languageRegex.test(britishSpelling); // true languageRegex.test(americanSpelling); // true ``` --- 以上是基礎用法&範例,方便工作時可以查閱!

關於 JavaScript 開發的 8 個少見、但還不錯用小技巧

JavaScipt 是非常流行的程式語言,其中有些少見技巧,但還不錯用,這篇文章會分享八個,給您參考看看! - 原文出處:https://dev.to/worldindev/8-javascript-tips-tricks-that-no-one-teaches-24g1 # 函數繼承 函數繼承就是先寫一個基礎函數,再寫一個擴充函數,來擴充屬性與方法,會像這樣: ``` // Base function function Drinks(data) { var that = {}; // Create an empty object that.name = data.name; // Add it a "name" property return that; // Return the object }; // Fuction which inherits from the base function function Coffee(data) { // Create the Drinks object var that = Drinks(data); // Extend base object that.giveName = function() { return 'This is ' + that.name; }; return that; }; // Usage var firstCoffee = Coffee({ name: 'Cappuccino' }); console.log(firstCoffee.giveName()); // Output: "This is Cappuccino" ``` # .map() 的替代方案 `.map()` 有一個替代方案,就是 `.from()`: ``` let dogs = [ { name: ‘Rio’, age: 2 }, { name: ‘Mac’, age: 3 }, { name: ‘Bruno’, age: 5 }, { name: ‘Jucas’, age: 10 }, { name: ‘Furr’, age: 8 }, { name: ‘Blu’, age: 7 }, ] let dogsNames = Array.from(dogs, ({name}) => name); console.log(dogsNames); // returns [“Rio”, “Mac”, “Bruno”, “Jucas”, “Furr”, “Blu”] ``` # 數字轉字串/字串轉數字 通常,要讓數字轉為字串,會這樣寫 ``` let num = 4 let newNum = num.toString(); ``` 然後字串轉數字,會這樣寫 ``` let num = "4" let stringNumber = Number(num); ``` 但有個更快的寫法是: ``` let num = 15; let numString = num + ""; // number to string let stringNum = + numString; // string to number ``` # 使用長度來調整和清空陣列 在 javascript 中,我們可以改寫 length 內建方法,直接設定一個新值。 舉個例: ``` let array_values = [1, 2, 3, 4, 5, 6, 7, 8]; console.log(array_values.length); // 8 array_values.length = 5; console.log(array_values.length); // 5 console.log(array_values); // [1, 2, 3, 4, 5] ``` 還能用來清空陣列: ``` let array_values = [1, 2, 3, 4, 5, 6, 7,8]; console.log(array_values.length); // 8 array_values.length = 0; console.log(array_values.length); // 0 console.log(array_values); // [] ``` # 使用陣列解構來交換值 陣列解構讓陣列或物件的屬性,可以拆出來到變數中。還可以用它來交換兩個元素,舉例如下: ``` let a = 1, b = 2 [a, b] = [b, a] console.log(a) // result -> 2 console.log(b) // result -> 1 ``` # 刪除陣列中的重複元素 這個技巧很簡單。比方說,我創建了一個包含重複元素的陣列,然後我想刪除重複項: ``` const array = [1, 3, 2, 3, 2, 1, true, false, true, 'Kio', 2, 3]; const filteredArray = [...new Set(array)]; console.log(filteredArray) // [1, 3, 2, true, false, "Kio"] ``` # for 迴圈的簡寫版 可以這樣寫: ``` const names = ["Kio", "Rio", "Mac"]; // Long Version for (let i = 0; i < names.length; i++) { const name = names[i]; console.log(name); } // Short Version for (let name of names) console.log(name); ``` # 效能監測 下面這張圖是 google 用秒數提示效能: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i7ed89oyhcyyjhqirvc6.png 在 JavaScript 中也能做到,就像這樣: ``` const firstTime = performance.now(); something(); const secondTime = performance.now(); console.log(`The something function took ${secondTime - firstTime} milliseconds.`); ``` --- 以上八個技巧,希望對您有幫助!

JavaScript 中關於陣列的 13 個入門小技巧

陣列是 JavaScript 中最常用到的概念之一。處理資料時很常用到這種資料結構。這篇文章介紹一些陣列操作的基本方法,希望對你有幫助! - 原文出處:https://dev.to/duomly/13-useful-javascript-array-tips-and-tricks-you-should-know-2jfo # 1. 從陣列中移除重複項目 很經典的面試問題,需要從陣列中找出獨立值。使用 Set 資料型態,可以輕易完成這任務。這邊介紹兩種方法,一個使用 .from() 一個使用 ... 展開運算子。 ``` var fruits = [“banana”, “apple”, “orange”, “watermelon”, “apple”, “orange”, “grape”, “apple”]; // First method var uniqueFruits = Array.from(new Set(fruits)); console.log(uniqueFruits); // returns [“banana”, “apple”, “orange”, “watermelon”, “grape”] // Second method var uniqueFruits2 = […new Set(fruits)]; console.log(uniqueFruits2); // returns [“banana”, “apple”, “orange”, “watermelon”, “grape”] ``` 很簡單吧! # 2. 從陣列中抽換掉某個元素 這個情境也很常見。有一個簡單的好方法,就是使用 .splice ,參數分別是開始修改的位置、修改幾個元素、要更改成哪些值。 ``` var fruits = [“banana”, “apple”, “orange”, “watermelon”, “apple”, “orange”, “grape”, “apple”]; fruits.splice(0, 2, “potato”, “tomato”); console.log(fruits); // returns [“potato”, “tomato”, “orange”, “watermelon”, “apple”, “orange”, “grape”, “apple”] ``` # 3. 不用 .map() 的 map 功能 .map() 很常用、大家都會用,但有一個方法也很不錯,也很簡潔,就是 .from() ``` var friends = [ { name: ‘John’, age: 22 }, { name: ‘Peter’, age: 23 }, { name: ‘Mark’, age: 24 }, { name: ‘Maria’, age: 22 }, { name: ‘Monica’, age: 21 }, { name: ‘Martha’, age: 19 }, ] var friendsNames = Array.from(friends, ({name}) => name); console.log(friendsNames); // returns [“John”, “Peter”, “Mark”, “Maria”, “Monica”, “Martha”] ``` # 4. 清空陣列 有時候你會需要清空一個陣列。一個一個把元素刪掉太慢了,下面這個方法快多了:直接把長度設為 0 吧! ``` var fruits = [“banana”, “apple”, “orange”, “watermelon”, “apple”, “orange”, “grape”, “apple”]; fruits.length = 0; console.log(fruits); // returns [] ``` # 5. 把陣列轉換為物件 有時需要把陣列轉成物件。使用 ... 展開運算子可以很快完成這任務。 ``` var fruits = [“banana”, “apple”, “orange”, “watermelon”]; var fruitsObj = { …fruits }; console.log(fruitsObj); // returns {0: “banana”, 1: “apple”, 2: “orange”, 3: “watermelon”, 4: “apple”, 5: “orange”, 6: “grape”, 7: “apple”} ``` # 6. 陣列塞滿資料 有時需要把一個陣列塞滿某些資料。使用 .fill() 可以快速完成這任務: ``` var newArray = new Array(10).fill(“1”); console.log(newArray); // returns [“1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”, “1”] ``` # 7. 合併陣列 老方法是使用 .concat() 來合併。但有個新方法,就是用 ... 展開運算子,非常簡單俐落: ``` var fruits = [“apple”, “banana”, “orange”]; var meat = [“poultry”, “beef”, “fish”]; var vegetables = [“potato”, “tomato”, “cucumber”]; var food = […fruits, …meat, …vegetables]; console.log(food); // [“apple”, “banana”, “orange”, “poultry”, “beef”, “fish”, “potato”, “tomato”, “cucumber”] ``` # 8. 找出陣列交集 這也是 JavaScript 面試最常見的問題。這邊使用 filter 跟 .includes 來完成這任務。 ``` var numOne = [0, 2, 4, 6, 8, 8]; var numTwo = [1, 2, 3, 4, 5, 6]; var duplicatedValues = […new Set(numOne)].filter(item => numTwo.includes(item)); console.log(duplicatedValues); // returns [2, 4, 6] ``` # 9. 把 false 相關的值從陣列移除 false 相關值包含 false, 0, "", null, NaN, undefined。使用 .filter() 可以俐落地過濾陣列。 ``` var mixedArr = [0, “blue”, “”, NaN, 9, true, undefined, “white”, false]; var trueArr = mixedArr.filter(Boolean); console.log(trueArr); // returns [“blue”, 9, true, “white”] ``` # 10. 從陣列撈出隨機元素 有時需要隨機撈元素出來。根據陣列長度,隨機撈一個索引出來,就可以囉。 ``` var colors = [“blue”, “white”, “green”, “navy”, “pink”, “purple”, “orange”, “yellow”, “black”, “brown”]; var randomColor = colors[(Math.floor(Math.random() * (colors.length)))] ``` # 11. 逆轉陣列 不需要複雜的迴圈跟函數,也能逆轉一個陣列。這樣一行就可以: ``` var colors = [“blue”, “white”, “green”, “navy”, “pink”, “purple”, “orange”, “yellow”, “black”, “brown”]; var reversedColors = colors.reverse(); console.log(reversedColors); // returns [“brown”, “black”, “yellow”, “orange”, “purple”, “pink”, “navy”, “green”, “white”, “blue”] ``` # 12. .lastIndexOf() 方法 這個有趣的方法,可以找到特定元素最後一次出現的索引。如果陣列中有重複值,就可用上這方法。 ``` var nums = [1, 5, 2, 6, 3, 5, 2, 3, 6, 5, 2, 7]; var lastIndex = nums.lastIndexOf(5); console.log(lastIndex); // returns 9 ``` # 13. 陣列中全部數值加總 這也是面試常見考題。使用 .reduce 可以快速解決這問題。 ``` var nums = [1, 5, 2, 6]; var sum = nums.reduce((x, y) => x + y); console.log(sum); // returns 14 ``` # 結論 這 13 個小技巧,分別有一些進階觀念可以研究,這篇文章作為入門介紹,希望對您的工作有幫助!

開發 React 時,推薦使用這些 Best Practices

在開發 React App 時,遵循一些 best practices 會使您的程式碼品質提高,這篇文章列出一些給您參考。 - 原文出處:https://dev.to/iambilalriaz/react-best-practices-ege # 強烈推薦 VS Code 作為 IDE Visual Studio Code 有幾個超好用的 React 功能。強大的外掛生態系,對開發者大有幫助: - Prettier - ES Lint - JavaScript (ES6) code snippets - Reactjs code snippets - Auto import # 使用 ES6 語法 程式碼越漂亮越好。在 JavaScript 中,採用 ES6 語法可以讓程式碼更簡潔。 ## Arrow Functions ``` // ES5 function getSum(a, b) { return a + b; } // ES6 const getSum = (a, b) => a + b; ``` ## Template Literal ``` // ES5 var name = "Bilal"; console.log("My name is " + name); // ES6 const name = "Bilal"; console.log(`My name is ${name}`); ``` ## const $ let const $ let 有各自的變數作用域。const 宣告的變數不能修改,let 宣告的變數可以修改。 ``` // ES5 var fruits = ["apple", "banana"]; // ES6 let fruits = ["apple", "banana"]; fruits.push("mango"); const workingHours = 8; ``` ## Object Destructuring ``` var person = { name: "John", age: 40, }; // ES5 var name = person.name; var age = person.age; // ES6 const { name, age } = person; ``` ## Defining Objects ``` var name = "John"; var age = 40; var designations = "Full Stack Developer"; var workingHours = 8; // ES5 var person = { name: name, age: age, designation: designation, workingHours: workingHours, }; // ES6 const person = { name, age, designation, workingHours }; ``` ES6 的語法特性、彈性,很多值得您一試。 # JSX 使用 map 時記得加上 key array map 時,永遠記得替每個元素加上獨立的 key 值。 ``` const students = [{id: 1, name: 'Bilal'}, {id: 2, name: 'Haris'}]; // in return function of component <ul> {students.map(({id, name}) => ( <li key={id}>{name}</li> ))} </ul>; ``` # 元件名稱使用 PascalCase ``` const helloText = () => <div>Hello</div>; // wrong const HelloText = () => <div>Hello</div>; // correct ``` # 變數和函數名稱使用 camelCase ``` const working_hours = 10; // bad approach const workingHours = 10; // good approach const get_sum = (a, b) => a + b; // bad approach const getSum = (a, b) => a + b; // good approach ``` # ID 和 css class 名稱使用 kebab-case ``` <!--bad approach--> <div className="hello_word" id="hello_world">Hello World</div> <!--good approach --> <div className="hello-word" id="hello-world">Hello World</div> ``` # 永遠要檢查物件&陣列的 null & undefined 忘記檢查的話,常常會導致一堆錯誤。 所以要保持檢查的習慣。 ``` const person = { name: "Haris", city: "Lahore", }; console.log("Age", person.age); // error console.log("Age", person.age ? person.age : 20); // correct console.log("Age", person.age ?? 20); //correct const oddNumbers = undefined; console.log(oddNumbers.length); // error console.log(oddNumbers.length ? oddNumbers.length : "Array is undefined"); // correct console.log(oddNumbers.length ?? "Array is undefined"); // correct ``` # 避免 Inline Styling Inline styling 會讓 jsx 程式碼變得很亂。用單獨的 css 文件拆分出來比較好。 ``` const text = <div style={{ fontWeight: "bold" }}>Happy Learing!</div>; // bad approach const text = <div className="learning-text">Happy Learing!</div>; // good approach ``` 在 .css 文件中: ``` .learning-text { font-weight: bold; } ``` # 避免 DOM 操作 用 React state 為主,別用 DOM 操作 糟糕做法: ``` <div id="error-msg">Please enter a valid value</div> ``` ``` document.getElementById("error-msg").visibility = visible; ``` 推薦做法: ``` const [isValid, setIsValid] = useState(false); <div hidden={isValid}>Please enter a valid value</div>; ``` 使用 isValid 來管理 UI 顯示邏輯。 # 在 useEffect 記得清乾淨每個事件監聽器 加過的事件監聽器,都要記得清乾淨: ``` const printHello = () => console.log("HELLO"); useEffect(() => { document.addEventListener("click", printHello); return () => document.removeEventListener("click", printHello); }); ``` # 避免重複開發,多寫通用元件 讓程式碼越乾淨越好。相似的東西可以寫通用元件。再根據 props 內容傳遞來處理相異處即可: ``` const Input=(props)=>{ const [inputValue, setInputValue]=useState(''); return( <label>{props.thing}</label> <input type='text' value={inputValue} onChange={(e)=>setInputValue(e.target.value)} /> ) } ``` 在其他元件中,就能這樣用: ``` <div> <Input thing="First Name" /> <Input thing="Second Name" /> </div> ``` # 檔案要分類一下 相關檔案可以分類成一個資料夾。 例如在 React 寫一個導覽列,那就可以開一個資料夾,相關的 .js 與 .css 檔案放裡面。 # 寫 functional components 為主 簡單顯示一些東西、沒用到 state 的話,那寫 functional components 比寫 class components 好。 如果你會寫 react hooks 的話,那就連 state 都完全不成問題。 # 養成編寫輔助函數的習慣 有時你在 React App 中會需要一些通用功能。 這種情況,可以開一個 `helper-functions.js` 檔案,在裡面寫輔助函數,就可以到處使用了。 ## 使用三元運算子代替 if/else if 使用 `if/else if` 語句會使程式碼變得龐大。使用三元運算子,就簡潔、清楚多了: ``` // Bad approach if (name === "Ali") { return 1; } else if (name === "Bilal") { return 2; } else { return 3; } // Good approach name === "Ali" ? 1 : name === "Bilal" ? 2 : 3; ``` # 新增 index.js 檔案,讓匯入元件更簡單 如果你在 actions 資料夾中有一個 index.js 檔案,當你想在元件中導入時,會像這樣: ``` import { actionName } from "src/redux/actions"; ``` actions 後面的 index.js 可以省略不寫,就不用這樣囉唆了: ``` import { actionName } from "src/redux/actions/index"; ``` # Destructuring of Props 物件屬性名稱可以拆出來,後面用起來比較方便。 假設你的元件有 `name`、`age` 和 `designation` 這些 props: ``` // Bad approach const Details = (props) => { return ( <div> <p>{props.name}</p> <p>{props.age}</p> <p>{props.designation}</p> </div> ); }; // Good approach const Details = ({ name, age, designation }) => { return ( <div> <p>{name}</p> <p>{age}</p> <p>{designation}</p> </div> ); }; ``` # 不要嘗試在同一函數中,去碰修改過的 state 變數 在一個函數中,如果你正在為一個狀態變數賦值,在同一個函數中,是拿不到新值的 ``` const Message = () => { const [message, setMessage] = useState("Hello World"); const changeMessage = (messageText) => { setMessage("Happy Learning"); console.log(message); // It will print Hello World on console }; return <div>{message}</div>; }; ``` # 使用 === 運算子代替 == 在比較兩個值時,嚴格檢查變數型別比較好: ``` "2" == 2 ? true : false; // true "2" === 2 ? true : false; // false ``` --- 以上 Best Practices 供您參考,祝福您不斷變強!

10 個現代 JavaScript 中的好用語法:新手推薦

在 ES6 版本之後,Javascript 多了很多好用的語法,建議新手一定要學起來這幾招。 - 原文出處:https://dev.to/azure/modern-javascript-10-things-you-should-be-using-starting-today-1adm # -1- 展開運算子 Spred operator 在物件或陣列前面寫 ... 可以很輕鬆地把資料展開,舉例來說: ## Spread array ``` let firstHalf = [ 'one', 'two']; let secondHalf = ['three', 'four', ...firstHalf]; ``` 寫起來非常簡潔。不然原本要這樣寫: ## NO Array spread ``` let firstHalf = [ 'one', 'two']; let secondHalf = ['three', 'four']; for(var i=0, i <firstHalf.length; i++ ) { secondHalf.push(firstHalf[i]); } ``` 用在物件也可以,能夠合併屬性: ## Spread object ``` const hero = { name: 'Xena - Warrior Princess', realName: 'Lucy Lawless' } const heroWithSword = { ...hero, weapon: 'sword' } ``` 不然的話,就要用迴圈來跑全部屬性: ## NO Object spread ``` let keys = Object.keys(hero); let obj = {}; for(var i=0; i< keys.length; i++) { obj[keys[i]] = keys[props[i]]; } ``` 舊寫法其實有 Object.assign() 可以用,看起來會像: ``` const heroWithSword = Object.assign({}, hero, {weapon:"sword"}) ``` 但展開運算子還是簡潔多了: ``` const heroWithSword = { ...hero, weapon: 'sword' } ``` # -2- 其餘參數 Rest parameter 其餘參數能夠將剩下的參數蒐集到一個陣列中。JavaScript 有足夠彈性可以處理這些參數。通常會這樣寫: ``` function add(first, second, ...remaining) { return first + second; } ``` 以上只是加總前兩個參數,也就是 add(1,2) 或 add(1,2,3, 4) 結果一樣。接著這樣改寫: ``` function add(first, second, ...remaining) { return first + second + remaining.reduce((acc, curr) => acc + curr, 0); } ``` 這樣就會把全部參數都加總在一起了。 如您所見,前面加上 ... 就可以搜集其餘參數。這是一種命名變數的方式而已,比較少人知道這招,但可以知道一下。 # -3- 字串插值 String interpolation 看過這種寫法嗎? ``` class Product { constructor(name, description, price) { this.name = name; this.description = description; this.price = price; } getDescription() { return " Full description \n" + " name: " + this.name + " description: " + this.description } } ``` 看看那個 getDescription() 方法,又長、跨行、又難讀。在大多數程式語言都只能這樣寫。幸好,有些程式語言支援字串插值,包括 JavaScript,所以可以改寫如下: ``` getDescription() { return `Full description \n: name: ${this.name} description ${this.description} `; } ``` 反引號 ` 可以定義多行字串。再使用 ${} 進行插值。是不是好多了呢:) # -4- 屬性縮寫 Shorthand properties 雖然還沒搞懂,你可能早就在用了。在 ES5 需要這樣寫: ``` function createCoord(x, y) { return { x: x, y: y } } ``` 在 ES6 之後,如果 : 後面名稱一樣,可以直接省略,像這樣: ``` function createCoord(x, y) { return { x, y } } ``` 簡潔多了吧? # -5- 方法屬性 Method properties 在物件裡面指向方法的寫法。以下是 ES5 寫法: ``` const math = { add: function(a,b) { return a + b; }, sub: function(a,b) { return a - b; }, multiply: function(a,b) { return a * b; } } ``` 在 ES6 之後可以少寫一大堆,像這樣: ``` const math = { add(a,b) { return a + b; }, sub(a,b) { return a - b; }, multiply(a,b) { return a * b; } } ``` # -6- 解構 Destructuring 解構用得好,有益身心健康。 ## Object destructuring 這段: ``` function handle(req, res) { const name = req.body.name; const description = req.body.description; const url = req.url; log('url endpoint', url); // lots of logic happening dbService.createPerson( name, description ) } ``` 有點難讀吧,但要從多層深度挖資料,就會寫成這樣。還能怎麼辦?其實有以下妙招喔: ``` function handle(req, res) { const { body: { name, description }, url }, = req; log('url endpoint', url); // lots of logic happening dbService.createPerson( name, description ) ``` 變成俐落的一行了。 ## Array destructuring 不只物件能用,陣列也可以用,像這段: ``` const array = [1,2,3,4,5,6]; const a = array[0]; const c = array[2]; ``` 可以更優雅地改寫成這樣: ``` const array = [1,2,3,4,5,6]; const [a, ,c, ...remaining] = array; // remaining = [4,5,6] ``` 上面的模式配對,就可以拆出我們需要的變數。如果要跳過某值,就寫 , , 即可。我另外多寫了一個 rest parameter 來取得其餘資料。 ## Parameter matching 函數的參數也能這樣寫。當函數有超過 2-3 個參數時,業界慣例常常是這樣寫: ``` function doSomething(config) { if(config.a) { ... } if(config.b) { ... } if(config.c) { ... } } ``` 更漂亮的寫法其實是: ``` function doSomething({ a, b, c }) { if(a) { ... } if(b) { ... } if(c) { ... } } ``` # -7- 陣列方法 ES6 有大量好用的陣列方法,例如: - find(),回傳符合條件的項目,否則回傳 null - findIndex(),尋找項目的索引 - some(), 確認是否包含符合條件的項目 - includes(), 確認是否包含某個項目 舉例說明如下: ``` const array = [{ id: 1, checked: true }, { id: 2 }]; arr.find(item => item.id === 2) // { id: 2 } arr.findIndex(item => item.id === 2) // 1 arr.some(item => item.checked) // true const numberArray = [1,2,3,4]; numberArray.includes(2) // true ``` # -8- Promises + Async/Await 在只有 callback 能寫的年代,這種寫法很常見: ``` function doSomething(cb) { setTimeout(() => { cb('done') }, 3000) } doSomething((arg) => { console.log('done here', arg); }) ``` 用來寫非同步任務時,就會這樣寫。但現在我們有 promise 能寫了,所以可以這樣: ``` function doSomething() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('done') }, 3000) }) } doSomething().then(arg => { console.log('done here', arg); }) ``` 多個流程還能整個串起來,就像這樣: ``` getUser() .then(getOrderByUser) .then(getOrderItemsByOrder) .then(orderItems => { // do something with order items }) ``` ## Async/await 接著還有 async/await 可以用。上方的範例,相關 promise 變成: ``` async function getItems() { try { const user = await getUser(); const order = await getOrderByUser(user); const items = await getOrderItemsByOrder(order); return items; } catch(err) { // handle error here, the suggestion to return something or rethrow } } getItems().then(items => { // do something with order items }) ``` 看起來像是同步,但其實非同步的一段程式碼:) # -9- 模塊 Modules 幾乎所有程式語言都支援模塊功能。將程式碼分為多個檔案,各自為獨立單元,就是模塊了。像這樣: ``` // math.js export function add(a,b) { return a + b; } export function sub(a,b) { return a - b; } export default (a,b) => a * b; // main.js import mult, { add, sub } from './math'; mult(2, 4) // 8 add(1,1) // 2 sub(1,2) // -1 ``` 使用 export 關鍵字來表示 add 跟 sub 是公開可用的。export default 代表不指定函數時直接導入的內容。在 main.js 中,將預設導入命名為 mult,然後指定導入函數 add 和 sub。 # -10- 箭頭函數 + this 整篇文章一直在用箭頭函數,其實只是另一種函數的寫法而已。以前要這樣寫: ``` function printArray(arr) { // do something } ``` 現在可以這樣寫: ``` const printArray = (arr) => { // do something } ``` ## 單行函數 函數還可以用一行寫完: ``` const add = (a,b) => a + b ``` 這種寫法可以省略 return 直接回傳結果。要回傳物件也可以,這樣即可: ``` const create = (a,b) = > ({ x: a, y: b }) ``` ## Lexical this 以前常常會搞混 this 代表什麼,舉例來說: ``` let array = [1,2,3]; function sum() { this.total = 0; arr.forEach(function(item) { this.total+= item; // `this` is the inner functions `this`, BAD }) return total; } ``` 這個例子中,this 在 forEach 指錯地方了。以前的解法是: ``` function sum() { this.total = 0; var self = this; arr.forEach(function(item) { self.total+= item; // now we are using `self`, it solves it but feels hacky }) return total; } ``` 雖然多寫個 self 變數可以解決,但實在很鳥。新的箭頭函數寫法則解決了這問題: ``` function sum() { this.total = 0; arr.forEach((item) => { this.total+= item; // all is well `this` points to outer function }) return total; } ``` # 結論 ES6 之後有很多好東西可以用,今天先介紹一些,希望對大家有幫助!

7個超特別的工程師作品集網頁:讓您大開眼界

工程師要怎麼設計作品集網頁呢?來看看這些人的網頁,或許能給你一些靈感! - 原文出處:https://dev.to/ruppysuppy/7-developer-portfolio-for-inspiration-4no7 # 1. Bruno Simon 如果您有試過開發 3D 網站,那你一定聽過 Bruno Simon。他是 Three.js Journey 的作者。從他的作品集就可看出為什麼他是這個領域的高手。 他的作品集網站,本身就是一個電玩遊戲。你可以在裡面控制吉普車,在 3D 世界裡面開車,然後可在裡面探索他的作品集世界。這網站可說是作品集網站的巔峰之作。 https://bruno-simon.com/ ![](https://imgur.com/kqpLGNH.png) # 2. Robby Leonardi 另一個超厲害的作品集網站!Robby Leonardi 的作品集是一個互動式的履歷表,往下滑就可以瀏覽他的作品、看到更多個人資訊。 http://www.rleonardi.com/interactive-resume/ ![](https://imgur.com/tZ6QJcX.png) # 3. Nitin Ranganath 一個有創意、又很新潮的網站!整個作品集頁面,看起來就像是 VS Code 編輯器! https://vscode-portfolio.vercel.app/ ![](https://imgur.com/4ePEkBe.png) # 4. Dejan Markovic 與傳統網頁設計的風格大相徑庭,但實際操作起來,卻非常順暢、巧妙! https://www.dejan.works/ ![](https://imgur.com/w0jf0i6.png) # 5. Hype4 極簡主義風格的網站,具有超級簡潔、專業的設計感。 https://hype4.com/ ![](https://imgur.com/FhT8j3c.png) # 6. Jacek Jeznach 利用微互動來提高留存率的絕佳範例。雖然網站上的廣告很煩人,但對於互動細節的設計,值得您親自見識一下! https://jacekjeznach.com/ ![](https://imgur.com/NR7v2KV.png) # 7. Tapajyoti Bose 最後一個範例讓我老王賣瓜一下!😜 我做了一個帶有滾動特效的單頁式作品集網站! https://tapajyoti-bose.vercel.app/ ![](https://imgur.com/GpmgsPC.png) --- 以上,希望大家覺得有趣、有啓發性!