🔍 搜尋結果:專案

🔍 搜尋結果:專案

JavaScript 系列八:結語

恭喜你完成了一系列的專案開發挑戰 放眼市面上的新手教材,應該沒人會把作業設定到這麼困難! 但我認為時機差不多了,所以要求一些有挑戰性、有趣的專案來讓你做,應該難不倒你 而且這種只用基本功能,就完成複雜專案的經驗,有助於掌握框架的本質、熟練框架基礎 既然你通通順利完成了,代表你的學習狀況「相當不錯」...... 再次跟你說聲恭喜! --- 這些專案內容,已經相當接近實務上、職場上會遇到的開發需求 也就是說,你的開發經驗已經「大大提升」了不少 事實上,光是目前的技能與經驗,已經可以應付職場上絕大多數的功能要求 你已經離「進入職場工作」,又大大靠近了一步! 但是呢,要能夠與團隊共同開發中大型專案,還是需要學習框架進階觀念、生態系、以及 JavaScript 生態系各種工具 坊間補習班,通常會在課程很早期開始教上述這些內容。我認為這會令學習者非常眼花撩亂 所以我讓你僅僅學完 `Essentials` 的內容,就立刻動手開發複雜、好玩的應用程式 我認為這樣才能清楚認識框架的強大,以及知道「工具不是導入越多、搞得越複雜就越好」 而是要視情況,只導入必要的、大小適宜的技術工具,這樣才能收放自如 那麼更大型的專案,又該引入哪些進階觀念、生態系工具呢? 這些會在後續的課程提到! --- 消化、研究完本課程之後,關於 JavaScript 更多必學的基本觀念 請接著前往「自學網頁の嬰兒教材:JavaScript(九)」開始學習吧! https://codelove.tw/@howtomakeaturn/course/QxMYx5

前 Netflix 資深工程師:爲什麼我會辭掉年薪 $450,000 美元的工作

Michael Lin 是前網飛資深工程師,年薪高達 45 萬美元,約合新台幣 1300 萬元 但是他在工作四年後離職了,並且在網路上分享了心得 - 原文出處:https://dev.to/_michaellin/why-i-quit-a-450000-engineering-job-at-netflix-1f0g --- ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucmypesj5zywleeojx92.png) > 金手銬 —— 你留在一份你寧願辭職、只是為了錢而待著的工作。 我以為我會永遠留在 Netflix。市場上薪酬最高。講求自由與責任。無限帶薪假期。你還能要求什麼呢? 所以當我在 2021 年 5 月離開 Netflix 時,每個人都認為我瘋了。我父母首先反對。他們來自文化大革命時期的中國,當時幾乎沒有足夠的食物吃,他們認為我正在拋棄他們來到美國所經歷辛苦的一切。 “低下頭去幹活就對了!”他們說。 “不要對你所擁有的不知感恩!”他們說。 我的朋友們也不相信。 “有一堆免費食物欸!” “FAANG 巨頭欸!” “帶著慢慢領股票呀!” 我聽到的唯一讓我略微停頓的反對論點,來自我在 Netflix 的導師。他說我不應該在沒有找到另一份工作的情況下辭職,因為“我會放棄我在 Netflix 的高薪所擁有的影響力。” ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lb8qyf1sxngv1xeateei.png) > 一邊休息一邊慢慢領股票 這讓我停頓了整整 3 天,但我還是放棄了。8 個月後的現在,我 100% 確定這是正確的決定。 在這篇文章中,我想談談幫助我了解金手銬真正成本的 3 個因素,以及為什麼每年 50 萬美元的薪水也無法讓我繼續從事我不再喜歡的工作。 ## 一個失敗的角色轉換 隨著辦公室於 2020 年 3 月關閉,工作中所有最好的部分 ——社交、同事、津貼,都消失了。 而你剩下的就是工作本身。因此,如果您不喜歡這份工作,而這就是您的全部,那麼 COVID 會將這一事實放大 10 倍以上。 而且我不喜歡這份工作。但原本不是這樣的。 我在 Netflix 工作了將近 4 年,擔任用戶增長方面的資深軟體工程師。一開始,我覺得自己得到了豐厚的報酬來學習。工作了 1.5 年左右,我都喜歡它。 Netflix 的文化與我之前在亞馬遜經歷過的更為隱秘的文化截然不同。每個產品決策的備忘錄都可供所有員工閱讀。這就像拿錢去讀 MBA。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2amgontvgl7nkhlkecsf.png) > Netflix 對其所有產品決策的透明度是在那裡工作的最佳福利之一。這與蘋果和亞馬遜更為隱秘的文化形成鮮明對比。 但是在我的後半段時間裡,工程工作開始感覺像是複制粘貼。 需要啟動一個新的微服務? 複製粘貼一個舊的,更改業務邏輯,你就完成了。 新的 A/B 測試? 複製粘貼舊的,更改一些測試變體,就完成了。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8g1j19x9dvj8lvbga9wk.png) > Netflix 非常喜歡 A/B 測試。這是他們從主頁(來自 Netflix 技術部落格)測試的 CTA 的 4 個變體 我覺得毫無疑問工程可以為 Netflix 所用,但我覺得更好的問題是,某個特定專案是否充分利用了工程資源。所以我想過渡到產品管理,在那裡我可以領導這些工作。我花了 2 年的時間在公司轉了一圈,不停地建立聯繫,與每個組織交談,併申請我能找到的每一個職位。 當我向每個組織申請時,我提交了關於我作為 PM 的優先事項的建議:客戶服務、開發人員生產力、工作室、合作夥伴關係和通知。我建議在我自己的團隊中建立一個角色來幫助管理不斷增長的基礎設施。我還建議其他 PM 可以將更多工作委託給我,這樣他們就可以騰出時間來發展他們的組織。所有這些提議最終都沒有成功。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rchwbz4agbjhitt38tiq.png) > 我花了 2 年的時間兜圈子試圖在 Netflix 找到一份 PM 的工作,但最終落得一場空。 回過頭來看,我意識到自己的錯誤。我想如果我再努力一點,我最終會得到這份工作。但現在我意識到,有時由於結構性問題,事情超出了你的控制。 Netflix 沒有適當的流程來支持這樣的橫向角色變更;我從未見過工程師在這裡成功過渡到產品管理。 他們為我提供了更多與產品管理合作的機會,以培養產品技能,對此我深表感謝。但合作與擁有角色本身不同。歸根結底,你不能只讀一本關於游泳的書就指望學會游泳。你必須跳入水中。 ## 動力減弱,表現減弱 在我失敗的 PM 求職接近尾聲時,我覺得高薪是一個越來越糟糕的優點。原本是在賺錢和學習。現在我只是在賺錢。 我團隊的目標和我的興趣也開始出現分歧。我的團隊正在朝著涉及平台遷移的更注重工程的方向發展。但我的興趣更多地轉向創業和產品管理。我分配的工程工作永遠不會適用於我以後所做的任何其他工作。 我開始覺得我又犯了以前的職業錯誤 - 在一份不適合我的工作上待的時間比我應該做的要長。這個錯誤的代價比人們想像的要高。如果你在一份你想離開的工作上多呆了兩年,並且在你的一生中做了 5 份以上的工作,那麼你只是在你不想做的工作上浪費了你生命中的 10 年。我覺得我在浪費時間。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mz85i3mpvnky6zos5qye.png) > 沒有什麼比錯過工作訊息更讓人焦慮的了。 我的動力減弱了,我的表現也隨之減弱。我越來越少參加會議,盡量減少做任何與開發產品管理技能不直接相關的工作,並在溝通方面拖拖拉拉。最後唯一的動機就是不想被解僱。感覺我已經達到了我的目標是這麼低的標準,甚至努力跨越它,這讓我有點難過。 不幸的是,我的經理開始注意到了。在持續 2 個多小時的激烈績效評估中,他告訴我,我需要 1) 更多地參與這次遷移,以及 2) 更加溝通。用他的話說,“如果我想留在團隊中”,我必須在這些方面有所改進。 ## 重新評估 COVID-19 期間的生活優先事項 疫情大流行是一記警鐘。 看著數以百萬計的人死於 COVID 讓我意識到明天是無法保證的。在您的任何夢想實現之前,您可能會死於 COVID。你推遲夢想的時間越長,它永遠不會實現的風險就越大。所以如果有什麼你想要的,你必須現在就去做。 不想再說晚點才是時候了。現在就是時候。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5oawd1k9a5lnzses4is3.png) > 被推遲的夢想就是被拒絕的夢想。我一直以來最喜歡的名言。 我意識到金手銬的真正代價是什麼。代價是你的青春,你的時間,你的生命。人們不會準確判斷這些成本,因為薪水是一個硬數字,而你的青春價值更無形。但僅僅因為某些東西難以衡量,並不意味著它的價值就低於金錢等可數的東西。很難衡量品牌、心理健康或愛情的價值,但我們知道這很重要。 看到所有這些人死於 COVID,我害怕有一天我的墓碑上會寫著: > “這裡躺著 Michael。他一生都在做他不想做的工作。然後他感染了 COVID 接著就死掉了。祝安息。” 我在一份我不喜歡的工作上待的時間越長,這成為我墓碑的可能性就越大。我知道我現在必須採取行動 - 我不能一直把棘手的職業問題推到一邊。我不得不辭職。 ## 最後的日子 我把糟糕的績效評估和被解僱的威脅當成是一種解脫。但我想在不被解僱的情況下先拿到遣散費。 因此,幾週後,我在一對一面談中,向我的經理提案,我們討論了“先發制人的遣散費方案”。 我這樣說:“我的表現在下降,因為我的動力在下降。我沒看到我的積極性有可能提高,因為團隊的目標與我的職業目標背道而馳。如果我們現在討論 Netflix 的先發制人遣散費而不是拖延下去會怎麼樣?這樣 Netflix 就可以省錢,你可以更快地找到更適合團隊的人選,我也可以去做我想做的事。對每個人來說都是雙贏的局面。” ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpr7oownjm47eomrnyne.png) > 掙脫束縛。 在他與 HR 討論後,我與他和 HR 進行了最後一次會面,他們同意先發制人地解僱我,然後我拿到了最後的遣散費。金手銬 —— 再見了。 ## Netflix 之後的生活 我以為離開公司我的生活就結束了,但事實恰恰相反。我擔心我會沒有社交生活,但實際上我在退出後遇到了更多的人 —— 其他的創業者、企業家和建設者。 我看到我的心理健康得到改善,因為如果我錯過了另一封電子郵件或 slack 訊息,我因擔心而產生的焦慮消失了。 我現在感到內心深處的平靜,一種堅定的信念,即一切都會好起來的,即使現在不能保證未來的成功。當我在周日晚上打字時,如果工作對我有利,我對周末工作沒有任何問題。沒有比知道我掌握了自己工作的所有價值更好的動力了。 ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvzbuxd6dx1klb8a6mdz.png) 通過只做讓我充滿活力的事情,它可能會諷刺地釋放比我以前賺的更多的潛在收入。 我從 2021 年 5 月辭職已經 8 個月了。我在 2021 年剩下的時間裡休息了一段時間。我在紐約住了幾個月,在猶他州和亞利桑那州進行了一次公路旅行,總體上很享受生活。 我決定全身心地為自己工作。雖然我才剛剛起步,沒有任何真正可靠的收入來源,但我會相信這個過程,如果我致力於讓我充滿活力的事情,好事就會發生。 --- 我現在真的相信,安全行事是最冒險的選擇。當你謹慎行事時,你同樣會暴露在所有的危險之中,而且沒有向上的機會。正如海倫凱勒曾經說過的: ![圖片說明](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srvmeb69o4owf6mhgu66.png) > 謹慎行事是最冒險的選擇。

JavaScript 系列七:第2課 ── 體驗一下 Reactivity 的效果與便利

## 課程目標 - 體驗一下 Reactivity 的效果與便利 ## 課程內容 來學 Vue 之中 Reactivity 的基本觀念 - https://vuejs.org/guide/essentials/reactivity-fundamentals.html 老樣子,大部份看不懂沒關係,稍微有個印象就好 記得之前的課程,每次更新完 state,你都要接著去執行 `render()` 函式嗎? 所謂 Reactivity 就只是說:當你更新完 application state 之後,Vue 會自動幫你更新 UI 上的內容 就只是這樣,不要把它想得太複雜 ``` <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <div id="app"> 嗨,我是 {{ user.name }} <button @click="changeNewName"> 改名字 </button> </div> <script> const { createApp } = Vue createApp({ data() { return { user: { name: "John Doe" } } }, mounted() { this.user.name = "Frank" }, methods: { changeNewName() { this.user.name = "Kevin" } } }).mount('#app') </script> ``` 到 jsfiddle 跑跑看,看看畫面上出現什麼 `mounted` 是 vue 將畫面第一次載入之後,可以安排任務的地方,通常會放一些「系統初始化任務」 `@click` 跟 `methods` 那些,就只是操作事件的寫法而已,先照做就好 以上兩點,後面課程會詳談 --- 在 Vue 文件中,你會到處看到 `this` 這個關鍵字 要存取 application state,有時前面要加 `this.` 有時又不用 關於 `this` 關鍵字,它是一個 JavaScript 程式語言裡面過時又晦澀難懂的觀念 我不想細談,你也先不用研究。就先照做、程式能跑就好了 反正改天你真的遇到問題,大概知道要往這方向研究就是了 --- 接著來學 Vue 之中 Computed 屬性的觀念 - https://vuejs.org/guide/essentials/computed.html 老話一句,看不懂沒關係 雖然大家都說用這寫法,效能會比較好、程式碼會比較優雅 但實際上,我自己在好幾個專案,就完全不使用任何 `computed` 功能 一律通通只用 `methods` 來寫程式,根本也不會怎麼樣 --- 在整門系列課程,會常常像這樣,我叫你讀官網文件的很多內容 但我接著又會說,看不懂沒差,其中 XXX 根本沒用,其中 YYY 也沒必要用,只學 ZZZ 就好 這些都是我個人的主觀意見。如果你在網路上找資料,會看到許多工程師,有跟我完全相反的建議 這是軟體工程師圈子的常態,充滿各種主觀喜好、偏見,你要習慣一下 (如果你很好奇我是怎麼做出這些判斷的,請重新閱讀此系列課程,第一篇文章:前言,裡面的最後一段) 你不需要完全同意我的觀點,在研究過程中,如果你有發現比較喜歡的寫法,就直接用沒關係 如同我多次提醒過:只要能解決問題就好,你就隨便寫沒關係 各種做法細微的差異,將來有一天你會慢慢理解 ## 課後作業 承接上一課的作業 這一課來簡單體驗一下 reactivity 的效果就好 也就是簡單更新一下 application state 就好 請加入 `mounted` 函式,在裡面把「第一個記事」的內容更新為「多出門、到處走走、也要多運動」 完成之後,你會發現,你的春節行程安排,看起來積極多了~ 做出以上功能,你就完成這次的課程目標了!

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

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

開發者的寫作格式:Markdown 格式的好用 Cheatsheet 分享

身為開發者,一定會常常需要使用 Markdown 格式來寫文件。 Markdown 究竟是什麼?它看起來像純文本,有點像 HTML,但兩者都不是? 別擔心,我第一次使用 Markdown 時也是有點困惑。但不久之後,我就習慣了,並意識到它真的很酷。到本文結束時,您將掌握日常使用 Markdown 所需了解的一切。 原文出處:https://dev.to/imluka/the-only-markdown-cheatsheet-you-will-ever-need-ccg --- ## 好的,再告訴我一次,什麼是 Markdown,我將在哪裡使用它? Markdown 是一種輕量級標記語言,可用於格式化純文本文檔。 您可能知道 GitHub 上的每個存儲庫都有自己的 README 文件,其中解釋了存儲庫的用途。每個專案都需要好的文件。 GitHub 的文件是使用 Markdown 編寫的。這正是為什麼有必要知道一些基礎知識。第二個原因是,您最有可能通過吸引人的個人檔案 README 來吸引新的人脈並改善您的網絡。 就是這樣!今天的理論足夠了。來點實用的吧。 --- ## 段落 通過編寫常規文本,您基本上是在寫一個段落。 ![段落](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/anf2ny3no3t0l26ntyax.png) ## 標題 有 6 種標題變體。後面跟著文字的“**#**”符號的數量表示標題的重要性。 ![標題](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wotzyypxewzlaa84et9z.png) ## 重點 修改文本是如此整潔和容易。您可以將文本設為粗體、斜體、刪除線、突出顯示、下標或上標。 ![強調](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4c3y52wflw9gic3t1jn0.png) ## 區塊引用 想強調文本的重要性?這樣即可。 ![塊引用](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47mu4id1ouay1ts795jk.png) ## 圖片 如果您使用的是 GitHub,最好的方法是簡單地將圖像從您的計算機直接拖放到 README 文件中。您還可以建立對圖像的引用並以這種方式顯示它。 ![圖片](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3iduze0f60z7j9rnjcpo.png) ## 連結 與圖像類似,連結也可以直接插入或通過建立引用來插入。您可以建立內聯連結和塊連結。 ![鏈接](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cawmi3zosms4depgytp.png) ## 程式碼 您可以建立內聯和全塊程式碼片段。您還可以定義您在程式碼段中使用的程式語言。全都是使用反引號。 ![程式碼](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dmo2rbbn75ti3y5w7gz.png) ## 列表 正如您在 HTML 中所做的那樣,Markdown 允許建立有序列表和無序列表。 ![有序列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7upx1ft4g8dfnbmrp6o.png) ![無序列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pnmiwji4ln87x7bzrweo.png) 您還可以混合兩個列表並建立子列表。 **PS.** 盡量不要建立超過兩層的列表。這是最佳實踐。 ![混合列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86oqskyuzib8dd4zwe7w.png) 也可以建立定義列表(術語 - 定義),您可能不會常使用這個,但有機會用到。 ![定義列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5dqaeqf7q8r6d1w4hls9.png) ## 表格 顯示排列資料的好方法。使用“**|**”符號分隔列,使用“**:**”符號對齊行內容。 ![表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vnmyt4zro4kigpmnvyaa.png) 您還可以通過排除外部“**|**”符號而不是使您的程式碼結構良好來建立“混亂”的表格。當然,它仍然有效,但是嘿 → 我們應該始終以正確的方式安排事情。 ![凌亂的表格](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndzx63vvfhh03lwvdj9a.png) ## 任務列表 跟踪已完成的任務和需要完成的任務。 ![任務列表](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6h86g897t6kkvemtkcyn.png) ## 腳註 想在文件末尾描述一些東西嗎?使用腳註! ![腳註](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2qqxz9zl9wmrbssi5yx.png) ## 標題編號 您可以為標題指定 ID,以便無論您身在何處都可以直接跳轉到文件的該部分。 ![標題 ID](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mn8jdfrpda8qmr4vi5jp.png) ## 水平線 您可以使用星號、連字符或下劃線(*、-、_)來建立水平線。唯一的規則是您必須至少包含符號的三個字符。 ![水平線](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4ep9mrq25p88cl5wo71.png) ## HTML 您還可以在 Markdown 文件中使用原始 HTML。大多數情況下效果很好,但有時您會遇到一些在使用標準 HTML 時不習慣的差異。使用 CSS 將不起作用。 ![HTML](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cixf2wjyykc1yi2zlhg.png) --- 以上簡單分享,希望對您有幫助!

JavaScript 系列六:結語

讓我總結說明一下,老方法、新方法的關鍵思維差異: - 在老方法中,工程師眼中主要關心 html,開發過程會一直去思考 html 結構,因為「應用程式的狀態(資料)」就存在 html 之中,html 同時是狀態、也是 UI - 在新方法中,工程師眼中主要關心 data model,通常就是一個 JSON 物件。這個物件的各個屬性,足以表達目前應用程式的狀態。至於狀態要怎麼呈現為 UI,則視為另一個獨立任務,可以另外處理。像這樣把兩件事分開來思考,對頭腦的負擔也比較小 --- 同樣的待辦清單小工具,原本的寫法,與現在的新寫法,請你比較一下程式碼 有沒有覺得變得易讀、好維護許多呢? 在課程中,我多次說過以下這段描述: > 原本那種寫法,我稱之為「在各處胡亂更新各處 DOM」的寫法 > 新的那種寫法,只有在寫 render 時,腦中要思考 DOM > 在應用程式的其他地方,腦中都是思考 data model 就好 現在你懂我描述的感覺了嗎? 在這個小工具的例子中,改善的程度可能不夠明顯 但在中型以上的網站、具有高互動性的複雜網頁,一定是用新寫法比較好 --- 這次的課程,讓你的能力從「前端設計」進入到「前端工程」了 之所以叫「工程」,是因為有時候需要建立中型、大型應用程式,這時就需要工程素養 原本那種「在各處胡亂更新各處 DOM」的寫法,絕對無法建立出大型軟體 就跟蓋房子一樣,隨便蓋的小房子臨時居住一下還可以,真的要蓋出厲害的高樓,當然需要足夠的工程技法、素養 --- 寫本課程作業時,render function 的內容會變很多 在實務上,render function 的任務會由框架或者某種模板引擎(template engine)套件完成 所以開發起來會省力很多,不像本課程作業寫起來那樣吃力 你未來使用任何工具只要知道:這些工具的背後,大概就是做了類似這樣 data model + render function 的事情即可! --- 本課所教的 data model + render function 的寫法 是我為了教學方便,設計出來的一種「手工」開發方法 實務上,中型以上專案,幾乎都會使用 React 或者 Vue 框架 我留意到坊間許多課程、補習班,很快就進入框架的教學 我認為許多學員在結業之後,還是一知半解,甚至分不清哪些是 JavaScript 觀念,哪些是框架獨有的觀念 所以我才在這邊,教導這套手工、但很簡單的開發方法 寫過這種開發方法,接著再去學前端框架,我認為可以大幅改善那種「框架後面很黑箱」的感覺 所以你之後挑選任何框架學習,關於 `application state` 與 `render 出 UI` 這兩者的關係,就大致有個底了 --- 最後,老話一句,視網頁的需要,如果只是簡單頁面、小小 UI 工具,那麼就用老方法隨便寫即可。何況還有 data attribute 可以使用來管理狀態,簡單又方便。很多實務情境下,這樣也很夠了 如果真的有工程等級的需要,則可以使用本課程技巧,管理好「應用程式的狀態」,或者直接挑選框架使用 這行業有一句話叫做:No Silver Bullet(沒有萬用解法) 在開發手法的選擇上,也是一樣,請綜合權衡之後,選擇當下適合的方法吧! --- 消化、研究完本課程之後,關於 JavaScript 更多必學的基本觀念 請接著前往「自學網頁の嬰兒教材:JavaScript(七)」開始學習吧! https://codelove.tw/@howtomakeaturn/course/AqJGxd

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

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

討論-淺談html/js之關係以及,延伸至XSS

>最近在忙著實作我的一些小項目,沒有上來發文,但還是一直學習JS, >累積滿多經驗,也累積不少疑問。 >之前站長阿川有跟我提到相關話題,也就是UJS,想說把它拿過來聊一聊。 >剛好最近弄的東西,跟這個也有一些關聯性。 ## html與JS的交互關係。 Inline JavaScript是什麼呢? 就把JS寫在html裡面的一種手段,也就是onclick那些東西,在自學教材會學到唷:))。 其中也有個東西叫做JavaScript pseudo-protocol,他好像有點像是給一個js的前綴, 讓瀏覽器讀取html的時候知道要開始讀取JS了,用法如: `<a href="javascript:alert(1)">my website</a>` 這樣子的作法都讓JS侵入到html裡面,也就是行為跟結構沒有分離。 是否要UJS,站長上次有提到這可以看專案大小來區分,這篇閒聊開起來可以提供更多細節。 --- 不過我不打算就此結束文章,我要額外分享與XSS相關的內容。 XSS其實是CSS,跨站指令碼Cross Site Script的意思,只是因為縮寫重複CSS樣式(Cascading Style Sheets )所以用X代替。 簡單理解它就是一種攻擊手段,讓別人網站上執行我的代碼。 --- 有趣的事情來了,那html跟JS交互關係跟XSS又有什麼關聯呢? 想像一下,當今天小明要做一個討論區,讓使用者用html編輯打文章,就必須小心有人會放一些JS的代碼。 小明想說,我要過濾`<script>`標籤來保證他們乖乖地寫html。 請問這樣子是否就安全了呢? 答案是否定的,這時候使用Inline JavaScript會發生什麼狀況? 試想一下因為小明沒有CSP相關設定,防止使用者偷偷塞JS到html裡面,導致小明的壞朋友大胖, 可以直接寫一個`<img src=x onerror="alert(1)">`在留言區裡面, 完全沒有使用到`<script>`標籤,卻也能造成XSS。 --- ## 關於防禦: ### CSP 設定嚴格一點,可以阻止很多XSS,舉例來說文章一開始有`href="javascript:alert(1)"`, 可以設定href後面只能接上http開頭的東西。 ### WAF 他是Web Application Firewall 的簡稱,中文通常叫作「網站應用程式防火牆」 可以建立及管理避免網際網路威脅的規則,包括IP 位址、HTTP 標頭、HTTP 主體、URI 字串、跨網站命令檔(XSS)、SQL 隱碼攻擊及其他OWASP 定義的漏洞。 ### 自己建立fliter 自己過濾也是可行的(不建議),把字串符碼都轉成HTML Entities,例如把 (<)寫成 ` &lt; or &#60;` ,透過這樣的過濾render出來的就不會是指令了。 為什麼不建議,是因為你過濾的東西有可能會被double encoded URL之類的手法繞過。 或是你覆蓋了document.write,以為安全了,但是我用孿生函數(twin function)的document.writeIn你可能就忘了過濾。 這剛好就是我最近在研究的東西。 ## 相關討論問題: 1.對於文章的內容,有沒有什麼錯誤呢?或相關名詞想法想補充? 2.是否要UJS的實際使用,有哪些想法?或是有什麼經驗?

JavaScript 系列五:第5課 ── 學會 AJAX 錯誤處理

## 課程目標 認識 AJAX 錯誤處理 ## 課程內容 在前一課,我們說過以下的話 > 有些任務現在還不會立刻執行,但我先把要執行的任務交待清楚,時間點到的時候,就執行 > 以 UI 動作來說,時間點就是 `onclick` 之時、`onchange` 之時 > 以 AJAX 動作來說,時間點就是 `拿到主機回應` 之時 實際上,AJAX 的時間點,除了 `拿到主機回應` 之時,還有一個,就是 `發現主機回應失敗` 之時 把原本的範例 ``` fetch('https://fakestoreapi.com/users/1') .then(res=>res.json()) .then(json=>console.log(json)) ``` 故意打錯字試試看,然後加上錯誤處理機制 ``` fetch('https://fakestoreapi.com/users1') .then(res=>res.json()) .then(json=>console.log(json)) .catch(error => { alert(error); }) ``` 就跟 `.then()` 函式把任務傳進去類似,`.catch()` 一樣是把任務傳進去,只是改傳「AJAX 失敗的時候要執行的任務」 --- 這邊只是舉例,才故意打錯字 實務上,AJAX 失敗可能是 - 主機故障、或者過度忙碌無法回應 - 呼叫 API 時,登入驗證資訊過期 - API 設計成有額度限制,用戶額度耗完了,被主機拒絕 - 用戶自己的網路斷線了(網頁打開時正常,但發送 AJAX 時已斷線) 等等很多可能,要看 API 主機是如何設計的 --- 實務上,`.catch()` 內要提醒使用者,剛才的動作失敗,請他重新嘗試 我個人通常就用 alert 跳一個訊息「抱歉,系統出現錯誤,請稍後重新嘗試。若持續出錯,請聯絡客服信箱」就結束了 但在公司的大型專案,需要更好 UX 的話,請與設計師討論後決定如何優雅地處理錯誤情境 ## 課後作業 接續前一課的作業,請加上錯誤處理機制 用 alert 跳出 `抱歉,請稍後重新嘗試。` 就好了 接著,請把電腦的 wifi 或有線網路,斷線 然後點擊「Load Products」按鈕,應該會看到錯誤提示訊息 做出以上功能,你就完成這次的課程目標了!

7 個好用的 React Hooks:可以在很多專案直接使用

Hooks 是 React 最強大的功能之一。 它們使我們能夠輕鬆地在應用程式的元件中重用功能。掛鉤的最大優點在於它們的可重用性——您可以跨元件和專案重用掛鉤。 以下是我在每個 React 專案中重複使用的七個最重要的鉤子。今天就試一試,看看它們在建置您自己的 React 應用程式時是否有幫助吧。 原文出處:https://dev.to/webdevhero-com/7-react-hooks-for-every-project-1jdo --- 在我們開始之前,要先澄清一下:並非每個自定義 React 鉤子都需要由您編寫。事實上,我將提到的所有鉤子都來自一個庫“@mantine/hooks”。 Mantine 是一個很棒的第三方庫,其中包含這些鉤子等等。他們將為您的 React 應用程式加入您能想到的幾乎所有重要功能。 您可以在 [mantine.dev](https://mantine.dev) 查看“@mantine/hooks”的文件。 ## `useIntersection` 鉤子 當用戶在您的應用程式中向下滾動頁面時,您可能想知道某個元素何時對他們可見。 例如,您可能希望僅在用戶看到特定元素時才啟動動畫。或者,您可能希望在他們向下滾動頁面一定程度後,顯示或隱藏元素。 ![use intersection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zilwvvdjppw9uz82iixo.gif) 要獲取有關元素是否可見的訊息,我們可以使用 **Intersection Observer API。**這是瀏覽器中內建的 JavaScript API。 我們可以使用純 JavaScript 單獨使用 API,但要知道有關特定元素是否在其滾動容器內,有個好方法是使用 useIntersection 掛鉤。 ``` import { useRef } from 'react'; import { useIntersection } from '@mantine/hooks'; function Demo() { const containerRef = useRef(); const { ref, entry } = useIntersection({ root: containerRef.current, threshold: 1, }); return ( <main ref={containerRef} style={{ overflowY: 'scroll', height: 300 }}> <div ref={ref}> <span> {entry?.isIntersecting ? 'Fully visible' : 'Obscured'} </span> </div> </main> ); } ``` 要使用它,我們需要做的就是在我們的元件中呼叫鉤子,並提供一個根元素。 Root 是滾動容器,可以使用 useRef 掛鉤將其作為 ref 提供。 `useIntersection` 回傳一個我們傳遞給目標元素的 ref,我們想要觀察其在滾動容器中的交集。 一旦我們有了對元素的引用,我們就可以追蹤元素是否相交。在上面的範例中,我們可以根據 entry.isIntersecting 的值查看元素何時被遮擋或何時完全可見。 您可以傳遞其他參數,這些參數允許您配置與目標可見百分比相關的**閾值**。 ## `useScrollLock` 鉤子 另一個與滾動相關的鉤子是 useScrollLock 鉤子。這個鉤子非常簡單:它使您能夠鎖定 body 元素上的任何滾動。 我發現當您想在當前頁面上顯示疊加層或跳出視窗,並且不想讓用戶在後台頁面上上下滾動時,它會很有幫助。這使您可以將注意力集中在視窗上,或允許在其自己的滾動容器內滾動。 ``` import { useScrollLock } from '@mantine/hooks'; import { Button, Group } from '@mantine/core'; import { IconLock, IconLockOpen } from '@tabler/icons'; function Demo() { const [scrollLocked, setScrollLocked] = useScrollLock(); return ( <Group position="center"> <Button onClick={() => setScrollLocked((c) => !c)} variant="outline" leftIcon={scrollLocked ? <IconLock size={16} /> : <IconLockOpen size={16} />} > {scrollLocked ? 'Unlock scroll' : 'Lock scroll'} </Button> </Group> ); } ``` `useScrollLock` 將用戶的滾動鎖定在頁面上的當前位置。該函數回傳一個陣列,它可以被解構,如上面的程式碼所示。 第二個值是一個允許我們鎖定滾動的函數。另一方面,第一個解構值是一個布林值,它告訴我們滾動條是否已被鎖定。 這個值很有用,例如,如果你想在滾動鎖定時顯示某些內容或告訴用戶它已被鎖定。您可以在下面的示例中看到,當滾動條被鎖定或解鎖時,我們會在我們的按鈕中進行指示。 ![use scroll lock](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wywccv7uexfrhfgayqj9.gif) ## `useClipboard` 鉤子 在許多情況下,您希望提供一個按鈕,允許用戶將內容複製到他們的剪貼板,這是存儲複製文本的地方。 一個很好的例子是,如果您的網站上有一個程式碼片段,並且您希望用戶輕鬆複製它。為此,我們可以使用另一個 Web API——**剪貼板 API**。 `@mantine/hooks` 為我們提供了一個方便的 `useClipboard` 鉤子,它回傳幾個屬性:`copied`,它是一個布林值,告訴我們是否已使用鉤子將值複製到剪貼板,以及` copy` 函數,我們可以將我們喜歡的任何字串值傳遞給它以進行複制。 在我們的範例中,我們想複製一個程式碼片段,供我們的用戶粘貼到他們喜歡的地方,如下面的影片所示: ![使用剪貼板](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6n0xd02vdg65bbfmb2xh.gif) ## useClipboard demo 當他們點擊我們指定的複制按鈕時,我們呼叫我們的 `copy` 函數,將程式碼片段傳遞給它,然後顯示一個小複選標記或向他們表明文本已被複製的東西。 巧妙的是 `useClipboard` 掛鉤帶有 **超時值**。在給定的超時時間(以毫秒為單位)之後,複製的狀態將被重置,向用戶顯示他們可以再次復製文本。 ## `useDebouncedValue` 鉤子 如果您的應用程式中有搜尋輸入,下一個鉤子“useDebouncedValue”是必不可少的。 每當用戶使用輸入執行搜尋時,搜尋操作通常涉及對 API 的 HTTP 請求。 您將遇到的一個典型問題是每次擊鍵都會執行查詢(請求),尤其是如果您希望用戶在鍵入時接收搜尋結果。即使對於一個簡單的搜尋查詢,也不需要在用戶完成輸入他們想要的內容之前執行這麼多請求。 這是 useDebounceValue 掛鉤的一個很好的用例,它對傳遞給它的文本應用「防抖」功能。 ``` import { useState } from 'react'; import { useDebouncedValue } from '@mantine/hooks'; import { getResults } from 'api'; function Demo() { const [value, setValue] = useState(''); const [results, setResults] = useState([]) const [debounced] = useDebouncedValue(value, 200); // wait time of 200 ms useEffect(() => { if (debounced) { handleGetResults() } async function handleGetResults() { const results = await getResults(debounced) setResults(results) } }, [debounced]) return ( <> <input label="Enter search query" value={value} style={{ flex: 1 }} onChange={(event) => setValue(event.currentTarget.value)} /> <ul>{results.map(result => <li>{result}</li>}</ul> </> ); } ``` 您使用 useState 將輸入的文本儲存在一個狀態中,並將狀態變數傳遞給 useDebouncedValue 。 作為該掛鉤的第二個參數,您可以提供一個等待時間,即值被「反抖」的時間段。反抖使我們能夠執行更少的查詢。 您可以在下面的影片中看到結果,用戶在其中鍵入內容,並且僅在 200 毫秒後,我們才能看到去抖值。 ![使用去抖值](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qfb5kqb6bxbkqfvog1hw.gif) ## `useMediaQuery` 鉤子 我一直使用的另一個非常有用的鉤子是 useMediaQuery 鉤子。 Media Queries 在純 CSS 中使用,`useMediaQuery` 鉤子允許我們訂閱我們傳遞給鉤子的任何媒體查詢。 例如,在我們的元件中,假設我們想要顯示一些文本或根據特定螢幕寬度(例如 900 像素)更改元件的樣式。我們像在 CSS 中一樣提供媒體查詢,並且 useMediaQuery 回傳給我們一個 true 或 false 的 matches 值。 ``` import { useMediaQuery } from '@mantine/hooks'; function Demo() { const matches = useMediaQuery('(min-width: 900px)'); return ( <div style={{ color: matches ? 'teal' : 'red' }}> {matches ? 'I am teal' : 'I am red'} </div> ); } ``` 它用 JavaScript 告訴我們媒體查詢的結果,這在我們想要使用 `style` 屬性在 JSX 中直接更改樣式時特別有用,例如。 ![使用媒體查詢](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7al1apywiq08ntgs4d8l.gif) 簡而言之,對於少數無法使用 CSS 處理媒體查詢的情況,這是一個必不可少的鉤子。 ## `useClickOutside` 鉤子 下一個掛鉤 - `useClickOutside` - 可能看起來很奇怪,但當您真正需要它時,您會發現它的重要性。 當你開發一個下拉菜單,或者在頁面內容前面彈出,並且之後需要關閉的東西時,這個鉤子是必不可少的。通過單擊按鈕打開這些類型的元件之一非常容易。關閉這些元件有點困難。 為了遵循良好的 UX 實踐,我們希望任何阻礙用戶視圖的東西都可以通過單擊元素外部輕鬆關閉。這正是 useClickOutside 掛鉤讓我們做的。 當我們呼叫 useClickOutside 時,它會返回一個 ref,我們必須將其傳遞給我們想要檢測點擊的外部元素。通常該元素將由一個布林狀態片段控制,例如我們在下面的示例中的狀態(即值“opened”)。 ``` import { useState } from 'react'; import { useClickOutside } from '@mantine/hooks'; function Demo() { const [opened, setOpened] = useState(false); const ref = useClickOutside(() => setOpened(false)); return ( <> <button onClick={() => setOpened(true)}>Open dropdown</button> {opened && ( <div ref={ref} shadow="sm"> <span>Click outside to close</span> </div> )} </> ); } ``` `useClickOutside` 接受一個回調函數,該函數控制當您實際單擊該元素外部時發生的情況。 在大多數情況下,我們想做一些非常簡單的事情,就是關閉它。為此,您可能需要一個狀態設置器(如 `setOpened`)並向其傳遞一個 false 值,然後隱藏您覆蓋的內容。 ![use click outside](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jidp380brennyatol7w.gif) ## `useForm` 鉤子 在這個列表中,我最喜歡和最有用的鉤子是 `useForm` 鉤子。 這個鉤子專門來自 Mantine,涉及從庫中安裝一個特定的包:`@mantine/form`。它會為您提供在 React 中建立表單所需的一切,包括驗證輸入、顯示錯誤訊息以及在提交表單之前確保輸入值正確的能力。 `useForm` 接受一些初始值,這些初始值對應於您在表單中的任何輸入。 ``` import { TextInput, Button } from '@mantine/core'; import { useForm } from '@mantine/form'; function Demo() { const form = useForm({ initialValues: { email: '' }, validate: { email: (value) => (/^\S+@\S+$/.test(value) ? null : 'Invalid email'), }, }); return ( <div> <form onSubmit={form.onSubmit((values) => console.log(values))}> <TextInput withAsterisk label="Email" placeholder="[email protected]" {...form.getInputProps('email')} /> <Button type="submit">Submit</Button> </form> </div> ); } ``` `useForm` 的最大好處是它的助手,例如 `validate` 函數,它接收輸入到每個輸入的值,然後允許您建立驗證規則。 例如,如果您有一個電子郵件輸入,您可能有一個正則表達式來確定它實際上是否是一個有效的電子郵件(如您在上面的程式碼中所見)。如果沒有,那麼您可以顯示一條錯誤訊息並阻止提交表單。 ![使用表格](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n13l1gqejzx6y227p0j2.gif) 您如何獲取已輸入到表單中的值? Mantine 提供了一個非常方便的助手,叫做“getInputProps”,你只需提供你正在使用的輸入的名稱(比如電子郵件),它就會自動設置一個 onChange 來追蹤你在表單中輸入的值. 此外,為了處理表單提交,並在其值未通過驗證規則時阻止送出,它有一個特殊的 `onSubmit` 函數,您可以將其包裹在常規的 onSubmit 函數中。除了應用驗證規則之外,它還會負責在表單事件上呼叫 `preventDefault()`,這樣您就不必手動執行此操作。 我只用了這個鉤子的基本功能,但我強烈建議您在下一個專案中使用它。傳統上,表單很難正常工作,尤其是需要驗證和可見錯誤訊息的表單。 `useForm` 讓它變得異常簡單! --- 以上,簡單分享,希望對您有幫助。

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

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

軟體工程師都應該養成寫部落格的習慣

軟體工程師寫部落格,對於職業生涯很有幫助,有很多好處。這篇文章的作者簡單分享心得。 原文出處:https://dev.to/nasirovelchin/every-software-developer-should-write-a-blog-4622 --- 作為一名軟體工程師,我常常打算明天、下週甚至下個月,就要開始寫部落格。但幾年過去了,我還沒有寫過一篇文章。我沒有開始的原因是,我覺得,我不是專家、不是名人、也不擅長寫作,只是一個普通的軟體工程師。因此,為什麼我要花時間寫一篇文章,根本沒有人會讀。這總是阻止我開始寫。但最近,在我閱讀了幾篇軟體工程師的文章後,我改變了主意,決定開始寫。 有很多理由開始寫文章,而且,我認為每個軟體開發人員都應該擁有部落格。理由大致如下: **更快地學習並提高您的技術技能** 當我試圖解釋或教別人時,我自己也學得更快。我從大學的電腦科學課的小組作業專案中了解到這一點。我仍然記得我試圖向其他小組成員解釋和展示的一切。解釋會促使你更多地了解這個主題,這不僅對你的讀者有好處,對你自己也有好處。開設技術部落格與教學非常相似,因為在您的部落格中,您將向世界教授寫程式和電腦科學。 **推銷自己並開始你的職業生涯** 您的部落格將為您可能無法找到的各種網絡和商業機會打開大門。通過部落格,您可以得到很多機會成為自由工作者和接案者。舉個真實的例子,我的一個朋友,他開始學習 Java 程式語言,並在他的部落格上分享他的進度,有招聘人員向他發送了他從未申請過的工作機會,他們發現他在網上分享的文章。而且,他甚至在完成 Java 課程之前就開始了他的軟體工程師生涯。 **記錄您的回饋進度** 您每周有多少次找到完美的 StackOverflow 文章來解決您的問題並節省您數小時的頭撞牆?有多少次您花費數小時解決問題,但沒有其他人從您的解決方案中獲益? 即使你不時地、每週寫一篇文章,你也可以展示你面臨什麼樣的挑戰,你是如何解決它們的,你使用了哪些方法和技術,你避免了哪些。一年後,當您回顧時,您會發現您的文件對別人幫助很大,這些有用的見解,以及解決問題的方法,都很有幫助。 此外,與經驗豐富的軟體工程師相比,寫程式經驗很少的人可以更好地展示他們如何在某些主題上掙扎,陷阱和不明顯的部分在哪裡。因此,閱讀您貼文的人不會陷入您所寫內容的陷阱。 **學習如何交流和表達你的想法** 信不信由你,但您的軟體職業生涯在很大程度上取決於您溝通和表達想法的能力。即使你是一個優秀的軟體工程師,如果沒有良好的溝通和展示自己的能力,你的軟體生涯也不會大放異彩,而且會受到限制。此外,許多軟體工程師都說寫文章也能幫助他們寫出更好的程式碼。 **消除你的壓力** 脫離日常的寫程式生活,給自己一些自由,隨心所欲地寫一些你想分享的東西,分享你自己的觀點,寫下來並發表。這些都會讓你感到放鬆。 總的來說,作為軟體開發人員,寫部落格是提升個人風格的絕佳方式。寫部落格可以促進您所做或計劃做的任何事情。它打開了您意想不到的大門。值得一試,看看會發生什麼好事吧。

JavaScript 系列四:第4課 ── jQuery 套件

## 課程目標 認識並且能使用 jQuery 套件 ## 課程內容 這一課要教的東西比較有爭議 jQuery 是 2006 - 2015 年代,前端網頁開發的王者 當時的瀏覽器廠商眾多,網頁規格 API 支援方式不同、不完整(尤其是 IE 一堆奇怪的 API) 當時的前端工程師,非常痛苦,要為了 IE 多改很多寫法 加上當時很多瀏覽器沒有支援 `.querySelector` `.querySelectorAll` 這些 Selector API 所以 jQuery 的出現,強大的選擇器語法,以及眾多方便的功能,大幅降低了前端開發的成本 不過,時至今日,jQuery 的大部份功能,都已在瀏覽器 JavaScript 語法中原生支援了 再加上開發大型應用程式,DOM 的管理一旦複雜起來,就會直接使用 React 或者 Vue 這種框架來管理 DOM,不會再手動去操作 DOM (前端框架會處理完 DOM 互動的部份。此時如果再手動操作 DOM,那程式碼就會一團混亂) 也就是說,小型專案,「不需要」用 jQuery;大型專案,「不可以」用 jQuery 除此之外,jQuery 套件本身檔案不小,引入此套件會影響網頁載入速度,影響 UX,同時會影響搜尋引擎 SEO 排名 --- 因為上述種種原因,在今天,前端工程師普遍鄙視 jQuery,避之惟恐不及 我個人的建議是:團隊在開發複雜的前端應用時,的確不要再用 jQuery 了! 但是,當只是做小網站,接小案子賺錢,或者做個人的業餘專案(side project),只是希望快速做完某些功能時,jQuery 還是非常好用! 原因有兩個 第一,jQuery 選擇器寫起來很短,可以少打很多字,開發很快速 第二,jQuery 外掛生態系存在已久,很多強大的 UI 元件會用到 jQuery,適合的話,實在沒道理全面放棄不用 而且,並不是所有網站,都需要直接導入 React 跟 Vue 這種大型框架!沒必要! 除此之外,維護一大堆現有的程式碼,難免已經用到 jQuery,還是能看懂 API 比較好 所以,還是稍微教大家一些 jQuery 的用法。至於什麼場合要使用,你就自行判斷吧 --- 官網 https://jquery.com/ API 用法 https://api.jquery.com/ CDN 連結 https://releases.jquery.com/ 請自行逛一逛,大概知道 jQuery 有哪些 API 就好,不用花太多時間學習 jQuery 你應該會發現,一大堆功能,你自己就寫得出來,而且寫起來也不複雜,例如 `.hide()` `.show()`,你之前的作業就寫過,根本不需要用 jQuery 剩下的一大堆功能,目前看不懂沒關係、覺得自己做不出來沒關係,未來的課程會教你 --- 簡單地說,jQuery 選擇器就是使用金錢符號來呼叫函示 `$()` 其實是 `jQuery()` 的簡寫而已 ``` <h1 class="title"> Hide me </h1> <p class="para"> Hide me </p> <p class="para"> Hide me </p> <p class="para"> Hide me </p> ``` ``` document.querySelector('.title').style.display = 'none'; for (var p of document.querySelectorAll('.para')) { p.style.display = 'none'; } ``` 像這樣的程式,隱藏了畫面上多個元素 使用 jQuery 的寫法會變成 ``` $('.title').hide(); $('.para').hide(); ``` 很多人覺得,jQuery 只剩一些少打字的功能,卻讓網頁多載入整個 jQuery 套件,很沒意義、不值得 我倒是覺得,還是滿方便的。快速開發時,少打很多字。而且 jQuery 可以自動處理多個元素,可以少寫 for 迴圈 當然了,上面的程式碼,跟下面這段是完全一樣的 ``` jQuery('.title').hide(); jQuery('.para').hide(); ``` jQuery 基本上就這樣而已,你喜歡嗎? 實務上,使用時,如果翻文件,還是不知怎麼寫,就去搜尋引擎找關鍵字 `jquery 改變顏色` `jquery change color` 之類的 別忘了,軟體工程師在工作時,會花很多時間在翻文件、上網到處看文章、搜尋範例程式碼,所以要習慣這件事 --- 坊間很多課程,會在一開始就教 jQuery。這跟直接教前端框架的問題一樣:學生的基本功,因此變得很差 但是本課程已讓你知道最基本的原生 DOM 寫法,所以你在用 jQuery 時,會知道背後發生什麼事,也知道刪掉 jQuery 的話,要怎麼用原生語法改寫 所以,我認為在本課程的安排下,jQuery 並不會耽誤你的學習旅程 喜歡 jQuery 的話,就把 API 網頁,多逛一逛,工作上想用的話,就大方使用吧! ## 課後作業 請使用 https://jsfiddle.net 這次的作業要交兩份 請建立兩份 jsfiddle,並使用以下 html ``` <h1 class="title"> Make me green </h1> <p class="para"> Make me red </p> <p class="para"> Me red too </p> <p class="para"> Also me </p> ``` 在第一份,不使用 jQuery,把 h1 文字變為綠色,p 文字變為紅色 在第二份,請使用 jQuery,把 h1 文字變為綠色,p 文字變為紅色 寫完之後,你自行比較一下,網頁多加一個肥大的套件,但是可以少打這些字,你覺得值得嗎? 這是一個主觀問題,你就根據情況決定你的答案吧! 做出以上功能,你就完成這次的課程目標了!

JavaScript 系列四:第1課 ── autosize 套件

## 課程目標 認識並且能使用 autosize 套件 ## 課程內容 這次的套件是 https://github.com/jackmoore/autosize 文件與 demo 在 https://www.jacklmoore.com/autosize/ 這是一個讓 `<textarea>` 的 UX(User Experience 使用者體驗)瞬間升級的好用套件 ``` // from a NodeList autosize(document.querySelectorAll('textarea')); // from a single Node autosize(document.querySelector('textarea')); ``` 使用起來非常簡單,把 DOM 元素找到,當成參數傳給 autosize 函式,就可以了 在設計各種第三方套件給別人的時候,通常都會設計成這樣,很簡單、易用吧 程式的使用方法,我們叫 API(Application Programming Interface,應用程式介面) 實務上,我們會跟同事說:「去查一下這個套件的 API」,也就是去看一下這套件的使用方法。可以理解成「產品規格」 --- 在上網搜尋套件的時候,第一個要先看這個專案的星星數量,至少要有幾百顆以上吧 如果是太冷門的套件,代表可能不夠成熟、文件不完整、潛在 bug 會很多 第二個要看的是最近更新日期,也就是 last commit 的時間,至少兩年內有更新過吧 太久沒更新的專案,可能有點過時,會跟最新的瀏覽器或者其他工具有衝突 不過,如果只是用在網站上的小小地方,真的出問題,再換掉的成本也不大,那就先導入也沒關係 --- 要使用第三方套件,除了直接下載然後使用 `<script>` 引入之外,還有一個常用的懶人方法 就是搜尋 `套件名稱 CDN`,直接找現成的 CDN 連結來用 CDN 全名 Content Distribution Network,內容傳遞網路。這是大型企業讓資源在全球加速載入用的 看不懂沒關係,反正搜尋 `套件名稱 CDN`,通常會有現成 `<script>` 可用 搜尋 `autosize cdn` 看看搜尋結果,就會知道了 (要注意這是一個懶人方法,工作上直接這樣用,網站可能會載入的有點慢) ## 課後作業 請使用 https://jsfiddle.net 假設你正在開發一個留言功能 有暱稱欄位、留言欄位、以及一個送出按鈕 留言的區塊,`textarea` 預設只有三行的高度 使用者在輸入時,輸入越多行,輸入區塊會自動變高,而不會出現捲軸 做出以上功能,你就完成這次的課程目標了!

JavaScript 系列二:第7課 ── 用 Selector API 選取元素

## 課程目標 學會基本的 Selector API 用法 學會基本的 `.closest()` 的用法 ## 課程內容 課程到目前為止,要存取元素,都是使用 `document.getElementById` `.parentElement` `.children` 然後上上下下到處爬來爬去、找到目標元素 在網頁結構簡單的時候還好,一旦內容複雜起來,你會發現這樣寫,有點麻煩 其實,在學習 css 的時候,就有一套指定元素的方法了,如果能直接用 css 那套設定樣式的方法,來找到元素,那不是很方便嗎? ``` <div> <div id="wrapper"> 我想跟您說: <p> Hi, <span id="target">早上好</span> </p> <p> Hi, <span>中午好</span> </p> <p> Hi, <span>晚上好</span> </p> </div> </div> ``` ``` document.querySelector('#wrapper p span').style.color = 'red'; ``` 在 jsfiddle 試試看,會發現「早上好」變成紅字了 使用 `.querySelector()` 可以很方便的找到元素!如果找到多個元素,只會回傳第一個元素 接著試試這樣 ``` var spans = document.querySelectorAll('#wrapper p span'); for (span of spans) { span.style.color = 'red'; } ``` 在 jsfiddle 試試看,會發現三塊文字,都變成紅字了 使用 `.querySelectorAll()` 可以很方便的找到多個元素!接著就用陣列來處理即可! 以上兩種用法,是不是比之前的老方法方便許多呢? --- 有件事要提一下,老方法的 `.getElementById()` 只能用在 `document` 物件上 新方法的 `.querySelector()` `.querySelectorAll()` 除了可以用在 `document` 之外,還能用在一般 DOM 元素上喔! ``` var wrapper = document.querySelector('#wrapper') wrapper.querySelector('p span').style.color = 'red'; ``` 所以這樣寫也可以!是不是覺得更彈性、更強大、更好用了呢? 有了這些,可以完全取代 `document.getElementById` 與 `children` 的寫法! --- 接著來看看有什麼新方法可以取代 `.parentElement` 吧 ``` var target = document.querySelector('#target') target.closest('span').style.color = 'red'; ``` ``` var target = document.querySelector('#target') target.closest('p').style.color = 'red'; ``` ``` var target = document.querySelector('#target') target.closest('div').style.color = 'red'; ``` 在 jsfiddle 分別試試看,這三種程式碼,會讓哪些文字變紅色吧! `.closest()` 會回傳第一個找到的「祖先元素」 也就是順序為父元素、祖父元素、曾祖父元素,依此類推,不斷往上尋找,到找到第一個為止 實務上這個函式非常好用,可以完全取代 `.parentElement` 的寫法! ## 課後作業 接續前一課的作業,現在要來重構(refactor)程式碼 所謂的「重構」程式碼,就是程式的功能完全不變,但是讓程式碼更好讀、好維護 --- 請把作業中出現的 `.getElementById()` `.parentElement` `.children` 全部拿掉 通通使用本課教導的函式來改寫 改寫完之後,你會發現,原本的程式碼,如果不看 html,只看 JavaScript,只會看到 parentElement、children、跟一堆索引,到處爬,不知道在幹嘛 而在改寫之後,至少看起來比較像在寫 css 樣式的時候,會用 `span` `li` `button` 這些元素名稱來上下查找元素 光看 JavaScript 程式碼,會比原本好讀一些些! 單看這次作業,可能感覺還好。但在專案很大的時候,你不會想在程式碼看到全是 parentElement、children、跟一堆索引,你會希望有更多額外資訊 你會希望程式碼能更清楚表達:「目前到底是在找什麼元素」。所以實務上都是以新寫法為主的 不過呢,這依然是主觀問題。如果你喜歡整個職業生涯都用老寫法來做,應該也可以。高興就好囉! --- 完成這次重構,你就完成這次的課程目標了!