[{"data":1,"prerenderedAt":3852},["ShallowReactive",2],{"all-posts":3,"post:\u002Fithome-2024-day-18":1210},[4,23,35,46,57,68,80,91,102,114,126,138,149,160,171,182,193,204,215,226,237,248,258,268,278,288,298,308,319,330,341,354,368,380,390,400,411,421,431,441,451,461,471,481,491,501,511,521,531,541,551,561,571,581,591,601,611,621,631,641,651,661,675,691,704,719,731,742,752,762,772,782,792,802,812,822,832,842,852,862,871,881,891,901,911,921,931,941,951,961,971,980,990,1000,1010,1020,1036,1050,1062,1073,1083,1095,1107,1121,1134,1145,1156,1167,1180,1191,1201],{"path":5,"title":6,"description":7,"date":8,"updated":9,"tags":10,"categories":14,"draft":15,"wordCount":16,"readingTime":17,"canonical":18,"series":19},"\u002Fithome-2026-day-30","Day 30：Angular Router Providers 與生命週期管理，路由離開後 Service 會銷毀嗎？","平常在 Angular 中，我們可以透過 providers 決定 Service 的注入範圍。例如註冊在 Root，讓整個 Application 共用同一個實例；或註冊在 Component，讓 Service 隨著…","2026-10-14T14:46:39+08:00",null,[11,12,13],"iThome 鐵人賽","2026 鐵人賽","Angular",[11,13],false,7227,7,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10424222",{"name":20,"url":21,"day":22},"2026 iThome 鐵人賽：Angular 22 Signal 進化論","https:\u002F\u002Fithelp.ithome.com.tw\u002Fusers\u002F20116554\u002Fironman\u002F9939",30,{"path":24,"title":25,"description":26,"date":27,"updated":9,"tags":28,"categories":29,"draft":15,"wordCount":30,"readingTime":31,"canonical":32,"series":33},"\u002Fithome-2026-day-29","Day 29：Angular 也有 VueUse？使用 Signality 整合常見 Browser API","在 Vue 生態系中，VueUse 提供許多 Composables，讓我們可以快速使用瀏覽器功能，例如監聽網路狀態、保存使用者設定，或偵測元素是否進入可視範圍。","2026-10-13T23:14:18+08:00",[11,12,13],[11,13],6387,6,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10424070",{"name":20,"url":21,"day":34},29,{"path":36,"title":37,"description":38,"date":39,"updated":9,"tags":40,"categories":41,"draft":15,"wordCount":42,"readingTime":31,"canonical":43,"series":44},"\u002Fithome-2026-day-28","Day 28：Angular 動態建立 Component，NgComponentOutlet 與 ViewContainerRef","平常在 Angular 中使用 Component，通常會直接在 Template 裡面宣告：","2026-10-12T17:27:41+08:00",[11,12,13],[11,13],6565,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10423641",{"name":20,"url":21,"day":45},28,{"path":47,"title":48,"description":49,"date":50,"updated":9,"tags":51,"categories":52,"draft":15,"wordCount":53,"readingTime":17,"canonical":54,"series":55},"\u002Fithome-2026-day-27","Day 27：NgRx Store vs SignalStore，從 Action、Reducer 到直接更新 State","前幾天我們使用 NgRx SignalStore 實作購物車，透過 withState() 管理商品資料、withComputed() 計算總金額，再利用 withMethods() 與 patchState() 更新 …","2026-10-11T20:06:41+08:00",[11,12,13],[11,13],7308,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10423362",{"name":20,"url":21,"day":56},27,{"path":58,"title":59,"description":60,"date":61,"updated":9,"tags":62,"categories":63,"draft":15,"wordCount":64,"readingTime":17,"canonical":65,"series":66},"\u002Fithome-2026-day-26","Day 26：SignalStore 與 Strategy Pattern，透過 DI 動態切換業務邏輯","昨天我們使用 Angular 原生 Signal 與 NgRx SignalStore 實作購物車，透過 State 管理商品資料，再利用 Computed 計算商品數量與總金額。","2026-10-10T22:01:59+08:00",[11,12,13],[11,13],7347,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10423116",{"name":20,"url":21,"day":67},26,{"path":69,"title":70,"description":71,"date":72,"updated":9,"tags":73,"categories":74,"draft":15,"wordCount":75,"readingTime":76,"canonical":77,"series":78},"\u002Fithome-2026-day-25","Day 25：Angular SignalStore，原生 Signal 不夠用嗎？","在 Angular 開發中，如果資料只會被單一 Component 使用，通常可以直接透過 signal() 管理。但當多個 Component 需要共用同一份資料時，就得考慮狀態應該放在哪裡。","2026-10-09T21:28:45+08:00",[11,12,13],[11,13],9117,9,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10422784",{"name":20,"url":21,"day":79},25,{"path":81,"title":82,"description":83,"date":84,"updated":9,"tags":85,"categories":86,"draft":15,"wordCount":87,"readingTime":31,"canonical":88,"series":89},"\u002Fithome-2026-day-24","Day 24：SPA Router 為什麼不再只靠 History API？","平常使用 Angular Router 時，可以透過 routerLink 或 router.navigate() 切換不同頁面。","2026-10-08T14:30:47+08:00",[11,12,13],[11,13],6330,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10422348",{"name":20,"url":21,"day":90},24,{"path":92,"title":93,"description":94,"date":95,"updated":9,"tags":96,"categories":97,"draft":15,"wordCount":98,"readingTime":17,"canonical":99,"series":100},"\u002Fithome-2026-day-23","Day 23：RouteReuseStrategy，切換路由一定要銷毀 Component 嗎？","在後台系統中，很常會看到頁籤式介面，例如：","2026-10-07T15:58:32+08:00",[11,12,13],[11,13],7361,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10422016",{"name":20,"url":21,"day":101},23,{"path":103,"title":104,"description":105,"date":106,"updated":9,"tags":107,"categories":108,"draft":15,"wordCount":109,"readingTime":110,"canonical":111,"series":112},"\u002Fithome-2026-day-22","Day 22：Angular Render Lifecycle，從 afterNextRender 到 DestroyRef","過去在 Angular 中，只要遇到初始化、View 建立或資源清理，通常會先想到 Lifecycle Hooks：","2026-10-06T23:36:23+08:00",[11,12,13],[11,13],8111,8,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10421810",{"name":20,"url":21,"day":113},22,{"path":115,"title":116,"description":117,"date":118,"updated":9,"tags":119,"categories":120,"draft":15,"wordCount":121,"readingTime":122,"canonical":123,"series":124},"\u002Fithome-2026-day-21","Day 21：Angular Template 還適合呼叫 Method 嗎？從 Pipe、RxJS 到 computed","過去在寫 Angular 時，因為 Template 可以直接呼叫 Method，很容易在專案裡看到大量這樣的寫法。","2026-10-05T23:30:32+08:00",[11,12,13],[11,13],5431,5,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10421425",{"name":20,"url":21,"day":125},21,{"path":127,"title":128,"description":129,"date":130,"updated":9,"tags":131,"categories":132,"draft":15,"wordCount":133,"readingTime":134,"canonical":135,"series":136},"\u002Fithome-2026-day-20","Day 20：Signal Forms 非同步驗證，validateHttp 與 validateAsync","前兩篇介紹了 Signal Forms 的基本驗證，以及需要參考其他欄位的 Cross-field Validation。","2026-10-04T20:56:17+08:00",[11,12,13],[11,13],4278,4,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10420910",{"name":20,"url":21,"day":137},20,{"path":139,"title":140,"description":141,"date":142,"updated":9,"tags":143,"categories":144,"draft":15,"wordCount":145,"readingTime":134,"canonical":146,"series":147},"\u002Fithome-2026-day-19","Day 19：Signal Forms Cross-field Validation 與欄位更新時機","上一篇介紹 Signal Forms 時，已經看到可以透過 Schema 定義欄位驗證，例如 required()、email()、minLength()。","2026-10-03T23:18:26+08:00",[11,12,13],[11,13],3783,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10420631",{"name":20,"url":21,"day":148},19,{"path":150,"title":151,"description":152,"date":153,"updated":9,"tags":154,"categories":155,"draft":15,"wordCount":156,"readingTime":31,"canonical":157,"series":158},"\u002Fithome-2026-day-18","Day 18：Angular Signal Forms 穩定了，跟我們用了這麼久的 Reactive Forms 到底差在哪？","在 Angular 中處理表單，很多專案使用的都是 Reactive Forms。","2026-10-02T23:28:36+08:00",[11,12,13],[11,13],5886,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10420249",{"name":20,"url":21,"day":159},18,{"path":161,"title":162,"description":163,"date":164,"updated":9,"tags":165,"categories":166,"draft":15,"wordCount":167,"readingTime":31,"canonical":168,"series":169},"\u002Fithome-2026-day-17","Day 17：effect() 不是拿來同步 Signal 的，Angular 的 Side Effect 該怎麼寫？","effect() 是 Angular signal 裡很容易被誤用的一個 API。因為寫法直覺，只要讀取 signal，就能在值改變時執行一些事情，所以很常被拿來同步狀態、打 API，甚至再去修改其他 signal。","2026-10-01T21:22:13+08:00",[11,12,13],[11,13],6473,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10419779",{"name":20,"url":21,"day":170},17,{"path":172,"title":173,"description":174,"date":175,"updated":9,"tags":176,"categories":177,"draft":15,"wordCount":178,"readingTime":31,"canonical":179,"series":180},"\u002Fithome-2026-day-16","Day 16：即將登場的 Route Resources，Angular Router 為什麼需要新的資料載入方式？","過去在 Angular Router 中，如果希望進入 Component 前先完成資料載入，可以透過 Resolver，讓資料取得流程在 Component 初始化之前執行。","2026-09-30T23:12:05+08:00",[11,12,13],[11,13],6534,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10419409",{"name":20,"url":21,"day":181},16,{"path":183,"title":184,"description":185,"date":186,"updated":9,"tags":187,"categories":188,"draft":15,"wordCount":189,"readingTime":17,"canonical":190,"series":191},"\u002Fithome-2026-day-15","Day 15：搞懂 Injection Context，從 inject()、runInInjectionContext() 到 injectAsync()","前面提到 Injection Context 時，可能會讓人聯想到先前介紹過的 Reactive Context。我一開始也有點搞混，因此花了一些時間重新理解 Angular 裡這些不同的執行環境。","2026-09-29T13:44:28+08:00",[11,12,13],[11,13],6986,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10418752",{"name":20,"url":21,"day":192},15,{"path":194,"title":195,"description":196,"date":197,"updated":9,"tags":198,"categories":199,"draft":15,"wordCount":200,"readingTime":17,"canonical":201,"series":202},"\u002Fithome-2026-day-14","Day 14：Lazy Loading 不只一種，從 Router Preloading、@defer 到 injectAsync()","當 Client Side Rendering 的應用越來越大時，我們通常會開始思考，能不能把原本一次載入的內容拆得更小，等到真正需要時再下載，避免初始載入過多 JavaScript，拉長畫面呈現的時間。","2026-09-28T22:44:46+08:00",[11,12,13],[11,13],7674,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10418485",{"name":20,"url":21,"day":203},14,{"path":205,"title":206,"description":207,"date":208,"updated":9,"tags":209,"categories":210,"draft":15,"wordCount":211,"readingTime":110,"canonical":212,"series":213},"\u002Fithome-2026-day-13","Day 13：從 Router Event 到 Signal","路由狀態管理在前端開發中比較少被單獨拿出來討論，但在 Angular 裡，一次路由導航其實會經過不少階段，也會在過程中發出不同的 Router Event，例如 NavigationStart、NavigationEnd…","2026-09-27T20:37:55+08:00",[11,12,13],[11,13],7777,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10417948",{"name":20,"url":21,"day":214},13,{"path":216,"title":217,"description":218,"date":219,"updated":9,"tags":220,"categories":221,"draft":15,"wordCount":222,"readingTime":122,"canonical":223,"series":224},"\u002Fithome-2026-day-12","Day 12：從 httpResource 到 TanStack Query，認識 Server State","前面我們花了不少時間討論，為什麼「請求本身的狀態」和「元件的顯示狀態」應該分開處理。","2026-09-26T23:35:12+08:00",[11,12,13],[11,13],5119,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10417614",{"name":20,"url":21,"day":225},12,{"path":227,"title":228,"description":229,"date":230,"updated":9,"tags":231,"categories":232,"draft":15,"wordCount":233,"readingTime":122,"canonical":234,"series":235},"\u002Fithome-2026-day-11","Day 11：用 rxResource 串起 Observable 與 Resource","前面介紹了不少 Resource 到 httpResource() 的應用。不過在 Angular 開發中，Observable 與 RxJS 仍然是很常見的非同步資料處理方式，像是 switchMap、map、debo…","2026-09-25T22:42:04+08:00",[11,12,13],[11,13],4908,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10417143",{"name":20,"url":21,"day":236},11,{"path":238,"title":239,"description":240,"date":241,"updated":9,"tags":242,"categories":243,"draft":15,"wordCount":244,"readingTime":31,"canonical":245,"series":246},"\u002Fithome-2026-day-10","Day 10：linkedSignal 讓相依狀態也能被修改","昨天我們透過 httpResource() 搭配 chain() 處理兩個非同步資料之間的依賴。下游 Request 需要使用上游資料時，會等上游完成後再繼續；當 Request 的來源改變，Resource 的狀態也會…","2026-09-24T23:49:49+08:00",[11,12,13],[11,13],5623,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10416746",{"name":20,"url":21,"day":247},10,{"path":249,"title":250,"description":251,"date":252,"updated":9,"tags":253,"categories":254,"draft":15,"wordCount":255,"readingTime":134,"canonical":256,"series":257},"\u002Fithome-2026-day-09","Day 9：httpResource 實務篇，統一回覆格式與 chain 相依請求","昨天我們透過 Orval 串起 API Contract，了解如何根據 OpenAPI 規格產生前端需要的型別與 API 呼叫方式。","2026-09-23T23:42:40+08:00",[11,12,13],[11,13],4358,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10416227",{"name":20,"url":21,"day":76},{"path":259,"title":260,"description":261,"date":262,"updated":9,"tags":263,"categories":264,"draft":15,"wordCount":265,"readingTime":122,"canonical":266,"series":267},"\u002Fithome-2026-day-08","Day 8：用 Orval 串起 Angular API Contract，同時產生 HttpClient、httpResource 與 Zod","前後端在對接 API 時，常見的問題之一，就是雙方對資料格式的定義逐漸不一致。","2026-09-22T23:48:12+08:00",[11,12,13],[11,13],4451,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10415694",{"name":20,"url":21,"day":110},{"path":269,"title":270,"description":271,"date":272,"updated":9,"tags":273,"categories":274,"draft":15,"wordCount":275,"readingTime":17,"canonical":276,"series":277},"\u002Fithome-2026-day-07","Day 7：從 Resource 到 httpResource，用 Signal 管理 HTTP 資料請求","昨天我們提到，Resource API 本身是一套通用的非同步資料模型，比較適合用在「讀取資料」這類情境，而不是新增、修改或刪除資料這種 Mutation 操作。","2026-09-21T22:13:18+08:00",[11,12,13],[11,13],6735,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10415038",{"name":20,"url":21,"day":17},{"path":279,"title":280,"description":281,"date":282,"updated":9,"tags":283,"categories":284,"draft":15,"wordCount":285,"readingTime":122,"canonical":286,"series":287},"\u002Fithome-2026-day-06","Day 6：Resource API，把非同步資料帶進 Signal","今天來看 Angular Signal 裡一個很重要的非同步資料 API：Resource API。","2026-09-20T19:25:37+08:00",[11,12,13],[11,13],5054,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10414377",{"name":20,"url":21,"day":31},{"path":289,"title":290,"description":291,"date":292,"updated":9,"tags":293,"categories":294,"draft":15,"wordCount":295,"readingTime":134,"canonical":296,"series":297},"\u002Fithome-2026-day-05","Day 5：從 Reactive Graph 到 View Tree，看 Angular 如何找到真正需要更新的畫面","前面我們已經知道，當 Signal 的值發生變化後，Angular 會透過 Reactive Graph 找到受到影響的 Consumer。","2026-09-19T20:19:47+08:00",[11,12,13],[11,13],4364,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10413852",{"name":20,"url":21,"day":122},{"path":299,"title":300,"description":301,"date":302,"updated":9,"tags":303,"categories":304,"draft":15,"wordCount":305,"readingTime":122,"canonical":306,"series":307},"\u002Fithome-2026-day-04","Day 4：Angular 怎麼知道誰正在讀 Signal？從 Reactive Context 理解依賴追蹤","前面我們看過，當 Template 讀取 Signal 時，Angular 會記住「誰依賴了誰」；當 Signal 發生變化後，也會透過 Reactive Graph 通知相關的 Consumer。","2026-09-18T21:58:16+08:00",[11,12,13],[11,13],4894,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10413313",{"name":20,"url":21,"day":134},{"path":309,"title":310,"description":311,"date":312,"updated":9,"tags":313,"categories":314,"draft":15,"wordCount":315,"readingTime":122,"canonical":316,"series":317},"\u002Fithome-2026-day-03","Day 3：從 set()、update() 看懂 Angular Signal 的基本使用與更新機制","昨天我們先試著理解，在 Template 中使用 Signal() 時，Angular 是如何建立依賴關係，並在 Signal 發生變化後，知道哪些 View 可能受到影響。","2026-09-17T23:08:58+08:00",[11,12,13],[11,13],5451,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10412826",{"name":20,"url":21,"day":318},3,{"path":320,"title":321,"description":322,"date":323,"updated":9,"tags":324,"categories":325,"draft":15,"wordCount":326,"readingTime":134,"canonical":327,"series":328},"\u002Fithome-2026-day-02","Day 2：Angular Signal 是什麼？從 Change Detection 理解它的運作原理","傳統 Angular 在監測資料變化時，通常會搭配 zone.js。像是 DOM 事件、Promise、Timer、HTTP 請求這些非同步操作發生時，zone.js 會幫忙攔截。","2026-09-16T20:19:12+08:00",[11,12,13],[11,13],4276,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10411944",{"name":20,"url":21,"day":329},2,{"path":331,"title":332,"description":333,"date":334,"updated":9,"tags":335,"categories":336,"draft":15,"wordCount":337,"readingTime":329,"canonical":338,"series":339},"\u002Fithome-2026-day-01","Day 1：為什麼想聊 Angular Signal？","相信講到前端框架，大家第一時間想到的通常會是 Vue、React，甚至也有人會推薦 Svelte 這類近年討論度很高的框架。但一講到 Angular，很多人的第一印象可能就像看到一座大城堡一樣：東西很多、規則很多，一時之…","2026-09-15T23:56:26+08:00",[11,12,13],[11,13],1478,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10411425",{"name":20,"url":21,"day":340},1,{"path":342,"title":343,"description":344,"date":345,"updated":9,"tags":346,"categories":351,"draft":15,"wordCount":353,"readingTime":134,"canonical":9,"series":9},"\u002FTS-Excess-Property-Checks","TypeScript 踩坑筆記：物件字面量的多餘屬性檢查機制","深入探討 TypeScript 的多餘屬性檢查（Excess Property Checks）機制，解析物件字面量與變數賦值的型別檢查差異，並提供實務開發中避免型別陷阱的最佳實踐方法。","2026-01-31T16:29:23+08:00",[347,348,349,350],"Excess Property Checks","Structural Typing","Type Safety","NestJS",[352],"TypeScript",3551,{"path":355,"title":356,"description":357,"date":358,"updated":9,"tags":359,"categories":361,"draft":15,"wordCount":363,"readingTime":329,"canonical":364,"series":365},"\u002Fithome-2025-day-30","Day 30：開發之旅完結 - 感謝與展望","終於來到鐵人賽的最後一天！這是我第二次參加鐵人賽，今年的主題是 LINE Bot 開發。這個主題源自於我參加的十二週讀書會分享，當時我發現大家對 LINE Bot 很感興趣，而我自己也一直很喜歡這個主題，於是早在六月就定…","2025-10-13T20:11:12+08:00",[11,360],"2025 鐵人賽",[11,362],"Line Bot",1751,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10396850",{"name":366,"url":367,"day":22},"2025 iThome 鐵人賽：Line Bot × NestJS：30 天開發日記","https:\u002F\u002Fithelp.ithome.com.tw\u002Fusers\u002F20116554\u002Fironman\u002F8779",{"path":369,"title":370,"description":371,"date":372,"updated":9,"tags":373,"categories":376,"draft":15,"wordCount":377,"readingTime":31,"canonical":378,"series":379},"\u002Fithome-2025-day-29","Day 29：LIFF 會員註冊 - 信箱驗證與 Swagger 文件整合","延續 Day 28 會員註冊的流程，在實際的會員註冊場景中，電子信箱驗證是確保用戶身份真實性的重要環節。本篇將基於昨天的註冊流程，新增兩個核心 API：發送驗證信與驗證驗證碼，讓會員註冊功能更加完整且安全。","2025-10-12T23:15:00+08:00",[11,360,362,374,350,375],"LIFF","Swagger",[11,362],6089,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10396512",{"name":366,"url":367,"day":34},{"path":381,"title":382,"description":383,"date":384,"updated":9,"tags":385,"categories":386,"draft":15,"wordCount":387,"readingTime":122,"canonical":388,"series":389},"\u002Fithome-2025-day-28","Day 28：LIFF 會員註冊 - ID Token 驗證與資料庫整合","今天的開發重點是建立會員卡系統，將 LIFF 前端與 NestJS 後端完整串接。","2025-10-11T22:57:29+08:00",[11,360,362,374,350],[11,362],5254,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10396146",{"name":366,"url":367,"day":45},{"path":391,"title":392,"description":393,"date":394,"updated":9,"tags":395,"categories":396,"draft":15,"wordCount":397,"readingTime":318,"canonical":398,"series":399},"\u002Fithome-2025-day-27","Day 27：群組事件與檔案訊息接收","今天主要補充 LINE Bot 在群組中的專屬特性，包括群組限定的 Webhook 事件，以及前面提到但尚未說明的第 7 種訊息類型 file 檔案訊息。","2025-10-10T21:01:52+08:00",[11,360,362,350],[11,362],2888,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10395785",{"name":366,"url":367,"day":56},{"path":401,"title":402,"description":403,"date":404,"updated":9,"tags":405,"categories":407,"draft":15,"wordCount":408,"readingTime":122,"canonical":409,"series":410},"\u002Fithome-2025-day-26","Day 26：LINE Pay 線上付款","LINE Pay 提供兩種付款方式：線上付款與實體付款。實體付款主要採用店家出示條碼的模式，顧客掃描後即可輸入金額完成付款。這兩種付款方式都支援在沙盒(Sandbox)環境中進行測試。本文將著重說明線上付款的整合流程。","2025-10-09T23:39:32+08:00",[11,360,406],"Line Pay",[11,362],4876,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10395481",{"name":366,"url":367,"day":67},{"path":412,"title":413,"description":414,"date":415,"updated":9,"tags":416,"categories":417,"draft":15,"wordCount":418,"readingTime":318,"canonical":419,"series":420},"\u002Fithome-2025-day-25","Day 25：優惠券設定與 Coupon Message 實作","LINE Official Account 的「優惠券」是提升顧客互動與忠誠度的重要功能。透過獎勵機制，不僅能吸引新客，更能有效促進回購。","2025-10-08T23:49:32+08:00",[11,360,362,350],[11,362],3207,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10395076",{"name":366,"url":367,"day":79},{"path":422,"title":423,"description":424,"date":425,"updated":9,"tags":426,"categories":427,"draft":15,"wordCount":428,"readingTime":134,"canonical":429,"series":430},"\u002Fithome-2025-day-24","Day 24：LIFF 刮刮樂實戰體驗","在了解 LIFF 的基礎設計流程後，本文將透過「刮刮樂」案例示範 LIFF API 的實際應用。從啟動時檢查權限與執行環境、確認用戶分享功能權限，到刮刮樂結束後發送訊息並關閉 LIFF，完整呈現 LIFF 在互動應用中的…","2025-10-07T22:36:58+08:00",[11,360,362,374],[11,362],4200,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10394618",{"name":366,"url":367,"day":90},{"path":432,"title":433,"description":434,"date":435,"updated":9,"tags":436,"categories":437,"draft":15,"wordCount":438,"readingTime":134,"canonical":439,"series":440},"\u002Fithome-2025-day-23","Day 23：LIFF 網頁應用開發入門","在鐵人賽前半段，我們深入探討了 LINE Bot 的兩大核心功能：Richmenu(選單設置)與各種 Reply Message(回覆訊息)的訊息類型。然而在實務應用中，若要提供更豐富的互動體驗，Line 往往需要搭配 …","2025-10-06T23:06:57+08:00",[11,360,362,374],[11,362],4400,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10394035",{"name":366,"url":367,"day":101},{"path":442,"title":443,"description":444,"date":445,"updated":9,"tags":446,"categories":447,"draft":15,"wordCount":448,"readingTime":329,"canonical":449,"series":450},"\u002Fithome-2025-day-22","Day 22：Render 雲端平台部署 Nest 後端伺服器","今天的目標是將系統正式上線。經過這段時間的開發，我們已完成 Line Message API 的核心功能與日誌處理機制。","2025-10-05T22:52:11+08:00",[11,360,362,350],[11,362],1895,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10393809",{"name":366,"url":367,"day":113},{"path":452,"title":453,"description":454,"date":455,"updated":9,"tags":456,"categories":457,"draft":15,"wordCount":458,"readingTime":318,"canonical":459,"series":460},"\u002Fithome-2025-day-21","Day 21：Nest Pino 整合 Grafana Loki 日誌","Loki 環境變數可參考 Day 20 文章的 Grafana Data Source settings 設定","2025-10-04T17:24:26+08:00",[11,360,362,350],[11,362],2740,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10393305",{"name":366,"url":367,"day":125},{"path":462,"title":463,"description":464,"date":465,"updated":9,"tags":466,"categories":467,"draft":15,"wordCount":468,"readingTime":318,"canonical":469,"series":470},"\u002Fithome-2025-day-20","Day 20：Grafana Loki 日誌服務 - 從申請到 API 串接測試","目前已經理解了 LINE Messaging API 的核心功能，包括如何接收訊息、串接第三方服務，以及發送多種類型的訊息。接下來，我們將把原本架設在 ngrok 的後端伺服器，透過 GitHub 自動化部署到 Rend…","2025-10-03T23:16:16+08:00",[11,360,362,350],[11,362],2461,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10392910",{"name":366,"url":367,"day":137},{"path":472,"title":473,"description":474,"date":475,"updated":9,"tags":476,"categories":477,"draft":15,"wordCount":478,"readingTime":318,"canonical":479,"series":480},"\u002Fithome-2025-day-19","Day 19：Flex Message Carousel 食譜分享","Flex Message 可以分成 bubble(單張卡片) 跟 carousel(多張卡片輪播) 兩種方式，昨天示範了 bubble 格式的電子個人名片後，今天主要展示 carousel 的應用，兩者的基本結構大致相同…","2025-10-02T16:06:17+08:00",[11,360,362,350],[11,362],2267,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10392256",{"name":366,"url":367,"day":148},{"path":482,"title":483,"description":484,"date":485,"updated":9,"tags":486,"categories":487,"draft":15,"wordCount":488,"readingTime":122,"canonical":489,"series":490},"\u002Fithome-2025-day-18","Day 18：Flex Message 設計個人名片","從基礎的文字互動開始，我們逐步探索了六大核心訊息類型的發送機制、Template Message 的結構化設計，以及 ImageMap Message 的互動式體驗。今天，我們將進入 LINE Bot 最具彈性的訊息格式…","2025-10-01T17:57:47+08:00",[11,360,362,350],[11,362],4468,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10391723",{"name":366,"url":367,"day":159},{"path":492,"title":493,"description":494,"date":495,"updated":9,"tags":496,"categories":497,"draft":15,"wordCount":498,"readingTime":122,"canonical":499,"series":500},"\u002Fithome-2025-day-17","Day 17：ImageMap Message  從互動海報到影片嵌入","在 Day 16 文章中，我們使用 Cloudflare Workers 實作了圖片代理功能。到目前為止，我們已經完成以下準備工作:","2025-09-30T11:58:32+08:00",[11,360,362,350],[11,362],4807,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10391164",{"name":366,"url":367,"day":170},{"path":502,"title":503,"description":504,"date":505,"updated":9,"tags":506,"categories":507,"draft":15,"wordCount":508,"readingTime":134,"canonical":509,"series":510},"\u002Fithome-2025-day-16","Day 16：Cloudflare Workers 圖片代理實作","在 Day 15 文章中，我們處理了 ImageMap Message 的背景圖，接著我們遇到了圖片不能出現副檔名及動態路徑支援不同解析度的問題。今天主要會透過 Cloudflare Workers 來解決這兩個問題，讓…","2025-09-29T16:15:41+08:00",[11,360,362,350],[11,362],3412,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10390567",{"name":366,"url":367,"day":181},{"path":512,"title":513,"description":514,"date":515,"updated":9,"tags":516,"categories":517,"draft":15,"wordCount":518,"readingTime":134,"canonical":519,"series":520},"\u002Fithome-2025-day-15","Day 15：共通屬性處理優化及 Imagemap  圖片製作","針對 Day 14 的程式碼架構進行優化。由於 Sender 和 Quick Reply 功能在所有回覆訊息類型中都能使用，我們應該將這些共用屬性抽取為獨立函數進行統一處理。","2025-09-28T21:03:38+08:00",[11,360,362,350],[11,362],4033,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10389697",{"name":366,"url":367,"day":192},{"path":522,"title":523,"description":524,"date":525,"updated":9,"tags":526,"categories":527,"draft":15,"wordCount":528,"readingTime":31,"canonical":529,"series":530},"\u002Fithome-2025-day-14","Day 14：LINE Bot Template Message 訊息回覆","經過前幾天的學習，我們已經成功掌握了 LINE Bot 六大基礎訊息類型的發送技巧，為訊息互動奠定了穩固的基礎。今天，我們將踏入更具挑戰性的進階應用領域！","2025-09-27T15:54:06+08:00",[11,360,362,350],[11,362],6372,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10388976",{"name":366,"url":367,"day":203},{"path":532,"title":533,"description":534,"date":535,"updated":9,"tags":536,"categories":537,"draft":15,"wordCount":538,"readingTime":122,"canonical":539,"series":540},"\u002Fithome-2025-day-13","Day 13：LINE Bot 客製化 Sender 與 Quick Reply 功能實作","LINE Bot 所有回覆訊息類型都具備「共用屬性」功能，這些屬性帶來兩項重要的互動體驗提升：","2025-09-26T11:41:34+08:00",[11,360,362,350],[11,362],4426,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10388037",{"name":366,"url":367,"day":214},{"path":542,"title":543,"description":544,"date":545,"updated":9,"tags":546,"categories":547,"draft":15,"wordCount":548,"readingTime":318,"canonical":549,"series":550},"\u002Fithome-2025-day-12","Day 12：LINE Bot Image、Video、Audio、Location 訊息回覆","Day 11 文章中，我們針對 LINE Bot 可以回覆的Text及Sticker基礎型別進行了封裝，不僅新增了 line-message.ts模組，還讓開發者可以用最少的參數產生 LINE Message 所需要的格…","2025-09-25T18:08:09+08:00",[11,360,362,350],[11,362],2977,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10387598",{"name":366,"url":367,"day":225},{"path":552,"title":553,"description":554,"date":555,"updated":9,"tags":556,"categories":557,"draft":15,"wordCount":558,"readingTime":31,"canonical":559,"series":560},"\u002Fithome-2025-day-11","Day 11：LINE Bot Text Emoji 與 Sticker 訊息回覆","目前我們的 LINE Bot 主要使用 Text 方式回覆訊息。今天將探討 Text 類型的 Emoji 應用，以及 Sticker 回覆方式，基於 Day 8 版本進行改寫。","2025-09-24T23:21:11+08:00",[11,360,350,362],[11,362],5659,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10386993",{"name":366,"url":367,"day":236},{"path":562,"title":563,"description":564,"date":565,"updated":9,"tags":566,"categories":567,"draft":15,"wordCount":568,"readingTime":318,"canonical":569,"series":570},"\u002Fithome-2025-day-10","Day 10：LINE Rich Menu Switch Action 提升使用者體驗","在 Day 9 文章中，我們結合 LINE 平台的功能，將天氣服務與圖片上傳服務整合，打造出第一張 LINE 圖文選單，透過 URI action 的方式觸發平台提供的互動效果。接著，我們使用客製化選單製作出 9 格的客…","2025-09-23T15:02:57+08:00",[11,360,362,350],[11,362],2906,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10386165",{"name":366,"url":367,"day":247},{"path":572,"title":573,"description":574,"date":575,"updated":9,"tags":576,"categories":577,"draft":15,"wordCount":578,"readingTime":318,"canonical":579,"series":580},"\u002Fithome-2025-day-09","Day  9：打造 LINE Rich Menu - 後台設計 vs API 客製化","在 Day8 文章中，我們透過整合雲端服務 Cloudinary，學習如何處理使用者上傳的圖片檔案，並將其儲存至雲端。然而，LINE Bot 除了讓使用者輸入文字回覆的方式之外，更常見的是透過圖文選單(Rich Menu…","2025-09-22T21:54:25+08:00",[11,360,362,350],[11,362],3285,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10385658",{"name":366,"url":367,"day":76},{"path":582,"title":583,"description":584,"date":585,"updated":9,"tags":586,"categories":587,"draft":15,"wordCount":588,"readingTime":17,"canonical":589,"series":590},"\u002Fithome-2025-day-08","Day 8：Cloudinary 雲端圖片儲存整合","在 Day 6 中，我們透過整合 OpenWeatherMap API 與座標位置訊息學習了如何結合第三方服務。今天將探索 Cloudinary 雲端服務，解決 LINE 圖片資源會過期的問題，學習如何透過 LINE M…","2025-09-21T23:13:19+08:00",[11,360,362,350],[11,362],7215,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10384968",{"name":366,"url":367,"day":110},{"path":592,"title":593,"description":594,"date":595,"updated":9,"tags":596,"categories":597,"draft":15,"wordCount":598,"readingTime":122,"canonical":599,"series":600},"\u002Fithome-2025-day-07","Day 7：Joi 環境變數統一驗證，重構 LINE Bot 天氣服務模組","在 Day 6 開發 LINE Bot 結合 OpenWeatherMap API 的過程中，我們採用私有方法將 API 請求處理與資料格式化整合在一起。今天將對 Day 6 的實作進行架構重構，主要目標是建立更完善的環…","2025-09-20T23:07:08+08:00",[11,360,362,350],[11,362],5157,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10384302",{"name":366,"url":367,"day":17},{"path":602,"title":603,"description":604,"date":605,"updated":9,"tags":606,"categories":607,"draft":15,"wordCount":608,"readingTime":134,"canonical":609,"series":610},"\u002Fithome-2025-day-06","Day 6：整合第三方 API 天氣查詢服務","Day 5 帶大家了解 LINE Bot 能接收使用者傳遞的「6+1」種訊息類型。之所以這樣強調，是因為 File 類型僅能在群組聊天中使用，這個限制我自己也經常忘記，所以習慣用「6+1」來提醒自己。","2025-09-19T21:07:47+08:00",[11,360,362,350],[11,362],3892,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10383636",{"name":366,"url":367,"day":31},{"path":612,"title":613,"description":614,"date":615,"updated":9,"tags":616,"categories":617,"draft":15,"wordCount":618,"readingTime":122,"canonical":619,"series":620},"\u002Fithome-2025-day-05","Day 5：整合 Pino Logger 提升 LINE Bot 專案的可維護性","看著專案逐漸成型，現在該開始重視日誌記錄的規劃了。在實際部署時，我們通常會區分 develop(開發環境)和 production(正式環境)兩種不同的執行環境，針對不同環境採用相應的日誌策略。","2025-09-18T23:30:00+08:00",[11,360,362,350],[11,362],4746,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10382298",{"name":366,"url":367,"day":122},{"path":622,"title":623,"description":624,"date":625,"updated":9,"tags":626,"categories":627,"draft":15,"wordCount":628,"readingTime":31,"canonical":629,"series":630},"\u002Fithome-2025-day-04","Day 4：掌握 LINE Bot 七種訊息類型與 NestJS 架構優化","目前我們都只使用 LINE Message Event 中的純文字(text)格式進行回覆，但除了純文字之外，LINE Bot 後端伺服器其實可以接收多種不同類型的訊息。今天就讓我們一起來深入了解這些訊息類型吧！","2025-09-17T22:53:37+08:00",[11,360,362,350],[11,362],5828,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10381651",{"name":366,"url":367,"day":134},{"path":632,"title":633,"description":634,"date":635,"updated":9,"tags":636,"categories":637,"draft":15,"wordCount":638,"readingTime":122,"canonical":639,"series":640},"\u002Fithome-2025-day-03","Day 3：Webhook 簽章驗證與訊息回覆策略(Push & Reply)","上一篇帶大家透過「Webhook 模式」成功架設了專屬的 LINE Bot 代理人。相信大家在體驗基礎功能後，對於 LINE Bot Webhook 還能監聽哪些事件、支援哪些類型的訊息回覆，以及如何確保後端收到的訊息確…","2025-09-16T21:53:39+08:00",[11,360,362,350],[11,362],5360,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10381303",{"name":366,"url":367,"day":318},{"path":642,"title":643,"description":644,"date":645,"updated":9,"tags":646,"categories":647,"draft":15,"wordCount":648,"readingTime":31,"canonical":649,"series":650},"\u002Fithome-2025-day-02","Day 2：從 Webhook 到後端，打造你的專屬機器人","上一篇，帶大家透過「Chat 模式」，讓自身變成客服機器人的方式。這篇會從「Webhook 模式」切入，並以 NestJS 作為後端框架，教你如何在休息時間，也能讓後端伺服器當你的替身幫你解惑使用者的問題。","2025-09-15T21:20:49+08:00",[11,360,362,350],[11,362],6590,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10380524",{"name":366,"url":367,"day":329},{"path":652,"title":653,"description":654,"date":655,"updated":9,"tags":656,"categories":657,"draft":15,"wordCount":658,"readingTime":318,"canonical":659,"series":660},"\u002Fithome-2025-day-01","Day 1：Hello World LINE Bot","每個程式語言的開始通常都會以練習 Hello World！作為一個簡單的起手式，LINE Bot 也不意外。這一系列會著重在 LINE Bot 的相關應用，帶大家用輕鬆的方式一起建立屬於自己的 Line Bot 聊天機器…","2025-09-14T22:48:33+08:00",[11,360,362,350],[11,362],2723,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10379895",{"name":366,"url":367,"day":340},{"path":662,"title":663,"description":664,"date":665,"updated":9,"tags":666,"categories":671,"draft":15,"wordCount":674,"readingTime":134,"canonical":9,"series":9},"\u002Fdbdiagram-tool","關聯式資料庫設計必備 - dbdiagram.io ERD 繪圖工具","還在煩惱如何設計關聯式資料表實體關聯圖嗎？ 使用 dbdiagram.io 加快你與同事之間的距離","2024-11-05T20:18:24+08:00",[667,668,669,670],"ERD","dbdiagram.io","DBML","資料庫設計",[672,673],"Database","開發工具",3982,{"path":676,"title":677,"description":678,"date":679,"updated":9,"tags":680,"categories":687,"draft":15,"wordCount":690,"readingTime":122,"canonical":9,"series":9},"\u002FPostgreSQL-1","前端勇士大闖六角後端體驗營 - 初探 PostgreSQL DML 語法","初步踏入後端的世界，了解何謂後端以及資料庫常見語法 DDL、DML。","2024-10-30T22:43:49+08:00",[681,682,683,684,685,686],"PostgreSQL","SQL","DML","DDL","資料庫","六角學院",[672,688,689],"後端實戰","學習心得",5220,{"path":692,"title":693,"description":694,"date":695,"updated":9,"tags":696,"categories":700,"draft":15,"wordCount":703,"readingTime":329,"canonical":9,"series":9},"\u002Fcss-flex-1","CSS flex 軸線對齊技巧 - 預設屬性","CSS flex 排版技巧你都了解了嗎？回歸學習初心的認識 flex 預設屬性","2024-10-24T20:29:08+08:00",[697,698,699],"Flexbox","前端排版","切版技巧",[701,702],"CSS","前端開發",1856,{"path":705,"title":706,"description":707,"date":708,"updated":9,"tags":709,"categories":712,"draft":15,"wordCount":714,"readingTime":329,"canonical":715,"series":716},"\u002Fithome-2024-day-30","Vue 3 用實作帶你看過核心概念 - Day 30：新手村的鐵人證書 - 完賽心得","花了整整半年左右的時間，每天下班都很用心的準備範例或是看書，這一段旅程對我來說真的很重要。擔心、害怕跟不安的心情一直充斥自己心中，擔心寫錯或是寫不好，想讓自己再多準備久一點再開始，所以拖到中秋連假才開始，想下定決心讓自己…","2024-10-13T12:42:25+08:00",[11,710,711],"2024 鐵人賽","Vue 3",[11,713],"Vue",1381,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10367206",{"name":717,"url":718,"day":22},"2024 iThome 鐵人賽：Vue 3 初學者：用實作帶你看過核心概念","https:\u002F\u002Fithelp.ithome.com.tw\u002Fusers\u002F20116554\u002Fironman\u002F7800",{"path":720,"title":721,"description":722,"date":723,"updated":9,"tags":724,"categories":727,"draft":15,"wordCount":728,"readingTime":134,"canonical":729,"series":730},"\u002Fithome-2024-day-29","Vue 3 用實作帶你看過核心概念 - Day 29：Composables(組合式函數)","Composables是 Vue 3 中的一個重要概念，它是利用 Vue 的 Composition API 來創建和管理可重用的有狀態邏輯的函數。Composables 允許我們將組件邏輯抽象成可重用的函數，使得代碼更…","2024-10-12T15:07:55+08:00",[11,710,711,725,726],"Options API","Composition API",[11,713],4233,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10366865",{"name":717,"url":718,"day":34},{"path":732,"title":733,"description":734,"date":735,"updated":9,"tags":736,"categories":738,"draft":15,"wordCount":739,"readingTime":134,"canonical":740,"series":741},"\u002Fithome-2024-day-28","Vue 3 用實作帶你看過核心概念 - Day 28：官方 Vue Router 的應用與技巧","路由設定方式，一般可以分成兩種：","2024-10-11T17:14:44+08:00",[11,710,711,725,737],"Vue Router",[11,713],4095,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10366520",{"name":717,"url":718,"day":45},{"path":743,"title":744,"description":745,"date":746,"updated":9,"tags":747,"categories":748,"draft":15,"wordCount":749,"readingTime":122,"canonical":750,"series":751},"\u002Fithome-2024-day-27","Vue 3 用實作帶你看過核心概念 - Day 27：VeeValidate 表單驗證工具","在開發 Vue 應用程式時，表單驗證至關重要，它能確保使用者輸入的資料符合預期的格式和要求。今天來介紹一款專門用於 Vue 的表單驗證工具—VeeValidate v4。這個工具不僅能幫助開發者輕鬆實現表單驗證，還提供了…","2024-10-10T21:02:16+08:00",[11,710,711,725],[11,713],4461,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10366165",{"name":717,"url":718,"day":56},{"path":753,"title":754,"description":755,"date":756,"updated":9,"tags":757,"categories":758,"draft":15,"wordCount":759,"readingTime":318,"canonical":760,"series":761},"\u002Fithome-2024-day-26","Vue 3 用實作帶你看過核心概念 - Day 26：KeepAlive 與 Teleport 內置組件","預設情況下，切換組件會導致組件的創建及銷毀，無法保持組件內部的狀態。","2024-10-09T18:50:53+08:00",[11,710,711,725],[11,713],3158,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10365724",{"name":717,"url":718,"day":67},{"path":763,"title":764,"description":765,"date":766,"updated":9,"tags":767,"categories":768,"draft":15,"wordCount":769,"readingTime":318,"canonical":770,"series":771},"\u002Fithome-2024-day-25","Vue 3 用實作帶你看過核心概念 - Day 25：自定義指令(Custom Directives)","Vue不僅提供了豐富的內置指令用於操作DOM元素，還允許開發者創建自定義指令。透過自定義指令，我們可以對DOM元素進行更細緻的控制，並在指令的不同生命週期階段執行特定的邏輯，從而實現更靈活的功能擴展。","2024-10-08T22:05:32+08:00",[11,710,711,725],[11,713],3116,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10365355",{"name":717,"url":718,"day":79},{"path":773,"title":774,"description":775,"date":776,"updated":9,"tags":777,"categories":778,"draft":15,"wordCount":779,"readingTime":329,"canonical":780,"series":781},"\u002Fithome-2024-day-24","Vue 3 用實作帶你看過核心概念 - Day 24：異步加載(Lazy loading)","在大型項目中，我們通常需要將應用拆分為更小的代碼模塊，並僅在需要時才從服務器加載相關組件，以減少初次加載的資源量。Vue 提供了 defineAsyncComponent 方法來實現組件的異步加載，這樣可以有效提高應用的…","2024-10-07T20:28:27+08:00",[11,710,711,725],[11,713],2171,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10364861",{"name":717,"url":718,"day":90},{"path":783,"title":784,"description":785,"date":786,"updated":9,"tags":787,"categories":788,"draft":15,"wordCount":789,"readingTime":318,"canonical":790,"series":791},"\u002Fithome-2024-day-23","Vue 3 用實作帶你看過核心概念 - Day 23：依賴注入( Provide-Inject )","在Dayxx中提到過，父子組件之間的數據傳遞可以通過props來實現。然而，當祖孫層組件需要進行數據傳遞時，中間層級的組件可能並不需要這個props，但卻不得不為了使子組件獲取數據而被迫傳遞。","2024-10-06T15:14:51+08:00",[11,710,711,725],[11,713],3183,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10364252",{"name":717,"url":718,"day":101},{"path":793,"title":794,"description":795,"date":796,"updated":9,"tags":797,"categories":798,"draft":15,"wordCount":799,"readingTime":134,"canonical":800,"series":801},"\u002Fithome-2024-day-22","Vue 3 用實作帶你看過核心概念 - Day 22：v-slot 插槽使用","先前Day 18中提到父組件可以通過props將參數資料傳遞給子組件進行渲染，這樣可以有效地將資料處理與畫面渲染的工作分開。然而，當我們需要更加客製化的呈現內容，由父組件來控制子組件的部分顯示時，可以使用v-slot 指…","2024-10-05T12:32:51+08:00",[11,710,711,725],[11,713],4292,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10363713",{"name":717,"url":718,"day":113},{"path":803,"title":804,"description":805,"date":806,"updated":9,"tags":807,"categories":808,"draft":15,"wordCount":809,"readingTime":329,"canonical":810,"series":811},"\u002Fithome-2024-day-21","Vue 3 用實作帶你看過核心概念 - Day 21： 組件透傳屬性(Attributes)的應用","當父組件向子組件傳遞屬性或監聽器，而這些屬性未在子組件中定義為props或emits時，它們會自動繼承並附加到子組件的根元素上，常見的屬性包括class、style、id等。這些屬性可以透過$attrs屬性訪問並進行操作…","2024-10-04T22:42:54+08:00",[11,710,711,725],[11,713],2146,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10363469",{"name":717,"url":718,"day":125},{"path":813,"title":814,"description":815,"date":816,"updated":9,"tags":817,"categories":818,"draft":15,"wordCount":819,"readingTime":122,"canonical":820,"series":821},"\u002Fithome-2024-day-20","Vue 3 用實作帶你看過核心概念 - Day 20：組件使用 v-model 雙向綁定","在Day 13中，我們介紹了表單元素（例如輸入框）如何處理數據雙向綁定。當需要將表單元素與一個響應式變數綁定時，v-model提供雙向綁定功能。這代表當畫面上表單元素的變動會即時影響Vue數據，同時當Vue數據的值改變時…","2024-10-03T23:40:48+08:00",[11,710,711,725],[11,713],5191,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10362957",{"name":717,"url":718,"day":137},{"path":823,"title":824,"description":825,"date":826,"updated":9,"tags":827,"categories":828,"draft":15,"wordCount":829,"readingTime":318,"canonical":830,"series":831},"\u002Fithome-2024-day-19","Vue 3 用實作帶你看過核心概念 - Day 19：子組件向父組件發射事件 - emits","組件可以通過$emit(functionName, params)自定義事件名稱並傳遞參數。自定義事件名稱建議使用kebab-case來命名自定義事件名稱，以確保命名風格與HTML 屬性一致性。此外，自定義事件還支持事件…","2024-10-02T15:51:16+08:00",[11,710,711,725],[11,713],2877,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10362144",{"name":717,"url":718,"day":148},{"path":833,"title":834,"description":835,"date":836,"updated":9,"tags":837,"categories":838,"draft":15,"wordCount":839,"readingTime":31,"canonical":840,"series":841},"\u002Fithome-2024-day-18","Vue 3 用實作帶你看過核心概念 - Day 18：父組件向子組件傳值 - props","組件之間的傳值必須透過聲明 props 的方式，這樣可以避免與HTML的屬性(attribute)混淆。父組件傳遞參數給子組件的方式有以下兩種方式：","2024-10-01T22:28:48+08:00",[11,710,711,725],[11,713],5782,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10361721",{"name":717,"url":718,"day":159},{"path":843,"title":844,"description":845,"date":846,"updated":9,"tags":847,"categories":848,"draft":15,"wordCount":849,"readingTime":318,"canonical":850,"series":851},"\u002Fithome-2024-day-17","Vue 3 用實作帶你看過核心概念 - Day 17：組件基礎 - 全局註冊與區域註冊","在 Day 5 我們提到可以將應用拆分為根組件和多個組件實例，並將功能模塊化。","2024-09-30T23:30:10+08:00",[11,710,711,725],[11,713],2954,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10361253",{"name":717,"url":718,"day":170},{"path":853,"title":854,"description":855,"date":856,"updated":9,"tags":857,"categories":858,"draft":15,"wordCount":859,"readingTime":122,"canonical":860,"series":861},"\u002Fithome-2024-day-16","Vue 3 用實作帶你看過核心概念 - Day 16：使用 ref 屬性引用模板元素","雖然 Vue 透過模板幫助我們處理了大部分的DOM 操作，但在某些情況下，仍然需要手動操作 DOM。例如，在使用第三方套件（如 Bootstrap 的 Modal）時，或者需要調用像video.play()和video.…","2024-09-29T16:25:45+08:00",[11,710,711,725],[11,713],4608,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10360419",{"name":717,"url":718,"day":181},{"path":863,"title":864,"description":865,"date":866,"updated":9,"tags":867,"categories":868,"draft":15,"wordCount":488,"readingTime":122,"canonical":869,"series":870},"\u002Fithome-2024-day-15","Vue 3 用實作帶你看過核心概念 - Day 15：監聽器(Watchers)","在響應式狀態變化時執行特定操作，需要使用watch 監聽器。這些操作可能包含副作用 (side effects)，如發送請求、調用 API，或更新 DOM 以外的系統狀態，亦或是處理自定義的邏輯。","2024-09-28T18:30:31+08:00",[11,710,711,725],[11,713],"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10359958",{"name":717,"url":718,"day":192},{"path":872,"title":873,"description":874,"date":875,"updated":9,"tags":876,"categories":877,"draft":15,"wordCount":878,"readingTime":134,"canonical":879,"series":880},"\u002Fithome-2024-day-14","Vue 3 用實作帶你看過核心概念 - Day 14：生命週期鉤子(Lifecycle Hooks)","在 Vue 中，當一個組件創建時，它會經歷一系列的流程，這些流程決定了組件從初始化到渲染，再到最終銷毀的過程。","2024-09-27T21:57:32+08:00",[11,710,711,725],[11,713],3780,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10359419",{"name":717,"url":718,"day":203},{"path":882,"title":883,"description":884,"date":885,"updated":9,"tags":886,"categories":887,"draft":15,"wordCount":888,"readingTime":318,"canonical":889,"series":890},"\u002Fithome-2024-day-13","Vue 3 用實作帶你看過核心概念 - Day 13：v-model 雙向綁定控制 - 常用於表單輸入","表單輸入是開發中非常常見的需求，原始方式通常需要手動使用v-bind綁定表單元素的值 (value)，並透過v-on綁定input事件來監聽輸入變化。","2024-09-26T21:49:25+08:00",[11,710,711,725],[11,713],3153,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10358850",{"name":717,"url":718,"day":214},{"path":892,"title":893,"description":894,"date":895,"updated":9,"tags":896,"categories":897,"draft":15,"wordCount":898,"readingTime":134,"canonical":899,"series":900},"\u002Fithome-2024-day-12","Vue 3 用實作帶你看過核心概念 - Day 12：v-on 指令 - 事件處理","在 Vue 中，監聽 HTML DOM 元素的事件變化，可以使用v-on 指令將 JavaScript 事件處理器綁定到對應的DOM 事件上。這個指令的縮寫符號為@，例如：v-on:click，其縮寫方式為@click。","2024-09-25T21:42:59+08:00",[11,710,711,725],[11,713],3808,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10358241",{"name":717,"url":718,"day":225},{"path":902,"title":903,"description":904,"date":905,"updated":9,"tags":906,"categories":907,"draft":15,"wordCount":908,"readingTime":134,"canonical":909,"series":910},"\u002Fithome-2024-day-11","Vue 3 用實作帶你看過核心概念 - Day 11：v-for 指令的基本與進階應用","當數據類型是陣列或物件時，我們不會希望將重複的選項或元素直接硬編碼在模板中。這樣的寫法會導致代碼冗長且不具可維護性。","2024-09-24T23:11:25+08:00",[11,710,711,725],[11,713],4381,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10357705",{"name":717,"url":718,"day":236},{"path":912,"title":913,"description":914,"date":915,"updated":9,"tags":916,"categories":917,"draft":15,"wordCount":918,"readingTime":318,"canonical":919,"series":920},"\u002Fithome-2024-day-10","Vue 3 用實作帶你看過核心概念 - Day 10：條件渲染 - v-if 與 v-show 的區別與應用","開發中遇到需要處理【如果是...就要...】的情境時，Vue 提供了 v-if 指令來幫助我們根據條件進行元素的渲染。這樣可以在特定條件滿足時動態地顯示或隱藏某些元素。","2024-09-23T23:39:24+08:00",[11,710,711,725],[11,713],2827,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10357160",{"name":717,"url":718,"day":247},{"path":922,"title":923,"description":924,"date":925,"updated":9,"tags":926,"categories":927,"draft":15,"wordCount":928,"readingTime":122,"canonical":929,"series":930},"\u002Fithome-2024-day-09","Vue 3 用實作帶你看過核心概念 - Day 9：Class 與 Style 的樣式綁定","v-bind 指令通常用於綁定 HTML 屬性，但在實際開發中，最常見的應用場景之一還是綁定class和 style這兩個 HTML 屬性。","2024-09-22T15:05:53+08:00",[11,710,711,725],[11,713],4630,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10356119",{"name":717,"url":718,"day":76},{"path":932,"title":933,"description":934,"date":935,"updated":9,"tags":936,"categories":937,"draft":15,"wordCount":938,"readingTime":134,"canonical":939,"series":940},"\u002Fithome-2024-day-08","Vue 3 用實作帶你看過核心概念 - Day 8：計算屬性應用與實踐","在 Day 6 在使用 Vue 的Mustache語法時，可以用來放置表達式。不過，這邊建議避免在 Mustache 中撰寫過於複雜的邏輯。這樣的建議主要有兩個原因：","2024-09-21T21:33:29+08:00",[11,710,711,725],[11,713],4060,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10355474",{"name":717,"url":718,"day":110},{"path":942,"title":943,"description":944,"date":945,"updated":9,"tags":946,"categories":947,"draft":15,"wordCount":948,"readingTime":122,"canonical":949,"series":950},"\u002Fithome-2024-day-07","Vue 3 用實作帶你看過核心概念 - Day 7： 響應式基礎 - Options API","前面提到了模板搭配指令及 Mustache 的用法。今天則是要介紹所謂透過getter跟setter取值跟賦值的方式在 JavaScript 是怎麼做到的，這部分會跟 Vue 本身的響應式基礎有很大相關。此外，我也會帶著…","2024-09-20T23:41:42+08:00",[11,710,711],[11,713],4407,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10354781",{"name":717,"url":718,"day":17},{"path":952,"title":953,"description":954,"date":955,"updated":9,"tags":956,"categories":957,"draft":15,"wordCount":958,"readingTime":134,"canonical":959,"series":960},"\u002Fithome-2024-day-06","Vue 3 用實作帶你看過核心概念 - Day 6：數據綁定和模板(Template)","Vue 使用基於 HTML 的模板語法（Template Syntax），將 Vue 實例中的數據綁定到模板中進行顯示。根據綁定的類型不同，數據可以影響元素的內容、屬性或樣式。","2024-09-19T20:39:46+08:00",[11,710,711,725],[11,713],3402,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10354231",{"name":717,"url":718,"day":31},{"path":962,"title":963,"description":964,"date":965,"updated":9,"tags":966,"categories":967,"draft":15,"wordCount":968,"readingTime":318,"canonical":969,"series":970},"\u002Fithome-2024-day-05","Vue 3 用實作帶你看過核心概念 - Day 5：Options API vs Composition API","前面已經詳細說明了 Vue 的環境建置方式，接下來將逐步介紹 Vue 應用說明，並比較Options API與Composition API的撰寫風格。","2024-09-18T22:10:36+08:00",[11,710,711,725,726],[11,713],2902,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10353717",{"name":717,"url":718,"day":122},{"path":972,"title":973,"description":974,"date":975,"updated":9,"tags":976,"categories":977,"draft":15,"wordCount":658,"readingTime":318,"canonical":978,"series":979},"\u002Fithome-2024-day-04","Vue 3 用實作帶你看過核心概念 - Day 4：基於 Vite 建構工具的 Vue 專案結構解析","在 Day 3 的教學中，學習了如何使用 Vue 鷹架工具(Vue project scaffolding tool)來生成一個基於 Vite 環境的專案。今天，我將更進一步地解析這個專案的資料夾結構，幫助大家更好地理解…","2024-09-17T23:27:07+08:00",[11,710,711,725],[11,713],"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10352470",{"name":717,"url":718,"day":134},{"path":981,"title":982,"description":983,"date":984,"updated":9,"tags":985,"categories":986,"draft":15,"wordCount":987,"readingTime":329,"canonical":988,"series":989},"\u002Fithome-2024-day-03","Vue 3 用實作帶你看過核心概念 - Day 3：使用 Vite 建構工具搭建 Vue 專案","⭐ 需要特別注意，需要事先安裝Nodejs。若不確定是否已安裝 Nodejs 也可以開啟終端機，執行以下指令確認版本。","2024-09-16T23:29:45+08:00",[11,710,711,725],[11,713],2100,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10351398",{"name":717,"url":718,"day":318},{"path":991,"title":992,"description":993,"date":994,"updated":9,"tags":995,"categories":996,"draft":15,"wordCount":997,"readingTime":329,"canonical":998,"series":999},"\u002Fithome-2024-day-02","Vue 3 用實作帶你看過核心概念 - Day 2：命令式編程 vs 聲明式編程","還記得我們在使用純 HTML 和 JavaScript 時，如何實現按下按鈕來變更文字顏色嗎？讓我們一起回想一下什麼是命令式宣告。","2024-09-15T22:52:27+08:00",[11,710,711,725,726],[11,713],1881,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10350459",{"name":717,"url":718,"day":329},{"path":1001,"title":1002,"description":1003,"date":1004,"updated":9,"tags":1005,"categories":1006,"draft":15,"wordCount":1007,"readingTime":340,"canonical":1008,"series":1009},"\u002Fithome-2024-day-01","Vue 3 用實作帶你看過核心概念 - Day 1：前言介紹","大家好，我是 Antonio(安東尼奧)，目前是一名 Angular 的新手工程師，同時，也是一名熱愛寫程式的工程師。去年參加六角學院的 Vue 直播班，在那時候就深深著迷著 Vue 的語言，自此這半年多的時間裡，我白天…","2024-09-14T17:32:19+08:00",[11,710,711],[11,713],988,"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10350457",{"name":717,"url":718,"day":340},{"path":1011,"title":1012,"description":1013,"date":1014,"updated":9,"tags":1015,"categories":1017,"draft":15,"wordCount":1019,"readingTime":329,"canonical":9,"series":9},"\u002Fhexschool-experience","六角學院 - 軟體工程師體驗營","這麼多線上課程? 你不想知道什麼是最吸引我的線上學習課程嗎?","2024-05-31T21:40:05+08:00",[686,1016],"軟體工程師體驗營",[689,1018],"前端成長記",1109,{"path":1021,"title":1022,"description":1023,"date":1024,"updated":9,"tags":1025,"categories":1033,"draft":15,"wordCount":1035,"readingTime":318,"canonical":9,"series":9},"\u002FJS-10","JavaScript：var、let、const之間的差異解析","var、let及const是JavaScript中宣告變數的關鍵字，它們在作用域、對於for迴圈的影響、提升 (Hoisting) 的差異及重複宣告的處理上有所不同。","2023-12-10T23:53:30+08:00",[1026,1027,1028,1029,1030,1031,1032],"ES6","var","let","const","Hoisting","Scope","TDZ",[1034,702],"JavaScript",2873,{"path":1037,"title":1038,"description":1039,"date":1040,"updated":9,"tags":1041,"categories":1048,"draft":15,"wordCount":1049,"readingTime":122,"canonical":9,"series":9},"\u002FJS-9","JavaScript：陣列的常見操作方法","掌握 JavaScript 陣列操作！從forEach、map、filter、findIndex、reduce、sort，深入了解這些方法，使你的程式碼更具靈活性和效率！","2023-12-01T15:01:06+08:00",[1042,1043,1044,1045,1046,1047],"forEach","map","filter","reduce","sort","findIndex",[1034,702],4846,{"path":1051,"title":1052,"description":1053,"date":1054,"updated":9,"tags":1055,"categories":1060,"draft":15,"wordCount":1061,"readingTime":318,"canonical":9,"series":9},"\u002FJS-8","JavaScript：ES module 匯入與匯出","使用\u003C script >標籤讓瀏覽器中的網頁能夠使用 ES 模組功能時，你了解不同的匯入及匯出方法了嗎？","2023-11-30T15:28:23+08:00",[1026,1056,1057,1058,1059],"ES Module","CommonJS","Node.js","模組化開發",[1034,702],2913,{"path":1063,"title":1064,"description":1065,"date":1066,"updated":9,"tags":1067,"categories":1070,"draft":15,"wordCount":1072,"readingTime":134,"canonical":9,"series":9},"\u002FReact-2","React：JSX 是什麼？為何在 React 中使用 JSX？","透過 JSX 語法糖，你能夠在一次 JavaScript 撰寫中包含 HTML 與 CSS 的內容","2023-11-29T16:03:40+08:00",[1068,1034,1069],"JSX","Babel",[1071,702],"React",3595,{"path":1074,"title":1075,"description":1076,"date":1077,"updated":9,"tags":1078,"categories":1081,"draft":15,"wordCount":1082,"readingTime":329,"canonical":9,"series":9},"\u002FReact-1","React：Pure Function 的概念及其在 React 中的應用","探索 Pure Function 概念及其與 React 的相互關係。","2023-11-29T15:50:17+08:00",[1034,1079,1080],"Pure Function","Functional Programming",[1071],1368,{"path":1084,"title":1085,"description":1086,"date":1087,"updated":9,"tags":1088,"categories":1093,"draft":15,"wordCount":1094,"readingTime":122,"canonical":9,"series":9},"\u002FJS-6","JavaScript：深入理解Promise的原理及實際應用","透過Promise，我們能夠有效解決JavaScript中的異步事件，使得程式碼更為清晰和可讀。","2023-11-29T14:49:18+08:00",[1089,1090,1091,1092],"Promise","AsyncAwait","Asynchronous Programming","異步處理",[1034,702],5479,{"path":1096,"title":1097,"description":1098,"date":1099,"updated":9,"tags":1100,"categories":1105,"draft":15,"wordCount":1106,"readingTime":122,"canonical":9,"series":9},"\u002FJS-5","JavaScript：物件傳參考特性(Pass by Reference)","淺拷貝(shallow copy)與深拷貝(deep copy)在JavaScript中的應用與理解","2023-11-29T09:55:50+08:00",[1101,1102,1103,1104],"Pass by Reference","Shallow Copy","Deep Copy","傳值與傳參考",[1034,702],4544,{"path":1108,"title":1109,"description":1110,"date":1111,"updated":9,"tags":1112,"categories":1118,"draft":15,"wordCount":1120,"readingTime":329,"canonical":9,"series":9},"\u002FJS-4","JavaScript：注重關注點的分離","透過關注點分離的設計方式，可顯著提高系統整體的可維護性。","2023-11-29T09:44:29+08:00",[1113,1114,1115,1116,1117],"SoC","MVC","Design Patterns","Clean Code","Refactoring",[1034,1119],"Software Engineering",1977,{"path":1122,"title":1123,"description":1124,"date":1125,"updated":9,"tags":1126,"categories":1132,"draft":15,"wordCount":1133,"readingTime":329,"canonical":9,"series":9},"\u002FJS-3","JavaScript：掌握箭頭函式，優雅簡約的程式寫作","深入解析ES6箭頭函數：揭開與傳統函式的差異。","2023-11-29T01:02:36+08:00",[1127,1128,1129,1130,1131],"Arrow Function","this","Lexical Scoping","Syntactic Sugar","Callback Function",[1034,702],2142,{"path":1135,"title":1136,"description":1137,"date":1138,"updated":9,"tags":1139,"categories":1143,"draft":15,"wordCount":1144,"readingTime":329,"canonical":9,"series":9},"\u002FJS-2","JavaScript：深入了解This的指向與應用","探索JavaScript This 的指向：深入剖析判斷的技巧。","2023-11-28T22:22:45+08:00",[1128,1140,1131,1141,1142],"Execution Context","Binding","Fundamentals",[1034,702],1963,{"path":1146,"title":1147,"description":1148,"date":1149,"updated":9,"tags":1150,"categories":1154,"draft":15,"wordCount":1155,"readingTime":340,"canonical":9,"series":9},"\u002FJS-1","JavaScript：淺談ES6常見縮寫","JavaScript ES6縮寫技巧：輕鬆簡化程式碼，提升效率！。","2023-11-28T13:38:14+08:00",[1026,1151,1152,1153],"Shorthand","Spread Operator","Object",[1034,702],818,{"path":1157,"title":1158,"description":1159,"date":1160,"updated":9,"tags":1161,"categories":1165,"draft":15,"wordCount":1166,"readingTime":340,"canonical":9,"series":9},"\u002FEmmet-1","前端開發神器：使用Emmet提升網頁開發效率","本文將介紹如何利用Emmet來大幅提高前端開發效率，讓你的編碼速度如專家般飛快。","2023-10-31T14:40:54+08:00",[1162,1163,1164],"Emmet","VSCode","HTML",[702,673],865,{"path":1168,"title":1169,"description":1170,"date":1171,"updated":9,"tags":1172,"categories":1177,"draft":15,"wordCount":1179,"readingTime":340,"canonical":9,"series":9},"\u002Fhexo-github-4","建立自己的部落格：了解Hexo指令，更換next部落格主題","今天的你跟我都是Hexo指令指揮官，讓我們將部落格造型大改造一下吧!!!","2023-10-20T14:33:38+08:00",[1173,1174,1175,1176],"Hexo","NexT","git clone","Hexo指令",[1178],"Blog",979,{"path":1181,"title":1182,"description":1183,"date":1184,"updated":9,"tags":1185,"categories":1189,"draft":15,"wordCount":1190,"readingTime":329,"canonical":9,"series":9},"\u002Fhexo-github-3","建立自己的部落格：修改Hexo設定檔中Site，查看其變化","今天的你跟我都是部落格工程師，我們一起來將網頁做一些小小的改變，有一天匯集在一起就會讓你的部落格變的與眾不同。","2023-10-18T20:50:31+08:00",[1173,1163,1186,1187,1188],"Sublime Text","YAML","SEO",[1178],1798,{"path":1192,"title":1193,"description":1194,"date":1195,"updated":9,"tags":1196,"categories":1199,"draft":15,"wordCount":1200,"readingTime":340,"canonical":9,"series":9},"\u002Fhexo-github-2","建立自己的部落格：創建Hexo Blog初始的模板","踏出那關鍵的第一步，從白紙到完整的部落格，一同見證你的部落格誕生的奇妙時刻。","2023-10-17T15:59:37+08:00",[1173,1197,1198],"Hexo-cli","hexo init",[1178],941,{"path":1202,"title":1203,"description":1204,"date":1205,"updated":9,"tags":1206,"categories":1208,"draft":15,"wordCount":1209,"readingTime":340,"canonical":9,"series":9},"\u002Fhexo-github-1","建立自己的部落格：認識Hexo及所其需工具(Nodejs & Git)","打造屬於自己風格的部落格其實不難，讓我們一步步手把手教你如何實現這個目標。","2023-10-16T08:30:27+08:00",[1173,1058,1207],"Git",[1178],790,{"id":1211,"title":834,"body":1212,"canonical":840,"categories":3836,"date":836,"description":835,"draft":15,"extension":3837,"meta":3838,"navigation":1596,"ogImage":9,"path":833,"rawbody":3839,"readingTime":31,"robots":9,"schemaOrg":9,"seo":3840,"series":3841,"sitemap":3842,"slug":3848,"stem":3849,"tags":3850,"updated":9,"wordCount":839,"__hash__":3851},"posts\u002F2024-10-01-ithome-2024-day-18.md",{"type":1213,"value":1214,"toc":3824},"minimark",[1215,1223,1227,1255,1258,1262,1273,1330,1340,1350,1353,1439,1442,1514,1542,1545,1639,1642,1730,1733,1739,1758,1774,1777,1783,1831,1838,1840,1904,1906,2022,2024,2101,2104,2192,2195,2210,2223,2230,2232,2235,2244,2247,2262,2264,2337,2339,2419,2421,2500,2502,2508,2515,2517,2542,2544,2755,2771,2781,2796,2799,2815,2832,2858,2885,2903,2905,2908,2915,2917,2993,2995,3250,3268,3271,3372,3374,3527,3529,3604,3610,3630,3632,3635,3647,3712,3719,3722,3820],[1216,1217,1218],"p",{},[1219,1220],"img",{"alt":1221,"src":1222},"文章背景圖","https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727786245\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002FDay18_%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC_-_props_ci0r3b.png",[1224,1225,1226],"h2",{"id":1226},"目錄",[1228,1229,1230,1234,1237,1240,1243,1246,1249,1252],"ul",{},[1231,1232,1233],"li",{},"props 基本用法",[1231,1235,1236],{},"props 單向資料流 - 組件之間的溝通方式",[1231,1238,1239],{},"props 子組件應用情境說明",[1231,1241,1242],{},"props 傳值類型 - 靜態傳值 vs 動態傳值",[1231,1244,1245],{},"props 多參數傳遞的方式",[1231,1247,1248],{},"props 校驗方式 - 檢查所有外來的參數",[1231,1250,1251],{},"props Boolean 型別規則判定方式",[1231,1253,1254],{},"總結",[1256,1257],"hr",{},[1259,1260,1233],"h3",{"id":1261},"props-基本用法",[1216,1263,1264,1265,1268,1269,1272],{},"組件之間的傳值必須透過聲明 props 的方式，這樣可以避免與",[1266,1267,1164],"code",{},"的",[1266,1270,1271],{},"屬性(attribute)","混淆。父組件傳遞參數給子組件的方式有以下兩種方式：",[1274,1275,1276,1301],"ol",{},[1231,1277,1278,1282,1283,1286,1287,1290,1291,1293,1294,1297,1298,1300],{},[1279,1280,1281],"strong",{},"不限制傳入的 props 型別或行為","：使用",[1266,1284,1285],{},"陣列","的方式來定義",[1266,1288,1289],{},"props","，這樣只需列出父組件傳遞的 ",[1266,1292,1289],{},"名稱。子組件可以直接通過",[1266,1295,1296],{},"this.xxx","的方式來獲取傳遞進來的",[1266,1299,1289],{},"參數。",[1231,1302,1303,1282,1306,1286,1309,1311,1312,1314,1315,1318,1319,1318,1322,1325,1326,1329],{},[1279,1304,1305],{},"限制傳入的 props 型別、預設值、驗證器及是否必填等",[1266,1307,1308],{},"物件",[1266,1310,1289],{},"，在物件中指定",[1266,1313,1289],{},"的名稱，並對其",[1266,1316,1317],{},"型別","、",[1266,1320,1321],{},"預設值",[1266,1323,1324],{},"驗證器","和",[1266,1327,1328],{},"是否必填","等進行限制。這樣可以更嚴格地控制傳入的數據，確保組件的行為符合預期。",[1216,1331,1332,1333],{},"👉 ",[1334,1335,1339],"a",{"href":1336,"rel":1337},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FwvLEBWj",[1338],"nofollow","Vue3 Options API props 基本用法實作連結",[1216,1341,1342,1343,1345,1346,1349],{},"以下透過一個範例來說明",[1266,1344,1289],{},"的動態綁定基本用法，使用",[1266,1347,1348],{},":","來進行綁定：",[1216,1351,1352],{},"父組件 Vue Template：",[1354,1355,1360],"pre",{"className":1356,"code":1357,"language":1358,"meta":1359,"style":1359},"language-html shiki shiki-themes github-light github-dark-dimmed","\u003Cdiv id=\"app\">\n  \u003Cchild-component-a :special-msg=\"specialMsg\">\u003C\u002Fchild-component-a>\n  \u003Cchild-component-b :special-msg=\"specialMsg\">\u003C\u002Fchild-component-b>\n\u003C\u002Fdiv>\n","html","",[1266,1361,1362,1388,1411,1430],{"__ignoreMap":1359},[1363,1364,1366,1370,1374,1378,1381,1385],"span",{"class":1365,"line":340},"line",[1363,1367,1369],{"class":1368},"sYgZi","\u003C",[1363,1371,1373],{"class":1372},"sIAta","div",[1363,1375,1377],{"class":1376},"sMOND"," id",[1363,1379,1380],{"class":1368},"=",[1363,1382,1384],{"class":1383},"s-HuK","\"app\"",[1363,1386,1387],{"class":1368},">\n",[1363,1389,1390,1393,1396,1399,1401,1404,1407,1409],{"class":1365,"line":329},[1363,1391,1392],{"class":1368},"  \u003C",[1363,1394,1395],{"class":1372},"child-component-a",[1363,1397,1398],{"class":1376}," :special-msg",[1363,1400,1380],{"class":1368},[1363,1402,1403],{"class":1383},"\"specialMsg\"",[1363,1405,1406],{"class":1368},">\u003C\u002F",[1363,1408,1395],{"class":1372},[1363,1410,1387],{"class":1368},[1363,1412,1413,1415,1418,1420,1422,1424,1426,1428],{"class":1365,"line":318},[1363,1414,1392],{"class":1368},[1363,1416,1417],{"class":1372},"child-component-b",[1363,1419,1398],{"class":1376},[1363,1421,1380],{"class":1368},[1363,1423,1403],{"class":1383},[1363,1425,1406],{"class":1368},[1363,1427,1417],{"class":1372},[1363,1429,1387],{"class":1368},[1363,1431,1432,1435,1437],{"class":1365,"line":134},[1363,1433,1434],{"class":1368},"\u003C\u002F",[1363,1436,1373],{"class":1372},[1363,1438,1387],{"class":1368},[1216,1440,1441],{},"父組件 javascript：",[1354,1443,1447],{"className":1444,"code":1445,"language":1446,"meta":1359,"style":1359},"language-javascript shiki shiki-themes github-light github-dark-dimmed","\u002F\u002F 根組件\nconst rootComponent = {\n  data() {\n    return {\n      specialMsg: \"hello vue!\"\n    };\n  },\n  components: { childComponentA, childComponentB }\n};\n","javascript",[1266,1448,1449,1455,1470,1479,1486,1494,1499,1504,1509],{"__ignoreMap":1359},[1363,1450,1451],{"class":1365,"line":340},[1363,1452,1454],{"class":1453},"sDN9O","\u002F\u002F 根組件\n",[1363,1456,1457,1460,1464,1467],{"class":1365,"line":329},[1363,1458,1029],{"class":1459},"s7YZ4",[1363,1461,1463],{"class":1462},"sviXB"," rootComponent",[1363,1465,1466],{"class":1459}," =",[1363,1468,1469],{"class":1368}," {\n",[1363,1471,1472,1476],{"class":1365,"line":318},[1363,1473,1475],{"class":1474},"sPO5f","  data",[1363,1477,1478],{"class":1368},"() {\n",[1363,1480,1481,1484],{"class":1365,"line":134},[1363,1482,1483],{"class":1459},"    return",[1363,1485,1469],{"class":1368},[1363,1487,1488,1491],{"class":1365,"line":122},[1363,1489,1490],{"class":1368},"      specialMsg: ",[1363,1492,1493],{"class":1383},"\"hello vue!\"\n",[1363,1495,1496],{"class":1365,"line":31},[1363,1497,1498],{"class":1368},"    };\n",[1363,1500,1501],{"class":1365,"line":17},[1363,1502,1503],{"class":1368},"  },\n",[1363,1505,1506],{"class":1365,"line":110},[1363,1507,1508],{"class":1368},"  components: { childComponentA, childComponentB }\n",[1363,1510,1511],{"class":1365,"line":76},[1363,1512,1513],{"class":1368},"};\n",[1216,1515,1516,1517,1520,1521,1524,1525,1527,1528,1530,1531,1534,1535,1537,1538,1541],{},"⭐ ",[1266,1518,1519],{},":special-msg=\"specialMsg\""," 中，",[1266,1522,1523],{},"special-msg","是子組件中定義的",[1266,1526,1289],{},"名稱，優先使用",[1266,1529,1164],{},"可解析的 ",[1266,1532,1533],{},"kebab-case（串燒)","命名方式，以確保與",[1266,1536,1164],{},"標準保持一致，並避免可能的瀏覽器解析問題，而 ",[1266,1539,1540],{},"specialMsg","是父組件中的變數名稱。",[1216,1543,1544],{},"子組件 Vue Template：",[1354,1546,1548],{"className":1356,"code":1547,"language":1358,"meta":1359,"style":1359},"\u003C!-- childComponentA 畫面 -->\n\u003Ctemplate id=\"childComponentA\">\n  \u003Cp>childComponentA title：{{ specialMsg }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n\n\u003C!-- childComponentB 畫面 -->\n\u003Ctemplate id=\"childComponentB\">\n  \u003Cp>childComponentB title：{{ specialMsg }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n",[1266,1549,1550,1555,1571,1584,1592,1598,1603,1618,1631],{"__ignoreMap":1359},[1363,1551,1552],{"class":1365,"line":340},[1363,1553,1554],{"class":1453},"\u003C!-- childComponentA 畫面 -->\n",[1363,1556,1557,1559,1562,1564,1566,1569],{"class":1365,"line":329},[1363,1558,1369],{"class":1368},[1363,1560,1561],{"class":1372},"template",[1363,1563,1377],{"class":1376},[1363,1565,1380],{"class":1368},[1363,1567,1568],{"class":1383},"\"childComponentA\"",[1363,1570,1387],{"class":1368},[1363,1572,1573,1575,1577,1580,1582],{"class":1365,"line":318},[1363,1574,1392],{"class":1368},[1363,1576,1216],{"class":1372},[1363,1578,1579],{"class":1368},">childComponentA title：{{ specialMsg }}\u003C\u002F",[1363,1581,1216],{"class":1372},[1363,1583,1387],{"class":1368},[1363,1585,1586,1588,1590],{"class":1365,"line":134},[1363,1587,1434],{"class":1368},[1363,1589,1561],{"class":1372},[1363,1591,1387],{"class":1368},[1363,1593,1594],{"class":1365,"line":122},[1363,1595,1597],{"emptyLinePlaceholder":1596},true,"\n",[1363,1599,1600],{"class":1365,"line":31},[1363,1601,1602],{"class":1453},"\u003C!-- childComponentB 畫面 -->\n",[1363,1604,1605,1607,1609,1611,1613,1616],{"class":1365,"line":17},[1363,1606,1369],{"class":1368},[1363,1608,1561],{"class":1372},[1363,1610,1377],{"class":1376},[1363,1612,1380],{"class":1368},[1363,1614,1615],{"class":1383},"\"childComponentB\"",[1363,1617,1387],{"class":1368},[1363,1619,1620,1622,1624,1627,1629],{"class":1365,"line":110},[1363,1621,1392],{"class":1368},[1363,1623,1216],{"class":1372},[1363,1625,1626],{"class":1368},">childComponentB title：{{ specialMsg }}\u003C\u002F",[1363,1628,1216],{"class":1372},[1363,1630,1387],{"class":1368},[1363,1632,1633,1635,1637],{"class":1365,"line":76},[1363,1634,1434],{"class":1368},[1363,1636,1561],{"class":1372},[1363,1638,1387],{"class":1368},[1216,1640,1641],{},"子組件 javascript：",[1354,1643,1645],{"className":1444,"code":1644,"language":1446,"meta":1359,"style":1359},"const childComponentA = {\n  \u002F\u002F 陣列定義 props，無型別的定義\n  props: [\"specialMsg\"],\n  template: \"#childComponentA\"\n};\n\nconst childComponentB = {\n  \u002F\u002F 物件定義，搭配型別限制\n  props: {\n    specialMsg: String\n  },\n  template: \"#childComponentB\"\n};\n",[1266,1646,1647,1658,1663,1673,1681,1685,1689,1700,1705,1710,1715,1719,1726],{"__ignoreMap":1359},[1363,1648,1649,1651,1654,1656],{"class":1365,"line":340},[1363,1650,1029],{"class":1459},[1363,1652,1653],{"class":1462}," childComponentA",[1363,1655,1466],{"class":1459},[1363,1657,1469],{"class":1368},[1363,1659,1660],{"class":1365,"line":329},[1363,1661,1662],{"class":1453},"  \u002F\u002F 陣列定義 props，無型別的定義\n",[1363,1664,1665,1668,1670],{"class":1365,"line":318},[1363,1666,1667],{"class":1368},"  props: [",[1363,1669,1403],{"class":1383},[1363,1671,1672],{"class":1368},"],\n",[1363,1674,1675,1678],{"class":1365,"line":134},[1363,1676,1677],{"class":1368},"  template: ",[1363,1679,1680],{"class":1383},"\"#childComponentA\"\n",[1363,1682,1683],{"class":1365,"line":122},[1363,1684,1513],{"class":1368},[1363,1686,1687],{"class":1365,"line":31},[1363,1688,1597],{"emptyLinePlaceholder":1596},[1363,1690,1691,1693,1696,1698],{"class":1365,"line":17},[1363,1692,1029],{"class":1459},[1363,1694,1695],{"class":1462}," childComponentB",[1363,1697,1466],{"class":1459},[1363,1699,1469],{"class":1368},[1363,1701,1702],{"class":1365,"line":110},[1363,1703,1704],{"class":1453},"  \u002F\u002F 物件定義，搭配型別限制\n",[1363,1706,1707],{"class":1365,"line":76},[1363,1708,1709],{"class":1368},"  props: {\n",[1363,1711,1712],{"class":1365,"line":247},[1363,1713,1714],{"class":1368},"    specialMsg: String\n",[1363,1716,1717],{"class":1365,"line":236},[1363,1718,1503],{"class":1368},[1363,1720,1721,1723],{"class":1365,"line":225},[1363,1722,1677],{"class":1368},[1363,1724,1725],{"class":1383},"\"#childComponentB\"\n",[1363,1727,1728],{"class":1365,"line":214},[1363,1729,1513],{"class":1368},[1259,1731,1236],{"id":1732},"props-單向資料流-組件之間的溝通方式",[1216,1734,1735],{},[1219,1736],{"alt":1737,"src":1738},"父子組件傳值關係(props 及 emits)","https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727789558\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002F%E7%88%B6%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%E9%97%9C%E4%BF%82_props_%E5%8F%8A_emits_xyv9sg.png",[1216,1740,1741,1742,1744,1745,1747,1748,1750,1751,1754,1755,1757],{},"父組件可以透過",[1266,1743,1289],{},"將資料傳遞給子組件，然而，子組件無法直接修改由父組件傳遞進來的",[1266,1746,1289],{},"。如果子組件需要更改",[1266,1749,1289],{},"的值，應該透過 ",[1266,1752,1753],{},"emits","事件的方式通知父組件，由父組件來進行變更，而非直接在子組件中修改",[1266,1756,1289],{},"。這種單向資料流的設計可以更清楚資料的流向，同時也有助於後續的維護與測試。",[1216,1759,1760,1761,1763,1764,1766,1767,1770],{},"如果意圖修改",[1266,1762,1289],{},"會跑出錯誤，告訴你",[1266,1765,1289],{},"是唯讀的：",[1768,1769],"br",{},[1219,1771],{"alt":1772,"src":1773},"修改組件 props 警告","https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727789953\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002F%E4%BF%AE%E6%94%B9%E7%B5%84%E4%BB%B6_props_%E8%AD%A6%E5%91%8A_t4lys0.png",[1259,1775,1239],{"id":1776},"props-子組件應用情境說明",[1216,1778,1779,1780,1782],{},"如果想要使用",[1266,1781,1289],{},"參數在子組件做應用，可以使用下面兩種方式：",[1274,1784,1785,1812],{},[1231,1786,1787,1790,1791,1794,1795,1797,1798,1801,1802,1804,1805,1808,1809,1811],{},[1279,1788,1789],{},"使用 data 初始化值","： ",[1266,1792,1793],{},"data 函數","會在",[1266,1796,1289],{},"初始化之後被呼叫一次，因此可以在",[1266,1799,1800],{},"data","中基於 ",[1266,1803,1289],{},"進行",[1266,1806,1807],{},"初始值","的設定。但是其值不會因為後續",[1266,1810,1289],{},"改動而連動影響。",[1231,1813,1814,1817,1818,1821,1822,1824,1825,1827,1828,1830],{},[1279,1815,1816],{},"使用 computed 監聽 props","：",[1266,1819,1820],{},"computed","屬性會在",[1266,1823,1289],{},"變更時重新計算，因此可以在 ",[1266,1826,1820],{},"中進行",[1266,1829,1289],{},"的格式化處理或其他計算。",[1216,1832,1332,1833],{},[1334,1834,1837],{"href":1835,"rel":1836},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FrNEqjRZ",[1338],"Vue3 Options API props 子組件應用實作連結",[1216,1839,1544],{},[1354,1841,1843],{"className":1356,"code":1842,"language":1358,"meta":1359,"style":1359},"\u003Ctemplate id=\"child\">\n  \u003C!--   使用 data 初始化 props 值(初始化執行後不會變更) -->\n  \u003Cp>newCount：{{ newCount }}\u003C\u002Fp>\n  \u003C!--   使用 computed 格式化 props 值(監聽 props 變化執行函數) -->\n  \u003Cp>doubleCount：{{ doubleCount }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n",[1266,1844,1845,1860,1865,1878,1883,1896],{"__ignoreMap":1359},[1363,1846,1847,1849,1851,1853,1855,1858],{"class":1365,"line":340},[1363,1848,1369],{"class":1368},[1363,1850,1561],{"class":1372},[1363,1852,1377],{"class":1376},[1363,1854,1380],{"class":1368},[1363,1856,1857],{"class":1383},"\"child\"",[1363,1859,1387],{"class":1368},[1363,1861,1862],{"class":1365,"line":329},[1363,1863,1864],{"class":1453},"  \u003C!--   使用 data 初始化 props 值(初始化執行後不會變更) -->\n",[1363,1866,1867,1869,1871,1874,1876],{"class":1365,"line":318},[1363,1868,1392],{"class":1368},[1363,1870,1216],{"class":1372},[1363,1872,1873],{"class":1368},">newCount：{{ newCount }}\u003C\u002F",[1363,1875,1216],{"class":1372},[1363,1877,1387],{"class":1368},[1363,1879,1880],{"class":1365,"line":134},[1363,1881,1882],{"class":1453},"  \u003C!--   使用 computed 格式化 props 值(監聽 props 變化執行函數) -->\n",[1363,1884,1885,1887,1889,1892,1894],{"class":1365,"line":122},[1363,1886,1392],{"class":1368},[1363,1888,1216],{"class":1372},[1363,1890,1891],{"class":1368},">doubleCount：{{ doubleCount }}\u003C\u002F",[1363,1893,1216],{"class":1372},[1363,1895,1387],{"class":1368},[1363,1897,1898,1900,1902],{"class":1365,"line":31},[1363,1899,1434],{"class":1368},[1363,1901,1561],{"class":1372},[1363,1903,1387],{"class":1368},[1216,1905,1641],{},[1354,1907,1909],{"className":1444,"code":1908,"language":1446,"meta":1359,"style":1359},"const childComponent = {\n  props: [\"count\"],\n  template: \"#child\",\n  data(){\n    return{\n      newCount: this.count + 1\n    }\n  },\n  computed: {\n    doubleCount() {\n      return this.count + this.count;\n    }\n  }\n};\n",[1266,1910,1911,1922,1931,1941,1948,1955,1971,1976,1980,1985,1992,2009,2013,2018],{"__ignoreMap":1359},[1363,1912,1913,1915,1918,1920],{"class":1365,"line":340},[1363,1914,1029],{"class":1459},[1363,1916,1917],{"class":1462}," childComponent",[1363,1919,1466],{"class":1459},[1363,1921,1469],{"class":1368},[1363,1923,1924,1926,1929],{"class":1365,"line":329},[1363,1925,1667],{"class":1368},[1363,1927,1928],{"class":1383},"\"count\"",[1363,1930,1672],{"class":1368},[1363,1932,1933,1935,1938],{"class":1365,"line":318},[1363,1934,1677],{"class":1368},[1363,1936,1937],{"class":1383},"\"#child\"",[1363,1939,1940],{"class":1368},",\n",[1363,1942,1943,1945],{"class":1365,"line":134},[1363,1944,1475],{"class":1474},[1363,1946,1947],{"class":1368},"(){\n",[1363,1949,1950,1952],{"class":1365,"line":122},[1363,1951,1483],{"class":1459},[1363,1953,1954],{"class":1368},"{\n",[1363,1956,1957,1960,1962,1965,1968],{"class":1365,"line":31},[1363,1958,1959],{"class":1368},"      newCount: ",[1363,1961,1128],{"class":1462},[1363,1963,1964],{"class":1368},".count ",[1363,1966,1967],{"class":1459},"+",[1363,1969,1970],{"class":1462}," 1\n",[1363,1972,1973],{"class":1365,"line":17},[1363,1974,1975],{"class":1368},"    }\n",[1363,1977,1978],{"class":1365,"line":110},[1363,1979,1503],{"class":1368},[1363,1981,1982],{"class":1365,"line":76},[1363,1983,1984],{"class":1368},"  computed: {\n",[1363,1986,1987,1990],{"class":1365,"line":247},[1363,1988,1989],{"class":1474},"    doubleCount",[1363,1991,1478],{"class":1368},[1363,1993,1994,1997,2000,2002,2004,2006],{"class":1365,"line":236},[1363,1995,1996],{"class":1459},"      return",[1363,1998,1999],{"class":1462}," this",[1363,2001,1964],{"class":1368},[1363,2003,1967],{"class":1459},[1363,2005,1999],{"class":1462},[1363,2007,2008],{"class":1368},".count;\n",[1363,2010,2011],{"class":1365,"line":225},[1363,2012,1975],{"class":1368},[1363,2014,2015],{"class":1365,"line":214},[1363,2016,2017],{"class":1368},"  }\n",[1363,2019,2020],{"class":1365,"line":203},[1363,2021,1513],{"class":1368},[1216,2023,1352],{},[1354,2025,2027],{"className":1356,"code":2026,"language":1358,"meta":1359,"style":1359},"\u003Cdiv id=\"app\">\n  \u003Cchild-component :count=\"count\">\u003C\u002Fchild-component>\n  \u003Cbutton @click=\"add\" type=\"button\"> +1\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n",[1266,2028,2029,2043,2063,2093],{"__ignoreMap":1359},[1363,2030,2031,2033,2035,2037,2039,2041],{"class":1365,"line":340},[1363,2032,1369],{"class":1368},[1363,2034,1373],{"class":1372},[1363,2036,1377],{"class":1376},[1363,2038,1380],{"class":1368},[1363,2040,1384],{"class":1383},[1363,2042,1387],{"class":1368},[1363,2044,2045,2047,2050,2053,2055,2057,2059,2061],{"class":1365,"line":329},[1363,2046,1392],{"class":1368},[1363,2048,2049],{"class":1372},"child-component",[1363,2051,2052],{"class":1376}," :count",[1363,2054,1380],{"class":1368},[1363,2056,1928],{"class":1383},[1363,2058,1406],{"class":1368},[1363,2060,2049],{"class":1372},[1363,2062,1387],{"class":1368},[1363,2064,2065,2067,2070,2073,2075,2078,2081,2083,2086,2089,2091],{"class":1365,"line":318},[1363,2066,1392],{"class":1368},[1363,2068,2069],{"class":1372},"button",[1363,2071,2072],{"class":1376}," @click",[1363,2074,1380],{"class":1368},[1363,2076,2077],{"class":1383},"\"add\"",[1363,2079,2080],{"class":1376}," type",[1363,2082,1380],{"class":1368},[1363,2084,2085],{"class":1383},"\"button\"",[1363,2087,2088],{"class":1368},"> +1\u003C\u002F",[1363,2090,2069],{"class":1372},[1363,2092,1387],{"class":1368},[1363,2094,2095,2097,2099],{"class":1365,"line":134},[1363,2096,1434],{"class":1368},[1363,2098,1373],{"class":1372},[1363,2100,1387],{"class":1368},[1216,2102,2103],{},"父組件 javasciprt：",[1354,2105,2107],{"className":1444,"code":2106,"language":1446,"meta":1359,"style":1359},"const rootComponent = {\n  data() {\n    return {\n      count: 10\n    };\n  },\n  methods: {\n    add() {\n      this.count += 1;\n    }\n  },\n  components: { childComponent }\n};\n",[1266,2108,2109,2119,2125,2131,2139,2143,2147,2152,2159,2175,2179,2183,2188],{"__ignoreMap":1359},[1363,2110,2111,2113,2115,2117],{"class":1365,"line":340},[1363,2112,1029],{"class":1459},[1363,2114,1463],{"class":1462},[1363,2116,1466],{"class":1459},[1363,2118,1469],{"class":1368},[1363,2120,2121,2123],{"class":1365,"line":329},[1363,2122,1475],{"class":1474},[1363,2124,1478],{"class":1368},[1363,2126,2127,2129],{"class":1365,"line":318},[1363,2128,1483],{"class":1459},[1363,2130,1469],{"class":1368},[1363,2132,2133,2136],{"class":1365,"line":134},[1363,2134,2135],{"class":1368},"      count: ",[1363,2137,2138],{"class":1462},"10\n",[1363,2140,2141],{"class":1365,"line":122},[1363,2142,1498],{"class":1368},[1363,2144,2145],{"class":1365,"line":31},[1363,2146,1503],{"class":1368},[1363,2148,2149],{"class":1365,"line":17},[1363,2150,2151],{"class":1368},"  methods: {\n",[1363,2153,2154,2157],{"class":1365,"line":110},[1363,2155,2156],{"class":1474},"    add",[1363,2158,1478],{"class":1368},[1363,2160,2161,2164,2166,2169,2172],{"class":1365,"line":76},[1363,2162,2163],{"class":1462},"      this",[1363,2165,1964],{"class":1368},[1363,2167,2168],{"class":1459},"+=",[1363,2170,2171],{"class":1462}," 1",[1363,2173,2174],{"class":1368},";\n",[1363,2176,2177],{"class":1365,"line":247},[1363,2178,1975],{"class":1368},[1363,2180,2181],{"class":1365,"line":236},[1363,2182,1503],{"class":1368},[1363,2184,2185],{"class":1365,"line":225},[1363,2186,2187],{"class":1368},"  components: { childComponent }\n",[1363,2189,2190],{"class":1365,"line":214},[1363,2191,1513],{"class":1368},[1259,2193,1242],{"id":2194},"props-傳值類型-靜態傳值-vs-動態傳值",[1216,2196,2197,2198,2201,2202,2205,2206,2209],{},"當父組件向子組件傳遞值時，如果使用靜態傳值（例如：",[1266,2199,2200],{},"\u003Ctest-component isShow=\"true\">\u003C\u002Ftest-component>","），",[1266,2203,2204],{},"isShow","參數傳入的值會被視為純字串，因為其未使用",[1266,2207,2208],{},"v-bind","的方式動態綁定。",[1216,2211,2212,2213,2216,2217,2219,2220,2222],{},"若需要傳入不同類型的參數值，比如 Number、Boolean、Array、Object 等。應該使用",[1266,2214,2215],{},"動態傳值","的方式，即使用",[1266,2218,2208],{},"或縮寫",[1266,2221,1348],{},"來動態綁定表達式。這樣可以確保傳入的值保持其原有的數據類型，而不會被轉換為字串。",[1216,2224,1332,2225],{},[1334,2226,2229],{"href":2227,"rel":2228},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FYzoOXeR",[1338],"Vue3 Options API 動態傳值與靜態傳值實作連結",[1256,2231],{},[1259,2233,1245],{"id":2234},"props-多參數傳遞的方式",[1216,2236,2237,2238,2240,2241,2243],{},"如果需要將一個物件中的多個屬性傳遞給子組件進行後續的畫面顯示或邏輯處理時，可以使用",[1266,2239,2208],{}," 將整個物件直接綁定到子組件。這樣做等於將物件內的所有屬性動態綁定到子組件的對應",[1266,2242,1289],{},"上。",[1216,2245,2246],{},"流程說明：",[1274,2248,2249,2256],{},[1231,2250,2251,2252,2255],{},"定義一個",[1266,2253,2254],{},"userInfo","物件內有多個屬性(name、age)",[1231,2257,2258,2259,2261],{},"將",[1266,2260,2254],{},"全部參數值傳遞給子組件使用",[1216,2263,1441],{},[1354,2265,2267],{"className":1444,"code":2266,"language":1446,"meta":1359,"style":1359},"const rootComponent = {\n  data() {\n    return {\n      userInfo: {\n        name: \"Antonio\",\n        age: 25,\n      }\n    };\n  },\n  components: { childComponent }\n};\n",[1266,2268,2269,2279,2285,2291,2296,2306,2316,2321,2325,2329,2333],{"__ignoreMap":1359},[1363,2270,2271,2273,2275,2277],{"class":1365,"line":340},[1363,2272,1029],{"class":1459},[1363,2274,1463],{"class":1462},[1363,2276,1466],{"class":1459},[1363,2278,1469],{"class":1368},[1363,2280,2281,2283],{"class":1365,"line":329},[1363,2282,1475],{"class":1474},[1363,2284,1478],{"class":1368},[1363,2286,2287,2289],{"class":1365,"line":318},[1363,2288,1483],{"class":1459},[1363,2290,1469],{"class":1368},[1363,2292,2293],{"class":1365,"line":134},[1363,2294,2295],{"class":1368},"      userInfo: {\n",[1363,2297,2298,2301,2304],{"class":1365,"line":122},[1363,2299,2300],{"class":1368},"        name: ",[1363,2302,2303],{"class":1383},"\"Antonio\"",[1363,2305,1940],{"class":1368},[1363,2307,2308,2311,2314],{"class":1365,"line":31},[1363,2309,2310],{"class":1368},"        age: ",[1363,2312,2313],{"class":1462},"25",[1363,2315,1940],{"class":1368},[1363,2317,2318],{"class":1365,"line":17},[1363,2319,2320],{"class":1368},"      }\n",[1363,2322,2323],{"class":1365,"line":110},[1363,2324,1498],{"class":1368},[1363,2326,2327],{"class":1365,"line":76},[1363,2328,1503],{"class":1368},[1363,2330,2331],{"class":1365,"line":247},[1363,2332,2187],{"class":1368},[1363,2334,2335],{"class":1365,"line":236},[1363,2336,1513],{"class":1368},[1216,2338,1352],{},[1354,2340,2342],{"className":1356,"code":2341,"language":1358,"meta":1359,"style":1359},"\u003Cdiv id=\"app\">\n  \u003C!--     以下兩種達到的效果相同 -->\n  \u003Cchild-component v-bind=\"userInfo\">\u003C\u002Fchild-component>\n  \u003Cchild-component :name=\"userInfo.name\" :age=\"userInfo.age\">\u003C\u002Fchild-component>\n\u003C\u002Fdiv>\n",[1266,2343,2344,2358,2363,2383,2411],{"__ignoreMap":1359},[1363,2345,2346,2348,2350,2352,2354,2356],{"class":1365,"line":340},[1363,2347,1369],{"class":1368},[1363,2349,1373],{"class":1372},[1363,2351,1377],{"class":1376},[1363,2353,1380],{"class":1368},[1363,2355,1384],{"class":1383},[1363,2357,1387],{"class":1368},[1363,2359,2360],{"class":1365,"line":329},[1363,2361,2362],{"class":1453},"  \u003C!--     以下兩種達到的效果相同 -->\n",[1363,2364,2365,2367,2369,2372,2374,2377,2379,2381],{"class":1365,"line":318},[1363,2366,1392],{"class":1368},[1363,2368,2049],{"class":1372},[1363,2370,2371],{"class":1376}," v-bind",[1363,2373,1380],{"class":1368},[1363,2375,2376],{"class":1383},"\"userInfo\"",[1363,2378,1406],{"class":1368},[1363,2380,2049],{"class":1372},[1363,2382,1387],{"class":1368},[1363,2384,2385,2387,2389,2392,2394,2397,2400,2402,2405,2407,2409],{"class":1365,"line":134},[1363,2386,1392],{"class":1368},[1363,2388,2049],{"class":1372},[1363,2390,2391],{"class":1376}," :name",[1363,2393,1380],{"class":1368},[1363,2395,2396],{"class":1383},"\"userInfo.name\"",[1363,2398,2399],{"class":1376}," :age",[1363,2401,1380],{"class":1368},[1363,2403,2404],{"class":1383},"\"userInfo.age\"",[1363,2406,1406],{"class":1368},[1363,2408,2049],{"class":1372},[1363,2410,1387],{"class":1368},[1363,2412,2413,2415,2417],{"class":1365,"line":122},[1363,2414,1434],{"class":1368},[1363,2416,1373],{"class":1372},[1363,2418,1387],{"class":1368},[1216,2420,1544],{},[1354,2422,2424],{"className":1356,"code":2423,"language":1358,"meta":1359,"style":1359},"\u003Ctemplate id=\"child\">\n  \u003Cdiv class=\"card\">\n    \u003Cp>姓名：{{ name }}\u003C\u002Fp>\n    \u003Cp>標題：{{ age }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[1266,2425,2426,2440,2456,2470,2483,2492],{"__ignoreMap":1359},[1363,2427,2428,2430,2432,2434,2436,2438],{"class":1365,"line":340},[1363,2429,1369],{"class":1368},[1363,2431,1561],{"class":1372},[1363,2433,1377],{"class":1376},[1363,2435,1380],{"class":1368},[1363,2437,1857],{"class":1383},[1363,2439,1387],{"class":1368},[1363,2441,2442,2444,2446,2449,2451,2454],{"class":1365,"line":329},[1363,2443,1392],{"class":1368},[1363,2445,1373],{"class":1372},[1363,2447,2448],{"class":1376}," class",[1363,2450,1380],{"class":1368},[1363,2452,2453],{"class":1383},"\"card\"",[1363,2455,1387],{"class":1368},[1363,2457,2458,2461,2463,2466,2468],{"class":1365,"line":318},[1363,2459,2460],{"class":1368},"    \u003C",[1363,2462,1216],{"class":1372},[1363,2464,2465],{"class":1368},">姓名：{{ name }}\u003C\u002F",[1363,2467,1216],{"class":1372},[1363,2469,1387],{"class":1368},[1363,2471,2472,2474,2476,2479,2481],{"class":1365,"line":134},[1363,2473,2460],{"class":1368},[1363,2475,1216],{"class":1372},[1363,2477,2478],{"class":1368},">標題：{{ age }}\u003C\u002F",[1363,2480,1216],{"class":1372},[1363,2482,1387],{"class":1368},[1363,2484,2485,2488,2490],{"class":1365,"line":122},[1363,2486,2487],{"class":1368},"  \u003C\u002F",[1363,2489,1373],{"class":1372},[1363,2491,1387],{"class":1368},[1363,2493,2494,2496,2498],{"class":1365,"line":31},[1363,2495,1434],{"class":1368},[1363,2497,1561],{"class":1372},[1363,2499,1387],{"class":1368},[1256,2501],{},[1216,2503,2504,2505,2507],{},"這邊特別舉一個產品列表陣列包產品資訊物件的案例，讓大家理解當",[1266,2506,1289],{},"傳遞物件時，需要注意傳值的陷阱：",[1216,2509,1332,2510],{},[1334,2511,2514],{"href":2512,"rel":2513},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FoNKbZVQ",[1338],"Vue3 Options API v-for 搭配 props 傳值陷阱實作連結",[1216,2516,2246],{},[1274,2518,2519,2529],{},[1231,2520,2521,2522,2525,2526,2528],{},"將產品列表中裡面每一個產品資訊的物件直接透過",[1266,2523,2524],{},"v-for","綁定動態",[1266,2527,1289],{},"給子組件",[1231,2530,2531,2532,2534,2535,2538,2539,2541],{},"子組件根據這個",[1266,2533,1289],{},"的值當作子組件",[1266,2536,2537],{},"v-model","綁定的初始值(改動子組件的值不應該影響",[1266,2540,1289],{},")",[1216,2543,1352],{},[1354,2545,2547],{"className":1356,"code":2546,"language":1358,"meta":1359,"style":1359},"\u003Cdiv id=\"app\">\n  \u003Cdiv class=\"parent-content\">\n    \u003Ch2>我是 parent-content\u003C\u002Fh2>\n    \u003Cli v-for=\"product in productList\" :key=\"product.id\">\n      名稱：\u003Cinput type=\"text\" v-model=\"product.name\">\n      價格：\u003Cinput type=\"text\" v-model=\"product.price\">\n    \u003C\u002Fli>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"child-content\">\n    \u003Ch2>我是 child-content\u003C\u002Fh2>\n    \u003Cchild-component v-for=\"product in productList\" :key=\"product.id\" :product-info=\"product\">\u003C\u002Fchild-component>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n",[1266,2548,2549,2563,2578,2591,2615,2640,2662,2671,2679,2694,2707,2739,2747],{"__ignoreMap":1359},[1363,2550,2551,2553,2555,2557,2559,2561],{"class":1365,"line":340},[1363,2552,1369],{"class":1368},[1363,2554,1373],{"class":1372},[1363,2556,1377],{"class":1376},[1363,2558,1380],{"class":1368},[1363,2560,1384],{"class":1383},[1363,2562,1387],{"class":1368},[1363,2564,2565,2567,2569,2571,2573,2576],{"class":1365,"line":329},[1363,2566,1392],{"class":1368},[1363,2568,1373],{"class":1372},[1363,2570,2448],{"class":1376},[1363,2572,1380],{"class":1368},[1363,2574,2575],{"class":1383},"\"parent-content\"",[1363,2577,1387],{"class":1368},[1363,2579,2580,2582,2584,2587,2589],{"class":1365,"line":318},[1363,2581,2460],{"class":1368},[1363,2583,1224],{"class":1372},[1363,2585,2586],{"class":1368},">我是 parent-content\u003C\u002F",[1363,2588,1224],{"class":1372},[1363,2590,1387],{"class":1368},[1363,2592,2593,2595,2597,2600,2602,2605,2608,2610,2613],{"class":1365,"line":134},[1363,2594,2460],{"class":1368},[1363,2596,1231],{"class":1372},[1363,2598,2599],{"class":1376}," v-for",[1363,2601,1380],{"class":1368},[1363,2603,2604],{"class":1383},"\"product in productList\"",[1363,2606,2607],{"class":1376}," :key",[1363,2609,1380],{"class":1368},[1363,2611,2612],{"class":1383},"\"product.id\"",[1363,2614,1387],{"class":1368},[1363,2616,2617,2620,2623,2625,2627,2630,2633,2635,2638],{"class":1365,"line":122},[1363,2618,2619],{"class":1368},"      名稱：\u003C",[1363,2621,2622],{"class":1372},"input",[1363,2624,2080],{"class":1376},[1363,2626,1380],{"class":1368},[1363,2628,2629],{"class":1383},"\"text\"",[1363,2631,2632],{"class":1376}," v-model",[1363,2634,1380],{"class":1368},[1363,2636,2637],{"class":1383},"\"product.name\"",[1363,2639,1387],{"class":1368},[1363,2641,2642,2645,2647,2649,2651,2653,2655,2657,2660],{"class":1365,"line":31},[1363,2643,2644],{"class":1368},"      價格：\u003C",[1363,2646,2622],{"class":1372},[1363,2648,2080],{"class":1376},[1363,2650,1380],{"class":1368},[1363,2652,2629],{"class":1383},[1363,2654,2632],{"class":1376},[1363,2656,1380],{"class":1368},[1363,2658,2659],{"class":1383},"\"product.price\"",[1363,2661,1387],{"class":1368},[1363,2663,2664,2667,2669],{"class":1365,"line":17},[1363,2665,2666],{"class":1368},"    \u003C\u002F",[1363,2668,1231],{"class":1372},[1363,2670,1387],{"class":1368},[1363,2672,2673,2675,2677],{"class":1365,"line":110},[1363,2674,2487],{"class":1368},[1363,2676,1373],{"class":1372},[1363,2678,1387],{"class":1368},[1363,2680,2681,2683,2685,2687,2689,2692],{"class":1365,"line":76},[1363,2682,1392],{"class":1368},[1363,2684,1373],{"class":1372},[1363,2686,2448],{"class":1376},[1363,2688,1380],{"class":1368},[1363,2690,2691],{"class":1383},"\"child-content\"",[1363,2693,1387],{"class":1368},[1363,2695,2696,2698,2700,2703,2705],{"class":1365,"line":247},[1363,2697,2460],{"class":1368},[1363,2699,1224],{"class":1372},[1363,2701,2702],{"class":1368},">我是 child-content\u003C\u002F",[1363,2704,1224],{"class":1372},[1363,2706,1387],{"class":1368},[1363,2708,2709,2711,2713,2715,2717,2719,2721,2723,2725,2728,2730,2733,2735,2737],{"class":1365,"line":236},[1363,2710,2460],{"class":1368},[1363,2712,2049],{"class":1372},[1363,2714,2599],{"class":1376},[1363,2716,1380],{"class":1368},[1363,2718,2604],{"class":1383},[1363,2720,2607],{"class":1376},[1363,2722,1380],{"class":1368},[1363,2724,2612],{"class":1383},[1363,2726,2727],{"class":1376}," :product-info",[1363,2729,1380],{"class":1368},[1363,2731,2732],{"class":1383},"\"product\"",[1363,2734,1406],{"class":1368},[1363,2736,2049],{"class":1372},[1363,2738,1387],{"class":1368},[1363,2740,2741,2743,2745],{"class":1365,"line":225},[1363,2742,2487],{"class":1368},[1363,2744,1373],{"class":1372},[1363,2746,1387],{"class":1368},[1363,2748,2749,2751,2753],{"class":1365,"line":214},[1363,2750,1434],{"class":1368},[1363,2752,1373],{"class":1372},[1363,2754,1387],{"class":1368},[1216,2756,1516,2757,2760,2761,2763,2764,2767,2768,2770],{},[1266,2758,2759],{},"javaScript","物件具有引用相同記憶體地址的特性，因此當傳遞給子組件的",[1266,2762,1289],{},"不是基礎型別（例如：",[1266,2765,2766],{},":product-name=\"product.name\"","），而是引用型別(如物件或陣列)時，子組件對",[1266,2769,1289],{},"的改動會直接影響父組件中的數據。這是因為父子組件之間實際上共享的是對同一物件的引用，而不是物件本身的拷貝。",[1216,2772,2773,2774,2777,2778,2780],{},"改正方式可以參考上面",[1266,2775,2776],{},"多參數傳遞的方式","，綁定單一屬性或是透過",[1266,2779,2208],{},"一次綁定物件內所有屬性。",[1216,2782,1332,2783,2788,2790,2791],{},[1334,2784,2787],{"href":2785,"rel":2786},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FeYqJVpV",[1338],"Vue3 Options API v-for 搭配 props 傳值手動綁定物件內所有屬性實作連結",[1768,2789],{},"\n👉 ",[1334,2792,2795],{"href":2793,"rel":2794},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FVwoeQeO",[1338],"Vue3 Options API v-for 搭配 props 傳值透過 v-bind 綁定物件所有屬性實作連結",[1259,2797,1248],{"id":2798},"props-校驗方式-檢查所有外來的參數",[1216,2800,2801,2802,2804,2805,2807,2808,2811,2812,2814],{},"在 Vue 組件中，",[1266,2803,1289],{},"是從父組件傳遞過來的參數，而非子組件本身定義的變數。為了確保後續數據的維護方便，建議對",[1266,2806,1289],{},"進行限制和驗證。在",[1266,2809,2810],{},"開發環境","中，如果傳入的",[1266,2813,1289],{},"未通過驗證，Vue 會發出警告並說明原因。",[1216,2816,2817,2818,1318,2821,2824,2825,2827,2828,2831],{},"限制方式大致可以分成",[1266,2819,2820],{},"型別限制",[1266,2822,2823],{},"必填限制","或",[1266,2826,1321],{},"及",[1266,2829,2830],{},"驗證函數","三種方式，可互相搭配使用：",[1274,2833,2834,2853],{},[1231,2835,2836,2838,2839,1268,2841,2844,2845,2848,2849,2852],{},[1279,2837,2820],{},"：通過",[1266,2840,1446],{},[1266,2842,2843],{},"內建構造函數","來限制 props 的類型，例如：String、Number、Boolean、Array、Object、Date、Function、Symbol 及 Error 等九種類型。如果傳入的型別是",[1266,2846,2847],{},"undefined","或是",[1266,2850,2851],{},"null","會直接通過型別的檢查。",[1231,2854,2855],{},[1279,2856,2857],{},"必填限制或預設值(擇一使用)",[1228,2859,2860,2866],{},[1231,2861,2862,2863,2865],{},"必填(required)：指定某個",[1266,2864,1289],{},"必須傳入。",[1231,2867,2868,2869,2871,2872,2874,2875,2877,2878,2880,2881,2884],{},"預設值(defulat)：當父組件沒有傳入",[1266,2870,1289],{},"時，",[1266,2873,1289],{},"將使用",[1266,2876,1321],{},"。判定是否使用預設值的條件在於 props 的值是否為",[1266,2879,2847],{},"，不論是顯式未傳遞還是隱式未定義，都會觸發",[1266,2882,2883],{},"default","。",[1274,2886,2887],{"start":318},[1231,2888,2889,2892,2893,2895,2896,2899,2900,2884],{},[1279,2890,2891],{},"驗證函式(validator)","：使用自定義的驗證函數來驗證傳入的",[1266,2894,1289],{},"是否符合特定規則。函數應返回 ",[1266,2897,2898],{},"true","表示驗證通過，否則返回",[1266,2901,2902],{},"false",[1256,2904],{},[1216,2906,2907],{},"以下面的案例示範校驗的方式，設定了四個不同型別跟行為限制組合，：",[1216,2909,1332,2910],{},[1334,2911,2914],{"href":2912,"rel":2913},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FJjQmvro",[1338],"Vue3 Options API props 規則限制實作連結",[1216,2916,2246],{},[1274,2918,2919,2940,2958],{},[1231,2920,2921,2924,2925,1318,2928,1318,2931,1325,2933,2936,2937,2939],{},[1279,2922,2923],{},"定義父組件變數值","：在父組件中，定義了",[1266,2926,2927],{},"count",[1266,2929,2930],{},"title",[1266,2932,2254],{},[1266,2934,2935],{},"status","四個變數，這些變數將作為子組件的",[1266,2938,1289],{},"傳遞，並根據不同的組合進行測試。",[1231,2941,2942,2945,2946,2948,2949,1268,2951,1318,2953,2827,2955,2884],{},[1279,2943,2944],{},"定義子組件 props 的限制規範","：子組件中使用",[1266,2947,1289],{},"接收從根組件傳遞的值，並設定每個",[1266,2950,1289],{},[1266,2952,1317],{},[1266,2954,1321],{},[1266,2956,2957],{},"驗證規則",[1231,2959,2960,2963,2964],{},[1279,2961,2962],{},"測試子組件的四種情形(若未給值會使用 props 定義的預設值)","：\n",[1274,2965,2966,2973,2979,2986],{},[1231,2967,2968,2969,2827,2971],{},"傳入",[1266,2970,2930],{},[1266,2972,2927],{},[1231,2974,2968,2975,2827,2977],{},[1266,2976,2254],{},[1266,2978,2927],{},[1231,2980,2968,2981,2827,2984],{},[1266,2982,2983],{},"status(status 會給非合法值",[1266,2985,2927],{},[1231,2987,2968,2988,2827,2991],{},[1266,2989,2990],{},"status(status 給合法值)",[1266,2992,2927],{},[1216,2994,1641],{},[1354,2996,2998],{"className":1444,"code":2997,"language":1446,"meta":1359,"style":1359},"const childComponent = {\n  props: {\n    \u002F\u002F 檢查型別是否為 Number 或 String\n    inputVal: [Number, String],\n    \u002F\u002F 檢查型別是 Number 且為必填\n    count: {\n      type: Number,\n      required: true\n    },\n    \u002F\u002F 檢查型別是 String，非必填，設定 undefined 情況下的預設值\n    title: {\n      type: String,\n      default: \"子組件預設標題\"\n    },\n    \u002F\u002F 檢查型別是 Object，非必填，設定預設物件格式\n    \u002F\u002F params：代表 props 物件，可以讀取其他 props 值(這邊讀取上面定義的 title)\n    userInfo: {\n      type: Object,\n      \u002F\u002F params：傳入的 props 物件值\n      default(params) {\n        return { name: \"預設人員名稱\", age: \"xxxx\", title: params.title };\n      }\n    },\n    \u002F\u002F 檢查型別是 String，非必填，設定預設值 big\n    \u002F\u002F 設定驗證器：回傳規則是 true 通過驗證， false 則是未通過\n    \u002F\u002F value：代表傳入的參數值\n    status: {\n      type: String,\n      default: \"big\",\n      validator(value) {\n        return [\"big\", \"medium\", \"small\"].includes(params);\n      }\n    }\n  },\n  template: \"#child\"\n};\n",[1266,2999,3000,3010,3014,3019,3024,3029,3034,3039,3047,3052,3057,3062,3067,3075,3079,3084,3089,3094,3099,3104,3119,3139,3143,3147,3152,3157,3162,3167,3171,3180,3192,3222,3227,3232,3237,3245],{"__ignoreMap":1359},[1363,3001,3002,3004,3006,3008],{"class":1365,"line":340},[1363,3003,1029],{"class":1459},[1363,3005,1917],{"class":1462},[1363,3007,1466],{"class":1459},[1363,3009,1469],{"class":1368},[1363,3011,3012],{"class":1365,"line":329},[1363,3013,1709],{"class":1368},[1363,3015,3016],{"class":1365,"line":318},[1363,3017,3018],{"class":1453},"    \u002F\u002F 檢查型別是否為 Number 或 String\n",[1363,3020,3021],{"class":1365,"line":134},[1363,3022,3023],{"class":1368},"    inputVal: [Number, String],\n",[1363,3025,3026],{"class":1365,"line":122},[1363,3027,3028],{"class":1453},"    \u002F\u002F 檢查型別是 Number 且為必填\n",[1363,3030,3031],{"class":1365,"line":31},[1363,3032,3033],{"class":1368},"    count: {\n",[1363,3035,3036],{"class":1365,"line":17},[1363,3037,3038],{"class":1368},"      type: Number,\n",[1363,3040,3041,3044],{"class":1365,"line":110},[1363,3042,3043],{"class":1368},"      required: ",[1363,3045,3046],{"class":1462},"true\n",[1363,3048,3049],{"class":1365,"line":76},[1363,3050,3051],{"class":1368},"    },\n",[1363,3053,3054],{"class":1365,"line":247},[1363,3055,3056],{"class":1453},"    \u002F\u002F 檢查型別是 String，非必填，設定 undefined 情況下的預設值\n",[1363,3058,3059],{"class":1365,"line":236},[1363,3060,3061],{"class":1368},"    title: {\n",[1363,3063,3064],{"class":1365,"line":225},[1363,3065,3066],{"class":1368},"      type: String,\n",[1363,3068,3069,3072],{"class":1365,"line":214},[1363,3070,3071],{"class":1368},"      default: ",[1363,3073,3074],{"class":1383},"\"子組件預設標題\"\n",[1363,3076,3077],{"class":1365,"line":203},[1363,3078,3051],{"class":1368},[1363,3080,3081],{"class":1365,"line":192},[1363,3082,3083],{"class":1453},"    \u002F\u002F 檢查型別是 Object，非必填，設定預設物件格式\n",[1363,3085,3086],{"class":1365,"line":181},[1363,3087,3088],{"class":1453},"    \u002F\u002F params：代表 props 物件，可以讀取其他 props 值(這邊讀取上面定義的 title)\n",[1363,3090,3091],{"class":1365,"line":170},[1363,3092,3093],{"class":1368},"    userInfo: {\n",[1363,3095,3096],{"class":1365,"line":159},[1363,3097,3098],{"class":1368},"      type: Object,\n",[1363,3100,3101],{"class":1365,"line":148},[1363,3102,3103],{"class":1453},"      \u002F\u002F params：傳入的 props 物件值\n",[1363,3105,3106,3109,3112,3116],{"class":1365,"line":137},[1363,3107,3108],{"class":1474},"      default",[1363,3110,3111],{"class":1368},"(",[1363,3113,3115],{"class":3114},"stnAF","params",[1363,3117,3118],{"class":1368},") {\n",[1363,3120,3121,3124,3127,3130,3133,3136],{"class":1365,"line":125},[1363,3122,3123],{"class":1459},"        return",[1363,3125,3126],{"class":1368}," { name: ",[1363,3128,3129],{"class":1383},"\"預設人員名稱\"",[1363,3131,3132],{"class":1368},", age: ",[1363,3134,3135],{"class":1383},"\"xxxx\"",[1363,3137,3138],{"class":1368},", title: params.title };\n",[1363,3140,3141],{"class":1365,"line":113},[1363,3142,2320],{"class":1368},[1363,3144,3145],{"class":1365,"line":101},[1363,3146,3051],{"class":1368},[1363,3148,3149],{"class":1365,"line":90},[1363,3150,3151],{"class":1453},"    \u002F\u002F 檢查型別是 String，非必填，設定預設值 big\n",[1363,3153,3154],{"class":1365,"line":79},[1363,3155,3156],{"class":1453},"    \u002F\u002F 設定驗證器：回傳規則是 true 通過驗證， false 則是未通過\n",[1363,3158,3159],{"class":1365,"line":67},[1363,3160,3161],{"class":1453},"    \u002F\u002F value：代表傳入的參數值\n",[1363,3163,3164],{"class":1365,"line":56},[1363,3165,3166],{"class":1368},"    status: {\n",[1363,3168,3169],{"class":1365,"line":45},[1363,3170,3066],{"class":1368},[1363,3172,3173,3175,3178],{"class":1365,"line":34},[1363,3174,3071],{"class":1368},[1363,3176,3177],{"class":1383},"\"big\"",[1363,3179,1940],{"class":1368},[1363,3181,3182,3185,3187,3190],{"class":1365,"line":22},[1363,3183,3184],{"class":1474},"      validator",[1363,3186,3111],{"class":1368},[1363,3188,3189],{"class":3114},"value",[1363,3191,3118],{"class":1368},[1363,3193,3195,3197,3200,3202,3205,3208,3210,3213,3216,3219],{"class":1365,"line":3194},31,[1363,3196,3123],{"class":1459},[1363,3198,3199],{"class":1368}," [",[1363,3201,3177],{"class":1383},[1363,3203,3204],{"class":1368},", ",[1363,3206,3207],{"class":1383},"\"medium\"",[1363,3209,3204],{"class":1368},[1363,3211,3212],{"class":1383},"\"small\"",[1363,3214,3215],{"class":1368},"].",[1363,3217,3218],{"class":1474},"includes",[1363,3220,3221],{"class":1368},"(params);\n",[1363,3223,3225],{"class":1365,"line":3224},32,[1363,3226,2320],{"class":1368},[1363,3228,3230],{"class":1365,"line":3229},33,[1363,3231,1975],{"class":1368},[1363,3233,3235],{"class":1365,"line":3234},34,[1363,3236,1503],{"class":1368},[1363,3238,3240,3242],{"class":1365,"line":3239},35,[1363,3241,1677],{"class":1368},[1363,3243,3244],{"class":1383},"\"#child\"\n",[1363,3246,3248],{"class":1365,"line":3247},36,[1363,3249,1513],{"class":1368},[1216,3251,1516,3252,3254,3255,3258,3259,3261,3262,3264,3265,3267],{},[1266,3253,2254],{},"物件必須透過",[1266,3256,3257],{},"工廠函數","來定義",[1266,3260,1321],{},"，不能直接定義。因為如果直接使用物件來設定",[1266,3263,1321],{},"，會導致所有使用該預設值的組件共享相同的物件引用，從而造成不同組件之間的資料相互影響。使用",[1266,3266,3257],{},"可以確保每個組件實例擁有自己獨立的物件。",[1216,3269,3270],{},"子組件 Vue Template",[1354,3272,3274],{"className":1356,"code":3273,"language":1358,"meta":1359,"style":1359},"\u003Ctemplate id=\"child\">\n  \u003Cdiv class=\"card\">\n    \u003Ch2>{{ title }}\u003C\u002Fh2>\n    \u003Cp>Count：{{ count }}\u003C\u002Fp>\n    \u003Cp>{{ userInfo }}\u003C\u002Fp>\n    \u003Cp>狀態：{{ status }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[1266,3275,3276,3290,3304,3317,3330,3343,3356,3364],{"__ignoreMap":1359},[1363,3277,3278,3280,3282,3284,3286,3288],{"class":1365,"line":340},[1363,3279,1369],{"class":1368},[1363,3281,1561],{"class":1372},[1363,3283,1377],{"class":1376},[1363,3285,1380],{"class":1368},[1363,3287,1857],{"class":1383},[1363,3289,1387],{"class":1368},[1363,3291,3292,3294,3296,3298,3300,3302],{"class":1365,"line":329},[1363,3293,1392],{"class":1368},[1363,3295,1373],{"class":1372},[1363,3297,2448],{"class":1376},[1363,3299,1380],{"class":1368},[1363,3301,2453],{"class":1383},[1363,3303,1387],{"class":1368},[1363,3305,3306,3308,3310,3313,3315],{"class":1365,"line":318},[1363,3307,2460],{"class":1368},[1363,3309,1224],{"class":1372},[1363,3311,3312],{"class":1368},">{{ title }}\u003C\u002F",[1363,3314,1224],{"class":1372},[1363,3316,1387],{"class":1368},[1363,3318,3319,3321,3323,3326,3328],{"class":1365,"line":134},[1363,3320,2460],{"class":1368},[1363,3322,1216],{"class":1372},[1363,3324,3325],{"class":1368},">Count：{{ count }}\u003C\u002F",[1363,3327,1216],{"class":1372},[1363,3329,1387],{"class":1368},[1363,3331,3332,3334,3336,3339,3341],{"class":1365,"line":122},[1363,3333,2460],{"class":1368},[1363,3335,1216],{"class":1372},[1363,3337,3338],{"class":1368},">{{ userInfo }}\u003C\u002F",[1363,3340,1216],{"class":1372},[1363,3342,1387],{"class":1368},[1363,3344,3345,3347,3349,3352,3354],{"class":1365,"line":31},[1363,3346,2460],{"class":1368},[1363,3348,1216],{"class":1372},[1363,3350,3351],{"class":1368},">狀態：{{ status }}\u003C\u002F",[1363,3353,1216],{"class":1372},[1363,3355,1387],{"class":1368},[1363,3357,3358,3360,3362],{"class":1365,"line":17},[1363,3359,2487],{"class":1368},[1363,3361,1373],{"class":1372},[1363,3363,1387],{"class":1368},[1363,3365,3366,3368,3370],{"class":1365,"line":110},[1363,3367,1434],{"class":1368},[1363,3369,1561],{"class":1372},[1363,3371,1387],{"class":1368},[1216,3373,1352],{},[1354,3375,3377],{"className":1356,"code":3376,"language":1358,"meta":1359,"style":1359},"\u003Cdiv id=\"app\">\n  \u003Cdiv class=\"card-group\">\n    \u003Cchild-component title=\"父組件傳入的標題\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component :user-Info=\"userInfo\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component status=\"fail\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component :status=\"status\" :count=\"count\">\u003C\u002Fchild-component>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n",[1266,3378,3379,3393,3408,3434,3459,3485,3511,3519],{"__ignoreMap":1359},[1363,3380,3381,3383,3385,3387,3389,3391],{"class":1365,"line":340},[1363,3382,1369],{"class":1368},[1363,3384,1373],{"class":1372},[1363,3386,1377],{"class":1376},[1363,3388,1380],{"class":1368},[1363,3390,1384],{"class":1383},[1363,3392,1387],{"class":1368},[1363,3394,3395,3397,3399,3401,3403,3406],{"class":1365,"line":329},[1363,3396,1392],{"class":1368},[1363,3398,1373],{"class":1372},[1363,3400,2448],{"class":1376},[1363,3402,1380],{"class":1368},[1363,3404,3405],{"class":1383},"\"card-group\"",[1363,3407,1387],{"class":1368},[1363,3409,3410,3412,3414,3417,3419,3422,3424,3426,3428,3430,3432],{"class":1365,"line":318},[1363,3411,2460],{"class":1368},[1363,3413,2049],{"class":1372},[1363,3415,3416],{"class":1376}," title",[1363,3418,1380],{"class":1368},[1363,3420,3421],{"class":1383},"\"父組件傳入的標題\"",[1363,3423,2052],{"class":1376},[1363,3425,1380],{"class":1368},[1363,3427,1928],{"class":1383},[1363,3429,1406],{"class":1368},[1363,3431,2049],{"class":1372},[1363,3433,1387],{"class":1368},[1363,3435,3436,3438,3440,3443,3445,3447,3449,3451,3453,3455,3457],{"class":1365,"line":134},[1363,3437,2460],{"class":1368},[1363,3439,2049],{"class":1372},[1363,3441,3442],{"class":1376}," :user-Info",[1363,3444,1380],{"class":1368},[1363,3446,2376],{"class":1383},[1363,3448,2052],{"class":1376},[1363,3450,1380],{"class":1368},[1363,3452,1928],{"class":1383},[1363,3454,1406],{"class":1368},[1363,3456,2049],{"class":1372},[1363,3458,1387],{"class":1368},[1363,3460,3461,3463,3465,3468,3470,3473,3475,3477,3479,3481,3483],{"class":1365,"line":122},[1363,3462,2460],{"class":1368},[1363,3464,2049],{"class":1372},[1363,3466,3467],{"class":1376}," status",[1363,3469,1380],{"class":1368},[1363,3471,3472],{"class":1383},"\"fail\"",[1363,3474,2052],{"class":1376},[1363,3476,1380],{"class":1368},[1363,3478,1928],{"class":1383},[1363,3480,1406],{"class":1368},[1363,3482,2049],{"class":1372},[1363,3484,1387],{"class":1368},[1363,3486,3487,3489,3491,3494,3496,3499,3501,3503,3505,3507,3509],{"class":1365,"line":31},[1363,3488,2460],{"class":1368},[1363,3490,2049],{"class":1372},[1363,3492,3493],{"class":1376}," :status",[1363,3495,1380],{"class":1368},[1363,3497,3498],{"class":1383},"\"status\"",[1363,3500,2052],{"class":1376},[1363,3502,1380],{"class":1368},[1363,3504,1928],{"class":1383},[1363,3506,1406],{"class":1368},[1363,3508,2049],{"class":1372},[1363,3510,1387],{"class":1368},[1363,3512,3513,3515,3517],{"class":1365,"line":17},[1363,3514,2487],{"class":1368},[1363,3516,1373],{"class":1372},[1363,3518,1387],{"class":1368},[1363,3520,3521,3523,3525],{"class":1365,"line":110},[1363,3522,1434],{"class":1368},[1363,3524,1373],{"class":1372},[1363,3526,1387],{"class":1368},[1216,3528,1441],{},[1354,3530,3532],{"className":1444,"code":3531,"language":1446,"meta":1359,"style":1359},"const rootComponent = {\n  data() {\n    return {\n      count: 0,\n      userInfo: { name: \"Antonio\", age: 16 },\n      status: \"small\"\n    };\n  },\n  components: { childComponent }\n};\n",[1266,3533,3534,3544,3550,3556,3565,3580,3588,3592,3596,3600],{"__ignoreMap":1359},[1363,3535,3536,3538,3540,3542],{"class":1365,"line":340},[1363,3537,1029],{"class":1459},[1363,3539,1463],{"class":1462},[1363,3541,1466],{"class":1459},[1363,3543,1469],{"class":1368},[1363,3545,3546,3548],{"class":1365,"line":329},[1363,3547,1475],{"class":1474},[1363,3549,1478],{"class":1368},[1363,3551,3552,3554],{"class":1365,"line":318},[1363,3553,1483],{"class":1459},[1363,3555,1469],{"class":1368},[1363,3557,3558,3560,3563],{"class":1365,"line":134},[1363,3559,2135],{"class":1368},[1363,3561,3562],{"class":1462},"0",[1363,3564,1940],{"class":1368},[1363,3566,3567,3570,3572,3574,3577],{"class":1365,"line":122},[1363,3568,3569],{"class":1368},"      userInfo: { name: ",[1363,3571,2303],{"class":1383},[1363,3573,3132],{"class":1368},[1363,3575,3576],{"class":1462},"16",[1363,3578,3579],{"class":1368}," },\n",[1363,3581,3582,3585],{"class":1365,"line":31},[1363,3583,3584],{"class":1368},"      status: ",[1363,3586,3587],{"class":1383},"\"small\"\n",[1363,3589,3590],{"class":1365,"line":17},[1363,3591,1498],{"class":1368},[1363,3593,3594],{"class":1365,"line":110},[1363,3595,1503],{"class":1368},[1363,3597,3598],{"class":1365,"line":76},[1363,3599,2187],{"class":1368},[1363,3601,3602],{"class":1365,"line":247},[1363,3603,1513],{"class":1368},[1216,3605,3606],{},[1219,3607],{"alt":3608,"src":3609},"props 驗證情形結果比較圖","https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727792254\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002Fprops_%E9%A9%97%E8%AD%89%E6%83%85%E5%BD%A2%E7%B5%90%E6%9E%9C%E6%AF%94%E8%BC%83%E5%9C%96_nckouu.png",[1216,3611,1516,3612,3614,3615,3617,3618,3620,3621,3623,3624,3626,3627,3629],{},[1266,3613,2930],{},"如果有傳入值，則會影響",[1266,3616,2254],{},"中的",[1266,3619,2930],{},"屬性；如果",[1266,3622,2930],{},"沒有傳入，則使用",[1266,3625,2930],{}," 的預設值。",[1768,3628],{},"\n⭐ 即使傳入非合法值，Vue 仍然會接收並使用該值，但在開發環境中會顯示警告訊息。可以幫助開發者在開發過程中更容易發現和維護傳入值的合法性，從而避免潛在的錯誤。",[1256,3631],{},[1259,3633,1251],{"id":3634},"props-boolean-型別規則判定方式",[1216,3636,3637,3638,3640,3641,1317,3644,3646],{},"為了貼近原生",[1266,3639,2069],{},"屬性的行為，Vue 中的",[1266,3642,3643],{},"Boolean",[1266,3645,1289],{},"會遵循以下規則：",[1274,3648,3649,3667,3686],{},[1231,3650,3651,3652,3654,3655,3657,3658,3661,3662,3664,3665,2884],{},"當",[1266,3653,1289],{},"定義為",[1266,3656,3643],{},"型別時，只要在組件標籤上聲明了該",[1266,3659,3660],{},"prop","，即使沒有指定具體的值，它的值也會自動設置為",[1266,3663,2898],{},"。如果未在標籤上聲明，則默認為",[1266,3666,2902],{},[1231,3668,3651,3669,3671,3672,1325,3674,3677,3678,3680,3681,3683,3684,2884],{},[1266,3670,1289],{},"同時支援",[1266,3673,3643],{},[1266,3675,3676],{},"其他型別(如 Number)","，",[1266,3679,3643],{},"規則優先適用。也就是說，如果該 ",[1266,3682,1289],{},"被聲明但沒有具體的值，則會設置為",[1266,3685,2898],{},[1231,3687,3651,3688,3690,3691,1325,3693,3696,3697,3699,3700,3702,3703,3705,3706,3709,3710,2884],{},[1266,3689,1289],{},"同時支持",[1266,3692,3643],{},[1266,3694,3695],{},"String","型別時，若",[1266,3698,3695],{},"型別在",[1266,3701,3643],{},"型別前面，且",[1266,3704,1289],{},"未給值的時候，Vue 會將其值解析為",[1266,3707,3708],{},"空字串 \"\"","，而非",[1266,3711,2898],{},[1216,3713,1332,3714],{},[1334,3715,3718],{"href":3716,"rel":3717},"https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FxxoyoOW",[1338],"Vue3 Options API props Boolean 判定規則實作連結",[1259,3720,3721],{"id":3721},"結論",[1228,3723,3724,3749,3760,3772],{},[1231,3725,3726,1817,3729,3731,3732,3735,3736,3738,3739,3741,3742,3744,3745,3748],{},[1279,3727,3728],{},"props 是父組件傳遞給子組件的參數",[1266,3730,1289],{},"可以有兩種定義方式。一種是",[1266,3733,3734],{},"無限制","的參數傳遞，通過",[1266,3737,1285],{},"來標註允許的",[1266,3740,1289],{},"。另一種是使用",[1266,3743,1308],{},"來定義，並透過",[1266,3746,3747],{},"設定型別","和其他屬性來進行傳入參數的驗證與控制。",[1231,3750,3751,1817,3754,3756,3757,3759],{},[1279,3752,3753],{},"props 是單向資料流",[1266,3755,1289],{},"是父組件傳遞給子組件的單向數據流，子組件不應直接修改",[1266,3758,1289],{},"的值。特別是當傳遞的是物件或陣列時，直接修改它們會導致父子組件之間的數據共享，從而引發維護上的困難",[1231,3761,3762,3765,3766,3768,3769,3771],{},[1279,3763,3764],{},"props 校驗規則","：允許開發者通過型別檢查、是否必選、以及驗證函數來確保傳入的",[1266,3767,1289],{},"值符合要求。如果",[1266,3770,1289],{},"值不合法，Vue 會在開發環境中觸發警告，幫助開發者及時發現問題。",[1231,3773,3774,1817,3777,3617,3779,3781,3782,3784,3785,3787,3788,3790,3791,3793,3794,3796,3797,3799,3800,3802,3803,1325,3805,3807,3808,3810,3811,3813,3814,3817,3818,2884],{},[1279,3775,3776],{},"props Boolean 型別規則",[1266,3778,1289],{},[1266,3780,3643],{},"屬性遵循類似原生",[1266,3783,2069],{},"屬性的行為。當 ",[1266,3786,3643],{},"型別的",[1266,3789,1289],{},"被聲明時，會自動被設置為",[1266,3792,2898],{},"；若未聲明，則為",[1266,3795,2902],{},"。即使",[1266,3798,1289],{},"定義中包含多種型別，只要有",[1266,3801,3643],{},"，其規則依然適用。但在特殊情況下，當",[1266,3804,3695],{},[1266,3806,3643],{},"同時定義時，若傳入的值符合",[1266,3809,3695],{},"的條件，則該",[1266,3812,1289],{},"會被解析為",[1266,3815,3816],{},"空字串","，而不是",[1266,3819,2898],{},[3821,3822,3823],"style",{},"html pre.shiki code .sYgZi, html code.shiki .sYgZi{--shiki-default:#24292E;--shiki-dark:#ADBAC7}html pre.shiki code .sIAta, html code.shiki .sIAta{--shiki-default:#22863A;--shiki-dark:#8DDB8C}html pre.shiki code .sMOND, html code.shiki .sMOND{--shiki-default:#6F42C1;--shiki-dark:#6CB6FF}html pre.shiki code .s-HuK, html code.shiki .s-HuK{--shiki-default:#032F62;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sDN9O, html code.shiki .sDN9O{--shiki-default:#6A737D;--shiki-dark:#768390}html pre.shiki code .s7YZ4, html code.shiki .s7YZ4{--shiki-default:#D73A49;--shiki-dark:#F47067}html pre.shiki code .sviXB, html code.shiki .sviXB{--shiki-default:#005CC5;--shiki-dark:#6CB6FF}html pre.shiki code .sPO5f, html code.shiki .sPO5f{--shiki-default:#6F42C1;--shiki-dark:#DCBDFB}html pre.shiki code .stnAF, html code.shiki .stnAF{--shiki-default:#E36209;--shiki-dark:#F69D50}",{"title":1359,"searchDepth":134,"depth":134,"links":3825},[3826],{"id":1226,"depth":329,"text":1226,"children":3827},[3828,3829,3830,3831,3832,3833,3834,3835],{"id":1261,"depth":318,"text":1233},{"id":1732,"depth":318,"text":1236},{"id":1776,"depth":318,"text":1239},{"id":2194,"depth":318,"text":1242},{"id":2234,"depth":318,"text":1245},{"id":2798,"depth":318,"text":1248},{"id":3634,"depth":318,"text":1251},{"id":3721,"depth":318,"text":3721},[11,713],"md",{},"---\ntitle: \"Vue 3 用實作帶你看過核心概念 - Day 18：父組件向子組件傳值 - props\"\ndate: 2024-10-01 22:28:48\ntags:\n  - \"iThome 鐵人賽\"\n  - \"2024 鐵人賽\"\n  - \"Vue 3\"\n  - \"Options API\"\ncategories:\n  - \"iThome 鐵人賽\"\n  - \"Vue\"\ndescription: \"組件之間的傳值必須透過聲明 props 的方式，這樣可以避免與HTML的屬性(attribute)混淆。父組件傳遞參數給子組件的方式有以下兩種方式：\"\ncanonical: https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10361721\nseries:\n  name: \"2024 iThome 鐵人賽：Vue 3 初學者：用實作帶你看過核心概念\"\n  url: https:\u002F\u002Fithelp.ithome.com.tw\u002Fusers\u002F20116554\u002Fironman\u002F7800\n  day: 18\n---\n\n![文章背景圖](https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727786245\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002FDay18_%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC_-_props_ci0r3b.png)\n\n## 目錄\n\n- props 基本用法\n- props 單向資料流 - 組件之間的溝通方式\n- props 子組件應用情境說明\n- props 傳值類型 - 靜態傳值 vs 動態傳值\n- props 多參數傳遞的方式\n- props 校驗方式 - 檢查所有外來的參數\n- props Boolean 型別規則判定方式\n- 總結\n\n* * *\n\n### props 基本用法\n\n組件之間的傳值必須透過聲明 props 的方式，這樣可以避免與`HTML`的`屬性(attribute)`混淆。父組件傳遞參數給子組件的方式有以下兩種方式：\n\n1. **不限制傳入的 props 型別或行為**：使用`陣列`的方式來定義`props`，這樣只需列出父組件傳遞的 `props`名稱。子組件可以直接通過`this.xxx`的方式來獲取傳遞進來的`props`參數。\n2. **限制傳入的 props 型別、預設值、驗證器及是否必填等**：使用`物件`的方式來定義`props`，在物件中指定`props`的名稱，並對其`型別`、`預設值`、`驗證器`和`是否必填`等進行限制。這樣可以更嚴格地控制傳入的數據，確保組件的行為符合預期。\n\n👉 [Vue3 Options API props 基本用法實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FwvLEBWj)\n\n以下透過一個範例來說明`props`的動態綁定基本用法，使用`:`來進行綁定：\n\n父組件 Vue Template：\n\n```html\n\u003Cdiv id=\"app\">\n  \u003Cchild-component-a :special-msg=\"specialMsg\">\u003C\u002Fchild-component-a>\n  \u003Cchild-component-b :special-msg=\"specialMsg\">\u003C\u002Fchild-component-b>\n\u003C\u002Fdiv>\n```\n\n父組件 javascript：\n\n```javascript\n\u002F\u002F 根組件\nconst rootComponent = {\n  data() {\n    return {\n      specialMsg: \"hello vue!\"\n    };\n  },\n  components: { childComponentA, childComponentB }\n};\n```\n\n⭐ `:special-msg=\"specialMsg\"` 中，`special-msg`是子組件中定義的`props`名稱，優先使用`HTML`可解析的 `kebab-case（串燒)`命名方式，以確保與`HTML`標準保持一致，並避免可能的瀏覽器解析問題，而 `specialMsg`是父組件中的變數名稱。\n\n子組件 Vue Template：\n\n```html\n\u003C!-- childComponentA 畫面 -->\n\u003Ctemplate id=\"childComponentA\">\n  \u003Cp>childComponentA title：{{ specialMsg }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n\n\u003C!-- childComponentB 畫面 -->\n\u003Ctemplate id=\"childComponentB\">\n  \u003Cp>childComponentB title：{{ specialMsg }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n```\n\n子組件 javascript：\n\n```javascript\nconst childComponentA = {\n  \u002F\u002F 陣列定義 props，無型別的定義\n  props: [\"specialMsg\"],\n  template: \"#childComponentA\"\n};\n\nconst childComponentB = {\n  \u002F\u002F 物件定義，搭配型別限制\n  props: {\n    specialMsg: String\n  },\n  template: \"#childComponentB\"\n};\n```\n\n### props 單向資料流 - 組件之間的溝通方式\n\n![父子組件傳值關係(props 及 emits)](https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727789558\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002F%E7%88%B6%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%E9%97%9C%E4%BF%82_props_%E5%8F%8A_emits_xyv9sg.png)\n\n父組件可以透過`props`將資料傳遞給子組件，然而，子組件無法直接修改由父組件傳遞進來的`props`。如果子組件需要更改`props`的值，應該透過 `emits`事件的方式通知父組件，由父組件來進行變更，而非直接在子組件中修改`props`。這種單向資料流的設計可以更清楚資料的流向，同時也有助於後續的維護與測試。\n\n如果意圖修改`props`會跑出錯誤，告訴你`props`是唯讀的：  \n![修改組件 props 警告](https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727789953\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002F%E4%BF%AE%E6%94%B9%E7%B5%84%E4%BB%B6_props_%E8%AD%A6%E5%91%8A_t4lys0.png)\n\n### props 子組件應用情境說明\n\n如果想要使用`props`參數在子組件做應用，可以使用下面兩種方式：\n\n1. **使用 data 初始化值**： `data 函數`會在`props`初始化之後被呼叫一次，因此可以在`data`中基於 `props`進行`初始值`的設定。但是其值不會因為後續`props`改動而連動影響。\n2. **使用 computed 監聽 props**：`computed`屬性會在`props`變更時重新計算，因此可以在 `computed`中進行`props`的格式化處理或其他計算。\n\n👉 [Vue3 Options API props 子組件應用實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FrNEqjRZ)\n\n子組件 Vue Template：\n\n```html\n\u003Ctemplate id=\"child\">\n  \u003C!--   使用 data 初始化 props 值(初始化執行後不會變更) -->\n  \u003Cp>newCount：{{ newCount }}\u003C\u002Fp>\n  \u003C!--   使用 computed 格式化 props 值(監聽 props 變化執行函數) -->\n  \u003Cp>doubleCount：{{ doubleCount }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n```\n\n子組件 javascript：\n\n```javascript\nconst childComponent = {\n  props: [\"count\"],\n  template: \"#child\",\n  data(){\n    return{\n      newCount: this.count + 1\n    }\n  },\n  computed: {\n    doubleCount() {\n      return this.count + this.count;\n    }\n  }\n};\n```\n\n父組件 Vue Template：\n\n```html\n\u003Cdiv id=\"app\">\n  \u003Cchild-component :count=\"count\">\u003C\u002Fchild-component>\n  \u003Cbutton @click=\"add\" type=\"button\"> +1\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n父組件 javasciprt：\n\n```javascript\nconst rootComponent = {\n  data() {\n    return {\n      count: 10\n    };\n  },\n  methods: {\n    add() {\n      this.count += 1;\n    }\n  },\n  components: { childComponent }\n};\n```\n\n### props 傳值類型 - 靜態傳值 vs 動態傳值\n\n當父組件向子組件傳遞值時，如果使用靜態傳值（例如：`\u003Ctest-component isShow=\"true\">\u003C\u002Ftest-component>`），`isShow`參數傳入的值會被視為純字串，因為其未使用`v-bind`的方式動態綁定。\n\n若需要傳入不同類型的參數值，比如 Number、Boolean、Array、Object 等。應該使用`動態傳值`的方式，即使用`v-bind`或縮寫`:`來動態綁定表達式。這樣可以確保傳入的值保持其原有的數據類型，而不會被轉換為字串。\n\n👉 [Vue3 Options API 動態傳值與靜態傳值實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FYzoOXeR)\n\n* * *\n\n### props 多參數傳遞的方式\n\n如果需要將一個物件中的多個屬性傳遞給子組件進行後續的畫面顯示或邏輯處理時，可以使用`v-bind` 將整個物件直接綁定到子組件。這樣做等於將物件內的所有屬性動態綁定到子組件的對應`props`上。\n\n流程說明：\n\n1. 定義一個`userInfo`物件內有多個屬性(name、age)\n2. 將`userInfo`全部參數值傳遞給子組件使用\n\n父組件 javascript：\n\n```javascript\nconst rootComponent = {\n  data() {\n    return {\n      userInfo: {\n        name: \"Antonio\",\n        age: 25,\n      }\n    };\n  },\n  components: { childComponent }\n};\n```\n\n父組件 Vue Template：\n\n```html\n\u003Cdiv id=\"app\">\n  \u003C!--     以下兩種達到的效果相同 -->\n  \u003Cchild-component v-bind=\"userInfo\">\u003C\u002Fchild-component>\n  \u003Cchild-component :name=\"userInfo.name\" :age=\"userInfo.age\">\u003C\u002Fchild-component>\n\u003C\u002Fdiv>\n```\n\n子組件 Vue Template：\n\n```html\n\u003Ctemplate id=\"child\">\n  \u003Cdiv class=\"card\">\n    \u003Cp>姓名：{{ name }}\u003C\u002Fp>\n    \u003Cp>標題：{{ age }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n```\n\n* * *\n\n這邊特別舉一個產品列表陣列包產品資訊物件的案例，讓大家理解當`props`傳遞物件時，需要注意傳值的陷阱：\n\n👉 [Vue3 Options API v-for 搭配 props 傳值陷阱實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FoNKbZVQ)\n\n流程說明：\n\n1. 將產品列表中裡面每一個產品資訊的物件直接透過`v-for`綁定動態`props`給子組件\n2. 子組件根據這個`props`的值當作子組件`v-model`綁定的初始值(改動子組件的值不應該影響`props`)\n\n父組件 Vue Template：\n\n```html\n\u003Cdiv id=\"app\">\n  \u003Cdiv class=\"parent-content\">\n    \u003Ch2>我是 parent-content\u003C\u002Fh2>\n    \u003Cli v-for=\"product in productList\" :key=\"product.id\">\n      名稱：\u003Cinput type=\"text\" v-model=\"product.name\">\n      價格：\u003Cinput type=\"text\" v-model=\"product.price\">\n    \u003C\u002Fli>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"child-content\">\n    \u003Ch2>我是 child-content\u003C\u002Fh2>\n    \u003Cchild-component v-for=\"product in productList\" :key=\"product.id\" :product-info=\"product\">\u003C\u002Fchild-component>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n⭐ `javaScript`物件具有引用相同記憶體地址的特性，因此當傳遞給子組件的`props`不是基礎型別（例如：`:product-name=\"product.name\"`），而是引用型別(如物件或陣列)時，子組件對`props`的改動會直接影響父組件中的數據。這是因為父子組件之間實際上共享的是對同一物件的引用，而不是物件本身的拷貝。\n\n改正方式可以參考上面`多參數傳遞的方式`，綁定單一屬性或是透過`v-bind`一次綁定物件內所有屬性。\n\n👉 [Vue3 Options API v-for 搭配 props 傳值手動綁定物件內所有屬性實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FeYqJVpV)  \n👉 [Vue3 Options API v-for 搭配 props 傳值透過 v-bind 綁定物件所有屬性實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FVwoeQeO)\n\n### props 校驗方式 - 檢查所有外來的參數\n\n在 Vue 組件中，`props`是從父組件傳遞過來的參數，而非子組件本身定義的變數。為了確保後續數據的維護方便，建議對`props`進行限制和驗證。在`開發環境`中，如果傳入的`props`未通過驗證，Vue 會發出警告並說明原因。\n\n限制方式大致可以分成`型別限制`、`必填限制`或`預設值`及`驗證函數`三種方式，可互相搭配使用：\n\n1. **型別限制**：通過`javascript`的`內建構造函數`來限制 props 的類型，例如：String、Number、Boolean、Array、Object、Date、Function、Symbol 及 Error 等九種類型。如果傳入的型別是`undefined`或是`null`會直接通過型別的檢查。\n2. **必填限制或預設值(擇一使用)**\n\n- 必填(required)：指定某個`props`必須傳入。\n- 預設值(defulat)：當父組件沒有傳入`props`時，`props`將使用`預設值`。判定是否使用預設值的條件在於 props 的值是否為`undefined`，不論是顯式未傳遞還是隱式未定義，都會觸發`default`。\n\n3. **驗證函式(validator)**：使用自定義的驗證函數來驗證傳入的`props`是否符合特定規則。函數應返回 `true`表示驗證通過，否則返回`false`。\n\n* * *\n\n以下面的案例示範校驗的方式，設定了四個不同型別跟行為限制組合，：\n\n👉 [Vue3 Options API props 規則限制實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FJjQmvro)\n\n流程說明：\n\n1. **定義父組件變數值**：在父組件中，定義了`count`、`title`、`userInfo`和`status`四個變數，這些變數將作為子組件的`props`傳遞，並根據不同的組合進行測試。\n2. **定義子組件 props 的限制規範**：子組件中使用`props`接收從根組件傳遞的值，並設定每個`props`的`型別`、`預設值`及`驗證規則`。\n3. **測試子組件的四種情形(若未給值會使用 props 定義的預設值)**：\n    1. 傳入`title`及`count`\n    2. 傳入`userInfo`及`count`\n    3. 傳入`status(status 會給非合法值`及`count`\n    4. 傳入`status(status 給合法值)`及`count`\n\n子組件 javascript：\n\n```javascript\nconst childComponent = {\n  props: {\n    \u002F\u002F 檢查型別是否為 Number 或 String\n    inputVal: [Number, String],\n    \u002F\u002F 檢查型別是 Number 且為必填\n    count: {\n      type: Number,\n      required: true\n    },\n    \u002F\u002F 檢查型別是 String，非必填，設定 undefined 情況下的預設值\n    title: {\n      type: String,\n      default: \"子組件預設標題\"\n    },\n    \u002F\u002F 檢查型別是 Object，非必填，設定預設物件格式\n    \u002F\u002F params：代表 props 物件，可以讀取其他 props 值(這邊讀取上面定義的 title)\n    userInfo: {\n      type: Object,\n      \u002F\u002F params：傳入的 props 物件值\n      default(params) {\n        return { name: \"預設人員名稱\", age: \"xxxx\", title: params.title };\n      }\n    },\n    \u002F\u002F 檢查型別是 String，非必填，設定預設值 big\n    \u002F\u002F 設定驗證器：回傳規則是 true 通過驗證， false 則是未通過\n    \u002F\u002F value：代表傳入的參數值\n    status: {\n      type: String,\n      default: \"big\",\n      validator(value) {\n        return [\"big\", \"medium\", \"small\"].includes(params);\n      }\n    }\n  },\n  template: \"#child\"\n};\n```\n\n⭐ `userInfo`物件必須透過`工廠函數`來定義`預設值`，不能直接定義。因為如果直接使用物件來設定`預設值`，會導致所有使用該預設值的組件共享相同的物件引用，從而造成不同組件之間的資料相互影響。使用`工廠函數`可以確保每個組件實例擁有自己獨立的物件。\n\n子組件 Vue Template\n\n```html\n\u003Ctemplate id=\"child\">\n  \u003Cdiv class=\"card\">\n    \u003Ch2>{{ title }}\u003C\u002Fh2>\n    \u003Cp>Count：{{ count }}\u003C\u002Fp>\n    \u003Cp>{{ userInfo }}\u003C\u002Fp>\n    \u003Cp>狀態：{{ status }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n```\n\n父組件 Vue Template：\n\n```html\n\u003Cdiv id=\"app\">\n  \u003Cdiv class=\"card-group\">\n    \u003Cchild-component title=\"父組件傳入的標題\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component :user-Info=\"userInfo\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component status=\"fail\" :count=\"count\">\u003C\u002Fchild-component>\n    \u003Cchild-component :status=\"status\" :count=\"count\">\u003C\u002Fchild-component>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n父組件 javascript：\n\n```javascript\nconst rootComponent = {\n  data() {\n    return {\n      count: 0,\n      userInfo: { name: \"Antonio\", age: 16 },\n      status: \"small\"\n    };\n  },\n  components: { childComponent }\n};\n```\n\n![props 驗證情形結果比較圖](https:\u002F\u002Fres.cloudinary.com\u002Fdseg0uwc9\u002Fimage\u002Fupload\u002Fv1727792254\u002F2024%20%E9%90%B5%E4%BA%BA%E8%B3%BD\u002FDay%2018%EF%BC%9A%E7%88%B6%E7%B5%84%E4%BB%B6%E5%90%91%E5%AD%90%E7%B5%84%E4%BB%B6%E5%82%B3%E5%80%BC%20-%20props\u002Fprops_%E9%A9%97%E8%AD%89%E6%83%85%E5%BD%A2%E7%B5%90%E6%9E%9C%E6%AF%94%E8%BC%83%E5%9C%96_nckouu.png)\n\n⭐ `title`如果有傳入值，則會影響`userInfo`中的`title`屬性；如果`title`沒有傳入，則使用`title` 的預設值。  \n⭐ 即使傳入非合法值，Vue 仍然會接收並使用該值，但在開發環境中會顯示警告訊息。可以幫助開發者在開發過程中更容易發現和維護傳入值的合法性，從而避免潛在的錯誤。\n\n* * *\n\n### props Boolean 型別規則判定方式\n\n為了貼近原生`button`屬性的行為，Vue 中的`Boolean`型別`props`會遵循以下規則：\n\n1. 當`props`定義為`Boolean`型別時，只要在組件標籤上聲明了該`prop`，即使沒有指定具體的值，它的值也會自動設置為`true`。如果未在標籤上聲明，則默認為`false`。\n2. 當`props`同時支援`Boolean`和`其他型別(如 Number)`，`Boolean`規則優先適用。也就是說，如果該 `props`被聲明但沒有具體的值，則會設置為`true`。\n3. 當`props`同時支持`Boolean`和`String`型別時，若`String`型別在`Boolean`型別前面，且`props`未給值的時候，Vue 會將其值解析為`空字串 \"\"`，而非`true`。\n\n👉 [Vue3 Options API props Boolean 判定規則實作連結](https:\u002F\u002Fcodepen.io\u002Fgwhvusel-the-builder\u002Fpen\u002FxxoyoOW)\n\n### 結論\n\n- **props 是父組件傳遞給子組件的參數**：`props`可以有兩種定義方式。一種是`無限制`的參數傳遞，通過`陣列`來標註允許的`props`。另一種是使用`物件`來定義，並透過`設定型別`和其他屬性來進行傳入參數的驗證與控制。\n- **props 是單向資料流**：`props`是父組件傳遞給子組件的單向數據流，子組件不應直接修改`props`的值。特別是當傳遞的是物件或陣列時，直接修改它們會導致父子組件之間的數據共享，從而引發維護上的困難\n- **props 校驗規則**：允許開發者通過型別檢查、是否必選、以及驗證函數來確保傳入的`props`值符合要求。如果`props`值不合法，Vue 會在開發環境中觸發警告，幫助開發者及時發現問題。\n- **props Boolean 型別規則**：`props`中的`Boolean`屬性遵循類似原生`button`屬性的行為。當 `Boolean`型別的`props`被聲明時，會自動被設置為`true`；若未聲明，則為`false`。即使`props`定義中包含多種型別，只要有`Boolean`，其規則依然適用。但在特殊情況下，當`String`和`Boolean`同時定義時，若傳入的值符合`String`的條件，則該`props`會被解析為`空字串`，而不是`true`。\n",{"title":834,"description":835},{"name":717,"url":718,"day":159},{"loc":833,"images":3843,"lastmod":836},[3844,3845,3846,3847],{"loc":1222},{"loc":1738},{"loc":1773},{"loc":3609},"ithome-2024-day-18","2024-10-01-ithome-2024-day-18",[11,710,711,725],"PruxPxG3WdakToqNRW7LoQkFXXfvrMdh7vxT3umwv4A",1792575204367]