[{"data":1,"prerenderedAt":27241},["ShallowReactive",2],{"search-dialog-posts":3},[4,394,2044,4024,4574,5398,6030,6241,6718,7035,8412,10519,10714,10831,10931,11567,11602,11650,12316,12546,12644,12814,12890,13006,13424,13621,13669,14274,14548,14983,15047,15197,15397,16958,17361,17594,17870,17961,18043,18746,19061,19301,19423,19557,19939,20146,20374,22629,25295,25837,25943],{"id":5,"title":6,"body":7,"category":378,"description":379,"draft":380,"extension":381,"image":382,"meta":383,"navigation":102,"path":384,"publishedAt":385,"relatedExperiments":386,"seo":387,"stem":388,"tags":389,"updatedAt":392,"__hash__":393},"posts\u002Fposts\u002F20160919.if-switch-ternary.md","JavaScript 條件判斷：if、switch 與三元運算子",{"type":8,"value":9,"toc":371},"minimark",[10,14,18,21,55,58,61,63,150,154,157,298,301,304,326,329,367],[11,12,13],"p",{},"這篇是當時學 JavaScript 時整理的條件判斷筆記。",[15,16,17],"h2",{"id":17},"if",[11,19,20],{},"基本寫法：",[22,23,28],"pre",{"className":24,"code":25,"language":26,"meta":27,"style":27},"language-js shiki shiki-themes github-light github-dark-default","if (條件) {\n  語句;\n}\n","js","",[29,30,31,43,49],"code",{"__ignoreMap":27},[32,33,36,39],"span",{"class":34,"line":35},"line",1,[32,37,17],{"class":38},"sDgYj",[32,40,42],{"class":41},"szmH1"," (條件) {\n",[32,44,46],{"class":34,"line":45},2,[32,47,48],{"class":41},"  語句;\n",[32,50,52],{"class":34,"line":51},3,[32,53,54],{"class":41},"}\n",[11,56,57],{},"條件成立時，就會執行裡面的語句。",[15,59,60],{"id":60},"switch",[11,62,20],{},[22,64,66],{"className":24,"code":65,"language":26,"meta":27,"style":27},"switch (變數) {\n  case 值1:\n    語句1;\n    break;\n\n  case 值2:\n    語句2;\n    break;\n\n  default:\n    語句n;\n}\n",[29,67,68,75,83,88,97,104,112,118,125,130,139,145],{"__ignoreMap":27},[32,69,70,72],{"class":34,"line":35},[32,71,60],{"class":38},[32,73,74],{"class":41}," (變數) {\n",[32,76,77,80],{"class":34,"line":45},[32,78,79],{"class":38},"  case",[32,81,82],{"class":41}," 值1:\n",[32,84,85],{"class":34,"line":51},[32,86,87],{"class":41},"    語句1;\n",[32,89,91,94],{"class":34,"line":90},4,[32,92,93],{"class":38},"    break",[32,95,96],{"class":41},";\n",[32,98,100],{"class":34,"line":99},5,[32,101,103],{"emptyLinePlaceholder":102},true,"\n",[32,105,107,109],{"class":34,"line":106},6,[32,108,79],{"class":38},[32,110,111],{"class":41}," 值2:\n",[32,113,115],{"class":34,"line":114},7,[32,116,117],{"class":41},"    語句2;\n",[32,119,121,123],{"class":34,"line":120},8,[32,122,93],{"class":38},[32,124,96],{"class":41},[32,126,128],{"class":34,"line":127},9,[32,129,103],{"emptyLinePlaceholder":102},[32,131,133,136],{"class":34,"line":132},10,[32,134,135],{"class":38},"  default",[32,137,138],{"class":41},":\n",[32,140,142],{"class":34,"line":141},11,[32,143,144],{"class":41},"    語句n;\n",[32,146,148],{"class":34,"line":147},12,[32,149,54],{"class":41},[151,152,153],"h3",{"id":153},"判斷男女",[11,155,156],{},"當時寫的一個簡單範例：",[22,158,160],{"className":24,"code":159,"language":26,"meta":27,"style":27},"var name = 'abc';\nvar sex = '';\n\nswitch (sex) {\n  case '男':\n    alert(name + ' sir，您好');\n    break;\n\n  case '女':\n    alert(name + '，您好');\n    break;\n\n  default:\n    alert(name + '，您好');\n}\n",[29,161,162,179,193,197,204,213,231,237,241,250,263,269,273,280,293],{"__ignoreMap":27},[32,163,164,167,170,173,177],{"class":34,"line":35},[32,165,166],{"class":38},"var",[32,168,169],{"class":41}," name ",[32,171,172],{"class":38},"=",[32,174,176],{"class":175},"sNbzA"," 'abc'",[32,178,96],{"class":41},[32,180,181,183,186,188,191],{"class":34,"line":45},[32,182,166],{"class":38},[32,184,185],{"class":41}," sex ",[32,187,172],{"class":38},[32,189,190],{"class":175}," ''",[32,192,96],{"class":41},[32,194,195],{"class":34,"line":51},[32,196,103],{"emptyLinePlaceholder":102},[32,198,199,201],{"class":34,"line":90},[32,200,60],{"class":38},[32,202,203],{"class":41}," (sex) {\n",[32,205,206,208,211],{"class":34,"line":99},[32,207,79],{"class":38},[32,209,210],{"class":175}," '男'",[32,212,138],{"class":41},[32,214,215,219,222,225,228],{"class":34,"line":106},[32,216,218],{"class":217},"sVjZL","    alert",[32,220,221],{"class":41},"(name ",[32,223,224],{"class":38},"+",[32,226,227],{"class":175}," ' sir，您好'",[32,229,230],{"class":41},");\n",[32,232,233,235],{"class":34,"line":114},[32,234,93],{"class":38},[32,236,96],{"class":41},[32,238,239],{"class":34,"line":120},[32,240,103],{"emptyLinePlaceholder":102},[32,242,243,245,248],{"class":34,"line":127},[32,244,79],{"class":38},[32,246,247],{"class":175}," '女'",[32,249,138],{"class":41},[32,251,252,254,256,258,261],{"class":34,"line":132},[32,253,218],{"class":217},[32,255,221],{"class":41},[32,257,224],{"class":38},[32,259,260],{"class":175}," '，您好'",[32,262,230],{"class":41},[32,264,265,267],{"class":34,"line":141},[32,266,93],{"class":38},[32,268,96],{"class":41},[32,270,271],{"class":34,"line":147},[32,272,103],{"emptyLinePlaceholder":102},[32,274,276,278],{"class":34,"line":275},13,[32,277,135],{"class":38},[32,279,138],{"class":41},[32,281,283,285,287,289,291],{"class":34,"line":282},14,[32,284,218],{"class":217},[32,286,221],{"class":41},[32,288,224],{"class":38},[32,290,260],{"class":175},[32,292,230],{"class":41},[32,294,296],{"class":34,"line":295},15,[32,297,54],{"class":41},[15,299,300],{"id":300},"三元運算子",[11,302,303],{},"三元運算子的基本格式：",[22,305,307],{"className":24,"code":306,"language":26,"meta":27,"style":27},"條件 ? 成立時的值 : 不成立時的值\n",[29,308,309],{"__ignoreMap":27},[32,310,311,314,317,320,323],{"class":34,"line":35},[32,312,313],{"class":41},"條件 ",[32,315,316],{"class":38},"?",[32,318,319],{"class":41}," 成立時的值 ",[32,321,322],{"class":38},":",[32,324,325],{"class":41}," 不成立時的值\n",[11,327,328],{},"例如：",[22,330,332],{"className":24,"code":331,"language":26,"meta":27,"style":27},"var result = age >= 18 ? '成年' : '未成年';\n",[29,333,334],{"__ignoreMap":27},[32,335,336,338,341,343,346,349,353,356,359,362,365],{"class":34,"line":35},[32,337,166],{"class":38},[32,339,340],{"class":41}," result ",[32,342,172],{"class":38},[32,344,345],{"class":41}," age ",[32,347,348],{"class":38},">=",[32,350,352],{"class":351},"sPgVT"," 18",[32,354,355],{"class":38}," ?",[32,357,358],{"class":175}," '成年'",[32,360,361],{"class":38}," :",[32,363,364],{"class":175}," '未成年'",[32,366,96],{"class":41},[368,369,370],"style",{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}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 .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":372},[373,374,377],{"id":17,"depth":45,"text":17},{"id":60,"depth":45,"text":60,"children":375},[376],{"id":153,"depth":51,"text":153},{"id":300,"depth":45,"text":300},"frontend","2016 年整理的 JavaScript 條件判斷筆記，包含 if、switch 與三元運算子的基本寫法。",false,"md",null,{},"\u002Fposts\u002Fif-switch-ternary","2016-09-19",[],{"title":6,"description":379},"posts\u002F20160919.if-switch-ternary",[390,391],"JavaScript","條件判斷","2026-08-05","dPXwwFB6y056Mc9ug83ByikB5NjDO606U7MRXBzIl5Q",{"id":395,"title":396,"body":397,"category":378,"description":2032,"draft":380,"extension":381,"image":382,"meta":2033,"navigation":102,"path":2034,"publishedAt":2035,"relatedExperiments":2036,"seo":2037,"stem":2038,"tags":2039,"updatedAt":392,"__hash__":2043},"posts\u002Fposts\u002F20170126.legacy-browser-detection.md","判斷瀏覽器與手機裝置的方法",{"type":8,"value":398,"toc":2024},[399,402,406,409,418,421,429,432,439,859,863,1208,1212,1452,1456,1992,1995,2001,2005,2008,2011,2018,2021],[11,400,401],{},"這篇是當時整理瀏覽器與手機裝置判斷方式時留下來的筆記。",[15,403,405],{"id":404},"css-hack","CSS Hack",[11,407,408],{},"當時參考：",[11,410,411],{},[412,413,417],"a",{"href":414,"rel":415},"https:\u002F\u002Fwww.w3cplus.com\u002Fcss\u002Fbrowser-hacks.html",[416],"nofollow","W3CPlus：CSS Browser Hacks",[11,419,420],{},"IE6、IE7、IE8、Firefox 的一些辨識符號：",[22,422,427],{"className":423,"code":425,"language":426,"meta":27},[424],"language-text","\\9\n*\n_\n","text",[29,428,425],{"__ignoreMap":27},[15,430,431],{"id":431},"判斷手機裝置",[11,433,434,435,438],{},"透過 ",[29,436,437],{},"navigator.userAgent"," 判斷目前使用的裝置。",[22,440,442],{"className":24,"code":441,"language":26,"meta":27,"style":27},"var uA = navigator.userAgent;\n\nif (\n  uA.match(\u002FiPod\u002F) ||\n  uA.match(\u002FiPad\u002F) ||\n  uA.match(\u002FiPhone\u002F)\n) {\n  $(\"#moLoAppDownload\").attr(\n    \"href\",\n    \"https:\u002F\u002Fitunes.apple.com\u002Fapp\u002Fapple-store\u002Fid919043762\"\n  );\n} else if (\n  uA.match(\u002FAndroid\u002F) ||\n  uA.match(\u002FWindows Phone\u002F)\n) {\n  \u002F* $(\"#moLoAppDownload\").attr(\"href\", getAPK(medium, \"\", \"\", activity)); *\u002F\n\n  $(\"#moLoAppDownload\").attr(\"href\", getAPK(medium));\n\n  $(\"#moLoAppDownload\").click(function () {\n    $(\".teachGroup\").fadeIn();\n  });\n} else {\n  $(\"#moLoAppDownload\").attr(\n    \"href\",\n    getEXE(medium, activity)\n  );\n}\n\n$(\"#closeTeach\").click(function () {\n  $(\".teachGroup\").fadeOut();\n});\n\n$(\"#homeURL\").attr(\n  \"href\",\n  location.protocol +\n    \"\u002F\u002F\" +\n    location.host +\n    \"\u002FmobileHD\u002F\"\n);\n",[29,443,444,456,460,467,487,502,516,521,540,548,553,558,571,586,599,603,610,615,642,647,669,688,694,704,719,726,735,740,745,750,771,787,793,798,814,822,831,840,848,854],{"__ignoreMap":27},[32,445,446,448,451,453],{"class":34,"line":35},[32,447,166],{"class":38},[32,449,450],{"class":41}," uA ",[32,452,172],{"class":38},[32,454,455],{"class":41}," navigator.userAgent;\n",[32,457,458],{"class":34,"line":45},[32,459,103],{"emptyLinePlaceholder":102},[32,461,462,464],{"class":34,"line":51},[32,463,17],{"class":38},[32,465,466],{"class":41}," (\n",[32,468,469,472,475,478,481,484],{"class":34,"line":90},[32,470,471],{"class":41},"  uA.",[32,473,474],{"class":217},"match",[32,476,477],{"class":41},"(",[32,479,480],{"class":175},"\u002FiPod\u002F",[32,482,483],{"class":41},") ",[32,485,486],{"class":38},"||\n",[32,488,489,491,493,495,498,500],{"class":34,"line":99},[32,490,471],{"class":41},[32,492,474],{"class":217},[32,494,477],{"class":41},[32,496,497],{"class":175},"\u002FiPad\u002F",[32,499,483],{"class":41},[32,501,486],{"class":38},[32,503,504,506,508,510,513],{"class":34,"line":106},[32,505,471],{"class":41},[32,507,474],{"class":217},[32,509,477],{"class":41},[32,511,512],{"class":175},"\u002FiPhone\u002F",[32,514,515],{"class":41},")\n",[32,517,518],{"class":34,"line":114},[32,519,520],{"class":41},") {\n",[32,522,523,526,528,531,534,537],{"class":34,"line":120},[32,524,525],{"class":217},"  $",[32,527,477],{"class":41},[32,529,530],{"class":175},"\"#moLoAppDownload\"",[32,532,533],{"class":41},").",[32,535,536],{"class":217},"attr",[32,538,539],{"class":41},"(\n",[32,541,542,545],{"class":34,"line":127},[32,543,544],{"class":175},"    \"href\"",[32,546,547],{"class":41},",\n",[32,549,550],{"class":34,"line":132},[32,551,552],{"class":175},"    \"https:\u002F\u002Fitunes.apple.com\u002Fapp\u002Fapple-store\u002Fid919043762\"\n",[32,554,555],{"class":34,"line":141},[32,556,557],{"class":41},"  );\n",[32,559,560,563,566,569],{"class":34,"line":147},[32,561,562],{"class":41},"} ",[32,564,565],{"class":38},"else",[32,567,568],{"class":38}," if",[32,570,466],{"class":41},[32,572,573,575,577,579,582,584],{"class":34,"line":275},[32,574,471],{"class":41},[32,576,474],{"class":217},[32,578,477],{"class":41},[32,580,581],{"class":175},"\u002FAndroid\u002F",[32,583,483],{"class":41},[32,585,486],{"class":38},[32,587,588,590,592,594,597],{"class":34,"line":282},[32,589,471],{"class":41},[32,591,474],{"class":217},[32,593,477],{"class":41},[32,595,596],{"class":175},"\u002FWindows Phone\u002F",[32,598,515],{"class":41},[32,600,601],{"class":34,"line":295},[32,602,520],{"class":41},[32,604,606],{"class":34,"line":605},16,[32,607,609],{"class":608},"sPyeA","  \u002F* $(\"#moLoAppDownload\").attr(\"href\", getAPK(medium, \"\", \"\", activity)); *\u002F\n",[32,611,613],{"class":34,"line":612},17,[32,614,103],{"emptyLinePlaceholder":102},[32,616,618,620,622,624,626,628,630,633,636,639],{"class":34,"line":617},18,[32,619,525],{"class":217},[32,621,477],{"class":41},[32,623,530],{"class":175},[32,625,533],{"class":41},[32,627,536],{"class":217},[32,629,477],{"class":41},[32,631,632],{"class":175},"\"href\"",[32,634,635],{"class":41},", ",[32,637,638],{"class":217},"getAPK",[32,640,641],{"class":41},"(medium));\n",[32,643,645],{"class":34,"line":644},19,[32,646,103],{"emptyLinePlaceholder":102},[32,648,650,652,654,656,658,661,663,666],{"class":34,"line":649},20,[32,651,525],{"class":217},[32,653,477],{"class":41},[32,655,530],{"class":175},[32,657,533],{"class":41},[32,659,660],{"class":217},"click",[32,662,477],{"class":41},[32,664,665],{"class":38},"function",[32,667,668],{"class":41}," () {\n",[32,670,672,675,677,680,682,685],{"class":34,"line":671},21,[32,673,674],{"class":217},"    $",[32,676,477],{"class":41},[32,678,679],{"class":175},"\".teachGroup\"",[32,681,533],{"class":41},[32,683,684],{"class":217},"fadeIn",[32,686,687],{"class":41},"();\n",[32,689,691],{"class":34,"line":690},22,[32,692,693],{"class":41},"  });\n",[32,695,697,699,701],{"class":34,"line":696},23,[32,698,562],{"class":41},[32,700,565],{"class":38},[32,702,703],{"class":41}," {\n",[32,705,707,709,711,713,715,717],{"class":34,"line":706},24,[32,708,525],{"class":217},[32,710,477],{"class":41},[32,712,530],{"class":175},[32,714,533],{"class":41},[32,716,536],{"class":217},[32,718,539],{"class":41},[32,720,722,724],{"class":34,"line":721},25,[32,723,544],{"class":175},[32,725,547],{"class":41},[32,727,729,732],{"class":34,"line":728},26,[32,730,731],{"class":217},"    getEXE",[32,733,734],{"class":41},"(medium, activity)\n",[32,736,738],{"class":34,"line":737},27,[32,739,557],{"class":41},[32,741,743],{"class":34,"line":742},28,[32,744,54],{"class":41},[32,746,748],{"class":34,"line":747},29,[32,749,103],{"emptyLinePlaceholder":102},[32,751,753,756,758,761,763,765,767,769],{"class":34,"line":752},30,[32,754,755],{"class":217},"$",[32,757,477],{"class":41},[32,759,760],{"class":175},"\"#closeTeach\"",[32,762,533],{"class":41},[32,764,660],{"class":217},[32,766,477],{"class":41},[32,768,665],{"class":38},[32,770,668],{"class":41},[32,772,774,776,778,780,782,785],{"class":34,"line":773},31,[32,775,525],{"class":217},[32,777,477],{"class":41},[32,779,679],{"class":175},[32,781,533],{"class":41},[32,783,784],{"class":217},"fadeOut",[32,786,687],{"class":41},[32,788,790],{"class":34,"line":789},32,[32,791,792],{"class":41},"});\n",[32,794,796],{"class":34,"line":795},33,[32,797,103],{"emptyLinePlaceholder":102},[32,799,801,803,805,808,810,812],{"class":34,"line":800},34,[32,802,755],{"class":217},[32,804,477],{"class":41},[32,806,807],{"class":175},"\"#homeURL\"",[32,809,533],{"class":41},[32,811,536],{"class":217},[32,813,539],{"class":41},[32,815,817,820],{"class":34,"line":816},35,[32,818,819],{"class":175},"  \"href\"",[32,821,547],{"class":41},[32,823,825,828],{"class":34,"line":824},36,[32,826,827],{"class":41},"  location.protocol ",[32,829,830],{"class":38},"+\n",[32,832,834,837],{"class":34,"line":833},37,[32,835,836],{"class":175},"    \"\u002F\u002F\"",[32,838,839],{"class":38}," +\n",[32,841,843,846],{"class":34,"line":842},38,[32,844,845],{"class":41},"    location.host ",[32,847,830],{"class":38},[32,849,851],{"class":34,"line":850},39,[32,852,853],{"class":175},"    \"\u002FmobileHD\u002F\"\n",[32,855,857],{"class":34,"line":856},40,[32,858,230],{"class":41},[15,860,862],{"id":861},"判斷-ie-版本","判斷 IE 版本",[22,864,866],{"className":24,"code":865,"language":26,"meta":27,"style":27},"$(document).ready(function () {\n  var isIE = function (ver) {\n    var b = document.createElement(\"b\");\n\n    b.innerHTML =\n      \"\u003C!--[if IE \" +\n      ver +\n      \"]>\u003Ci>\u003C\u002Fi>\u003C![endif]-->\";\n\n    return (\n      b.getElementsByTagName(\"i\").length === 1\n    );\n  };\n\n  \u002F* 判斷 IE8 \u002F IE9 透明貼圖 *\u002F\n  if (isIE(8) || isIE(9)) {\n    $(\"img\").each(function () {\n      if (\n        $(this)\n          .attr(\"src\")\n          .indexOf(\".png\") != -1\n      ) {\n        $(this).css({\n          filter:\n            'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\"' +\n            $(this).attr(\"src\") +\n            '\", sizingMethod=\"scale\");',\n        });\n      }\n    });\n  }\n});\n",[29,867,868,884,907,930,934,942,949,956,963,967,974,998,1003,1008,1012,1017,1047,1067,1074,1086,1100,1123,1128,1144,1149,1156,1177,1184,1189,1194,1199,1204],{"__ignoreMap":27},[32,869,870,872,875,878,880,882],{"class":34,"line":35},[32,871,755],{"class":217},[32,873,874],{"class":41},"(document).",[32,876,877],{"class":217},"ready",[32,879,477],{"class":41},[32,881,665],{"class":38},[32,883,668],{"class":41},[32,885,886,889,892,895,898,901,905],{"class":34,"line":45},[32,887,888],{"class":38},"  var",[32,890,891],{"class":217}," isIE",[32,893,894],{"class":38}," =",[32,896,897],{"class":38}," function",[32,899,900],{"class":41}," (",[32,902,904],{"class":903},"sjlk-","ver",[32,906,520],{"class":41},[32,908,909,912,915,917,920,923,925,928],{"class":34,"line":51},[32,910,911],{"class":38},"    var",[32,913,914],{"class":41}," b ",[32,916,172],{"class":38},[32,918,919],{"class":41}," document.",[32,921,922],{"class":217},"createElement",[32,924,477],{"class":41},[32,926,927],{"class":175},"\"b\"",[32,929,230],{"class":41},[32,931,932],{"class":34,"line":90},[32,933,103],{"emptyLinePlaceholder":102},[32,935,936,939],{"class":34,"line":99},[32,937,938],{"class":41},"    b.innerHTML ",[32,940,941],{"class":38},"=\n",[32,943,944,947],{"class":34,"line":106},[32,945,946],{"class":175},"      \"\u003C!--[if IE \"",[32,948,839],{"class":38},[32,950,951,954],{"class":34,"line":114},[32,952,953],{"class":41},"      ver ",[32,955,830],{"class":38},[32,957,958,961],{"class":34,"line":120},[32,959,960],{"class":175},"      \"]>\u003Ci>\u003C\u002Fi>\u003C![endif]-->\"",[32,962,96],{"class":41},[32,964,965],{"class":34,"line":127},[32,966,103],{"emptyLinePlaceholder":102},[32,968,969,972],{"class":34,"line":132},[32,970,971],{"class":38},"    return",[32,973,466],{"class":41},[32,975,976,979,982,984,987,989,992,995],{"class":34,"line":141},[32,977,978],{"class":41},"      b.",[32,980,981],{"class":217},"getElementsByTagName",[32,983,477],{"class":41},[32,985,986],{"class":175},"\"i\"",[32,988,533],{"class":41},[32,990,991],{"class":351},"length",[32,993,994],{"class":38}," ===",[32,996,997],{"class":351}," 1\n",[32,999,1000],{"class":34,"line":147},[32,1001,1002],{"class":41},"    );\n",[32,1004,1005],{"class":34,"line":275},[32,1006,1007],{"class":41},"  };\n",[32,1009,1010],{"class":34,"line":282},[32,1011,103],{"emptyLinePlaceholder":102},[32,1013,1014],{"class":34,"line":295},[32,1015,1016],{"class":608},"  \u002F* 判斷 IE8 \u002F IE9 透明貼圖 *\u002F\n",[32,1018,1019,1022,1024,1027,1029,1032,1034,1037,1039,1041,1044],{"class":34,"line":605},[32,1020,1021],{"class":38},"  if",[32,1023,900],{"class":41},[32,1025,1026],{"class":217},"isIE",[32,1028,477],{"class":41},[32,1030,1031],{"class":351},"8",[32,1033,483],{"class":41},[32,1035,1036],{"class":38},"||",[32,1038,891],{"class":217},[32,1040,477],{"class":41},[32,1042,1043],{"class":351},"9",[32,1045,1046],{"class":41},")) {\n",[32,1048,1049,1051,1053,1056,1058,1061,1063,1065],{"class":34,"line":612},[32,1050,674],{"class":217},[32,1052,477],{"class":41},[32,1054,1055],{"class":175},"\"img\"",[32,1057,533],{"class":41},[32,1059,1060],{"class":217},"each",[32,1062,477],{"class":41},[32,1064,665],{"class":38},[32,1066,668],{"class":41},[32,1068,1069,1072],{"class":34,"line":617},[32,1070,1071],{"class":38},"      if",[32,1073,466],{"class":41},[32,1075,1076,1079,1081,1084],{"class":34,"line":644},[32,1077,1078],{"class":217},"        $",[32,1080,477],{"class":41},[32,1082,1083],{"class":351},"this",[32,1085,515],{"class":41},[32,1087,1088,1091,1093,1095,1098],{"class":34,"line":649},[32,1089,1090],{"class":41},"          .",[32,1092,536],{"class":217},[32,1094,477],{"class":41},[32,1096,1097],{"class":175},"\"src\"",[32,1099,515],{"class":41},[32,1101,1102,1104,1107,1109,1112,1114,1117,1120],{"class":34,"line":671},[32,1103,1090],{"class":41},[32,1105,1106],{"class":217},"indexOf",[32,1108,477],{"class":41},[32,1110,1111],{"class":175},"\".png\"",[32,1113,483],{"class":41},[32,1115,1116],{"class":38},"!=",[32,1118,1119],{"class":38}," -",[32,1121,1122],{"class":351},"1\n",[32,1124,1125],{"class":34,"line":690},[32,1126,1127],{"class":41},"      ) {\n",[32,1129,1130,1132,1134,1136,1138,1141],{"class":34,"line":696},[32,1131,1078],{"class":217},[32,1133,477],{"class":41},[32,1135,1083],{"class":351},[32,1137,533],{"class":41},[32,1139,1140],{"class":217},"css",[32,1142,1143],{"class":41},"({\n",[32,1145,1146],{"class":34,"line":706},[32,1147,1148],{"class":41},"          filter:\n",[32,1150,1151,1154],{"class":34,"line":721},[32,1152,1153],{"class":175},"            'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\"'",[32,1155,839],{"class":38},[32,1157,1158,1161,1163,1165,1167,1169,1171,1173,1175],{"class":34,"line":728},[32,1159,1160],{"class":217},"            $",[32,1162,477],{"class":41},[32,1164,1083],{"class":351},[32,1166,533],{"class":41},[32,1168,536],{"class":217},[32,1170,477],{"class":41},[32,1172,1097],{"class":175},[32,1174,483],{"class":41},[32,1176,830],{"class":38},[32,1178,1179,1182],{"class":34,"line":737},[32,1180,1181],{"class":175},"            '\", sizingMethod=\"scale\");'",[32,1183,547],{"class":41},[32,1185,1186],{"class":34,"line":742},[32,1187,1188],{"class":41},"        });\n",[32,1190,1191],{"class":34,"line":747},[32,1192,1193],{"class":41},"      }\n",[32,1195,1196],{"class":34,"line":752},[32,1197,1198],{"class":41},"    });\n",[32,1200,1201],{"class":34,"line":773},[32,1202,1203],{"class":41},"  }\n",[32,1205,1206],{"class":34,"line":789},[32,1207,792],{"class":41},[15,1209,1211],{"id":1210},"javascript-判斷瀏覽器版本-1","JavaScript 判斷瀏覽器：版本 1",[22,1213,1215],{"className":24,"code":1214,"language":26,"meta":27,"style":27},"var isFirefox =\n  navigator.userAgent.match(\"Firefox\");\n\u002F\u002F 判斷是否為 Firefox\n\nvar isIE =\n  \u002FTrident\\\u002F7\\.\u002F.test(navigator.userAgent);\n\nvar isOpera =\n  navigator.userAgent.match(\"Opera\");\n\u002F\u002F 判斷是否為 Opera\n\nvar isSafari =\n  navigator.userAgent.match(\"Safari\");\n\u002F\u002F 判斷是否為 Safari 或 Google Chrome\n\nif (isIE) {\n  alert(\"你使用的是 IE\");\n}\n\nif (isFirefox) {\n  alert(\"你使用的是 FireFox\");\n}\n\nif (isOpera) {\n  alert(\"你使用的是 Opera\");\n}\n\nif (isSafari) {\n  alert(\"你使用的是 Chrome 或 Safari\");\n}\n",[29,1216,1217,1226,1240,1245,1249,1258,1285,1289,1298,1311,1316,1320,1329,1342,1347,1351,1358,1370,1374,1378,1385,1396,1400,1404,1411,1422,1426,1430,1437,1448],{"__ignoreMap":27},[32,1218,1219,1221,1224],{"class":34,"line":35},[32,1220,166],{"class":38},[32,1222,1223],{"class":41}," isFirefox ",[32,1225,941],{"class":38},[32,1227,1228,1231,1233,1235,1238],{"class":34,"line":45},[32,1229,1230],{"class":41},"  navigator.userAgent.",[32,1232,474],{"class":217},[32,1234,477],{"class":41},[32,1236,1237],{"class":175},"\"Firefox\"",[32,1239,230],{"class":41},[32,1241,1242],{"class":34,"line":51},[32,1243,1244],{"class":608},"\u002F\u002F 判斷是否為 Firefox\n",[32,1246,1247],{"class":34,"line":90},[32,1248,103],{"emptyLinePlaceholder":102},[32,1250,1251,1253,1256],{"class":34,"line":99},[32,1252,166],{"class":38},[32,1254,1255],{"class":41}," isIE ",[32,1257,941],{"class":38},[32,1259,1260,1263,1267,1270,1273,1276,1279,1282],{"class":34,"line":106},[32,1261,1262],{"class":175},"  \u002FTrident",[32,1264,1266],{"class":1265},"sh9l7","\\\u002F",[32,1268,1269],{"class":175},"7",[32,1271,1272],{"class":1265},"\\.",[32,1274,1275],{"class":175},"\u002F",[32,1277,1278],{"class":41},".",[32,1280,1281],{"class":217},"test",[32,1283,1284],{"class":41},"(navigator.userAgent);\n",[32,1286,1287],{"class":34,"line":114},[32,1288,103],{"emptyLinePlaceholder":102},[32,1290,1291,1293,1296],{"class":34,"line":120},[32,1292,166],{"class":38},[32,1294,1295],{"class":41}," isOpera ",[32,1297,941],{"class":38},[32,1299,1300,1302,1304,1306,1309],{"class":34,"line":127},[32,1301,1230],{"class":41},[32,1303,474],{"class":217},[32,1305,477],{"class":41},[32,1307,1308],{"class":175},"\"Opera\"",[32,1310,230],{"class":41},[32,1312,1313],{"class":34,"line":132},[32,1314,1315],{"class":608},"\u002F\u002F 判斷是否為 Opera\n",[32,1317,1318],{"class":34,"line":141},[32,1319,103],{"emptyLinePlaceholder":102},[32,1321,1322,1324,1327],{"class":34,"line":147},[32,1323,166],{"class":38},[32,1325,1326],{"class":41}," isSafari ",[32,1328,941],{"class":38},[32,1330,1331,1333,1335,1337,1340],{"class":34,"line":275},[32,1332,1230],{"class":41},[32,1334,474],{"class":217},[32,1336,477],{"class":41},[32,1338,1339],{"class":175},"\"Safari\"",[32,1341,230],{"class":41},[32,1343,1344],{"class":34,"line":282},[32,1345,1346],{"class":608},"\u002F\u002F 判斷是否為 Safari 或 Google Chrome\n",[32,1348,1349],{"class":34,"line":295},[32,1350,103],{"emptyLinePlaceholder":102},[32,1352,1353,1355],{"class":34,"line":605},[32,1354,17],{"class":38},[32,1356,1357],{"class":41}," (isIE) {\n",[32,1359,1360,1363,1365,1368],{"class":34,"line":612},[32,1361,1362],{"class":217},"  alert",[32,1364,477],{"class":41},[32,1366,1367],{"class":175},"\"你使用的是 IE\"",[32,1369,230],{"class":41},[32,1371,1372],{"class":34,"line":617},[32,1373,54],{"class":41},[32,1375,1376],{"class":34,"line":644},[32,1377,103],{"emptyLinePlaceholder":102},[32,1379,1380,1382],{"class":34,"line":649},[32,1381,17],{"class":38},[32,1383,1384],{"class":41}," (isFirefox) {\n",[32,1386,1387,1389,1391,1394],{"class":34,"line":671},[32,1388,1362],{"class":217},[32,1390,477],{"class":41},[32,1392,1393],{"class":175},"\"你使用的是 FireFox\"",[32,1395,230],{"class":41},[32,1397,1398],{"class":34,"line":690},[32,1399,54],{"class":41},[32,1401,1402],{"class":34,"line":696},[32,1403,103],{"emptyLinePlaceholder":102},[32,1405,1406,1408],{"class":34,"line":706},[32,1407,17],{"class":38},[32,1409,1410],{"class":41}," (isOpera) {\n",[32,1412,1413,1415,1417,1420],{"class":34,"line":721},[32,1414,1362],{"class":217},[32,1416,477],{"class":41},[32,1418,1419],{"class":175},"\"你使用的是 Opera\"",[32,1421,230],{"class":41},[32,1423,1424],{"class":34,"line":728},[32,1425,54],{"class":41},[32,1427,1428],{"class":34,"line":737},[32,1429,103],{"emptyLinePlaceholder":102},[32,1431,1432,1434],{"class":34,"line":742},[32,1433,17],{"class":38},[32,1435,1436],{"class":41}," (isSafari) {\n",[32,1438,1439,1441,1443,1446],{"class":34,"line":747},[32,1440,1362],{"class":217},[32,1442,477],{"class":41},[32,1444,1445],{"class":175},"\"你使用的是 Chrome 或 Safari\"",[32,1447,230],{"class":41},[32,1449,1450],{"class":34,"line":752},[32,1451,54],{"class":41},[15,1453,1455],{"id":1454},"javascript-判斷瀏覽器版本-2","JavaScript 判斷瀏覽器：版本 2",[22,1457,1459],{"className":24,"code":1458,"language":26,"meta":27,"style":27},"\u002F\u002F Opera 8.0+\nvar isOpera =\n  (!!window.opr && !!opr.addons) ||\n  !!window.opera ||\n  navigator.userAgent.indexOf(\" OPR\u002F\") >= 0;\n\n\u002F\u002F Firefox 1.0+\nvar isFirefox =\n  typeof InstallTrigger !== \"undefined\";\n\n\u002F\u002F At least Safari 3+\nvar isSafari =\n  Object.prototype.toString\n    .call(window.HTMLElement)\n    .indexOf(\"Constructor\") > 0;\n\n\u002F\u002F Internet Explorer 6-11\nvar isIE =\n  false || !!document.documentMode;\n\n\u002F\u002F Edge 20+\nvar isEdge =\n  !isIE && !!window.StyleMedia;\n\n\u002F\u002F Chrome 1+\nvar isChrome =\n  !!window.chrome &&\n  !!window.chrome.webstore;\n\n\u002F\u002F Blink engine detection\nvar isBlink =\n  (isChrome || isOpera) &&\n  !!window.CSS;\n\nvar output =\n  \"Detecting browsers by ducktyping:\u003Chr>\";\n\noutput +=\n  \"isFirefox: \" + isFirefox + \"\u003Cbr>\";\n\noutput +=\n  \"isChrome: \" + isChrome + \"\u003Cbr>\";\n\noutput +=\n  \"isSafari: \" + isSafari + \"\u003Cbr>\";\n\noutput +=\n  \"isOpera: \" + isOpera + \"\u003Cbr>\";\n\noutput +=\n  \"isIE: \" + isIE + \"\u003Cbr>\";\n\noutput +=\n  \"isEdge: \" + isEdge + \"\u003Cbr>\";\n\noutput +=\n  \"isBlink: \" + isBlink + \"\u003Cbr>\";\n\ndocument.body.innerHTML = output;\n",[29,1460,1461,1466,1474,1496,1506,1526,1530,1535,1543,1559,1563,1568,1576,1589,1600,1620,1624,1629,1637,1650,1654,1659,1668,1683,1687,1692,1701,1711,1718,1722,1727,1736,1748,1760,1764,1773,1780,1784,1792,1809,1813,1820,1836,1841,1848,1864,1869,1876,1892,1897,1904,1920,1925,1932,1948,1953,1960,1976,1981],{"__ignoreMap":27},[32,1462,1463],{"class":34,"line":35},[32,1464,1465],{"class":608},"\u002F\u002F Opera 8.0+\n",[32,1467,1468,1470,1472],{"class":34,"line":45},[32,1469,166],{"class":38},[32,1471,1295],{"class":41},[32,1473,941],{"class":38},[32,1475,1476,1479,1482,1485,1488,1491,1494],{"class":34,"line":51},[32,1477,1478],{"class":41},"  (",[32,1480,1481],{"class":38},"!!",[32,1483,1484],{"class":41},"window.opr ",[32,1486,1487],{"class":38},"&&",[32,1489,1490],{"class":38}," !!",[32,1492,1493],{"class":41},"opr.addons) ",[32,1495,486],{"class":38},[32,1497,1498,1501,1504],{"class":34,"line":90},[32,1499,1500],{"class":38},"  !!",[32,1502,1503],{"class":41},"window.opera ",[32,1505,486],{"class":38},[32,1507,1508,1510,1512,1514,1517,1519,1521,1524],{"class":34,"line":99},[32,1509,1230],{"class":41},[32,1511,1106],{"class":217},[32,1513,477],{"class":41},[32,1515,1516],{"class":175},"\" OPR\u002F\"",[32,1518,483],{"class":41},[32,1520,348],{"class":38},[32,1522,1523],{"class":351}," 0",[32,1525,96],{"class":41},[32,1527,1528],{"class":34,"line":106},[32,1529,103],{"emptyLinePlaceholder":102},[32,1531,1532],{"class":34,"line":114},[32,1533,1534],{"class":608},"\u002F\u002F Firefox 1.0+\n",[32,1536,1537,1539,1541],{"class":34,"line":120},[32,1538,166],{"class":38},[32,1540,1223],{"class":41},[32,1542,941],{"class":38},[32,1544,1545,1548,1551,1554,1557],{"class":34,"line":127},[32,1546,1547],{"class":38},"  typeof",[32,1549,1550],{"class":41}," InstallTrigger ",[32,1552,1553],{"class":38},"!==",[32,1555,1556],{"class":175}," \"undefined\"",[32,1558,96],{"class":41},[32,1560,1561],{"class":34,"line":132},[32,1562,103],{"emptyLinePlaceholder":102},[32,1564,1565],{"class":34,"line":141},[32,1566,1567],{"class":608},"\u002F\u002F At least Safari 3+\n",[32,1569,1570,1572,1574],{"class":34,"line":147},[32,1571,166],{"class":38},[32,1573,1326],{"class":41},[32,1575,941],{"class":38},[32,1577,1578,1581,1583,1586],{"class":34,"line":275},[32,1579,1580],{"class":351},"  Object",[32,1582,1278],{"class":41},[32,1584,1585],{"class":351},"prototype",[32,1587,1588],{"class":41},".toString\n",[32,1590,1591,1594,1597],{"class":34,"line":282},[32,1592,1593],{"class":41},"    .",[32,1595,1596],{"class":217},"call",[32,1598,1599],{"class":41},"(window.HTMLElement)\n",[32,1601,1602,1604,1606,1608,1611,1613,1616,1618],{"class":34,"line":295},[32,1603,1593],{"class":41},[32,1605,1106],{"class":217},[32,1607,477],{"class":41},[32,1609,1610],{"class":175},"\"Constructor\"",[32,1612,483],{"class":41},[32,1614,1615],{"class":38},">",[32,1617,1523],{"class":351},[32,1619,96],{"class":41},[32,1621,1622],{"class":34,"line":605},[32,1623,103],{"emptyLinePlaceholder":102},[32,1625,1626],{"class":34,"line":612},[32,1627,1628],{"class":608},"\u002F\u002F Internet Explorer 6-11\n",[32,1630,1631,1633,1635],{"class":34,"line":617},[32,1632,166],{"class":38},[32,1634,1255],{"class":41},[32,1636,941],{"class":38},[32,1638,1639,1642,1645,1647],{"class":34,"line":644},[32,1640,1641],{"class":351},"  false",[32,1643,1644],{"class":38}," ||",[32,1646,1490],{"class":38},[32,1648,1649],{"class":41},"document.documentMode;\n",[32,1651,1652],{"class":34,"line":649},[32,1653,103],{"emptyLinePlaceholder":102},[32,1655,1656],{"class":34,"line":671},[32,1657,1658],{"class":608},"\u002F\u002F Edge 20+\n",[32,1660,1661,1663,1666],{"class":34,"line":690},[32,1662,166],{"class":38},[32,1664,1665],{"class":41}," isEdge ",[32,1667,941],{"class":38},[32,1669,1670,1673,1676,1678,1680],{"class":34,"line":696},[32,1671,1672],{"class":38},"  !",[32,1674,1675],{"class":41},"isIE ",[32,1677,1487],{"class":38},[32,1679,1490],{"class":38},[32,1681,1682],{"class":41},"window.StyleMedia;\n",[32,1684,1685],{"class":34,"line":706},[32,1686,103],{"emptyLinePlaceholder":102},[32,1688,1689],{"class":34,"line":721},[32,1690,1691],{"class":608},"\u002F\u002F Chrome 1+\n",[32,1693,1694,1696,1699],{"class":34,"line":728},[32,1695,166],{"class":38},[32,1697,1698],{"class":41}," isChrome ",[32,1700,941],{"class":38},[32,1702,1703,1705,1708],{"class":34,"line":737},[32,1704,1500],{"class":38},[32,1706,1707],{"class":41},"window.chrome ",[32,1709,1710],{"class":38},"&&\n",[32,1712,1713,1715],{"class":34,"line":742},[32,1714,1500],{"class":38},[32,1716,1717],{"class":41},"window.chrome.webstore;\n",[32,1719,1720],{"class":34,"line":747},[32,1721,103],{"emptyLinePlaceholder":102},[32,1723,1724],{"class":34,"line":752},[32,1725,1726],{"class":608},"\u002F\u002F Blink engine detection\n",[32,1728,1729,1731,1734],{"class":34,"line":773},[32,1730,166],{"class":38},[32,1732,1733],{"class":41}," isBlink ",[32,1735,941],{"class":38},[32,1737,1738,1741,1743,1746],{"class":34,"line":789},[32,1739,1740],{"class":41},"  (isChrome ",[32,1742,1036],{"class":38},[32,1744,1745],{"class":41}," isOpera) ",[32,1747,1710],{"class":38},[32,1749,1750,1752,1755,1758],{"class":34,"line":795},[32,1751,1500],{"class":38},[32,1753,1754],{"class":41},"window.",[32,1756,1757],{"class":351},"CSS",[32,1759,96],{"class":41},[32,1761,1762],{"class":34,"line":800},[32,1763,103],{"emptyLinePlaceholder":102},[32,1765,1766,1768,1771],{"class":34,"line":816},[32,1767,166],{"class":38},[32,1769,1770],{"class":41}," output ",[32,1772,941],{"class":38},[32,1774,1775,1778],{"class":34,"line":824},[32,1776,1777],{"class":175},"  \"Detecting browsers by ducktyping:\u003Chr>\"",[32,1779,96],{"class":41},[32,1781,1782],{"class":34,"line":833},[32,1783,103],{"emptyLinePlaceholder":102},[32,1785,1786,1789],{"class":34,"line":842},[32,1787,1788],{"class":41},"output ",[32,1790,1791],{"class":38},"+=\n",[32,1793,1794,1797,1800,1802,1804,1807],{"class":34,"line":850},[32,1795,1796],{"class":175},"  \"isFirefox: \"",[32,1798,1799],{"class":38}," +",[32,1801,1223],{"class":41},[32,1803,224],{"class":38},[32,1805,1806],{"class":175}," \"\u003Cbr>\"",[32,1808,96],{"class":41},[32,1810,1811],{"class":34,"line":856},[32,1812,103],{"emptyLinePlaceholder":102},[32,1814,1816,1818],{"class":34,"line":1815},41,[32,1817,1788],{"class":41},[32,1819,1791],{"class":38},[32,1821,1823,1826,1828,1830,1832,1834],{"class":34,"line":1822},42,[32,1824,1825],{"class":175},"  \"isChrome: \"",[32,1827,1799],{"class":38},[32,1829,1698],{"class":41},[32,1831,224],{"class":38},[32,1833,1806],{"class":175},[32,1835,96],{"class":41},[32,1837,1839],{"class":34,"line":1838},43,[32,1840,103],{"emptyLinePlaceholder":102},[32,1842,1844,1846],{"class":34,"line":1843},44,[32,1845,1788],{"class":41},[32,1847,1791],{"class":38},[32,1849,1851,1854,1856,1858,1860,1862],{"class":34,"line":1850},45,[32,1852,1853],{"class":175},"  \"isSafari: \"",[32,1855,1799],{"class":38},[32,1857,1326],{"class":41},[32,1859,224],{"class":38},[32,1861,1806],{"class":175},[32,1863,96],{"class":41},[32,1865,1867],{"class":34,"line":1866},46,[32,1868,103],{"emptyLinePlaceholder":102},[32,1870,1872,1874],{"class":34,"line":1871},47,[32,1873,1788],{"class":41},[32,1875,1791],{"class":38},[32,1877,1879,1882,1884,1886,1888,1890],{"class":34,"line":1878},48,[32,1880,1881],{"class":175},"  \"isOpera: \"",[32,1883,1799],{"class":38},[32,1885,1295],{"class":41},[32,1887,224],{"class":38},[32,1889,1806],{"class":175},[32,1891,96],{"class":41},[32,1893,1895],{"class":34,"line":1894},49,[32,1896,103],{"emptyLinePlaceholder":102},[32,1898,1900,1902],{"class":34,"line":1899},50,[32,1901,1788],{"class":41},[32,1903,1791],{"class":38},[32,1905,1907,1910,1912,1914,1916,1918],{"class":34,"line":1906},51,[32,1908,1909],{"class":175},"  \"isIE: \"",[32,1911,1799],{"class":38},[32,1913,1255],{"class":41},[32,1915,224],{"class":38},[32,1917,1806],{"class":175},[32,1919,96],{"class":41},[32,1921,1923],{"class":34,"line":1922},52,[32,1924,103],{"emptyLinePlaceholder":102},[32,1926,1928,1930],{"class":34,"line":1927},53,[32,1929,1788],{"class":41},[32,1931,1791],{"class":38},[32,1933,1935,1938,1940,1942,1944,1946],{"class":34,"line":1934},54,[32,1936,1937],{"class":175},"  \"isEdge: \"",[32,1939,1799],{"class":38},[32,1941,1665],{"class":41},[32,1943,224],{"class":38},[32,1945,1806],{"class":175},[32,1947,96],{"class":41},[32,1949,1951],{"class":34,"line":1950},55,[32,1952,103],{"emptyLinePlaceholder":102},[32,1954,1956,1958],{"class":34,"line":1955},56,[32,1957,1788],{"class":41},[32,1959,1791],{"class":38},[32,1961,1963,1966,1968,1970,1972,1974],{"class":34,"line":1962},57,[32,1964,1965],{"class":175},"  \"isBlink: \"",[32,1967,1799],{"class":38},[32,1969,1733],{"class":41},[32,1971,224],{"class":38},[32,1973,1806],{"class":175},[32,1975,96],{"class":41},[32,1977,1979],{"class":34,"line":1978},58,[32,1980,103],{"emptyLinePlaceholder":102},[32,1982,1984,1987,1989],{"class":34,"line":1983},59,[32,1985,1986],{"class":41},"document.body.innerHTML ",[32,1988,172],{"class":38},[32,1990,1991],{"class":41}," output;\n",[11,1993,1994],{},"當時在 Chrome 上測試的輸出：",[22,1996,1999],{"className":1997,"code":1998,"language":426,"meta":27},[424],"isFirefox: false\nisChrome: true\nisSafari: false\nisOpera: false\nisIE: false\nisEdge: false\nisBlink: true\n",[29,2000,1998],{"__ignoreMap":27},[15,2002,2004],{"id":2003},"_2026-年後記","2026 年後記",[11,2006,2007],{},"這篇是 2017 年留下來的瀏覽器相容性筆記，所以保留了當時使用 User Agent、IE 條件註解、jQuery 與瀏覽器特徵判斷的寫法。",[11,2009,2010],{},"現在瀏覽器環境已經和當時差很多，像是 IE、舊版 Edge、Windows Phone，以及程式碼裡拿來判斷瀏覽器的部分 API，都已經不適合直接套用到現在的新專案。",[11,2012,2013,2014,2017],{},"原文中的 ",[29,2015,2016],{},"AlphaImageLoader"," 也是早期 Internet Explorer 使用的專有濾鏡。這段程式碼保留下來，是作為當時處理瀏覽器相容性問題的紀錄，不建議拿來當現在的實作方式。",[11,2019,2020],{},"至於現在如果需要判斷裝置或瀏覽器能力，我會另外整理新的做法；這篇就先保留當年的版本。",[368,2022,2023],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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 .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sh9l7, html code.shiki .sh9l7{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#7EE787;--shiki-dark-font-weight:bold}",{"title":27,"searchDepth":51,"depth":51,"links":2025},[2026,2027,2028,2029,2030,2031],{"id":404,"depth":45,"text":405},{"id":431,"depth":45,"text":431},{"id":861,"depth":45,"text":862},{"id":1210,"depth":45,"text":1211},{"id":1454,"depth":45,"text":1455},{"id":2003,"depth":45,"text":2004},"2017 年整理的瀏覽器與手機裝置判斷筆記，包含 User Agent、IE 判斷、CSS Hack 與不同瀏覽器的判斷方式。",{},"\u002Fposts\u002Flegacy-browser-detection","2017-01-26",[],{"title":396,"description":2032},"posts\u002F20170126.legacy-browser-detection",[390,2040,2041,2042],"jQuery","IE","瀏覽器偵測","upOlKnPsbMT6pXq5GRVGBk0NuzYSLqmR31NLIB357l4",{"id":2045,"title":2046,"body":2047,"category":4012,"description":4013,"draft":380,"extension":381,"image":382,"meta":4014,"navigation":102,"path":4015,"publishedAt":4016,"relatedExperiments":4017,"seo":4018,"stem":4019,"tags":4020,"updatedAt":392,"__hash__":4023},"posts\u002Fposts\u002F20180105.git-commands-cheatsheet.md","Git 常用指令與終端機筆記",{"type":8,"value":2048,"toc":3946},[2049,2052,2055,2067,2070,2083,2086,2098,2101,2114,2117,2130,2133,2142,2145,2148,2161,2164,2177,2180,2183,2193,2196,2209,2212,2218,2221,2239,2242,2254,2257,2273,2276,2291,2294,2312,2315,2327,2330,2345,2352,2367,2370,2375,2379,2391,2394,2398,2401,2407,2410,2413,2425,2428,2434,2437,2440,2455,2458,2461,2464,2470,2473,2476,2479,2482,2497,2500,2514,2517,2520,2538,2544,2560,2563,2569,2572,2584,2587,2590,2596,2599,2617,2620,2637,2640,2642,2648,2651,2654,2673,2677,2696,2700,2717,2721,2724,2749,2752,2770,2773,2776,2779,2785,2789,2792,2821,2824,2830,2833,2839,2852,2855,2861,2864,2869,2872,2875,2889,2892,2897,2900,2903,2909,2912,2926,2929,2932,2946,2949,2965,2969,2972,2984,2986,3001,3007,3009,3023,3026,3040,3043,3047,3064,3067,3071,3087,3090,3097,3101,3117,3120,3123,3127,3139,3142,3145,3148,3154,3157,3163,3166,3169,3181,3184,3199,3202,3218,3221,3224,3237,3240,3256,3259,3261,3267,3270,3276,3279,3282,3284,3290,3293,3296,3310,3313,3327,3330,3333,3339,3343,3346,3363,3366,3369,3374,3376,3380,3383,3398,3401,3407,3411,3414,3429,3432,3466,3469,3499,3502,3505,3511,3515,3518,3520,3539,3543,3546,3565,3568,3580,3583,3594,3597,3642,3645,3671,3675,3678,3684,3687,3693,3696,3702,3705,3710,3714,3717,3723,3726,3739,3742,3744,3755,3758,3765,3776,3779,3791,3794,3808,3811,3823,3826,3840,3846,3852,3855,3867,3870,3876,3879,3886,3898,3901,3904,3907,3913,3924,3930,3940,3943],[11,2050,2051],{},"這篇是當時學 Git 時整理下來的指令筆記，除了 Git 本身，也一起記了一些終端機、SourceTree 和 Vim 的操作。",[15,2053,2054],{"id":2054},"基本終端機指令",[22,2056,2060],{"className":2057,"code":2058,"language":2059,"meta":27,"style":27},"language-bash shiki shiki-themes github-light github-dark-default","ls\n","bash",[29,2061,2062],{"__ignoreMap":27},[32,2063,2064],{"class":34,"line":35},[32,2065,2058],{"class":2066},"sYRkA",[11,2068,2069],{},"可以看到目前目錄下的檔案。",[22,2071,2073],{"className":2057,"code":2072,"language":2059,"meta":27,"style":27},"ls -a\n",[29,2074,2075],{"__ignoreMap":27},[32,2076,2077,2080],{"class":34,"line":35},[32,2078,2079],{"class":2066},"ls",[32,2081,2082],{"class":351}," -a\n",[11,2084,2085],{},"顯示包含隱藏檔案在內的內容。",[22,2087,2089],{"className":2057,"code":2088,"language":2059,"meta":27,"style":27},"ls -al\n",[29,2090,2091],{"__ignoreMap":27},[32,2092,2093,2095],{"class":34,"line":35},[32,2094,2079],{"class":2066},[32,2096,2097],{"class":351}," -al\n",[11,2099,2100],{},"顯示比較完整的檔案資訊。",[22,2102,2104],{"className":2057,"code":2103,"language":2059,"meta":27,"style":27},"which git\n",[29,2105,2106],{"__ignoreMap":27},[32,2107,2108,2111],{"class":34,"line":35},[32,2109,2110],{"class":351},"which",[32,2112,2113],{"class":175}," git\n",[11,2115,2116],{},"查看 Git 安裝在哪裡。",[22,2118,2120],{"className":2057,"code":2119,"language":2059,"meta":27,"style":27},"git --version\n",[29,2121,2122],{"__ignoreMap":27},[32,2123,2124,2127],{"class":34,"line":35},[32,2125,2126],{"class":2066},"git",[32,2128,2129],{"class":351}," --version\n",[11,2131,2132],{},"查看目前 Git 版本。",[22,2134,2136],{"className":2057,"code":2135,"language":2059,"meta":27,"style":27},"pwd\n",[29,2137,2138],{"__ignoreMap":27},[32,2139,2140],{"class":34,"line":35},[32,2141,2135],{"class":351},[11,2143,2144],{},"查看現在所在的位置。",[151,2146,2147],{"id":2147},"建立檔案與資料夾",[22,2149,2151],{"className":2057,"code":2150,"language":2059,"meta":27,"style":27},"touch git.html\n",[29,2152,2153],{"__ignoreMap":27},[32,2154,2155,2158],{"class":34,"line":35},[32,2156,2157],{"class":2066},"touch",[32,2159,2160],{"class":175}," git.html\n",[11,2162,2163],{},"建立檔案。",[22,2165,2167],{"className":2057,"code":2166,"language":2059,"meta":27,"style":27},"mkdir test\n",[29,2168,2169],{"__ignoreMap":27},[32,2170,2171,2174],{"class":34,"line":35},[32,2172,2173],{"class":2066},"mkdir",[32,2175,2176],{"class":175}," test\n",[11,2178,2179],{},"建立新的資料夾。",[11,2181,2182],{},"當時有特別記：",[2184,2185,2186],"blockquote",{},[11,2187,2188,2189,2192],{},"建立空的資料夾時 Git 不會感應到，要在資料夾裡面放入檔案後，",[29,2190,2191],{},"git status"," 才會出現。\n空的目錄本身無法提交到 Git。",[151,2194,2195],{"id":2195},"查看與操作檔案",[22,2197,2199],{"className":2057,"code":2198,"language":2059,"meta":27,"style":27},"echo \"hello\"\n",[29,2200,2201],{"__ignoreMap":27},[32,2202,2203,2206],{"class":34,"line":35},[32,2204,2205],{"class":351},"echo",[32,2207,2208],{"class":175}," \"hello\"\n",[11,2210,2211],{},"列印出：",[22,2213,2216],{"className":2214,"code":2215,"language":426,"meta":27},[424],"hello\n",[29,2217,2215],{"__ignoreMap":27},[11,2219,2220],{},"把內容寫入檔案：",[22,2222,2224],{"className":2057,"code":2223,"language":2059,"meta":27,"style":27},"echo \"hello\" > world.html\n",[29,2225,2226],{"__ignoreMap":27},[32,2227,2228,2230,2233,2236],{"class":34,"line":35},[32,2229,2205],{"class":351},[32,2231,2232],{"class":175}," \"hello\"",[32,2234,2235],{"class":38}," >",[32,2237,2238],{"class":175}," world.html\n",[11,2240,2241],{},"查看檔案內容：",[22,2243,2245],{"className":2057,"code":2244,"language":2059,"meta":27,"style":27},"cat world.html\n",[29,2246,2247],{"__ignoreMap":27},[32,2248,2249,2252],{"class":34,"line":35},[32,2250,2251],{"class":2066},"cat",[32,2253,2238],{"class":175},[11,2255,2256],{},"複製檔案：",[22,2258,2260],{"className":2057,"code":2259,"language":2059,"meta":27,"style":27},"cp test.html asd.html\n",[29,2261,2262],{"__ignoreMap":27},[32,2263,2264,2267,2270],{"class":34,"line":35},[32,2265,2266],{"class":2066},"cp",[32,2268,2269],{"class":175}," test.html",[32,2271,2272],{"class":175}," asd.html\n",[11,2274,2275],{},"移動或重新命名：",[22,2277,2279],{"className":2057,"code":2278,"language":2059,"meta":27,"style":27},"mv test.html cde.html\n",[29,2280,2281],{"__ignoreMap":27},[32,2282,2283,2286,2288],{"class":34,"line":35},[32,2284,2285],{"class":2066},"mv",[32,2287,2269],{"class":175},[32,2289,2290],{"class":175}," cde.html\n",[11,2292,2293],{},"也可以直接用：",[22,2295,2297],{"className":2057,"code":2296,"language":2059,"meta":27,"style":27},"git mv test2.html ruby.html\n",[29,2298,2299],{"__ignoreMap":27},[32,2300,2301,2303,2306,2309],{"class":34,"line":35},[32,2302,2126],{"class":2066},[32,2304,2305],{"class":175}," mv",[32,2307,2308],{"class":175}," test2.html",[32,2310,2311],{"class":175}," ruby.html\n",[151,2313,2314],{"id":2314},"刪除檔案",[22,2316,2318],{"className":2057,"code":2317,"language":2059,"meta":27,"style":27},"rm cde.html\n",[29,2319,2320],{"__ignoreMap":27},[32,2321,2322,2325],{"class":34,"line":35},[32,2323,2324],{"class":2066},"rm",[32,2326,2290],{"class":175},[11,2328,2329],{},"直接刪除檔案。",[22,2331,2333],{"className":2057,"code":2332,"language":2059,"meta":27,"style":27},"rm *.html\n",[29,2334,2335],{"__ignoreMap":27},[32,2336,2337,2339,2342],{"class":34,"line":35},[32,2338,2324],{"class":2066},[32,2340,2341],{"class":351}," *",[32,2343,2344],{"class":175},".html\n",[11,2346,2347,2348,2351],{},"刪除目前目錄下所有 ",[29,2349,2350],{},".html"," 檔案。",[22,2353,2355],{"className":2057,"code":2354,"language":2059,"meta":27,"style":27},"rm -rf .git\n",[29,2356,2357],{"__ignoreMap":27},[32,2358,2359,2361,2364],{"class":34,"line":35},[32,2360,2324],{"class":2066},[32,2362,2363],{"class":351}," -rf",[32,2365,2366],{"class":175}," .git\n",[11,2368,2369],{},"刪除目前專案的 Git 版控資料。",[2184,2371,2372],{},[11,2373,2374],{},"這個指令要非常小心。",[15,2376,2378],{"id":2377},"git-初始化","Git 初始化",[22,2380,2382],{"className":2057,"code":2381,"language":2059,"meta":27,"style":27},"git init\n",[29,2383,2384],{"__ignoreMap":27},[32,2385,2386,2388],{"class":34,"line":35},[32,2387,2126],{"class":2066},[32,2389,2390],{"class":175}," init\n",[11,2392,2393],{},"初始化 Git，讓目前這個目錄開始由 Git 控管。",[151,2395,2397],{"id":2396},"sourcetree","SourceTree",[11,2399,2400],{},"當時使用 SourceTree 的方式：",[22,2402,2405],{"className":2403,"code":2404,"language":426,"meta":27},[424],"New \u002F Create Local Repository\n",[29,2406,2404],{"__ignoreMap":27},[11,2408,2409],{},"建立新的本機 Repository。",[15,2411,2412],{"id":2412},"查看目前狀態",[22,2414,2416],{"className":2057,"code":2415,"language":2059,"meta":27,"style":27},"git status\n",[29,2417,2418],{"__ignoreMap":27},[32,2419,2420,2422],{"class":34,"line":35},[32,2421,2126],{"class":2066},[32,2423,2424],{"class":175}," status\n",[11,2426,2427],{},"如果看到：",[22,2429,2432],{"className":2430,"code":2431,"language":426,"meta":27},[424],"nothing to commit\n",[29,2433,2431],{"__ignoreMap":27},[11,2435,2436],{},"代表目前沒有新的變更需要提交。",[15,2438,2439],{"id":2439},"查詢檔案作者",[22,2441,2443],{"className":2057,"code":2442,"language":2059,"meta":27,"style":27},"git blame index.html\n",[29,2444,2445],{"__ignoreMap":27},[32,2446,2447,2449,2452],{"class":34,"line":35},[32,2448,2126],{"class":2066},[32,2450,2451],{"class":175}," blame",[32,2453,2454],{"class":175}," index.html\n",[11,2456,2457],{},"查看檔案每一行最後是由誰修改。",[151,2459,2397],{"id":2460},"sourcetree-1",[11,2462,2463],{},"對檔案按右鍵：",[22,2465,2468],{"className":2466,"code":2467,"language":426,"meta":27},[424],"Blame Selected\n",[29,2469,2467],{"__ignoreMap":27},[11,2471,2472],{},"也可以查看每一行的修改紀錄。",[15,2474,2475],{"id":2475},"加入暫存區",[11,2477,2478],{},"工作目錄 → 暫存區。",[11,2480,2481],{},"加入單一檔案：",[22,2483,2485],{"className":2057,"code":2484,"language":2059,"meta":27,"style":27},"git add welcome.html\n",[29,2486,2487],{"__ignoreMap":27},[32,2488,2489,2491,2494],{"class":34,"line":35},[32,2490,2126],{"class":2066},[32,2492,2493],{"class":175}," add",[32,2495,2496],{"class":175}," welcome.html\n",[11,2498,2499],{},"全部加入：",[22,2501,2503],{"className":2057,"code":2502,"language":2059,"meta":27,"style":27},"git add --all\n",[29,2504,2505],{"__ignoreMap":27},[32,2506,2507,2509,2511],{"class":34,"line":35},[32,2508,2126],{"class":2066},[32,2510,2493],{"class":175},[32,2512,2513],{"class":351}," --all\n",[15,2515,2516],{"id":2516},"提交",[11,2518,2519],{},"暫存區 → Git 紀錄。",[22,2521,2523],{"className":2057,"code":2522,"language":2059,"meta":27,"style":27},"git commit -m \"init commit\"\n",[29,2524,2525],{"__ignoreMap":27},[32,2526,2527,2529,2532,2535],{"class":34,"line":35},[32,2528,2126],{"class":2066},[32,2530,2531],{"class":175}," commit",[32,2533,2534],{"class":351}," -m",[32,2536,2537],{"class":175}," \"init commit\"\n",[11,2539,2540,2543],{},[29,2541,2542],{},"-m"," 後面接這次提交的訊息，例如：",[22,2545,2547],{"className":2057,"code":2546,"language":2059,"meta":27,"style":27},"git commit -m \"#34 bug fix\"\n",[29,2548,2549],{"__ignoreMap":27},[32,2550,2551,2553,2555,2557],{"class":34,"line":35},[32,2552,2126],{"class":2066},[32,2554,2531],{"class":175},[32,2556,2534],{"class":351},[32,2558,2559],{"class":175}," \"#34 bug fix\"\n",[11,2561,2562],{},"當時記的基本操作順序：",[22,2564,2567],{"className":2565,"code":2566,"language":426,"meta":27},[424],"git status\n↓\ngit add 檔案\n↓\ngit commit -m \"訊息\"\n",[29,2568,2566],{"__ignoreMap":27},[15,2570,2571],{"id":2571},"查詢歷史紀錄",[22,2573,2575],{"className":2057,"code":2574,"language":2059,"meta":27,"style":27},"git log\n",[29,2576,2577],{"__ignoreMap":27},[32,2578,2579,2581],{"class":34,"line":35},[32,2580,2126],{"class":2066},[32,2582,2583],{"class":175}," log\n",[11,2585,2586],{},"查看提交歷史。",[11,2588,2589],{},"每一筆 commit 都會有自己的 SHA：",[22,2591,2594],{"className":2592,"code":2593,"language":426,"meta":27},[424],"commit b11569e1ef6b1c873aa184350e07e490f78d3f50\n",[29,2595,2593],{"__ignoreMap":27},[11,2597,2598],{},"想看得簡單一點：",[22,2600,2602],{"className":2057,"code":2601,"language":2059,"meta":27,"style":27},"git log --oneline --graph\n",[29,2603,2604],{"__ignoreMap":27},[32,2605,2606,2608,2611,2614],{"class":34,"line":35},[32,2607,2126],{"class":2066},[32,2609,2610],{"class":175}," log",[32,2612,2613],{"class":351}," --oneline",[32,2615,2616],{"class":351}," --graph\n",[151,2618,2619],{"id":2619},"查詢單一檔案紀錄",[22,2621,2623],{"className":2057,"code":2622,"language":2059,"meta":27,"style":27},"git log -p test.html\n",[29,2624,2625],{"__ignoreMap":27},[32,2626,2627,2629,2631,2634],{"class":34,"line":35},[32,2628,2126],{"class":2066},[32,2630,2610],{"class":175},[32,2632,2633],{"class":351}," -p",[32,2635,2636],{"class":175}," test.html\n",[151,2638,2397],{"id":2639},"sourcetree-2",[11,2641,2463],{},[22,2643,2646],{"className":2644,"code":2645,"language":426,"meta":27},[424],"Log Selected\n",[29,2647,2645],{"__ignoreMap":27},[11,2649,2650],{},"可以查看這個檔案的歷史紀錄。",[151,2652,2653],{"id":2653},"查詢作者",[22,2655,2657],{"className":2057,"code":2656,"language":2059,"meta":27,"style":27},"git log --oneline --author=\"XXX\"\n",[29,2658,2659],{"__ignoreMap":27},[32,2660,2661,2663,2665,2667,2670],{"class":34,"line":35},[32,2662,2126],{"class":2066},[32,2664,2610],{"class":175},[32,2666,2613],{"class":351},[32,2668,2669],{"class":351}," --author=",[32,2671,2672],{"class":175},"\"XXX\"\n",[151,2674,2676],{"id":2675},"查詢-commit-訊息","查詢 Commit 訊息",[22,2678,2680],{"className":2057,"code":2679,"language":2059,"meta":27,"style":27},"git log --oneline --grep=\"wtf\"\n",[29,2681,2682],{"__ignoreMap":27},[32,2683,2684,2686,2688,2690,2693],{"class":34,"line":35},[32,2685,2126],{"class":2066},[32,2687,2610],{"class":175},[32,2689,2613],{"class":351},[32,2691,2692],{"class":351}," --grep=",[32,2694,2695],{"class":175},"\"wtf\"\n",[151,2697,2699],{"id":2698},"查詢曾經加入或刪除某段文字的-commit","查詢曾經加入或刪除某段文字的 Commit",[22,2701,2703],{"className":2057,"code":2702,"language":2059,"meta":27,"style":27},"git log -S \"xxx\"\n",[29,2704,2705],{"__ignoreMap":27},[32,2706,2707,2709,2711,2714],{"class":34,"line":35},[32,2708,2126],{"class":2066},[32,2710,2610],{"class":175},[32,2712,2713],{"class":351}," -S",[32,2715,2716],{"class":175}," \"xxx\"\n",[151,2718,2720],{"id":2719},"查詢一段時間內的-commit","查詢一段時間內的 Commit",[11,2722,2723],{},"例如查今天早上的紀錄：",[22,2725,2727],{"className":2057,"code":2726,"language":2059,"meta":27,"style":27},"git log --oneline --since=\"9am\" --until=\"12pm\"\n",[29,2728,2729],{"__ignoreMap":27},[32,2730,2731,2733,2735,2737,2740,2743,2746],{"class":34,"line":35},[32,2732,2126],{"class":2066},[32,2734,2610],{"class":175},[32,2736,2613],{"class":351},[32,2738,2739],{"class":351}," --since=",[32,2741,2742],{"class":175},"\"9am\"",[32,2744,2745],{"class":351}," --until=",[32,2747,2748],{"class":175},"\"12pm\"\n",[15,2750,2751],{"id":2751},"從暫存區移除",[22,2753,2755],{"className":2057,"code":2754,"language":2059,"meta":27,"style":27},"git rm --cached xxx.html\n",[29,2756,2757],{"__ignoreMap":27},[32,2758,2759,2761,2764,2767],{"class":34,"line":35},[32,2760,2126],{"class":2066},[32,2762,2763],{"class":175}," rm",[32,2765,2766],{"class":351}," --cached",[32,2768,2769],{"class":175}," xxx.html\n",[11,2771,2772],{},"不是刪除檔案，而是停止追蹤這個檔案。",[151,2774,2397],{"id":2775},"sourcetree-3",[11,2777,2778],{},"在暫存區對檔案按右鍵：",[22,2780,2783],{"className":2781,"code":2782,"language":426,"meta":27},[424],"Stop Tracking\n",[29,2784,2782],{"__ignoreMap":27},[15,2786,2788],{"id":2787},"修改最後一次-commit","修改最後一次 Commit",[11,2790,2791],{},"如果想把新的檔案合併到上一筆 Git 紀錄：",[22,2793,2795],{"className":2057,"code":2794,"language":2059,"meta":27,"style":27},"touch cat.html\ngit add cat.html\ngit commit --amend\n",[29,2796,2797,2804,2812],{"__ignoreMap":27},[32,2798,2799,2801],{"class":34,"line":35},[32,2800,2157],{"class":2066},[32,2802,2803],{"class":175}," cat.html\n",[32,2805,2806,2808,2810],{"class":34,"line":45},[32,2807,2126],{"class":2066},[32,2809,2493],{"class":175},[32,2811,2803],{"class":175},[32,2813,2814,2816,2818],{"class":34,"line":51},[32,2815,2126],{"class":2066},[32,2817,2531],{"class":175},[32,2819,2820],{"class":351}," --amend\n",[11,2822,2823],{},"進入 Vim 後：",[22,2825,2828],{"className":2826,"code":2827,"language":426,"meta":27},[424],":wq\n",[29,2829,2827],{"__ignoreMap":27},[11,2831,2832],{},"存檔並離開。",[11,2834,2835,2838],{},[29,2836,2837],{},"git commit --amend"," 也可以用來修改最後一次 Commit 的訊息：",[22,2840,2842],{"className":2057,"code":2841,"language":2059,"meta":27,"style":27},"git commit --amend\n",[29,2843,2844],{"__ignoreMap":27},[32,2845,2846,2848,2850],{"class":34,"line":35},[32,2847,2126],{"class":2066},[32,2849,2531],{"class":175},[32,2851,2820],{"class":351},[11,2853,2854],{},"進入編輯畫面後：",[22,2856,2859],{"className":2857,"code":2858,"language":426,"meta":27},[424],"i\n",[29,2860,2858],{"__ignoreMap":27},[11,2862,2863],{},"進入輸入模式，修改訊息後：",[22,2865,2867],{"className":2866,"code":2827,"language":426,"meta":27},[424],[29,2868,2827],{"__ignoreMap":27},[11,2870,2871],{},"存檔離開。",[11,2873,2874],{},"再查看：",[22,2876,2878],{"className":2057,"code":2877,"language":2059,"meta":27,"style":27},"git log --oneline\n",[29,2879,2880],{"__ignoreMap":27},[32,2881,2882,2884,2886],{"class":34,"line":35},[32,2883,2126],{"class":2066},[32,2885,2610],{"class":175},[32,2887,2888],{"class":351}," --oneline\n",[11,2890,2891],{},"當時也有記到一件事：",[2184,2893,2894],{},[11,2895,2896],{},"Commit 經過 amend 後，SHA 值也會跟著改變。",[151,2898,2397],{"id":2899},"sourcetree-4",[11,2901,2902],{},"當時的操作路徑：",[22,2904,2907],{"className":2905,"code":2906,"language":426,"meta":27},[424],"Working Copy\n→ Commit Options\n→ Amend Last Commit\n→ 修改訊息\n→ Commit\n",[29,2908,2906],{"__ignoreMap":27},[15,2910,2911],{"id":2911},"還原檔案",[22,2913,2915],{"className":2057,"code":2914,"language":2059,"meta":27,"style":27},"git checkout test.html\n",[29,2916,2917],{"__ignoreMap":27},[32,2918,2919,2921,2924],{"class":34,"line":35},[32,2920,2126],{"class":2066},[32,2922,2923],{"class":175}," checkout",[32,2925,2636],{"class":175},[11,2927,2928],{},"把尚未提交的檔案變更還原。",[11,2930,2931],{},"全部還原：",[22,2933,2935],{"className":2057,"code":2934,"language":2059,"meta":27,"style":27},"git checkout .\n",[29,2936,2937],{"__ignoreMap":27},[32,2938,2939,2941,2943],{"class":34,"line":35},[32,2940,2126],{"class":2066},[32,2942,2923],{"class":175},[32,2944,2945],{"class":175}," .\n",[11,2947,2948],{},"拿兩個版本之前的檔案內容：",[22,2950,2952],{"className":2057,"code":2951,"language":2059,"meta":27,"style":27},"git checkout HEAD~2 test.html\n",[29,2953,2954],{"__ignoreMap":27},[32,2955,2956,2958,2960,2963],{"class":34,"line":35},[32,2957,2126],{"class":2066},[32,2959,2923],{"class":175},[32,2961,2962],{"class":175}," HEAD~2",[32,2964,2636],{"class":175},[15,2966,2968],{"id":2967},"reset拆掉-commit-重做","Reset：拆掉 Commit 重做",[11,2970,2971],{},"先查看歷史：",[22,2973,2974],{"className":2057,"code":2877,"language":2059,"meta":27,"style":27},[29,2975,2976],{"__ignoreMap":27},[32,2977,2978,2980,2982],{"class":34,"line":35},[32,2979,2126],{"class":2066},[32,2981,2610],{"class":175},[32,2983,2888],{"class":351},[11,2985,328],{},[22,2987,2989],{"className":2057,"code":2988,"language":2059,"meta":27,"style":27},"git reset ae8a3ab^\n",[29,2990,2991],{"__ignoreMap":27},[32,2992,2993,2995,2998],{"class":34,"line":35},[32,2994,2126],{"class":2066},[32,2996,2997],{"class":175}," reset",[32,2999,3000],{"class":175}," ae8a3ab^\n",[11,3002,3003,3006],{},[29,3004,3005],{},"^"," 可以理解成往前一個 Commit。",[11,3008,328],{},[22,3010,3012],{"className":2057,"code":3011,"language":2059,"meta":27,"style":27},"git reset HEAD^\n",[29,3013,3014],{"__ignoreMap":27},[32,3015,3016,3018,3020],{"class":34,"line":35},[32,3017,2126],{"class":2066},[32,3019,2997],{"class":175},[32,3021,3022],{"class":175}," HEAD^\n",[11,3024,3025],{},"往前兩個：",[22,3027,3029],{"className":2057,"code":3028,"language":2059,"meta":27,"style":27},"git reset HEAD~2\n",[29,3030,3031],{"__ignoreMap":27},[32,3032,3033,3035,3037],{"class":34,"line":35},[32,3034,2126],{"class":2066},[32,3036,2997],{"class":175},[32,3038,3039],{"class":175}," HEAD~2\n",[11,3041,3042],{},"當時整理的三種模式：",[151,3044,3046],{"id":3045},"soft","Soft",[22,3048,3050],{"className":2057,"code":3049,"language":2059,"meta":27,"style":27},"git reset --soft 版號\n",[29,3051,3052],{"__ignoreMap":27},[32,3053,3054,3056,3058,3061],{"class":34,"line":35},[32,3055,2126],{"class":2066},[32,3057,2997],{"class":175},[32,3059,3060],{"class":351}," --soft",[32,3062,3063],{"class":175}," 版號\n",[11,3065,3066],{},"拆出來的檔案會保留在暫存區。",[151,3068,3070],{"id":3069},"mixed","Mixed",[22,3072,3074],{"className":2057,"code":3073,"language":2059,"meta":27,"style":27},"git reset --mixed 版號\n",[29,3075,3076],{"__ignoreMap":27},[32,3077,3078,3080,3082,3085],{"class":34,"line":35},[32,3079,2126],{"class":2066},[32,3081,2997],{"class":175},[32,3083,3084],{"class":351}," --mixed",[32,3086,3063],{"class":175},[11,3088,3089],{},"檔案會保留在工作目錄。",[11,3091,3092,3093,3096],{},"這也是 ",[29,3094,3095],{},"git reset"," 預設的模式。",[151,3098,3100],{"id":3099},"hard","Hard",[22,3102,3104],{"className":2057,"code":3103,"language":2059,"meta":27,"style":27},"git reset --hard 版號\n",[29,3105,3106],{"__ignoreMap":27},[32,3107,3108,3110,3112,3115],{"class":34,"line":35},[32,3109,2126],{"class":2066},[32,3111,2997],{"class":175},[32,3113,3114],{"class":351}," --hard",[32,3116,3063],{"class":175},[11,3118,3119],{},"工作目錄的變更也一起丟掉。",[11,3121,3122],{},"這個要特別小心。",[151,3124,3126],{"id":3125},"reflog","Reflog",[22,3128,3130],{"className":2057,"code":3129,"language":2059,"meta":27,"style":27},"git reflog\n",[29,3131,3132],{"__ignoreMap":27},[32,3133,3134,3136],{"class":34,"line":35},[32,3135,2126],{"class":2066},[32,3137,3138],{"class":175}," reflog\n",[11,3140,3141],{},"可以查看 Git 的 HEAD \u002F 分支移動紀錄。",[151,3143,2397],{"id":3144},"sourcetree-5",[11,3146,3147],{},"對某個 Commit 按右鍵：",[22,3149,3152],{"className":3150,"code":3151,"language":426,"meta":27},[424],"Reset master to this commit\n",[29,3153,3151],{"__ignoreMap":27},[11,3155,3156],{},"再選擇：",[22,3158,3161],{"className":3159,"code":3160,"language":426,"meta":27},[424],"Soft\nMixed\nHard\n",[29,3162,3160],{"__ignoreMap":27},[15,3164,3165],{"id":3165},"分支",[11,3167,3168],{},"查看目前分支：",[22,3170,3172],{"className":2057,"code":3171,"language":2059,"meta":27,"style":27},"git branch\n",[29,3173,3174],{"__ignoreMap":27},[32,3175,3176,3178],{"class":34,"line":35},[32,3177,2126],{"class":2066},[32,3179,3180],{"class":175}," branch\n",[11,3182,3183],{},"建立分支：",[22,3185,3187],{"className":2057,"code":3186,"language":2059,"meta":27,"style":27},"git branch xxx\n",[29,3188,3189],{"__ignoreMap":27},[32,3190,3191,3193,3196],{"class":34,"line":35},[32,3192,2126],{"class":2066},[32,3194,3195],{"class":175}," branch",[32,3197,3198],{"class":175}," xxx\n",[11,3200,3201],{},"刪除分支：",[22,3203,3205],{"className":2057,"code":3204,"language":2059,"meta":27,"style":27},"git branch -d xxx\n",[29,3206,3207],{"__ignoreMap":27},[32,3208,3209,3211,3213,3216],{"class":34,"line":35},[32,3210,2126],{"class":2066},[32,3212,3195],{"class":175},[32,3214,3215],{"class":351}," -d",[32,3217,3198],{"class":175},[11,3219,3220],{},"不能刪除目前正在使用的分支，需要先切換到其他分支。",[11,3222,3223],{},"切換分支：",[22,3225,3227],{"className":2057,"code":3226,"language":2059,"meta":27,"style":27},"git checkout xxx\n",[29,3228,3229],{"__ignoreMap":27},[32,3230,3231,3233,3235],{"class":34,"line":35},[32,3232,2126],{"class":2066},[32,3234,2923],{"class":175},[32,3236,3198],{"class":175},[11,3238,3239],{},"建立並直接切換：",[22,3241,3243],{"className":2057,"code":3242,"language":2059,"meta":27,"style":27},"git checkout -b xxx\n",[29,3244,3245],{"__ignoreMap":27},[32,3246,3247,3249,3251,3254],{"class":34,"line":35},[32,3248,2126],{"class":2066},[32,3250,2923],{"class":175},[32,3252,3253],{"class":351}," -b",[32,3255,3198],{"class":175},[151,3257,2397],{"id":3258},"sourcetree-6",[11,3260,3183],{},[22,3262,3265],{"className":3263,"code":3264,"language":426,"meta":27},[424],"Branch\n",[29,3266,3264],{"__ignoreMap":27},[11,3268,3269],{},"如果勾選：",[22,3271,3274],{"className":3272,"code":3273,"language":426,"meta":27},[424],"Checkout New Branch\n",[29,3275,3273],{"__ignoreMap":27},[11,3277,3278],{},"建立完成後會直接切換過去。",[11,3280,3281],{},"切換分支時，也可以直接對分支點兩下。",[11,3283,3201],{},[22,3285,3288],{"className":3286,"code":3287,"language":426,"meta":27},[424],"右鍵分支\n→ Delete xxx\n",[29,3289,3287],{"__ignoreMap":27},[15,3291,3292],{"id":3292},"合併分支",[11,3294,3295],{},"先切換回主線：",[22,3297,3299],{"className":2057,"code":3298,"language":2059,"meta":27,"style":27},"git checkout master\n",[29,3300,3301],{"__ignoreMap":27},[32,3302,3303,3305,3307],{"class":34,"line":35},[32,3304,2126],{"class":2066},[32,3306,2923],{"class":175},[32,3308,3309],{"class":175}," master\n",[11,3311,3312],{},"再把其他分支合併進來：",[22,3314,3316],{"className":2057,"code":3315,"language":2059,"meta":27,"style":27},"git merge xxx\n",[29,3317,3318],{"__ignoreMap":27},[32,3319,3320,3322,3325],{"class":34,"line":35},[32,3321,2126],{"class":2066},[32,3323,3324],{"class":175}," merge",[32,3326,3198],{"class":175},[151,3328,2397],{"id":3329},"sourcetree-7",[11,3331,3332],{},"對想合併的分支按右鍵：",[22,3334,3337],{"className":3335,"code":3336,"language":426,"meta":27},[424],"Merge xxx into current branch\n",[29,3338,3336],{"__ignoreMap":27},[15,3340,3342],{"id":3341},"不使用-fast-forward-合併","不使用 Fast-forward 合併",[11,3344,3345],{},"當時把這個畫面記成「小耳朵」。",[22,3347,3349],{"className":2057,"code":3348,"language":2059,"meta":27,"style":27},"git merge cat --no-ff\n",[29,3350,3351],{"__ignoreMap":27},[32,3352,3353,3355,3357,3360],{"class":34,"line":35},[32,3354,2126],{"class":2066},[32,3356,3324],{"class":175},[32,3358,3359],{"class":175}," cat",[32,3361,3362],{"class":351}," --no-ff\n",[11,3364,3365],{},"會保留一筆 Merge Commit。",[11,3367,3368],{},"如果進入 Vim：",[22,3370,3372],{"className":3371,"code":2827,"language":426,"meta":27},[424],[29,3373,2827],{"__ignoreMap":27},[11,3375,2871],{},[15,3377,3379],{"id":3378},"clone-專案","Clone 專案",[11,3381,3382],{},"把專案下載到本機：",[22,3384,3386],{"className":2057,"code":3385,"language":2059,"meta":27,"style":27},"git clone xxxxxxxxxxxxx\n",[29,3387,3388],{"__ignoreMap":27},[32,3389,3390,3392,3395],{"class":34,"line":35},[32,3391,2126],{"class":2066},[32,3393,3394],{"class":175}," clone",[32,3396,3397],{"class":175}," xxxxxxxxxxxxx\n",[151,3399,2397],{"id":3400},"sourcetree-8",[22,3402,3405],{"className":3403,"code":3404,"language":426,"meta":27},[424],"File\n→ New\n→ Clone Repository\n→ 貼上 Repository 資訊\n",[29,3406,3404],{"__ignoreMap":27},[15,3408,3410],{"id":3409},"git-config","Git Config",[11,3412,3413],{},"查看目前設定：",[22,3415,3417],{"className":2057,"code":3416,"language":2059,"meta":27,"style":27},"git config --list\n",[29,3418,3419],{"__ignoreMap":27},[32,3420,3421,3423,3426],{"class":34,"line":35},[32,3422,2126],{"class":2066},[32,3424,3425],{"class":175}," config",[32,3427,3428],{"class":351}," --list\n",[151,3430,3431],{"id":3431},"全域設定",[22,3433,3435],{"className":2057,"code":3434,"language":2059,"meta":27,"style":27},"git config --global user.name \"XXX\"\ngit config --global user.email \"XXX@xxx.xx\"\n",[29,3436,3437,3452],{"__ignoreMap":27},[32,3438,3439,3441,3443,3446,3449],{"class":34,"line":35},[32,3440,2126],{"class":2066},[32,3442,3425],{"class":175},[32,3444,3445],{"class":351}," --global",[32,3447,3448],{"class":175}," user.name",[32,3450,3451],{"class":175}," \"XXX\"\n",[32,3453,3454,3456,3458,3460,3463],{"class":34,"line":45},[32,3455,2126],{"class":2066},[32,3457,3425],{"class":175},[32,3459,3445],{"class":351},[32,3461,3462],{"class":175}," user.email",[32,3464,3465],{"class":175}," \"XXX@xxx.xx\"\n",[151,3467,3468],{"id":3468},"專案專屬設定",[22,3470,3472],{"className":2057,"code":3471,"language":2059,"meta":27,"style":27},"git config --local user.name \"XXX\"\ngit config --local user.email \"XXX@xxx.xx\"\n",[29,3473,3474,3487],{"__ignoreMap":27},[32,3475,3476,3478,3480,3483,3485],{"class":34,"line":35},[32,3477,2126],{"class":2066},[32,3479,3425],{"class":175},[32,3481,3482],{"class":351}," --local",[32,3484,3448],{"class":175},[32,3486,3451],{"class":175},[32,3488,3489,3491,3493,3495,3497],{"class":34,"line":45},[32,3490,2126],{"class":2066},[32,3492,3425],{"class":175},[32,3494,3482],{"class":351},[32,3496,3462],{"class":175},[32,3498,3465],{"class":175},[151,3500,2397],{"id":3501},"sourcetree-9",[11,3503,3504],{},"當時的設定位置：",[22,3506,3509],{"className":3507,"code":3508,"language":426,"meta":27},[424],"Repository Settings\n→ User Information\n",[29,3510,3508],{"__ignoreMap":27},[15,3512,3514],{"id":3513},"修改-git-編輯器","修改 Git 編輯器",[11,3516,3517],{},"當時 Git 預設會進 Vim，也可以換成其他編輯器。",[11,3519,328],{},[22,3521,3523],{"className":2057,"code":3522,"language":2059,"meta":27,"style":27},"git config --global core.editor emacs\n",[29,3524,3525],{"__ignoreMap":27},[32,3526,3527,3529,3531,3533,3536],{"class":34,"line":35},[32,3528,2126],{"class":2066},[32,3530,3425],{"class":175},[32,3532,3445],{"class":351},[32,3534,3535],{"class":175}," core.editor",[32,3537,3538],{"class":175}," emacs\n",[15,3540,3542],{"id":3541},"git-alias","Git Alias",[11,3544,3545],{},"可以幫常用指令設定縮寫。",[22,3547,3549],{"className":2057,"code":3548,"language":2059,"meta":27,"style":27},"git config --global alias.co checkout\n",[29,3550,3551],{"__ignoreMap":27},[32,3552,3553,3555,3557,3559,3562],{"class":34,"line":35},[32,3554,2126],{"class":2066},[32,3556,3425],{"class":175},[32,3558,3445],{"class":351},[32,3560,3561],{"class":175}," alias.co",[32,3563,3564],{"class":175}," checkout\n",[11,3566,3567],{},"之後：",[22,3569,3571],{"className":2057,"code":3570,"language":2059,"meta":27,"style":27},"git co\n",[29,3572,3573],{"__ignoreMap":27},[32,3574,3575,3577],{"class":34,"line":35},[32,3576,2126],{"class":2066},[32,3578,3579],{"class":175}," co\n",[11,3581,3582],{},"等同：",[22,3584,3586],{"className":2057,"code":3585,"language":2059,"meta":27,"style":27},"git checkout\n",[29,3587,3588],{"__ignoreMap":27},[32,3589,3590,3592],{"class":34,"line":35},[32,3591,2126],{"class":2066},[32,3593,3564],{"class":175},[11,3595,3596],{},"其他：",[22,3598,3600],{"className":2057,"code":3599,"language":2059,"meta":27,"style":27},"git config --global alias.br branch\ngit config --global alias.st status\ngit config --global alias.l \"log --oneline --graph\"\n",[29,3601,3602,3615,3628],{"__ignoreMap":27},[32,3603,3604,3606,3608,3610,3613],{"class":34,"line":35},[32,3605,2126],{"class":2066},[32,3607,3425],{"class":175},[32,3609,3445],{"class":351},[32,3611,3612],{"class":175}," alias.br",[32,3614,3180],{"class":175},[32,3616,3617,3619,3621,3623,3626],{"class":34,"line":45},[32,3618,2126],{"class":2066},[32,3620,3425],{"class":175},[32,3622,3445],{"class":351},[32,3624,3625],{"class":175}," alias.st",[32,3627,2424],{"class":175},[32,3629,3630,3632,3634,3636,3639],{"class":34,"line":51},[32,3631,2126],{"class":2066},[32,3633,3425],{"class":175},[32,3635,3445],{"class":351},[32,3637,3638],{"class":175}," alias.l",[32,3640,3641],{"class":175}," \"log --oneline --graph\"\n",[11,3643,3644],{},"之後就可以使用：",[22,3646,3648],{"className":2057,"code":3647,"language":2059,"meta":27,"style":27},"git br\ngit st\ngit l\n",[29,3649,3650,3657,3664],{"__ignoreMap":27},[32,3651,3652,3654],{"class":34,"line":35},[32,3653,2126],{"class":2066},[32,3655,3656],{"class":175}," br\n",[32,3658,3659,3661],{"class":34,"line":45},[32,3660,2126],{"class":2066},[32,3662,3663],{"class":175}," st\n",[32,3665,3666,3668],{"class":34,"line":51},[32,3667,2126],{"class":2066},[32,3669,3670],{"class":175}," l\n",[15,3672,3674],{"id":3673},"vim-基本操作","Vim 基本操作",[11,3676,3677],{},"當時順便記了一些 Vim 操作。",[22,3679,3682],{"className":3680,"code":3681,"language":426,"meta":27},[424],"i = insert\na = append\no = new line\n",[29,3683,3681],{"__ignoreMap":27},[11,3685,3686],{},"存檔：",[22,3688,3691],{"className":3689,"code":3690,"language":426,"meta":27},[424],":w\n",[29,3692,3690],{"__ignoreMap":27},[11,3694,3695],{},"離開：",[22,3697,3700],{"className":3698,"code":3699,"language":426,"meta":27},[424],":q\n",[29,3701,3699],{"__ignoreMap":27},[11,3703,3704],{},"存檔並離開：",[22,3706,3708],{"className":3707,"code":2827,"language":426,"meta":27},[424],[29,3709,2827],{"__ignoreMap":27},[15,3711,3713],{"id":3712},"windows-指令筆記","Windows 指令筆記",[11,3715,3716],{},"當時也一起記了一些 Windows 終端機常用指令：",[22,3718,3721],{"className":3719,"code":3720,"language":426,"meta":27},[424],"cd        切換目錄\ndir       列出目前檔案\nmkdir     建立新的資料夾\ncopy      複製檔案\nmove      移動檔案\ndel       刪除檔案\ncls       清除畫面內容\ncd ..     回到上一層\n",[29,3722,3720],{"__ignoreMap":27},[11,3724,3725],{},"另外在 Unix \u002F Git Bash 類型的終端機中：",[22,3727,3729],{"className":2057,"code":3728,"language":2059,"meta":27,"style":27},"cd ~\n",[29,3730,3731],{"__ignoreMap":27},[32,3732,3733,3736],{"class":34,"line":35},[32,3734,3735],{"class":351},"cd",[32,3737,3738],{"class":175}," ~\n",[11,3740,3741],{},"可以回到目前使用者的 Home 目錄。",[15,3743,2004],{"id":2003},[11,3745,3746,3747,3750,3751,3754],{},"這篇是 2018 年學 Git 時留下來的筆記，所以保留了當時使用 ",[29,3748,3749],{},"git checkout","、",[29,3752,3753],{},"master","、SourceTree 和 Vim 的操作方式。",[11,3756,3757],{},"現在回頭看，有幾個地方需要特別補充：",[151,3759,3761,3764],{"id":3760},"checkout-現在有更明確的替代指令",[29,3762,3763],{},"checkout"," 現在有更明確的替代指令",[11,3766,3767,3768,3771,3772,3775],{},"Git 2.23 之後新增了 ",[29,3769,3770],{},"git switch"," 和 ",[29,3773,3774],{},"git restore","。",[11,3777,3778],{},"以前切換分支：",[22,3780,3781],{"className":2057,"code":3226,"language":2059,"meta":27,"style":27},[29,3782,3783],{"__ignoreMap":27},[32,3784,3785,3787,3789],{"class":34,"line":35},[32,3786,2126],{"class":2066},[32,3788,2923],{"class":175},[32,3790,3198],{"class":175},[11,3792,3793],{},"現在也可以寫：",[22,3795,3797],{"className":2057,"code":3796,"language":2059,"meta":27,"style":27},"git switch xxx\n",[29,3798,3799],{"__ignoreMap":27},[32,3800,3801,3803,3806],{"class":34,"line":35},[32,3802,2126],{"class":2066},[32,3804,3805],{"class":175}," switch",[32,3807,3198],{"class":175},[11,3809,3810],{},"以前還原工作目錄的檔案：",[22,3812,3813],{"className":2057,"code":2914,"language":2059,"meta":27,"style":27},[29,3814,3815],{"__ignoreMap":27},[32,3816,3817,3819,3821],{"class":34,"line":35},[32,3818,2126],{"class":2066},[32,3820,2923],{"class":175},[32,3822,2636],{"class":175},[11,3824,3825],{},"現在也可以使用：",[22,3827,3829],{"className":2057,"code":3828,"language":2059,"meta":27,"style":27},"git restore test.html\n",[29,3830,3831],{"__ignoreMap":27},[32,3832,3833,3835,3838],{"class":34,"line":35},[32,3834,2126],{"class":2066},[32,3836,3837],{"class":175}," restore",[32,3839,2636],{"class":175},[11,3841,3842,3843,3845],{},"原本的 ",[29,3844,3749],{}," 並沒有不能用，只是現在多了語意比較清楚的寫法。",[151,3847,3849,3850],{"id":3848},"主分支名稱不一定是-master","主分支名稱不一定是 ",[29,3851,3753],{},[11,3853,3854],{},"這篇當年使用：",[22,3856,3857],{"className":2057,"code":3298,"language":2059,"meta":27,"style":27},[29,3858,3859],{"__ignoreMap":27},[32,3860,3861,3863,3865],{"class":34,"line":35},[32,3862,2126],{"class":2066},[32,3864,2923],{"class":175},[32,3866,3309],{"class":175},[11,3868,3869],{},"現在很多新的 Repository 預設主分支會叫做：",[22,3871,3874],{"className":3872,"code":3873,"language":426,"meta":27},[424],"main\n",[29,3875,3873],{"__ignoreMap":27},[11,3877,3878],{},"實際名稱還是要看專案本身。",[151,3880,3882,3883],{"id":3881},"刪除-git","刪除 ",[29,3884,3885],{},".git",[22,3887,3888],{"className":2057,"code":2354,"language":2059,"meta":27,"style":27},[29,3889,3890],{"__ignoreMap":27},[32,3891,3892,3894,3896],{"class":34,"line":35},[32,3893,2324],{"class":2066},[32,3895,2363],{"class":351},[32,3897,2366],{"class":175},[11,3899,3900],{},"會刪除目前目錄的 Git Repository 資訊，但不會把工作目錄裡的程式碼一起刪掉。",[11,3902,3903],{},"如果專案已經有推送到 GitHub 或其他遠端 Repository，歷史紀錄也不一定真的就此消失。",[11,3905,3906],{},"不過這仍然是一個要非常小心使用的指令。",[151,3908,3910],{"id":3909},"git-reset-hard",[29,3911,3912],{},"git reset --hard",[11,3914,3915,3916,3919,3920,3923],{},"這篇以前把 ",[29,3917,3918],{},"git reflog"," 記成誤用 ",[29,3921,3922],{},"--hard"," 後的救援方式，但它並不是所有情況都能救。",[11,3925,3926,3927,3929],{},"如果丟掉的是曾經 Commit 過、Git 還保有紀錄的內容，可能可以透過 ",[29,3928,3125],{}," 找回。",[11,3931,3932,3933,3936,3937,3939],{},"但如果只是工作目錄裡從來沒有 Commit 過的修改，被 ",[29,3934,3935],{},"reset --hard"," 丟掉之後，就不能把 ",[29,3938,3125],{}," 當成一定救得回來的方法。",[11,3941,3942],{},"這篇其他內容就先保留當年的學習紀錄。",[368,3944,3945],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}",{"title":27,"searchDepth":51,"depth":51,"links":3947},[3948,3953,3956,3957,3960,3961,3962,3970,3973,3976,3977,3984,3987,3990,3991,3994,3999,4000,4001,4002,4003],{"id":2054,"depth":45,"text":2054,"children":3949},[3950,3951,3952],{"id":2147,"depth":51,"text":2147},{"id":2195,"depth":51,"text":2195},{"id":2314,"depth":51,"text":2314},{"id":2377,"depth":45,"text":2378,"children":3954},[3955],{"id":2396,"depth":51,"text":2397},{"id":2412,"depth":45,"text":2412},{"id":2439,"depth":45,"text":2439,"children":3958},[3959],{"id":2460,"depth":51,"text":2397},{"id":2475,"depth":45,"text":2475},{"id":2516,"depth":45,"text":2516},{"id":2571,"depth":45,"text":2571,"children":3963},[3964,3965,3966,3967,3968,3969],{"id":2619,"depth":51,"text":2619},{"id":2639,"depth":51,"text":2397},{"id":2653,"depth":51,"text":2653},{"id":2675,"depth":51,"text":2676},{"id":2698,"depth":51,"text":2699},{"id":2719,"depth":51,"text":2720},{"id":2751,"depth":45,"text":2751,"children":3971},[3972],{"id":2775,"depth":51,"text":2397},{"id":2787,"depth":45,"text":2788,"children":3974},[3975],{"id":2899,"depth":51,"text":2397},{"id":2911,"depth":45,"text":2911},{"id":2967,"depth":45,"text":2968,"children":3978},[3979,3980,3981,3982,3983],{"id":3045,"depth":51,"text":3046},{"id":3069,"depth":51,"text":3070},{"id":3099,"depth":51,"text":3100},{"id":3125,"depth":51,"text":3126},{"id":3144,"depth":51,"text":2397},{"id":3165,"depth":45,"text":3165,"children":3985},[3986],{"id":3258,"depth":51,"text":2397},{"id":3292,"depth":45,"text":3292,"children":3988},[3989],{"id":3329,"depth":51,"text":2397},{"id":3341,"depth":45,"text":3342},{"id":3378,"depth":45,"text":3379,"children":3992},[3993],{"id":3400,"depth":51,"text":2397},{"id":3409,"depth":45,"text":3410,"children":3995},[3996,3997,3998],{"id":3431,"depth":51,"text":3431},{"id":3468,"depth":51,"text":3468},{"id":3501,"depth":51,"text":2397},{"id":3513,"depth":45,"text":3514},{"id":3541,"depth":45,"text":3542},{"id":3673,"depth":45,"text":3674},{"id":3712,"depth":45,"text":3713},{"id":2003,"depth":45,"text":2004,"children":4004},[4005,4007,4009,4011],{"id":3760,"depth":51,"text":4006},"checkout 現在有更明確的替代指令",{"id":3848,"depth":51,"text":4008},"主分支名稱不一定是 master",{"id":3881,"depth":51,"text":4010},"刪除 .git",{"id":3909,"depth":51,"text":3912},"notes","2018 年整理的 Git 學習筆記，包含基本終端機指令、Git 操作、分支、reset、SourceTree、Vim 與一些常用設定。",{},"\u002Fposts\u002Fgit-commands-cheatsheet","2018-01-05",[],{"title":2046,"description":4013},"posts\u002F20180105.git-commands-cheatsheet",[4021,4022],"Git","版本控制","uJ6Iyc7HRET6uc4zL9_isq3AGn9CO29Q9ojLjegfmFs",{"id":4025,"title":4026,"body":4027,"category":378,"description":4564,"draft":380,"extension":381,"image":382,"meta":4565,"navigation":102,"path":4566,"publishedAt":4567,"relatedExperiments":4568,"seo":4569,"stem":4570,"tags":4571,"updatedAt":392,"__hash__":4573},"posts\u002Fposts\u002F20180108.vue2-password-strength.md","用 Vue 寫一個密碼強度計",{"type":8,"value":4028,"toc":4558},[4029,4032,4036,4110,4114,4517,4519,4534,4537,4555],[11,4030,4031],{},"這篇記錄用 Vue 做一個簡單的密碼強度判斷。",[15,4033,4035],{"id":4034},"html","HTML",[22,4037,4040],{"className":4038,"code":4039,"language":4034,"meta":27,"style":27},"language-html shiki shiki-themes github-light github-dark-default","\u003Cdiv id=\"app\">\n  \u003Cinput type=\"password\" v-model=\"password\">\n  \u003Cp>{{ strength }}\u003C\u002Fp>\n\u003C\u002Fdiv>\n",[29,4041,4042,4063,4088,4101],{"__ignoreMap":27},[32,4043,4044,4047,4051,4055,4057,4060],{"class":34,"line":35},[32,4045,4046],{"class":41},"\u003C",[32,4048,4050],{"class":4049},"sXQ1o","div",[32,4052,4054],{"class":4053},"syv4q"," id",[32,4056,172],{"class":41},[32,4058,4059],{"class":175},"\"app\"",[32,4061,4062],{"class":41},">\n",[32,4064,4065,4068,4071,4074,4076,4079,4082,4084,4086],{"class":34,"line":45},[32,4066,4067],{"class":41},"  \u003C",[32,4069,4070],{"class":4049},"input",[32,4072,4073],{"class":4053}," type",[32,4075,172],{"class":41},[32,4077,4078],{"class":175},"\"password\"",[32,4080,4081],{"class":4053}," v-model",[32,4083,172],{"class":41},[32,4085,4078],{"class":175},[32,4087,4062],{"class":41},[32,4089,4090,4092,4094,4097,4099],{"class":34,"line":51},[32,4091,4067],{"class":41},[32,4093,11],{"class":4049},[32,4095,4096],{"class":41},">{{ strength }}\u003C\u002F",[32,4098,11],{"class":4049},[32,4100,4062],{"class":41},[32,4102,4103,4106,4108],{"class":34,"line":90},[32,4104,4105],{"class":41},"\u003C\u002F",[32,4107,4050],{"class":4049},[32,4109,4062],{"class":41},[15,4111,4113],{"id":4112},"vue","Vue",[22,4115,4117],{"className":4038,"code":4116,"language":4034,"meta":27,"style":27},"\u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fvue@2\">\u003C\u002Fscript>\n\n\u003Cscript>\n  const vm = new Vue({\n    el: '#app',\n\n    data: {\n      password: '',\n    },\n\n    computed: {\n      strength() {\n        let score = this.password.length;\n\n        \u002F\u002F 包含大寫 A-Z\n        if (\u002F[A-Z]\u002F.test(this.password)) score *= 1.25;\n\n        \u002F\u002F 包含小寫 a-z\n        if (\u002F[a-z]\u002F.test(this.password)) score *= 1.25;\n\n        \u002F\u002F 包含數字 0-9\n        if (\u002F[0-9]\u002F.test(this.password)) score *= 1.25;\n\n        \u002F\u002F 包含不是大寫 A-Z、小寫 a-z、數字 0-9 的字元\n        if (\u002F[^A-Za-z0-9]\u002F.test(this.password)) score *= 1.25;\n\n        \u002F\u002F 密碼夠長夠完美\n        if (score > 40) return 'Perfect';\n\n        if (score > 20) return 'Great';\n\n        if (score > 10) return 'Good';\n\n        return 'weak';\n      },\n    },\n  });\n\u003C\u002Fscript>\n",[29,4118,4119,4141,4145,4153,4171,4181,4185,4190,4200,4205,4209,4214,4222,4242,4246,4251,4284,4288,4293,4322,4326,4331,4360,4364,4369,4403,4407,4412,4434,4438,4458,4462,4482,4486,4496,4501,4505,4509],{"__ignoreMap":27},[32,4120,4121,4123,4126,4129,4131,4134,4137,4139],{"class":34,"line":35},[32,4122,4046],{"class":41},[32,4124,4125],{"class":4049},"script",[32,4127,4128],{"class":4053}," src",[32,4130,172],{"class":41},[32,4132,4133],{"class":175},"\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fvue@2\"",[32,4135,4136],{"class":41},">\u003C\u002F",[32,4138,4125],{"class":4049},[32,4140,4062],{"class":41},[32,4142,4143],{"class":34,"line":45},[32,4144,103],{"emptyLinePlaceholder":102},[32,4146,4147,4149,4151],{"class":34,"line":51},[32,4148,4046],{"class":41},[32,4150,4125],{"class":4049},[32,4152,4062],{"class":41},[32,4154,4155,4158,4161,4163,4166,4169],{"class":34,"line":90},[32,4156,4157],{"class":38},"  const",[32,4159,4160],{"class":351}," vm",[32,4162,894],{"class":38},[32,4164,4165],{"class":38}," new",[32,4167,4168],{"class":217}," Vue",[32,4170,1143],{"class":41},[32,4172,4173,4176,4179],{"class":34,"line":99},[32,4174,4175],{"class":41},"    el: ",[32,4177,4178],{"class":175},"'#app'",[32,4180,547],{"class":41},[32,4182,4183],{"class":34,"line":106},[32,4184,103],{"emptyLinePlaceholder":102},[32,4186,4187],{"class":34,"line":114},[32,4188,4189],{"class":41},"    data: {\n",[32,4191,4192,4195,4198],{"class":34,"line":120},[32,4193,4194],{"class":41},"      password: ",[32,4196,4197],{"class":175},"''",[32,4199,547],{"class":41},[32,4201,4202],{"class":34,"line":127},[32,4203,4204],{"class":41},"    },\n",[32,4206,4207],{"class":34,"line":132},[32,4208,103],{"emptyLinePlaceholder":102},[32,4210,4211],{"class":34,"line":141},[32,4212,4213],{"class":41},"    computed: {\n",[32,4215,4216,4219],{"class":34,"line":147},[32,4217,4218],{"class":217},"      strength",[32,4220,4221],{"class":41},"() {\n",[32,4223,4224,4227,4230,4232,4235,4238,4240],{"class":34,"line":275},[32,4225,4226],{"class":38},"        let",[32,4228,4229],{"class":41}," score ",[32,4231,172],{"class":38},[32,4233,4234],{"class":351}," this",[32,4236,4237],{"class":41},".password.",[32,4239,991],{"class":351},[32,4241,96],{"class":41},[32,4243,4244],{"class":34,"line":282},[32,4245,103],{"emptyLinePlaceholder":102},[32,4247,4248],{"class":34,"line":295},[32,4249,4250],{"class":608},"        \u002F\u002F 包含大寫 A-Z\n",[32,4252,4253,4256,4258,4260,4263,4265,4267,4269,4271,4273,4276,4279,4282],{"class":34,"line":605},[32,4254,4255],{"class":38},"        if",[32,4257,900],{"class":41},[32,4259,1275],{"class":175},[32,4261,4262],{"class":351},"[A-Z]",[32,4264,1275],{"class":175},[32,4266,1278],{"class":41},[32,4268,1281],{"class":217},[32,4270,477],{"class":41},[32,4272,1083],{"class":351},[32,4274,4275],{"class":41},".password)) score ",[32,4277,4278],{"class":38},"*=",[32,4280,4281],{"class":351}," 1.25",[32,4283,96],{"class":41},[32,4285,4286],{"class":34,"line":612},[32,4287,103],{"emptyLinePlaceholder":102},[32,4289,4290],{"class":34,"line":617},[32,4291,4292],{"class":608},"        \u002F\u002F 包含小寫 a-z\n",[32,4294,4295,4297,4299,4301,4304,4306,4308,4310,4312,4314,4316,4318,4320],{"class":34,"line":644},[32,4296,4255],{"class":38},[32,4298,900],{"class":41},[32,4300,1275],{"class":175},[32,4302,4303],{"class":351},"[a-z]",[32,4305,1275],{"class":175},[32,4307,1278],{"class":41},[32,4309,1281],{"class":217},[32,4311,477],{"class":41},[32,4313,1083],{"class":351},[32,4315,4275],{"class":41},[32,4317,4278],{"class":38},[32,4319,4281],{"class":351},[32,4321,96],{"class":41},[32,4323,4324],{"class":34,"line":649},[32,4325,103],{"emptyLinePlaceholder":102},[32,4327,4328],{"class":34,"line":671},[32,4329,4330],{"class":608},"        \u002F\u002F 包含數字 0-9\n",[32,4332,4333,4335,4337,4339,4342,4344,4346,4348,4350,4352,4354,4356,4358],{"class":34,"line":690},[32,4334,4255],{"class":38},[32,4336,900],{"class":41},[32,4338,1275],{"class":175},[32,4340,4341],{"class":351},"[0-9]",[32,4343,1275],{"class":175},[32,4345,1278],{"class":41},[32,4347,1281],{"class":217},[32,4349,477],{"class":41},[32,4351,1083],{"class":351},[32,4353,4275],{"class":41},[32,4355,4278],{"class":38},[32,4357,4281],{"class":351},[32,4359,96],{"class":41},[32,4361,4362],{"class":34,"line":696},[32,4363,103],{"emptyLinePlaceholder":102},[32,4365,4366],{"class":34,"line":706},[32,4367,4368],{"class":608},"        \u002F\u002F 包含不是大寫 A-Z、小寫 a-z、數字 0-9 的字元\n",[32,4370,4371,4373,4375,4377,4380,4382,4385,4387,4389,4391,4393,4395,4397,4399,4401],{"class":34,"line":721},[32,4372,4255],{"class":38},[32,4374,900],{"class":41},[32,4376,1275],{"class":175},[32,4378,4379],{"class":351},"[",[32,4381,3005],{"class":38},[32,4383,4384],{"class":351},"A-Za-z0-9]",[32,4386,1275],{"class":175},[32,4388,1278],{"class":41},[32,4390,1281],{"class":217},[32,4392,477],{"class":41},[32,4394,1083],{"class":351},[32,4396,4275],{"class":41},[32,4398,4278],{"class":38},[32,4400,4281],{"class":351},[32,4402,96],{"class":41},[32,4404,4405],{"class":34,"line":728},[32,4406,103],{"emptyLinePlaceholder":102},[32,4408,4409],{"class":34,"line":737},[32,4410,4411],{"class":608},"        \u002F\u002F 密碼夠長夠完美\n",[32,4413,4414,4416,4419,4421,4424,4426,4429,4432],{"class":34,"line":742},[32,4415,4255],{"class":38},[32,4417,4418],{"class":41}," (score ",[32,4420,1615],{"class":38},[32,4422,4423],{"class":351}," 40",[32,4425,483],{"class":41},[32,4427,4428],{"class":38},"return",[32,4430,4431],{"class":175}," 'Perfect'",[32,4433,96],{"class":41},[32,4435,4436],{"class":34,"line":747},[32,4437,103],{"emptyLinePlaceholder":102},[32,4439,4440,4442,4444,4446,4449,4451,4453,4456],{"class":34,"line":752},[32,4441,4255],{"class":38},[32,4443,4418],{"class":41},[32,4445,1615],{"class":38},[32,4447,4448],{"class":351}," 20",[32,4450,483],{"class":41},[32,4452,4428],{"class":38},[32,4454,4455],{"class":175}," 'Great'",[32,4457,96],{"class":41},[32,4459,4460],{"class":34,"line":773},[32,4461,103],{"emptyLinePlaceholder":102},[32,4463,4464,4466,4468,4470,4473,4475,4477,4480],{"class":34,"line":789},[32,4465,4255],{"class":38},[32,4467,4418],{"class":41},[32,4469,1615],{"class":38},[32,4471,4472],{"class":351}," 10",[32,4474,483],{"class":41},[32,4476,4428],{"class":38},[32,4478,4479],{"class":175}," 'Good'",[32,4481,96],{"class":41},[32,4483,4484],{"class":34,"line":795},[32,4485,103],{"emptyLinePlaceholder":102},[32,4487,4488,4491,4494],{"class":34,"line":800},[32,4489,4490],{"class":38},"        return",[32,4492,4493],{"class":175}," 'weak'",[32,4495,96],{"class":41},[32,4497,4498],{"class":34,"line":816},[32,4499,4500],{"class":41},"      },\n",[32,4502,4503],{"class":34,"line":824},[32,4504,4204],{"class":41},[32,4506,4507],{"class":34,"line":833},[32,4508,693],{"class":41},[32,4510,4511,4513,4515],{"class":34,"line":842},[32,4512,4105],{"class":41},[32,4514,4125],{"class":4049},[32,4516,4062],{"class":41},[15,4518,2004],{"id":2003},[11,4520,4521,4522,4525,4526,4529,4530,4533],{},"這篇是 2018 年留下來的 Vue 練習，當時是直接透過 CDN 引入 Vue 2，再使用 ",[29,4523,4524],{},"new Vue()"," 搭配 ",[29,4527,4528],{},"el"," 掛載到頁面上。\n現在 Vue 專案的寫法已經和當年不同，Vue 3 也改成使用 ",[29,4531,4532],{},"createApp()"," 建立應用程式。\n另外，這裡的密碼強度計分方式只是當時練習使用的簡單判斷，並不適合直接作為正式服務的密碼安全標準。\n這篇就保留當年的寫法，作為以前的技術紀錄。",[15,4535,4536],{"id":4536},"參考資料",[4538,4539,4540,4548],"ul",{},[4541,4542,4543],"li",{},[412,4544,4547],{"href":4545,"rel":4546},"https:\u002F\u002Fv2.vuejs.org\u002Fv2\u002Fguide\u002F",[416],"Vue 2 官方文件（封存版）",[4541,4549,4550],{},[412,4551,4554],{"href":4552,"rel":4553},"https:\u002F\u002Fv2.vuejs.org\u002Fv2\u002Fguide\u002Fcomputed.html",[416],"Vue 2 computed 屬性",[368,4556,4557],{},"html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}",{"title":27,"searchDepth":51,"depth":51,"links":4559},[4560,4561,4562,4563],{"id":4034,"depth":45,"text":4035},{"id":4112,"depth":45,"text":4113},{"id":2003,"depth":45,"text":2004},{"id":4536,"depth":45,"text":4536},"使用 Vue 的 computed 製作一個簡單的密碼強度判斷。",{},"\u002Fposts\u002Fvue2-password-strength","2018-01-08",[],{"title":4026,"description":4564},"posts\u002F20180108.vue2-password-strength",[4113,390,4572],"表單驗證","IxRQGjJZoHSSvXZgZiycMAIsFzwL7N7YT7gQtY3ihXI",{"id":4575,"title":4576,"body":4577,"category":378,"description":5388,"draft":380,"extension":381,"image":382,"meta":5389,"navigation":102,"path":5390,"publishedAt":5391,"relatedExperiments":5392,"seo":5393,"stem":5394,"tags":5395,"updatedAt":392,"__hash__":5397},"posts\u002Fposts\u002F20180813.vue-cli3-project-setup.md","Vue CLI 3.0 安裝與建立專案筆記",{"type":8,"value":4578,"toc":5355},[4579,4582,4586,4590,4593,4606,4609,4613,4616,4635,4639,4657,4661,4672,4680,4683,4695,4698,4701,4704,4707,4710,4713,4716,4719,4726,4729,4732,4756,4759,4762,4765,4773,4776,4779,4785,4788,4803,4806,4810,4813,4819,4822,4825,4831,4834,4837,4860,4863,4867,4870,4873,4879,4882,4893,4896,4902,4905,4908,4914,4917,4920,4923,4929,4932,4934,4940,4946,4949,4952,4965,4968,4971,4984,4987,4990,4994,4997,5000,5006,5009,5012,5015,5018,5022,5029,5120,5127,5130,5143,5146,5149,5155,5158,5175,5178,5210,5213,5220,5226,5229,5235,5241,5293,5299,5303,5306,5320,5322,5325,5328,5338,5341,5343,5352],[11,4580,4581],{},"這篇是當時學 Vue CLI 3.0 時留下來的安裝與操作筆記。",[15,4583,4585],{"id":4584},"安裝-vue-cli-30","安裝 Vue CLI 3.0",[151,4587,4589],{"id":4588},"_1-確認-nodejs-版本","1. 確認 Node.js 版本",[11,4591,4592],{},"Node.js 需要 8.9 以上。",[22,4594,4596],{"className":2057,"code":4595,"language":2059,"meta":27,"style":27},"node -v\n",[29,4597,4598],{"__ignoreMap":27},[32,4599,4600,4603],{"class":34,"line":35},[32,4601,4602],{"class":2066},"node",[32,4604,4605],{"class":351}," -v\n",[11,4607,4608],{},"查看目前的 Node.js 版本。",[151,4610,4612],{"id":4611},"_2-移除舊版-vue-cli","2. 移除舊版 Vue CLI",[11,4614,4615],{},"如果之前有安裝 Vue CLI 1.x 或 2.x：",[22,4617,4619],{"className":2057,"code":4618,"language":2059,"meta":27,"style":27},"npm uninstall vue-cli -g\n",[29,4620,4621],{"__ignoreMap":27},[32,4622,4623,4626,4629,4632],{"class":34,"line":35},[32,4624,4625],{"class":2066},"npm",[32,4627,4628],{"class":175}," uninstall",[32,4630,4631],{"class":175}," vue-cli",[32,4633,4634],{"class":351}," -g\n",[151,4636,4638],{"id":4637},"_3-安裝-vue-cli-30","3. 安裝 Vue CLI 3.0",[22,4640,4642],{"className":2057,"code":4641,"language":2059,"meta":27,"style":27},"npm install -g @vue\u002Fcli\n",[29,4643,4644],{"__ignoreMap":27},[32,4645,4646,4648,4651,4654],{"class":34,"line":35},[32,4647,4625],{"class":2066},[32,4649,4650],{"class":175}," install",[32,4652,4653],{"class":351}," -g",[32,4655,4656],{"class":175}," @vue\u002Fcli\n",[151,4658,4660],{"id":4659},"_4-確認是否安裝成功","4. 確認是否安裝成功",[22,4662,4664],{"className":2057,"code":4663,"language":2059,"meta":27,"style":27},"vue --version\n",[29,4665,4666],{"__ignoreMap":27},[32,4667,4668,4670],{"class":34,"line":35},[32,4669,4112],{"class":2066},[32,4671,2129],{"class":351},[15,4673,4675,4676,4679],{"id":4674},"使用-vue-ui-建立專案","使用 ",[29,4677,4678],{},"vue ui"," 建立專案",[11,4681,4682],{},"在終端機輸入：",[22,4684,4686],{"className":2057,"code":4685,"language":2059,"meta":27,"style":27},"vue ui\n",[29,4687,4688],{"__ignoreMap":27},[32,4689,4690,4692],{"class":34,"line":35},[32,4691,4112],{"class":2066},[32,4693,4694],{"class":175}," ui\n",[11,4696,4697],{},"會開啟 Vue CLI 的圖形化管理介面，可以從裡面建立與管理專案。",[11,4699,4700],{},"專案建立完成後，可以在後台看到幾個功能。",[151,4702,4703],{"id":4703},"插件",[11,4705,4706],{},"查看目前已經安裝的插件。",[151,4708,4709],{"id":4709},"套件",[11,4711,4712],{},"可以新增專案需要使用的套件。",[151,4714,4715],{"id":4715},"設定",[11,4717,4718],{},"可以調整專案相關設定。",[11,4720,4721,4722,4725],{},"當時有記到 ",[29,4723,4724],{},"Base URL","，用來設定 build 後資源的路徑。",[151,4727,4728],{"id":4728},"任務",[11,4730,4731],{},"可以看到：",[22,4733,4735],{"className":2057,"code":4734,"language":2059,"meta":27,"style":27},"npm run serve\nnpm run build\n",[29,4736,4737,4747],{"__ignoreMap":27},[32,4738,4739,4741,4744],{"class":34,"line":35},[32,4740,4625],{"class":2066},[32,4742,4743],{"class":175}," run",[32,4745,4746],{"class":175}," serve\n",[32,4748,4749,4751,4753],{"class":34,"line":45},[32,4750,4625],{"class":2066},[32,4752,4743],{"class":175},[32,4754,4755],{"class":175}," build\n",[11,4757,4758],{},"等專案任務。",[11,4760,4761],{},"點選執行可以啟動專案，也可以從 Output 查看指令執行的訊息。",[11,4763,4764],{},"當時 Vue UI 裡還有 Dashboard 與分析功能，可以查看專案執行與打包後的資訊，例如：",[4538,4766,4767,4770],{},[4541,4768,4769],{},"Speed Stats：查看載入速度",[4541,4771,4772],{},"Assets：查看各個檔案的大小",[11,4774,4775],{},"Build 任務則可以用來編譯專案。",[11,4777,4778],{},"如果原本已經用指令建立專案，也可以透過 Vue UI 的匯入功能，把專案加入管理介面。",[15,4780,4675,4782,4679],{"id":4781},"使用-vue-create-建立專案",[29,4783,4784],{},"vue create",[11,4786,4787],{},"建立專案：",[22,4789,4791],{"className":2057,"code":4790,"language":2059,"meta":27,"style":27},"vue create vueclidemo\n",[29,4792,4793],{"__ignoreMap":27},[32,4794,4795,4797,4800],{"class":34,"line":35},[32,4796,4112],{"class":2066},[32,4798,4799],{"class":175}," create",[32,4801,4802],{"class":175}," vueclidemo\n",[11,4804,4805],{},"建立過程中會詢問要使用哪一種設定。",[151,4807,4809],{"id":4808},"preset","Preset",[11,4811,4812],{},"可以選：",[22,4814,4817],{"className":4815,"code":4816,"language":426,"meta":27},[424],"default\n",[29,4818,4816],{"__ignoreMap":27},[11,4820,4821],{},"使用預設的 Babel、ESLint。",[11,4823,4824],{},"或選：",[22,4826,4829],{"className":4827,"code":4828,"language":426,"meta":27},[424],"Manually select features\n",[29,4830,4828],{"__ignoreMap":27},[11,4832,4833],{},"自己選擇需要的功能。",[11,4835,4836],{},"當時筆記裡有記到：",[4538,4838,4839,4842,4845,4848,4851,4854,4857],{},[4541,4840,4841],{},"Vue Router",[4541,4843,4844],{},"Vuex",[4541,4846,4847],{},"Sass",[4541,4849,4850],{},"Babel",[4541,4852,4853],{},"ESLint",[4541,4855,4856],{},"Unit Testing",[4541,4858,4859],{},"E2E Testing",[11,4861,4862],{},"也可以把選好的設定儲存成 Preset，之後建立其他專案時繼續使用。",[15,4864,4866],{"id":4865},"linter-formatter","Linter \u002F Formatter",[11,4868,4869],{},"建立專案時可以選擇 JavaScript 的程式碼規範。",[11,4871,4872],{},"當時的選項包含：",[22,4874,4877],{"className":4875,"code":4876,"language":426,"meta":27},[424],"TSLint\nESLint with error prevention only\nESLint + Airbnb config\nESLint + Standard config\nESLint + Prettier\n",[29,4878,4876],{"__ignoreMap":27},[11,4880,4881],{},"當時自己的筆記是：",[4538,4883,4884,4887,4890],{},[4541,4885,4886],{},"Airbnb：規則比較嚴格",[4541,4888,4889],{},"Standard：相對適合剛開始使用",[4541,4891,4892],{},"初學時如果還不熟 Linter，也可以先不要選太複雜的設定",[11,4894,4895],{},"接著會詢問什麼時候執行 Lint：",[22,4897,4900],{"className":4898,"code":4899,"language":426,"meta":27},[424],"Lint on save\n",[29,4901,4899],{"__ignoreMap":27},[11,4903,4904],{},"存檔時檢查。",[11,4906,4907],{},"或：",[22,4909,4912],{"className":4910,"code":4911,"language":426,"meta":27},[424],"Lint and fix on commit\n",[29,4913,4911],{"__ignoreMap":27},[11,4915,4916],{},"Commit 時進行檢查與修正。",[15,4918,4919],{"id":4919},"設定檔放哪裡",[11,4921,4922],{},"建立專案時還會詢問設定要放在哪裡。",[22,4924,4927],{"className":4925,"code":4926,"language":426,"meta":27},[424],"In dedicated config files\n",[29,4928,4926],{"__ignoreMap":27},[11,4930,4931],{},"使用獨立的設定檔。",[11,4933,4907],{},[22,4935,4938],{"className":4936,"code":4937,"language":426,"meta":27},[424],"In package.json\n",[29,4939,4937],{"__ignoreMap":27},[11,4941,4942,4943,3775],{},"把設定放進 ",[29,4944,4945],{},"package.json",[15,4947,4948],{"id":4948},"啟動專案",[11,4950,4951],{},"安裝完成後，就可以執行：",[22,4953,4955],{"className":2057,"code":4954,"language":2059,"meta":27,"style":27},"npm run serve\n",[29,4956,4957],{"__ignoreMap":27},[32,4958,4959,4961,4963],{"class":34,"line":35},[32,4960,4625],{"class":2066},[32,4962,4743],{"class":175},[32,4964,4746],{"class":175},[11,4966,4967],{},"啟動開發環境。",[11,4969,4970],{},"Build：",[22,4972,4974],{"className":2057,"code":4973,"language":2059,"meta":27,"style":27},"npm run build\n",[29,4975,4976],{"__ignoreMap":27},[32,4977,4978,4980,4982],{"class":34,"line":35},[32,4979,4625],{"class":2066},[32,4981,4743],{"class":175},[32,4983,4755],{"class":175},[11,4985,4986],{},"編譯正式環境使用的檔案。",[11,4988,4989],{},"開發伺服器啟動後，當時會看到 Local 與 Network 的網址。",[15,4991,4993],{"id":4992},"vue-cli-30-專案結構","Vue CLI 3.0 專案結構",[11,4995,4996],{},"Vue CLI 3.0 和 Vue CLI 2.0 的專案結構不太一樣。",[11,4998,4999],{},"當時主要記了：",[22,5001,5004],{"className":5002,"code":5003,"language":426,"meta":27},[424],"src\u002F\n├── components\u002F\n├── views\u002F\n├── router.js\n├── App.vue\n└── main.js\n",[29,5005,5003],{"__ignoreMap":27},[151,5007,5008],{"id":5008},"components",[11,5010,5011],{},"放置專案內使用的元件。",[151,5013,5014],{"id":5014},"views",[11,5016,5017],{},"放置 Router 切換的頁面元件。",[151,5019,5021],{"id":5020},"routerjs","router.js",[11,5023,5024,5025,5028],{},"當時可以直接使用動態 ",[29,5026,5027],{},"import()"," 載入頁面：",[22,5030,5032],{"className":24,"code":5031,"language":26,"meta":27,"style":27},"export default new Router({\n  routes: [\n    {\n      path: '\u002F',\n      name: 'home',\n      component: () => import('.\u002Fviews\u002FHome.vue'),\n    },\n  ],\n});\n",[29,5033,5034,5050,5055,5060,5070,5080,5102,5106,5113],{"__ignoreMap":27},[32,5035,5036,5039,5042,5044,5047],{"class":34,"line":35},[32,5037,5038],{"class":38},"export",[32,5040,5041],{"class":38}," default",[32,5043,4165],{"class":38},[32,5045,5046],{"class":217}," Router",[32,5048,1143],{"class":5049},"sfpNf",[32,5051,5052],{"class":34,"line":45},[32,5053,5054],{"class":41},"  routes: [\n",[32,5056,5057],{"class":34,"line":51},[32,5058,5059],{"class":41},"    {\n",[32,5061,5062,5065,5068],{"class":34,"line":90},[32,5063,5064],{"class":41},"      path: ",[32,5066,5067],{"class":175},"'\u002F'",[32,5069,547],{"class":41},[32,5071,5072,5075,5078],{"class":34,"line":99},[32,5073,5074],{"class":41},"      name: ",[32,5076,5077],{"class":175},"'home'",[32,5079,547],{"class":41},[32,5081,5082,5085,5088,5091,5094,5096,5099],{"class":34,"line":106},[32,5083,5084],{"class":217},"      component",[32,5086,5087],{"class":41},": () ",[32,5089,5090],{"class":38},"=>",[32,5092,5093],{"class":38}," import",[32,5095,477],{"class":41},[32,5097,5098],{"class":175},"'.\u002Fviews\u002FHome.vue'",[32,5100,5101],{"class":41},"),\n",[32,5103,5104],{"class":34,"line":114},[32,5105,4204],{"class":41},[32,5107,5108,5111],{"class":34,"line":120},[32,5109,5110],{"class":41},"  ]",[32,5112,547],{"class":5049},[32,5114,5115,5118],{"class":34,"line":127},[32,5116,5117],{"class":5049},"})",[32,5119,96],{"class":41},[11,5121,5122,5123,5126],{},"不用先在檔案上方把 ",[29,5124,5125],{},"Home.vue"," import 進來。",[11,5128,5129],{},"當時另外有記到：",[2184,5131,5132],{},[11,5133,5134,5135,5138,5139,5142],{},"在 ",[29,5136,5137],{},"main.js"," 引入 ",[29,5140,5141],{},".vue"," 檔案時，要注意檔案名稱與副檔名。",[15,5144,5145],{"id":5145},"環境變數",[11,5147,5148],{},"先建立：",[22,5150,5153],{"className":5151,"code":5152,"language":426,"meta":27},[424],".env\n",[29,5154,5152],{"__ignoreMap":27},[11,5156,5157],{},"當時的設定：",[22,5159,5163],{"className":5160,"code":5161,"language":5162,"meta":27,"style":27},"language-env shiki shiki-themes github-light github-dark-default","VUE_APP_APIPATH=https:\u002F\u002Fvue-course-api.hexschool.io\nVUE_APP_CUSTOMPATH=rockayumitw\n","env",[29,5164,5165,5170],{"__ignoreMap":27},[32,5166,5167],{"class":34,"line":35},[32,5168,5169],{},"VUE_APP_APIPATH=https:\u002F\u002Fvue-course-api.hexschool.io\n",[32,5171,5172],{"class":34,"line":45},[32,5173,5174],{},"VUE_APP_CUSTOMPATH=rockayumitw\n",[11,5176,5177],{},"在程式裡可以透過：",[22,5179,5181],{"className":24,"code":5180,"language":26,"meta":27,"style":27},"created() {\n  console.log(process.env.VUE_APP_APIPATH);\n}\n",[29,5182,5183,5190,5206],{"__ignoreMap":27},[32,5184,5185,5188],{"class":34,"line":35},[32,5186,5187],{"class":217},"created",[32,5189,4221],{"class":41},[32,5191,5192,5195,5198,5201,5204],{"class":34,"line":45},[32,5193,5194],{"class":41},"  console.",[32,5196,5197],{"class":217},"log",[32,5199,5200],{"class":41},"(process.env.",[32,5202,5203],{"class":351},"VUE_APP_APIPATH",[32,5205,230],{"class":41},[32,5207,5208],{"class":34,"line":51},[32,5209,54],{"class":41},[11,5211,5212],{},"取得環境變數。",[11,5214,5215,5216,5219],{},"修改 ",[29,5217,5218],{},".env"," 後，需要重新啟動開發環境。",[15,5221,5223,5224],{"id":5222},"不同環境的-env","不同環境的 ",[29,5225,5218],{},[11,5227,5228],{},"也可以依照不同環境建立：",[22,5230,5233],{"className":5231,"code":5232,"language":426,"meta":27},[424],".env.development\n.env.production\n",[29,5234,5232],{"__ignoreMap":27},[11,5236,5237,5238,5240],{},"例如 ",[29,5239,4945],{},"：",[22,5242,5246],{"className":5243,"code":5244,"language":5245,"meta":27,"style":27},"language-json shiki shiki-themes github-light github-dark-default","{\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve --mode development\",\n    \"build\": \"vue-cli-service build\"\n  }\n}\n","json",[29,5247,5248,5253,5262,5275,5285,5289],{"__ignoreMap":27},[32,5249,5250],{"class":34,"line":35},[32,5251,5252],{"class":41},"{\n",[32,5254,5255,5259],{"class":34,"line":45},[32,5256,5258],{"class":5257},"swgif","  \"scripts\"",[32,5260,5261],{"class":41},": {\n",[32,5263,5264,5267,5270,5273],{"class":34,"line":51},[32,5265,5266],{"class":5257},"    \"serve\"",[32,5268,5269],{"class":41},": ",[32,5271,5272],{"class":175},"\"vue-cli-service serve --mode development\"",[32,5274,547],{"class":41},[32,5276,5277,5280,5282],{"class":34,"line":90},[32,5278,5279],{"class":5257},"    \"build\"",[32,5281,5269],{"class":41},[32,5283,5284],{"class":175},"\"vue-cli-service build\"\n",[32,5286,5287],{"class":34,"line":99},[32,5288,1203],{"class":41},[32,5290,5291],{"class":34,"line":106},[32,5292,54],{"class":41},[11,5294,5295,5296,5298],{},"當時的筆記是：如果不同 ",[29,5297,5218],{}," 中有相同名稱的變數，會依照目前執行的 mode 載入對應設定。",[15,5300,5302],{"id":5301},"移除-vue-cli","移除 Vue CLI",[11,5304,5305],{},"如果需要移除舊版 Vue CLI：",[22,5307,5308],{"className":2057,"code":4618,"language":2059,"meta":27,"style":27},[29,5309,5310],{"__ignoreMap":27},[32,5311,5312,5314,5316,5318],{"class":34,"line":35},[32,5313,4625],{"class":2066},[32,5315,4628],{"class":175},[32,5317,4631],{"class":175},[32,5319,4634],{"class":351},[15,5321,2004],{"id":2003},[11,5323,5324],{},"這篇是 2018 年 Vue CLI 3.0 時期留下來的學習筆記，所以介面、建立流程、套件選項與專案結構都是當時的環境。",[11,5326,5327],{},"現在建立新的 Vue 專案已經不會以 Vue CLI 3.0 作為主要方式，因此這篇不適合直接拿來照著建立新的專案。",[11,5329,5330,5331,5333,5334,5337],{},"不過 ",[29,5332,4678],{},"、Vue CLI 的 Preset、",[29,5335,5336],{},"VUE_APP_"," 環境變數，以及當時 Vue CLI 專案的結構，還是很常在舊專案裡看到。",[11,5339,5340],{},"這篇就保留當時的安裝與操作方式，作為 Vue CLI 時期的學習紀錄。",[15,5342,4536],{"id":4536},[4538,5344,5345],{},[4541,5346,5347],{},[412,5348,5351],{"href":5349,"rel":5350},"https:\u002F\u002Fcli.vuejs.org\u002Fzh\u002F",[416],"Vue CLI 官方文件（封存版）",[368,5353,5354],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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 .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .swgif, html code.shiki .swgif{--shiki-default:#005CC5;--shiki-dark:#7EE787}",{"title":27,"searchDepth":51,"depth":51,"links":5356},[5357,5363,5370,5374,5375,5376,5377,5382,5383,5385,5386,5387],{"id":4584,"depth":45,"text":4585,"children":5358},[5359,5360,5361,5362],{"id":4588,"depth":51,"text":4589},{"id":4611,"depth":51,"text":4612},{"id":4637,"depth":51,"text":4638},{"id":4659,"depth":51,"text":4660},{"id":4674,"depth":45,"text":5364,"children":5365},"使用 vue ui 建立專案",[5366,5367,5368,5369],{"id":4703,"depth":51,"text":4703},{"id":4709,"depth":51,"text":4709},{"id":4715,"depth":51,"text":4715},{"id":4728,"depth":51,"text":4728},{"id":4781,"depth":45,"text":5371,"children":5372},"使用 vue create 建立專案",[5373],{"id":4808,"depth":51,"text":4809},{"id":4865,"depth":45,"text":4866},{"id":4919,"depth":45,"text":4919},{"id":4948,"depth":45,"text":4948},{"id":4992,"depth":45,"text":4993,"children":5378},[5379,5380,5381],{"id":5008,"depth":51,"text":5008},{"id":5014,"depth":51,"text":5014},{"id":5020,"depth":51,"text":5021},{"id":5145,"depth":45,"text":5145},{"id":5222,"depth":45,"text":5384},"不同環境的 .env",{"id":5301,"depth":45,"text":5302},{"id":2003,"depth":45,"text":2004},{"id":4536,"depth":45,"text":4536},"2018 年整理的 Vue CLI 3.0 學習筆記，包含安裝、vue ui、vue create、專案結構與環境變數設定。",{},"\u002Fposts\u002Fvue-cli3-project-setup","2018-08-13",[],{"title":4576,"description":5388},"posts\u002F20180813.vue-cli3-project-setup",[4113,5396,4625],"Vue CLI","0wsdoWyq32GjCD8Yd8_29zfDppMa4jhYXEVvf8xssnQ",{"id":5399,"title":5400,"body":5401,"category":378,"description":6019,"draft":380,"extension":381,"image":382,"meta":6020,"navigation":102,"path":6021,"publishedAt":6022,"relatedExperiments":6023,"seo":6024,"stem":6025,"tags":6026,"updatedAt":392,"__hash__":6029},"posts\u002Fposts\u002F20180814.legacy-screen-orientation.md","移動裝置螢幕旋轉判斷與鎖定",{"type":8,"value":5402,"toc":6009},[5403,5406,5410,5480,5484,5506,5650,5654,5684,5688,5749,5753,5831,5835,5962,5965,5988,5990,6000,6006],[11,5404,5405],{},"這篇是 2018 年整理移動裝置螢幕方向判斷與鎖定方式時留下來的筆記。",[15,5407,5409],{"id":5408},"css-判斷","CSS 判斷",[22,5411,5414],{"className":5412,"code":5413,"language":1140,"meta":27,"style":27},"language-css shiki shiki-themes github-light github-dark-default","@media screen and (orientation: portrait) {\n  \u002F* 針對縱向 CSS 撰寫樣式 *\u002F\n}\n\n@media screen and (orientation: landscape) {\n  \u002F* 針對橫向 CSS 撰寫樣式 *\u002F\n}\n",[29,5415,5416,5439,5444,5448,5452,5471,5476],{"__ignoreMap":27},[32,5417,5418,5421,5424,5427,5429,5432,5434,5437],{"class":34,"line":35},[32,5419,5420],{"class":38},"@media",[32,5422,5423],{"class":351}," screen",[32,5425,5426],{"class":38}," and",[32,5428,900],{"class":41},[32,5430,5431],{"class":351},"orientation",[32,5433,5269],{"class":41},[32,5435,5436],{"class":351},"portrait",[32,5438,520],{"class":41},[32,5440,5441],{"class":34,"line":45},[32,5442,5443],{"class":608},"  \u002F* 針對縱向 CSS 撰寫樣式 *\u002F\n",[32,5445,5446],{"class":34,"line":51},[32,5447,54],{"class":41},[32,5449,5450],{"class":34,"line":90},[32,5451,103],{"emptyLinePlaceholder":102},[32,5453,5454,5456,5458,5460,5462,5464,5466,5469],{"class":34,"line":99},[32,5455,5420],{"class":38},[32,5457,5423],{"class":351},[32,5459,5426],{"class":38},[32,5461,900],{"class":41},[32,5463,5431],{"class":351},[32,5465,5269],{"class":41},[32,5467,5468],{"class":351},"landscape",[32,5470,520],{"class":41},[32,5472,5473],{"class":34,"line":106},[32,5474,5475],{"class":608},"  \u002F* 針對橫向 CSS 撰寫樣式 *\u002F\n",[32,5477,5478],{"class":34,"line":114},[32,5479,54],{"class":41},[15,5481,5483],{"id":5482},"orientationchange-事件","orientationchange 事件",[22,5485,5487],{"className":4038,"code":5486,"language":4034,"meta":27,"style":27},"\u003Cbody onorientationchange=\"updateOrientation();\">\n",[29,5488,5489],{"__ignoreMap":27},[32,5490,5491,5493,5496,5499,5501,5504],{"class":34,"line":35},[32,5492,4046],{"class":41},[32,5494,5495],{"class":4049},"body",[32,5497,5498],{"class":4053}," onorientationchange",[32,5500,172],{"class":41},[32,5502,5503],{"class":175},"\"updateOrientation();\"",[32,5505,4062],{"class":41},[22,5507,5509],{"className":24,"code":5508,"language":26,"meta":27,"style":27},"window.addEventListener(\n  \"onorientationchange\" in window ? \"orientationchange\" : \"resize\",\n  function () {\n    if (window.orientation === 180 || window.orientation === 0) {\n      alert(\"目前您的螢幕為縱向！\");\n    }\n\n    if (window.orientation === 90 || window.orientation === -90) {\n      alert(\"目前您的螢幕為橫向！\");\n    }\n  },\n  false,\n);\n",[29,5510,5511,5520,5543,5550,5575,5587,5592,5596,5620,5631,5635,5640,5646],{"__ignoreMap":27},[32,5512,5513,5515,5518],{"class":34,"line":35},[32,5514,1754],{"class":41},[32,5516,5517],{"class":217},"addEventListener",[32,5519,539],{"class":41},[32,5521,5522,5525,5528,5531,5533,5536,5538,5541],{"class":34,"line":45},[32,5523,5524],{"class":175},"  \"onorientationchange\"",[32,5526,5527],{"class":38}," in",[32,5529,5530],{"class":41}," window ",[32,5532,316],{"class":38},[32,5534,5535],{"class":175}," \"orientationchange\"",[32,5537,361],{"class":38},[32,5539,5540],{"class":175}," \"resize\"",[32,5542,547],{"class":41},[32,5544,5545,5548],{"class":34,"line":51},[32,5546,5547],{"class":38},"  function",[32,5549,668],{"class":41},[32,5551,5552,5555,5558,5561,5564,5566,5569,5571,5573],{"class":34,"line":90},[32,5553,5554],{"class":38},"    if",[32,5556,5557],{"class":41}," (window.orientation ",[32,5559,5560],{"class":38},"===",[32,5562,5563],{"class":351}," 180",[32,5565,1644],{"class":38},[32,5567,5568],{"class":41}," window.orientation ",[32,5570,5560],{"class":38},[32,5572,1523],{"class":351},[32,5574,520],{"class":41},[32,5576,5577,5580,5582,5585],{"class":34,"line":99},[32,5578,5579],{"class":217},"      alert",[32,5581,477],{"class":41},[32,5583,5584],{"class":175},"\"目前您的螢幕為縱向！\"",[32,5586,230],{"class":41},[32,5588,5589],{"class":34,"line":106},[32,5590,5591],{"class":41},"    }\n",[32,5593,5594],{"class":34,"line":114},[32,5595,103],{"emptyLinePlaceholder":102},[32,5597,5598,5600,5602,5604,5607,5609,5611,5613,5615,5618],{"class":34,"line":120},[32,5599,5554],{"class":38},[32,5601,5557],{"class":41},[32,5603,5560],{"class":38},[32,5605,5606],{"class":351}," 90",[32,5608,1644],{"class":38},[32,5610,5568],{"class":41},[32,5612,5560],{"class":38},[32,5614,1119],{"class":38},[32,5616,5617],{"class":351},"90",[32,5619,520],{"class":41},[32,5621,5622,5624,5626,5629],{"class":34,"line":127},[32,5623,5579],{"class":217},[32,5625,477],{"class":41},[32,5627,5628],{"class":175},"\"目前您的螢幕為橫向！\"",[32,5630,230],{"class":41},[32,5632,5633],{"class":34,"line":132},[32,5634,5591],{"class":41},[32,5636,5637],{"class":34,"line":141},[32,5638,5639],{"class":41},"  },\n",[32,5641,5642,5644],{"class":34,"line":147},[32,5643,1641],{"class":351},[32,5645,547],{"class":41},[32,5647,5648],{"class":34,"line":275},[32,5649,230],{"class":41},[15,5651,5653],{"id":5652},"meta-判斷","meta 判斷",[22,5655,5657],{"className":4038,"code":5656,"language":4034,"meta":27,"style":27},"\u003Cmeta name=\"x5-orientation\" content=\"portrait\">\n",[29,5658,5659],{"__ignoreMap":27},[32,5660,5661,5663,5666,5669,5671,5674,5677,5679,5682],{"class":34,"line":35},[32,5662,4046],{"class":41},[32,5664,5665],{"class":4049},"meta",[32,5667,5668],{"class":4053}," name",[32,5670,172],{"class":41},[32,5672,5673],{"class":175},"\"x5-orientation\"",[32,5675,5676],{"class":4053}," content",[32,5678,172],{"class":41},[32,5680,5681],{"class":175},"\"portrait\"",[32,5683,4062],{"class":41},[15,5685,5687],{"id":5686},"api","API",[22,5689,5691],{"className":24,"code":5690,"language":26,"meta":27,"style":27},"screen.addEventListener(\"orientationchange\", function () {\n  console.log(\"The orientation of the screen is: \" + screen.orientation);\n});\n\nscreen.lockOrientation(\"landscape\");\n",[29,5692,5693,5711,5727,5731,5735],{"__ignoreMap":27},[32,5694,5695,5698,5700,5702,5705,5707,5709],{"class":34,"line":35},[32,5696,5697],{"class":41},"screen.",[32,5699,5517],{"class":217},[32,5701,477],{"class":41},[32,5703,5704],{"class":175},"\"orientationchange\"",[32,5706,635],{"class":41},[32,5708,665],{"class":38},[32,5710,668],{"class":41},[32,5712,5713,5715,5717,5719,5722,5724],{"class":34,"line":45},[32,5714,5194],{"class":41},[32,5716,5197],{"class":217},[32,5718,477],{"class":41},[32,5720,5721],{"class":175},"\"The orientation of the screen is: \"",[32,5723,1799],{"class":38},[32,5725,5726],{"class":41}," screen.orientation);\n",[32,5728,5729],{"class":34,"line":51},[32,5730,792],{"class":41},[32,5732,5733],{"class":34,"line":90},[32,5734,103],{"emptyLinePlaceholder":102},[32,5736,5737,5739,5742,5744,5747],{"class":34,"line":99},[32,5738,5697],{"class":41},[32,5740,5741],{"class":217},"lockOrientation",[32,5743,477],{"class":41},[32,5745,5746],{"class":175},"\"landscape\"",[32,5748,230],{"class":41},[15,5750,5752],{"id":5751},"css-強制旋轉","CSS 強制旋轉",[22,5754,5756],{"className":5412,"code":5755,"language":1140,"meta":27,"style":27},"transform: rotate(90deg);\ntransform-origin: left bottom;\n-ms-transform: rotate(90deg); \u002F* Internet Explorer 9 *\u002F\n-ms-transform-origin: left bottom; \u002F* Internet Explorer 9 *\u002F\n-moz-transform: rotate(90deg); \u002F* Firefox *\u002F\n-moz-transform-origin: left bottom; \u002F* Firefox *\u002F\n-webkit-transform: rotate(90deg); \u002F* Safari & Chrome *\u002F\n-webkit-transform-origin: left bottom; \u002F* Safari & Chrome *\u002F\n-o-transform: rotate(90deg); \u002F* Opera *\u002F\n-o-transform-origin: left bottom; \u002F* Opera *\u002F\n",[29,5757,5758,5763,5771,5779,5786,5794,5801,5809,5816,5824],{"__ignoreMap":27},[32,5759,5760],{"class":34,"line":35},[32,5761,5762],{"class":41},"transform: rotate(90deg);\n",[32,5764,5765,5768],{"class":34,"line":45},[32,5766,5767],{"class":4049},"transform-origin",[32,5769,5770],{"class":41},": left bottom;\n",[32,5772,5773,5776],{"class":34,"line":51},[32,5774,5775],{"class":41},"-ms-transform: rotate(90deg); ",[32,5777,5778],{"class":608},"\u002F* Internet Explorer 9 *\u002F\n",[32,5780,5781,5784],{"class":34,"line":90},[32,5782,5783],{"class":41},"-ms-transform-origin: left bottom; ",[32,5785,5778],{"class":608},[32,5787,5788,5791],{"class":34,"line":99},[32,5789,5790],{"class":41},"-moz-transform: rotate(90deg); ",[32,5792,5793],{"class":608},"\u002F* Firefox *\u002F\n",[32,5795,5796,5799],{"class":34,"line":106},[32,5797,5798],{"class":41},"-moz-transform-origin: left bottom; ",[32,5800,5793],{"class":608},[32,5802,5803,5806],{"class":34,"line":114},[32,5804,5805],{"class":41},"-webkit-transform: rotate(90deg); ",[32,5807,5808],{"class":608},"\u002F* Safari & Chrome *\u002F\n",[32,5810,5811,5814],{"class":34,"line":120},[32,5812,5813],{"class":41},"-webkit-transform-origin: left bottom; ",[32,5815,5808],{"class":608},[32,5817,5818,5821],{"class":34,"line":127},[32,5819,5820],{"class":41},"-o-transform: rotate(90deg); ",[32,5822,5823],{"class":608},"\u002F* Opera *\u002F\n",[32,5825,5826,5829],{"class":34,"line":132},[32,5827,5828],{"class":41},"-o-transform-origin: left bottom; ",[32,5830,5823],{"class":608},[15,5832,5834],{"id":5833},"jquery-寫法","jQuery 寫法",[22,5836,5838],{"className":24,"code":5837,"language":26,"meta":27,"style":27},"$(document).bind(\"orientationchange\", function () {\n  if (window.orientation == 90 || window.orientation == -90) {\n    $(\".bottom_fix\").css(\"position\", \"static\");\n  } else {\n    $(\".bottom_fix\").css({\n      position: \"fixed\",\n      bottom: \"0\",\n    });\n  }\n});\n",[29,5839,5840,5859,5882,5907,5916,5930,5940,5950,5954,5958],{"__ignoreMap":27},[32,5841,5842,5844,5846,5849,5851,5853,5855,5857],{"class":34,"line":35},[32,5843,755],{"class":217},[32,5845,874],{"class":41},[32,5847,5848],{"class":217},"bind",[32,5850,477],{"class":41},[32,5852,5704],{"class":175},[32,5854,635],{"class":41},[32,5856,665],{"class":38},[32,5858,668],{"class":41},[32,5860,5861,5863,5865,5868,5870,5872,5874,5876,5878,5880],{"class":34,"line":45},[32,5862,1021],{"class":38},[32,5864,5557],{"class":41},[32,5866,5867],{"class":38},"==",[32,5869,5606],{"class":351},[32,5871,1644],{"class":38},[32,5873,5568],{"class":41},[32,5875,5867],{"class":38},[32,5877,1119],{"class":38},[32,5879,5617],{"class":351},[32,5881,520],{"class":41},[32,5883,5884,5886,5888,5891,5893,5895,5897,5900,5902,5905],{"class":34,"line":51},[32,5885,674],{"class":217},[32,5887,477],{"class":41},[32,5889,5890],{"class":175},"\".bottom_fix\"",[32,5892,533],{"class":41},[32,5894,1140],{"class":217},[32,5896,477],{"class":41},[32,5898,5899],{"class":175},"\"position\"",[32,5901,635],{"class":41},[32,5903,5904],{"class":175},"\"static\"",[32,5906,230],{"class":41},[32,5908,5909,5912,5914],{"class":34,"line":90},[32,5910,5911],{"class":41},"  } ",[32,5913,565],{"class":38},[32,5915,703],{"class":41},[32,5917,5918,5920,5922,5924,5926,5928],{"class":34,"line":99},[32,5919,674],{"class":217},[32,5921,477],{"class":41},[32,5923,5890],{"class":175},[32,5925,533],{"class":41},[32,5927,1140],{"class":217},[32,5929,1143],{"class":41},[32,5931,5932,5935,5938],{"class":34,"line":106},[32,5933,5934],{"class":41},"      position: ",[32,5936,5937],{"class":175},"\"fixed\"",[32,5939,547],{"class":41},[32,5941,5942,5945,5948],{"class":34,"line":114},[32,5943,5944],{"class":41},"      bottom: ",[32,5946,5947],{"class":175},"\"0\"",[32,5949,547],{"class":41},[32,5951,5952],{"class":34,"line":120},[32,5953,1198],{"class":41},[32,5955,5956],{"class":34,"line":127},[32,5957,1203],{"class":41},[32,5959,5960],{"class":34,"line":132},[32,5961,792],{"class":41},[15,5963,5964],{"id":5964},"原文參考連結",[4538,5966,5967,5974,5981],{},[4541,5968,5969],{},[412,5970,5973],{"href":5971,"rel":5972},"http:\u002F\u002Fsrdesign.com.tw\u002Fdesign\u002Fthread-517-1-1.html",[416],"srdesign.com.tw",[4541,5975,5976],{},[412,5977,5980],{"href":5978,"rel":5979},"https:\u002F\u002Fhk.saowen.com\u002Fa\u002Fd98d575aeda7cd3e201f60c3cde03cb7050119380497b75d1dab3cc382ec340e",[416],"hk.saowen.com",[4541,5982,5983],{},[412,5984,5987],{"href":5985,"rel":5986},"http:\u002F\u002Fwww.runoob.com\u002Fjquerymobile\u002Fjquerymobile-events-orientation.html",[416],"菜鳥教程：jQuery Mobile orientationchange 事件",[15,5989,2004],{"id":2003},[11,5991,5992,5993,3750,5996,5999],{},"這篇保留的是 2018 年使用 ",[29,5994,5995],{},"window.orientation",[29,5997,5998],{},"screen.lockOrientation()"," 與瀏覽器專屬 meta 標籤的寫法。前兩者已經棄用或不屬於現行標準，不建議直接用在新專案。",[11,6001,6002,6003,6005],{},"現在若要用 JavaScript 取得或鎖定螢幕方向，可參考《screen.orientation：現在判斷與鎖定螢幕方向的做法》。其中方向鎖定仍受瀏覽器與執行情境限制；單純依橫直向調整版面時，CSS 的 ",[29,6004,5431],{}," 媒體查詢仍然適用。",[368,6007,6008],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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 .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}",{"title":27,"searchDepth":51,"depth":51,"links":6010},[6011,6012,6013,6014,6015,6016,6017,6018],{"id":5408,"depth":45,"text":5409},{"id":5482,"depth":45,"text":5483},{"id":5652,"depth":45,"text":5653},{"id":5686,"depth":45,"text":5687},{"id":5751,"depth":45,"text":5752},{"id":5833,"depth":45,"text":5834},{"id":5964,"depth":45,"text":5964},{"id":2003,"depth":45,"text":2004},"2018 年整理的移動裝置螢幕方向筆記，包含 CSS 媒體查詢、window.orientation、舊版方向鎖定 API 與 jQuery 範例。",{},"\u002Fposts\u002Flegacy-screen-orientation","2018-08-14",[],{"title":5400,"description":6019},"posts\u002F20180814.legacy-screen-orientation",[390,2040,6027,6028],"RWD","螢幕方向","DHrrss7fhuuHCDYXLC39zyDTt4Hu8Ib2EcNeVqLs_8s",{"id":6031,"title":6032,"body":6033,"category":378,"description":6232,"draft":380,"extension":381,"image":382,"meta":6233,"navigation":102,"path":6234,"publishedAt":6235,"relatedExperiments":6236,"seo":6237,"stem":6238,"tags":6239,"updatedAt":392,"__hash__":6240},"posts\u002Fposts\u002F20180822.dynamic-link-stylesheet.md","用 JavaScript 動態建立與停用 CSS 檔案",{"type":8,"value":6034,"toc":6227},[6035,6038,6042,6174,6178,6209,6211,6218,6224],[11,6036,6037],{},"這篇是 2018 年整理用 JavaScript 動態建立與停用 CSS 檔案時留下來的筆記。",[15,6039,6041],{"id":6040},"動態建立-css-檔案","動態建立 CSS 檔案",[22,6043,6045],{"className":24,"code":6044,"language":26,"meta":27,"style":27},"\u002F\u002F CSS 亂數\nvar styleRandom = Math.floor(Math.random() * 1000);\n\n\u002F\u002F 建立 CSS 檔案\nvar styleDocument = document.createElement(\"link\");\n\n\u002F\u002F 設定 CSS 路徑\nstyleDocument.rel = \"StyleSheet\";\nstyleDocument.href = \"css\u002F01.css\" + \"?\" + styleRandom;\n\n\u002F\u002F 將 CSS 文件加入 head\ndocument.head.append(styleDocument);\n",[29,6046,6047,6052,6084,6088,6093,6113,6117,6122,6134,6154,6158,6163],{"__ignoreMap":27},[32,6048,6049],{"class":34,"line":35},[32,6050,6051],{"class":608},"\u002F\u002F CSS 亂數\n",[32,6053,6054,6056,6059,6061,6064,6067,6070,6073,6076,6079,6082],{"class":34,"line":45},[32,6055,166],{"class":38},[32,6057,6058],{"class":41}," styleRandom ",[32,6060,172],{"class":38},[32,6062,6063],{"class":41}," Math.",[32,6065,6066],{"class":217},"floor",[32,6068,6069],{"class":41},"(Math.",[32,6071,6072],{"class":217},"random",[32,6074,6075],{"class":41},"() ",[32,6077,6078],{"class":38},"*",[32,6080,6081],{"class":351}," 1000",[32,6083,230],{"class":41},[32,6085,6086],{"class":34,"line":51},[32,6087,103],{"emptyLinePlaceholder":102},[32,6089,6090],{"class":34,"line":90},[32,6091,6092],{"class":608},"\u002F\u002F 建立 CSS 檔案\n",[32,6094,6095,6097,6100,6102,6104,6106,6108,6111],{"class":34,"line":99},[32,6096,166],{"class":38},[32,6098,6099],{"class":41}," styleDocument ",[32,6101,172],{"class":38},[32,6103,919],{"class":41},[32,6105,922],{"class":217},[32,6107,477],{"class":41},[32,6109,6110],{"class":175},"\"link\"",[32,6112,230],{"class":41},[32,6114,6115],{"class":34,"line":106},[32,6116,103],{"emptyLinePlaceholder":102},[32,6118,6119],{"class":34,"line":114},[32,6120,6121],{"class":608},"\u002F\u002F 設定 CSS 路徑\n",[32,6123,6124,6127,6129,6132],{"class":34,"line":120},[32,6125,6126],{"class":41},"styleDocument.rel ",[32,6128,172],{"class":38},[32,6130,6131],{"class":175}," \"StyleSheet\"",[32,6133,96],{"class":41},[32,6135,6136,6139,6141,6144,6146,6149,6151],{"class":34,"line":127},[32,6137,6138],{"class":41},"styleDocument.href ",[32,6140,172],{"class":38},[32,6142,6143],{"class":175}," \"css\u002F01.css\"",[32,6145,1799],{"class":38},[32,6147,6148],{"class":175}," \"?\"",[32,6150,1799],{"class":38},[32,6152,6153],{"class":41}," styleRandom;\n",[32,6155,6156],{"class":34,"line":132},[32,6157,103],{"emptyLinePlaceholder":102},[32,6159,6160],{"class":34,"line":141},[32,6161,6162],{"class":608},"\u002F\u002F 將 CSS 文件加入 head\n",[32,6164,6165,6168,6171],{"class":34,"line":147},[32,6166,6167],{"class":41},"document.head.",[32,6169,6170],{"class":217},"append",[32,6172,6173],{"class":41},"(styleDocument);\n",[15,6175,6177],{"id":6176},"停用-css","停用 CSS",[22,6179,6181],{"className":24,"code":6180,"language":26,"meta":27,"style":27},"$(\"link[href='_css\u002FMobile_landscape.css']\").prop(\"disabled\", true);\n",[29,6182,6183],{"__ignoreMap":27},[32,6184,6185,6187,6189,6192,6194,6197,6199,6202,6204,6207],{"class":34,"line":35},[32,6186,755],{"class":217},[32,6188,477],{"class":41},[32,6190,6191],{"class":175},"\"link[href='_css\u002FMobile_landscape.css']\"",[32,6193,533],{"class":41},[32,6195,6196],{"class":217},"prop",[32,6198,477],{"class":41},[32,6200,6201],{"class":175},"\"disabled\"",[32,6203,635],{"class":41},[32,6205,6206],{"class":351},"true",[32,6208,230],{"class":41},[15,6210,2004],{"id":2003},[11,6212,6213,6214,6217],{},"動態建立 ",[29,6215,6216],{},"\u003Clink>"," 與停用樣式表的做法現在仍可使用；原文在網址加亂數是為了避開瀏覽器快取，但也會讓每次載入都使用不同網址。現在的建置工具通常會以檔名雜湊處理靜態資源快取。",[11,6219,6220,6221,6223],{},"如果需求是直接用 JavaScript 建立並套用樣式表，也可以參考《document.adoptedStyleSheets：不用 link 元素也能動態套用樣式》。這裡保留原本的 ",[29,6222,6216],{}," 寫法作為當時的紀錄。",[368,6225,6226],{},"html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":6228},[6229,6230,6231],{"id":6040,"depth":45,"text":6041},{"id":6176,"depth":45,"text":6177},{"id":2003,"depth":45,"text":2004},"2018 年整理的動態 CSS 筆記，包含建立 link 元素、以亂數參數避開快取，以及用 jQuery 停用樣式表。",{},"\u002Fposts\u002Fdynamic-link-stylesheet","2018-08-22",[],{"title":6032,"description":6232},"posts\u002F20180822.dynamic-link-stylesheet",[390,2040,1757],"WJki7QRO4-w1nU3GxXrk7vRMlw2cHKmjk88Fvpc8G5s",{"id":6242,"title":6243,"body":6244,"category":378,"description":6706,"draft":380,"extension":381,"image":382,"meta":6707,"navigation":102,"path":6708,"publishedAt":6709,"relatedExperiments":6710,"seo":6711,"stem":6712,"tags":6713,"updatedAt":6716,"__hash__":6717},"posts\u002Fposts\u002F20180923.tweenmax-install-notes.md","TweenMax 安裝與使用筆記",{"type":8,"value":6245,"toc":6693},[6246,6250,6253,6272,6313,6342,6345,6355,6358,6364,6368,6371,6391,6395,6414,6420,6425,6437,6443,6448,6454,6457,6480,6483,6489,6494,6562,6565,6569,6575,6578,6581,6599,6602,6608,6632,6635,6661,6669,6672,6690],[15,6247,6249],{"id":6248},"使用-nvm-管理-nodejs","使用 NVM 管理 Node.js",[11,6251,6252],{},"如果直接從官網下載 Node.js，只會安裝固定版本；NVM 可以用來安裝及切換不同版本。",[4538,6254,6255,6263,6269],{},[4541,6256,6257,6258],{},"下載：",[412,6259,6262],{"href":6260,"rel":6261},"https:\u002F\u002Fgithub.com\u002Fcoreybutler\u002Fnvm-windows\u002Freleases",[416],"nvm-windows",[4541,6264,6265,6266],{},"點選 ",[29,6267,6268],{},"nvm-setup.zip",[4541,6270,6271],{},"開啟命令提示字元安裝 Node.js",[22,6273,6275],{"className":2057,"code":6274,"language":2059,"meta":27,"style":27},"nvm list\nnvm list available\nnvm install v8.12.0\nnvm use v8.12.0\n",[29,6276,6277,6285,6295,6304],{"__ignoreMap":27},[32,6278,6279,6282],{"class":34,"line":35},[32,6280,6281],{"class":2066},"nvm",[32,6283,6284],{"class":175}," list\n",[32,6286,6287,6289,6292],{"class":34,"line":45},[32,6288,6281],{"class":2066},[32,6290,6291],{"class":175}," list",[32,6293,6294],{"class":175}," available\n",[32,6296,6297,6299,6301],{"class":34,"line":51},[32,6298,6281],{"class":2066},[32,6300,4650],{"class":175},[32,6302,6303],{"class":175}," v8.12.0\n",[32,6305,6306,6308,6311],{"class":34,"line":90},[32,6307,6281],{"class":2066},[32,6309,6310],{"class":175}," use",[32,6312,6303],{"class":175},[4538,6314,6315,6321,6327,6333,6339],{},[4541,6316,6317,6320],{},[29,6318,6319],{},"nvm list","：查看已安裝的版本",[4541,6322,6323,6326],{},[29,6324,6325],{},"nvm list available","：查看可以安裝的 Node.js 版本",[4541,6328,6329,6332],{},[29,6330,6331],{},"nvm install v8.12.0","：安裝指定版本",[4541,6334,6335,6338],{},[29,6336,6337],{},"nvm use v8.12.0","：切換到指定版本",[4541,6340,6341],{},"LTS：穩定版本",[11,6343,6344],{},"確認是否安裝完成：",[22,6346,6347],{"className":2057,"code":4595,"language":2059,"meta":27,"style":27},[29,6348,6349],{"__ignoreMap":27},[32,6350,6351,6353],{"class":34,"line":35},[32,6352,4602],{"class":2066},[32,6354,4605],{"class":351},[11,6356,6357],{},"安裝的版本是：",[22,6359,6362],{"className":6360,"code":6361,"language":426,"meta":27},[424],"v8.12.0\n",[29,6363,6361],{"__ignoreMap":27},[15,6365,6367],{"id":6366},"vs-code-套件","VS Code 套件",[11,6369,6370],{},"這裡也順便分享常用的VSCode套件:",[4538,6372,6373,6376,6379,6382,6385,6388],{},[4541,6374,6375],{},"Monokai Dark Soda：編輯器配色",[4541,6377,6378],{},"Live Server：模擬 server 環境並開啟網頁",[4541,6380,6381],{},"colorize：顯示顏色標籤",[4541,6383,6384],{},"AutoFileName：協助尋找路徑",[4541,6386,6387],{},"vscode-icons：顯示專案資料夾圖示",[4541,6389,6390],{},"Copy filename：在右鍵選單直接複製檔名",[15,6392,6394],{"id":6393},"tweenmax","TweenMax",[4538,6396,6397,6406],{},[4541,6398,6399,6400,6405],{},"安裝：",[412,6401,6404],{"href":6402,"rel":6403},"https:\u002F\u002Fgreensock.com\u002Ftweenmax",[416],"TweenMax 下載頁","（右上角下載）",[4541,6407,6408,6409],{},"動畫曲線：",[412,6410,6413],{"href":6411,"rel":6412},"https:\u002F\u002Fgreensock.com\u002Fease-visualizer",[416],"Ease Visualizer",[151,6415,6417],{"id":6416},"to",[29,6418,6419],{},"to()",[11,6421,6422,6424],{},[29,6423,6416],{}," 表示動畫要到哪裡，可以帶三個參數：",[6426,6427,6428,6431,6434],"ol",{},[4541,6429,6430],{},"要改變哪個物件，例如 ID 或 class。",[4541,6432,6433],{},"動畫要在幾秒內完成。",[4541,6435,6436],{},"要改變的屬性、函式與其他選項。",[151,6438,6440],{"id":6439},"transformorigin",[29,6441,6442],{},"transformOrigin",[11,6444,6445,6447],{},[29,6446,6442],{}," 是中心點定位屬性：",[22,6449,6452],{"className":6450,"code":6451,"language":426,"meta":27},[424],"(0,0)   (50,0)   (100,0)\n(0,50)  (50,50)  (100,50)\n(0,100) (50,100) (100,100)\n",[29,6453,6451],{"__ignoreMap":27},[151,6455,6456],{"id":6456},"回呼函式",[4538,6458,6459,6465,6471],{},[4541,6460,6461,6464],{},[29,6462,6463],{},"onStart","：動畫開始以前執行，只會執行一次。",[4541,6466,6467,6470],{},[29,6468,6469],{},"onUpdate","：動畫移動過程中不斷執行。",[4541,6472,6473,6476,6477,3775],{},[29,6474,6475],{},"onComplete","：動畫結束時呼叫，只會執行一次，例如 ",[29,6478,6479],{},"onComplete: move",[11,6481,6482],{},"這些回呼可用來做動畫生命週期的階段性偵測。",[151,6484,6486],{"id":6485},"staggerto",[29,6487,6488],{},"staggerTo",[11,6490,6491,6493],{},[29,6492,6488],{}," 會依序處理元素：",[22,6495,6497],{"className":24,"code":6496,"language":26,"meta":27,"style":27},"TweenMax.staggerTo(\n  '.pic',\n  0.5,\n  {\n    transform: 'translateY(0px)',\n    opacity: 1,\n  },\n  0.2,\n);\n",[29,6498,6499,6508,6515,6522,6527,6537,6547,6551,6558],{"__ignoreMap":27},[32,6500,6501,6504,6506],{"class":34,"line":35},[32,6502,6503],{"class":41},"TweenMax.",[32,6505,6488],{"class":217},[32,6507,539],{"class":41},[32,6509,6510,6513],{"class":34,"line":45},[32,6511,6512],{"class":175},"  '.pic'",[32,6514,547],{"class":41},[32,6516,6517,6520],{"class":34,"line":51},[32,6518,6519],{"class":351},"  0.5",[32,6521,547],{"class":41},[32,6523,6524],{"class":34,"line":90},[32,6525,6526],{"class":41},"  {\n",[32,6528,6529,6532,6535],{"class":34,"line":99},[32,6530,6531],{"class":41},"    transform: ",[32,6533,6534],{"class":175},"'translateY(0px)'",[32,6536,547],{"class":41},[32,6538,6539,6542,6545],{"class":34,"line":106},[32,6540,6541],{"class":41},"    opacity: ",[32,6543,6544],{"class":351},"1",[32,6546,547],{"class":41},[32,6548,6549],{"class":34,"line":114},[32,6550,5639],{"class":41},[32,6552,6553,6556],{"class":34,"line":120},[32,6554,6555],{"class":351},"  0.2",[32,6557,547],{"class":41},[32,6559,6560],{"class":34,"line":127},[32,6561,230],{"class":41},[11,6563,6564],{},"所有物件會間隔 0.2 秒出現。",[151,6566,6568],{"id":6567},"scrolltoplugin","ScrollToPlugin",[11,6570,6571,6572,3775],{},"捲軸處理使用 ScrollToPlugin，使用方式可查官方文件裡的 ",[29,6573,6574],{},"scrollTo",[15,6576,6577],{"id":6577},"其他動畫筆記",[11,6579,6580],{},"水平置中的 CSS：",[22,6582,6584],{"className":5412,"code":6583,"language":1140,"meta":27,"style":27},"display: flex;\njustify-content: center;\n",[29,6585,6586,6591],{"__ignoreMap":27},[32,6587,6588],{"class":34,"line":35},[32,6589,6590],{"class":41},"display: flex;\n",[32,6592,6593,6596],{"class":34,"line":45},[32,6594,6595],{"class":4049},"justify-content",[32,6597,6598],{"class":41},": center;\n",[11,6600,6601],{},"製作動畫時，先想好最後要呈現的樣子，再做初始化動作。",[11,6603,6604,6605,5240],{},"取得瀏覽器高度時，要扣掉物件本身的高度。物件的起始位置是左上角 ",[29,6606,6607],{},"(0, 0)",[22,6609,6611],{"className":24,"code":6610,"language":26,"meta":27,"style":27},"const availableHeight = window.innerHeight - elementHeight;\n",[29,6612,6613],{"__ignoreMap":27},[32,6614,6615,6618,6621,6623,6626,6629],{"class":34,"line":35},[32,6616,6617],{"class":38},"const",[32,6619,6620],{"class":351}," availableHeight",[32,6622,894],{"class":38},[32,6624,6625],{"class":41}," window.innerHeight ",[32,6627,6628],{"class":38},"-",[32,6630,6631],{"class":41}," elementHeight;\n",[11,6633,6634],{},"無限重複旋轉與運動速率：",[22,6636,6638],{"className":24,"code":6637,"language":26,"meta":27,"style":27},"repeat: -1;\nease: Linear.easeInOut;\n",[29,6639,6640,6653],{"__ignoreMap":27},[32,6641,6642,6645,6647,6649,6651],{"class":34,"line":35},[32,6643,6644],{"class":2066},"repeat",[32,6646,5269],{"class":41},[32,6648,6628],{"class":38},[32,6650,6544],{"class":351},[32,6652,96],{"class":41},[32,6654,6655,6658],{"class":34,"line":45},[32,6656,6657],{"class":2066},"ease",[32,6659,6660],{"class":41},": Linear.easeInOut;\n",[11,6662,6663,6664,3775],{},"各瀏覽器滑鼠滾動事件相容性可參考：",[412,6665,6668],{"href":6666,"rel":6667},"https:\u002F\u002Fwww.zhangxinxu.com\u002Fstudy\u002F201304\u002Fmousewheel-dommousescroll-same-different.html",[416],"滑鼠滾輪事件的相容性整理",[15,6670,6671],{"id":6671},"快捷鍵",[4538,6673,6674,6680],{},[4541,6675,6676,6679],{},[29,6677,6678],{},"Shift"," + 滑鼠右鍵：開啟命令視窗",[4541,6681,6682,6685,6686,6689],{},[29,6683,6684],{},"Ctrl+P","：輸入 ",[29,6687,6688],{},">icon"," 更換 VS Code 圖示",[368,6691,6692],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}",{"title":27,"searchDepth":51,"depth":51,"links":6694},[6695,6696,6697,6704,6705],{"id":6248,"depth":45,"text":6249},{"id":6366,"depth":45,"text":6367},{"id":6393,"depth":45,"text":6394,"children":6698},[6699,6700,6701,6702,6703],{"id":6416,"depth":51,"text":6419},{"id":6439,"depth":51,"text":6442},{"id":6456,"depth":51,"text":6456},{"id":6485,"depth":51,"text":6488},{"id":6567,"depth":51,"text":6568},{"id":6577,"depth":45,"text":6577},{"id":6671,"depth":45,"text":6671},"2018 年整理的 Node.js、VS Code 與 TweenMax 安裝及動畫操作筆記。",{},"\u002Fposts\u002Ftweenmax-install-notes","2018-09-23",[],{"title":6243,"description":6706},"posts\u002F20180923.tweenmax-install-notes",[6714,6394,6715,390],"GSAP","動畫","2026-08-24","bKt6DRP6TnBxibZGme3mfoXPifvC_27ObmOt0Rs1rrQ",{"id":6719,"title":6720,"body":6721,"category":378,"description":7025,"draft":380,"extension":381,"image":382,"meta":7026,"navigation":102,"path":7027,"publishedAt":7028,"relatedExperiments":7029,"seo":7030,"stem":7031,"tags":7032,"updatedAt":392,"__hash__":7034},"posts\u002Fposts\u002F20180926.legacy-virtual-keyboard-detection.md","JavaScript 虛擬鍵盤高度偵測筆記",{"type":8,"value":6722,"toc":7023},[6723,6730,7020],[11,6724,6725,6726,6729],{},"這段程式會記錄頁面原本的高度，並在 ",[29,6727,6728],{},"resize"," 時比較目前高度，判斷手機虛擬鍵盤是否彈出。",[22,6731,6733],{"className":24,"code":6732,"language":26,"meta":27,"style":27},"$(function () {\n  var winHeight = $(window).height();\n  $('.num').append('原高度:' + winHeight);\n\n  $(window).resize(function () {\n    var thisHeight = $(this).height();\n    $('.num').append('此高度:' + thisHeight);\n\n    if (winHeight - thisHeight > 50) {\n      \u002F\u002F 當軟鍵盤彈出，在這裡操作\n      $('body').css('height', winHeight + 'px');\n      $('body').css('background', 'red');\n      $('.num').append('鍵盤彈出後高度:' + winHeight);\n    } else {\n      \u002F\u002F 當軟鍵盤收起，在這裡操作\n      $('body').css('height', '100%');\n      $('.num').append('鍵盤收起:' + winHeight);\n    }\n  });\n});\n",[29,6734,6735,6745,6765,6788,6792,6806,6827,6849,6853,6871,6876,6905,6929,6950,6959,6964,6987,7008,7012,7016],{"__ignoreMap":27},[32,6736,6737,6739,6741,6743],{"class":34,"line":35},[32,6738,755],{"class":217},[32,6740,477],{"class":41},[32,6742,665],{"class":38},[32,6744,668],{"class":41},[32,6746,6747,6749,6752,6754,6757,6760,6763],{"class":34,"line":45},[32,6748,888],{"class":38},[32,6750,6751],{"class":41}," winHeight ",[32,6753,172],{"class":38},[32,6755,6756],{"class":217}," $",[32,6758,6759],{"class":41},"(window).",[32,6761,6762],{"class":217},"height",[32,6764,687],{"class":41},[32,6766,6767,6769,6771,6774,6776,6778,6780,6783,6785],{"class":34,"line":51},[32,6768,525],{"class":217},[32,6770,477],{"class":41},[32,6772,6773],{"class":175},"'.num'",[32,6775,533],{"class":41},[32,6777,6170],{"class":217},[32,6779,477],{"class":41},[32,6781,6782],{"class":175},"'原高度:'",[32,6784,1799],{"class":38},[32,6786,6787],{"class":41}," winHeight);\n",[32,6789,6790],{"class":34,"line":90},[32,6791,103],{"emptyLinePlaceholder":102},[32,6793,6794,6796,6798,6800,6802,6804],{"class":34,"line":99},[32,6795,525],{"class":217},[32,6797,6759],{"class":41},[32,6799,6728],{"class":217},[32,6801,477],{"class":41},[32,6803,665],{"class":38},[32,6805,668],{"class":41},[32,6807,6808,6810,6813,6815,6817,6819,6821,6823,6825],{"class":34,"line":106},[32,6809,911],{"class":38},[32,6811,6812],{"class":41}," thisHeight ",[32,6814,172],{"class":38},[32,6816,6756],{"class":217},[32,6818,477],{"class":41},[32,6820,1083],{"class":351},[32,6822,533],{"class":41},[32,6824,6762],{"class":217},[32,6826,687],{"class":41},[32,6828,6829,6831,6833,6835,6837,6839,6841,6844,6846],{"class":34,"line":114},[32,6830,674],{"class":217},[32,6832,477],{"class":41},[32,6834,6773],{"class":175},[32,6836,533],{"class":41},[32,6838,6170],{"class":217},[32,6840,477],{"class":41},[32,6842,6843],{"class":175},"'此高度:'",[32,6845,1799],{"class":38},[32,6847,6848],{"class":41}," thisHeight);\n",[32,6850,6851],{"class":34,"line":120},[32,6852,103],{"emptyLinePlaceholder":102},[32,6854,6855,6857,6860,6862,6864,6866,6869],{"class":34,"line":127},[32,6856,5554],{"class":38},[32,6858,6859],{"class":41}," (winHeight ",[32,6861,6628],{"class":38},[32,6863,6812],{"class":41},[32,6865,1615],{"class":38},[32,6867,6868],{"class":351}," 50",[32,6870,520],{"class":41},[32,6872,6873],{"class":34,"line":132},[32,6874,6875],{"class":608},"      \u002F\u002F 當軟鍵盤彈出，在這裡操作\n",[32,6877,6878,6881,6883,6886,6888,6890,6892,6895,6898,6900,6903],{"class":34,"line":141},[32,6879,6880],{"class":217},"      $",[32,6882,477],{"class":41},[32,6884,6885],{"class":175},"'body'",[32,6887,533],{"class":41},[32,6889,1140],{"class":217},[32,6891,477],{"class":41},[32,6893,6894],{"class":175},"'height'",[32,6896,6897],{"class":41},", winHeight ",[32,6899,224],{"class":38},[32,6901,6902],{"class":175}," 'px'",[32,6904,230],{"class":41},[32,6906,6907,6909,6911,6913,6915,6917,6919,6922,6924,6927],{"class":34,"line":147},[32,6908,6880],{"class":217},[32,6910,477],{"class":41},[32,6912,6885],{"class":175},[32,6914,533],{"class":41},[32,6916,1140],{"class":217},[32,6918,477],{"class":41},[32,6920,6921],{"class":175},"'background'",[32,6923,635],{"class":41},[32,6925,6926],{"class":175},"'red'",[32,6928,230],{"class":41},[32,6930,6931,6933,6935,6937,6939,6941,6943,6946,6948],{"class":34,"line":275},[32,6932,6880],{"class":217},[32,6934,477],{"class":41},[32,6936,6773],{"class":175},[32,6938,533],{"class":41},[32,6940,6170],{"class":217},[32,6942,477],{"class":41},[32,6944,6945],{"class":175},"'鍵盤彈出後高度:'",[32,6947,1799],{"class":38},[32,6949,6787],{"class":41},[32,6951,6952,6955,6957],{"class":34,"line":282},[32,6953,6954],{"class":41},"    } ",[32,6956,565],{"class":38},[32,6958,703],{"class":41},[32,6960,6961],{"class":34,"line":295},[32,6962,6963],{"class":608},"      \u002F\u002F 當軟鍵盤收起，在這裡操作\n",[32,6965,6966,6968,6970,6972,6974,6976,6978,6980,6982,6985],{"class":34,"line":605},[32,6967,6880],{"class":217},[32,6969,477],{"class":41},[32,6971,6885],{"class":175},[32,6973,533],{"class":41},[32,6975,1140],{"class":217},[32,6977,477],{"class":41},[32,6979,6894],{"class":175},[32,6981,635],{"class":41},[32,6983,6984],{"class":175},"'100%'",[32,6986,230],{"class":41},[32,6988,6989,6991,6993,6995,6997,6999,7001,7004,7006],{"class":34,"line":612},[32,6990,6880],{"class":217},[32,6992,477],{"class":41},[32,6994,6773],{"class":175},[32,6996,533],{"class":41},[32,6998,6170],{"class":217},[32,7000,477],{"class":41},[32,7002,7003],{"class":175},"'鍵盤收起:'",[32,7005,1799],{"class":38},[32,7007,6787],{"class":41},[32,7009,7010],{"class":34,"line":617},[32,7011,5591],{"class":41},[32,7013,7014],{"class":34,"line":644},[32,7015,693],{"class":41},[32,7017,7018],{"class":34,"line":649},[32,7019,792],{"class":41},[368,7021,7022],{},"html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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);}",{"title":27,"searchDepth":51,"depth":51,"links":7024},[],"2018 年透過 resize 前後的視窗高度差，判斷手機虛擬鍵盤是否彈出的筆記。",{},"\u002Fposts\u002Flegacy-virtual-keyboard-detection","2018-09-26",[],{"title":6720,"description":7025},"posts\u002F20180926.legacy-virtual-keyboard-detection",[390,2040,6027,7033],"虛擬鍵盤","8Urv9Xsdipg5PNg_ssEXmNCca4KT7IS9UI8ifjm87SA",{"id":7036,"title":7037,"body":7038,"category":378,"description":8402,"draft":380,"extension":381,"image":382,"meta":8403,"navigation":102,"path":8404,"publishedAt":8405,"relatedExperiments":8406,"seo":8407,"stem":8408,"tags":8409,"updatedAt":392,"__hash__":8411},"posts\u002Fposts\u002F20181024.webpack4-config-notes.md","Webpack 4 設定筆記",{"type":8,"value":7039,"toc":8394},[7040,7044,7047,7067,7073,7084,7094,7098,7190,7214,7226,7386,7389,7401,7404,7410,7420,7442,7455,7476,7489,7568,7571,7583,7587,7595,7730,7733,7747,7751,7760,7772,7784,7966,7985,7988,7992,7995,8017,8037,8041,8240,8245,8329,8332,8344,8356,8363,8366,8368,8391],[15,7041,7043],{"id":7042},"webpack-一開始的配置","Webpack 一開始的配置",[11,7045,7046],{},"建立環境：",[22,7048,7050],{"className":2057,"code":7049,"language":2059,"meta":27,"style":27},"npm install webpack webpack-cli --save-dev\n",[29,7051,7052],{"__ignoreMap":27},[32,7053,7054,7056,7058,7061,7064],{"class":34,"line":35},[32,7055,4625],{"class":2066},[32,7057,4650],{"class":175},[32,7059,7060],{"class":175}," webpack",[32,7062,7063],{"class":175}," webpack-cli",[32,7065,7066],{"class":351}," --save-dev\n",[11,7068,7069,7070,7072],{},"用 npm 建立 ",[29,7071,4945],{},"。設定檔資訊可以先按 Enter 跳過，之後再補：",[22,7074,7076],{"className":2057,"code":7075,"language":2059,"meta":27,"style":27},"npm init\n",[29,7077,7078],{"__ignoreMap":27},[32,7079,7080,7082],{"class":34,"line":35},[32,7081,4625],{"class":2066},[32,7083,2390],{"class":175},[11,7085,7086,7087,7090,7091,3775],{},"建立 ",[29,7088,7089],{},"webpack.config.js"," 與 ",[29,7092,7093],{},"index.js",[11,7095,7096,5240],{},[29,7097,7089],{},[22,7099,7101],{"className":24,"code":7100,"language":26,"meta":27,"style":27},"const path = require('path');\n\nmodule.exports = {\n  entry: '.\u002Findex.js',\n  output: {\n    filename: 'index.bundle.js',\n    path: path.resolve(__dirname, '.\u002F'),\n  },\n};\n",[29,7102,7103,7122,7126,7140,7150,7155,7165,7181,7185],{"__ignoreMap":27},[32,7104,7105,7107,7110,7112,7115,7117,7120],{"class":34,"line":35},[32,7106,6617],{"class":38},[32,7108,7109],{"class":351}," path",[32,7111,894],{"class":38},[32,7113,7114],{"class":217}," require",[32,7116,477],{"class":41},[32,7118,7119],{"class":175},"'path'",[32,7121,230],{"class":41},[32,7123,7124],{"class":34,"line":45},[32,7125,103],{"emptyLinePlaceholder":102},[32,7127,7128,7131,7133,7136,7138],{"class":34,"line":51},[32,7129,7130],{"class":351},"module",[32,7132,1278],{"class":41},[32,7134,7135],{"class":351},"exports",[32,7137,894],{"class":38},[32,7139,703],{"class":41},[32,7141,7142,7145,7148],{"class":34,"line":90},[32,7143,7144],{"class":41},"  entry: ",[32,7146,7147],{"class":175},"'.\u002Findex.js'",[32,7149,547],{"class":41},[32,7151,7152],{"class":34,"line":99},[32,7153,7154],{"class":41},"  output: {\n",[32,7156,7157,7160,7163],{"class":34,"line":106},[32,7158,7159],{"class":41},"    filename: ",[32,7161,7162],{"class":175},"'index.bundle.js'",[32,7164,547],{"class":41},[32,7166,7167,7170,7173,7176,7179],{"class":34,"line":114},[32,7168,7169],{"class":41},"    path: path.",[32,7171,7172],{"class":217},"resolve",[32,7174,7175],{"class":41},"(__dirname, ",[32,7177,7178],{"class":175},"'.\u002F'",[32,7180,5101],{"class":41},[32,7182,7183],{"class":34,"line":120},[32,7184,5639],{"class":41},[32,7186,7187],{"class":34,"line":127},[32,7188,7189],{"class":41},"};\n",[4538,7191,7192,7200],{},[4541,7193,7194,7197,7198,3775],{},[29,7195,7196],{},"entry","：進入點，這裡指定為 ",[29,7199,7093],{},[4541,7201,7202,7205,7206,7209,7210,7213],{},[29,7203,7204],{},"output","：打包後的輸出檔案。檔名在 ",[29,7207,7208],{},"index"," 後面加上 ",[29,7211,7212],{},"bundle","，用來辨認這是打包後的檔案。",[11,7215,5134,7216,7218,7219,7222,7223,5240],{},[29,7217,4945],{}," 的 ",[29,7220,7221],{},"scripts"," 加入 ",[29,7224,7225],{},"build",[22,7227,7229],{"className":5243,"code":7228,"language":5245,"meta":27,"style":27},"{\n  \"name\": \"webpack-test\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"build\": \"webpack\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"webpack\": \"^4.6.0\",\n    \"webpack-cli\": \"^2.0.15\"\n  }\n}\n",[29,7230,7231,7235,7247,7259,7271,7283,7289,7313,7322,7326,7337,7349,7356,7368,7378,7382],{"__ignoreMap":27},[32,7232,7233],{"class":34,"line":35},[32,7234,5252],{"class":41},[32,7236,7237,7240,7242,7245],{"class":34,"line":45},[32,7238,7239],{"class":5257},"  \"name\"",[32,7241,5269],{"class":41},[32,7243,7244],{"class":175},"\"webpack-test\"",[32,7246,547],{"class":41},[32,7248,7249,7252,7254,7257],{"class":34,"line":51},[32,7250,7251],{"class":5257},"  \"version\"",[32,7253,5269],{"class":41},[32,7255,7256],{"class":175},"\"1.0.0\"",[32,7258,547],{"class":41},[32,7260,7261,7264,7266,7269],{"class":34,"line":90},[32,7262,7263],{"class":5257},"  \"description\"",[32,7265,5269],{"class":41},[32,7267,7268],{"class":175},"\"\"",[32,7270,547],{"class":41},[32,7272,7273,7276,7278,7281],{"class":34,"line":99},[32,7274,7275],{"class":5257},"  \"main\"",[32,7277,5269],{"class":41},[32,7279,7280],{"class":175},"\"index.js\"",[32,7282,547],{"class":41},[32,7284,7285,7287],{"class":34,"line":106},[32,7286,5258],{"class":5257},[32,7288,5261],{"class":41},[32,7290,7291,7294,7296,7299,7303,7306,7308,7311],{"class":34,"line":114},[32,7292,7293],{"class":5257},"    \"test\"",[32,7295,5269],{"class":41},[32,7297,7298],{"class":175},"\"echo ",[32,7300,7302],{"class":7301},"sw7DY","\\\"",[32,7304,7305],{"class":175},"Error: no test specified",[32,7307,7302],{"class":7301},[32,7309,7310],{"class":175}," && exit 1\"",[32,7312,547],{"class":41},[32,7314,7315,7317,7319],{"class":34,"line":120},[32,7316,5279],{"class":5257},[32,7318,5269],{"class":41},[32,7320,7321],{"class":175},"\"webpack\"\n",[32,7323,7324],{"class":34,"line":127},[32,7325,5639],{"class":41},[32,7327,7328,7331,7333,7335],{"class":34,"line":132},[32,7329,7330],{"class":5257},"  \"author\"",[32,7332,5269],{"class":41},[32,7334,7268],{"class":175},[32,7336,547],{"class":41},[32,7338,7339,7342,7344,7347],{"class":34,"line":141},[32,7340,7341],{"class":5257},"  \"license\"",[32,7343,5269],{"class":41},[32,7345,7346],{"class":175},"\"ISC\"",[32,7348,547],{"class":41},[32,7350,7351,7354],{"class":34,"line":147},[32,7352,7353],{"class":5257},"  \"devDependencies\"",[32,7355,5261],{"class":41},[32,7357,7358,7361,7363,7366],{"class":34,"line":275},[32,7359,7360],{"class":5257},"    \"webpack\"",[32,7362,5269],{"class":41},[32,7364,7365],{"class":175},"\"^4.6.0\"",[32,7367,547],{"class":41},[32,7369,7370,7373,7375],{"class":34,"line":282},[32,7371,7372],{"class":5257},"    \"webpack-cli\"",[32,7374,5269],{"class":41},[32,7376,7377],{"class":175},"\"^2.0.15\"\n",[32,7379,7380],{"class":34,"line":295},[32,7381,1203],{"class":41},[32,7383,7384],{"class":34,"line":605},[32,7385,54],{"class":41},[11,7387,7388],{},"開啟終端機並執行打包：",[22,7390,7391],{"className":2057,"code":4973,"language":2059,"meta":27,"style":27},[29,7392,7393],{"__ignoreMap":27},[32,7394,7395,7397,7399],{"class":34,"line":35},[32,7396,4625],{"class":2066},[32,7398,4743],{"class":175},[32,7400,4755],{"class":175},[15,7402,7403],{"id":7403},"檔案路徑設定",[22,7405,7408],{"className":7406,"code":7407,"language":426,"meta":27},[424],"src\u002F  開發中的檔案\ndist\u002F 輸出編譯後的檔案\n",[29,7409,7407],{"__ignoreMap":27},[11,7411,7412,7413,7416,7417,7419],{},"Node.js 搬移檔案需要使用 ",[29,7414,7415],{},"path"," API，因此先在 ",[29,7418,7089],{}," 引入：",[22,7421,7423],{"className":24,"code":7422,"language":26,"meta":27,"style":27},"var path = require('path');\n",[29,7424,7425],{"__ignoreMap":27},[32,7426,7427,7429,7432,7434,7436,7438,7440],{"class":34,"line":35},[32,7428,166],{"class":38},[32,7430,7431],{"class":41}," path ",[32,7433,172],{"class":38},[32,7435,7114],{"class":217},[32,7437,477],{"class":41},[32,7439,7119],{"class":175},[32,7441,230],{"class":41},[11,7443,5134,7444,7222,7447,7450,7451,7454],{},[29,7445,7446],{},"module.exports",[29,7448,7449],{},"context","，用 ",[29,7452,7453],{},"path.resolve"," 指定起始路徑：",[22,7456,7458],{"className":24,"code":7457,"language":26,"meta":27,"style":27},"context: path.resolve(__dirname, 'src'),\n",[29,7459,7460],{"__ignoreMap":27},[32,7461,7462,7464,7467,7469,7471,7474],{"class":34,"line":35},[32,7463,7449],{"class":2066},[32,7465,7466],{"class":41},": path.",[32,7468,7172],{"class":217},[32,7470,7175],{"class":41},[32,7472,7473],{"class":175},"'src'",[32,7475,5101],{"class":41},[11,7477,7478,7481,7482,7484,7485,7488],{},[29,7479,7480],{},"__dirname"," 是目前執行檔案所在目錄的完整位置。第一個參數使用 ",[29,7483,7480],{},"，第二個參數指定從 ",[29,7486,7487],{},"src"," 資料夾開始找檔案。",[22,7490,7492],{"className":24,"code":7491,"language":26,"meta":27,"style":27},"var path = require('path');\n\nmodule.exports = {\n  context: path.resolve(__dirname, 'src'),\n  entry: '.\u002Findex.js',\n  output: {\n    filename: 'index-bundle.js',\n  },\n};\n",[29,7493,7494,7510,7514,7526,7539,7547,7551,7560,7564],{"__ignoreMap":27},[32,7495,7496,7498,7500,7502,7504,7506,7508],{"class":34,"line":35},[32,7497,166],{"class":38},[32,7499,7431],{"class":41},[32,7501,172],{"class":38},[32,7503,7114],{"class":217},[32,7505,477],{"class":41},[32,7507,7119],{"class":175},[32,7509,230],{"class":41},[32,7511,7512],{"class":34,"line":45},[32,7513,103],{"emptyLinePlaceholder":102},[32,7515,7516,7518,7520,7522,7524],{"class":34,"line":51},[32,7517,7130],{"class":351},[32,7519,1278],{"class":41},[32,7521,7135],{"class":351},[32,7523,894],{"class":38},[32,7525,703],{"class":41},[32,7527,7528,7531,7533,7535,7537],{"class":34,"line":90},[32,7529,7530],{"class":41},"  context: path.",[32,7532,7172],{"class":217},[32,7534,7175],{"class":41},[32,7536,7473],{"class":175},[32,7538,5101],{"class":41},[32,7540,7541,7543,7545],{"class":34,"line":99},[32,7542,7144],{"class":41},[32,7544,7147],{"class":175},[32,7546,547],{"class":41},[32,7548,7549],{"class":34,"line":106},[32,7550,7154],{"class":41},[32,7552,7553,7555,7558],{"class":34,"line":114},[32,7554,7159],{"class":41},[32,7556,7557],{"class":175},"'index-bundle.js'",[32,7559,547],{"class":41},[32,7561,7562],{"class":34,"line":120},[32,7563,5639],{"class":41},[32,7565,7566],{"class":34,"line":127},[32,7567,7189],{"class":41},[11,7569,7570],{},"設定路徑後執行：",[22,7572,7573],{"className":2057,"code":4973,"language":2059,"meta":27,"style":27},[29,7574,7575],{"__ignoreMap":27},[32,7576,7577,7579,7581],{"class":34,"line":35},[32,7578,4625],{"class":2066},[32,7580,4743],{"class":175},[32,7582,4755],{"class":175},[15,7584,7586],{"id":7585},"watch-設定","watch 設定",[11,7588,5134,7589,7222,7591,7594],{},[29,7590,4945],{},[29,7592,7593],{},"watch","，監控 JavaScript 檔案；檔案變動後會自動執行編譯。",[22,7596,7598],{"className":5243,"code":7597,"language":5245,"meta":27,"style":27},"{\n  \"name\": \"watch\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"webpack.config.js\",\n  \"scripts\": {\n    \"watch\": \"webpack --watch\",\n    \"build\": \"webpack\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"webpack\": \"^4.16.5\",\n    \"webpack-cli\": \"^3.1.0\"\n  }\n}\n",[29,7599,7600,7604,7615,7625,7635,7646,7652,7664,7672,7676,7686,7696,7702,7713,7722,7726],{"__ignoreMap":27},[32,7601,7602],{"class":34,"line":35},[32,7603,5252],{"class":41},[32,7605,7606,7608,7610,7613],{"class":34,"line":45},[32,7607,7239],{"class":5257},[32,7609,5269],{"class":41},[32,7611,7612],{"class":175},"\"watch\"",[32,7614,547],{"class":41},[32,7616,7617,7619,7621,7623],{"class":34,"line":51},[32,7618,7251],{"class":5257},[32,7620,5269],{"class":41},[32,7622,7256],{"class":175},[32,7624,547],{"class":41},[32,7626,7627,7629,7631,7633],{"class":34,"line":90},[32,7628,7263],{"class":5257},[32,7630,5269],{"class":41},[32,7632,7268],{"class":175},[32,7634,547],{"class":41},[32,7636,7637,7639,7641,7644],{"class":34,"line":99},[32,7638,7275],{"class":5257},[32,7640,5269],{"class":41},[32,7642,7643],{"class":175},"\"webpack.config.js\"",[32,7645,547],{"class":41},[32,7647,7648,7650],{"class":34,"line":106},[32,7649,5258],{"class":5257},[32,7651,5261],{"class":41},[32,7653,7654,7657,7659,7662],{"class":34,"line":114},[32,7655,7656],{"class":5257},"    \"watch\"",[32,7658,5269],{"class":41},[32,7660,7661],{"class":175},"\"webpack --watch\"",[32,7663,547],{"class":41},[32,7665,7666,7668,7670],{"class":34,"line":120},[32,7667,5279],{"class":5257},[32,7669,5269],{"class":41},[32,7671,7321],{"class":175},[32,7673,7674],{"class":34,"line":127},[32,7675,5639],{"class":41},[32,7677,7678,7680,7682,7684],{"class":34,"line":132},[32,7679,7330],{"class":5257},[32,7681,5269],{"class":41},[32,7683,7268],{"class":175},[32,7685,547],{"class":41},[32,7687,7688,7690,7692,7694],{"class":34,"line":141},[32,7689,7341],{"class":5257},[32,7691,5269],{"class":41},[32,7693,7346],{"class":175},[32,7695,547],{"class":41},[32,7697,7698,7700],{"class":34,"line":147},[32,7699,7353],{"class":5257},[32,7701,5261],{"class":41},[32,7703,7704,7706,7708,7711],{"class":34,"line":275},[32,7705,7360],{"class":5257},[32,7707,5269],{"class":41},[32,7709,7710],{"class":175},"\"^4.16.5\"",[32,7712,547],{"class":41},[32,7714,7715,7717,7719],{"class":34,"line":282},[32,7716,7372],{"class":5257},[32,7718,5269],{"class":41},[32,7720,7721],{"class":175},"\"^3.1.0\"\n",[32,7723,7724],{"class":34,"line":295},[32,7725,1203],{"class":41},[32,7727,7728],{"class":34,"line":605},[32,7729,54],{"class":41},[11,7731,7732],{},"設定完成後執行：",[22,7734,7736],{"className":2057,"code":7735,"language":2059,"meta":27,"style":27},"npm run watch\n",[29,7737,7738],{"__ignoreMap":27},[32,7739,7740,7742,7744],{"class":34,"line":35},[32,7741,4625],{"class":2066},[32,7743,4743],{"class":175},[32,7745,7746],{"class":175}," watch\n",[15,7748,7750],{"id":7749},"mode-設定","mode 設定",[11,7752,7753,7754,7090,7757,5240],{},"Webpack 編譯分為 ",[29,7755,7756],{},"production",[29,7758,7759],{},"development",[4538,7761,7762,7767],{},[4541,7763,7764,7766],{},[29,7765,7756],{},"：上線版本，會壓縮與最佳化檔案。",[4541,7768,7769,7771],{},[29,7770,7759],{},"：開發中，只編譯。",[11,7773,7774,7775,7777,7778,7781,7782,5240],{},"Webpack 4 預設是 ",[29,7776,7756],{},"。如果沒有設定 ",[29,7779,7780],{},"mode","，執行 watch 時也會壓縮與最佳化，比較消耗資源，因此在 npm script 加上 ",[29,7783,7759],{},[22,7785,7787],{"className":5243,"code":7786,"language":5245,"meta":27,"style":27},"{\n  \"name\": \"Babel\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"webpack.config.js\",\n  \"scripts\": {\n    \"watch\": \"webpack --mode development --watch\",\n    \"start\": \"webpack --mode development\",\n    \"deploy\": \"webpack --mode production\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"@babel\u002Fcore\": \"^7.0.0\",\n    \"@babel\u002Fpreset-env\": \"^7.0.0\",\n    \"babel-loader\": \"^8.0.2\",\n    \"webpack\": \"^4.21.0\",\n    \"webpack-cli\": \"^3.1.2\"\n  }\n}\n",[29,7788,7789,7793,7804,7814,7824,7834,7840,7851,7863,7873,7877,7887,7897,7903,7915,7926,7938,7949,7958,7962],{"__ignoreMap":27},[32,7790,7791],{"class":34,"line":35},[32,7792,5252],{"class":41},[32,7794,7795,7797,7799,7802],{"class":34,"line":45},[32,7796,7239],{"class":5257},[32,7798,5269],{"class":41},[32,7800,7801],{"class":175},"\"Babel\"",[32,7803,547],{"class":41},[32,7805,7806,7808,7810,7812],{"class":34,"line":51},[32,7807,7251],{"class":5257},[32,7809,5269],{"class":41},[32,7811,7256],{"class":175},[32,7813,547],{"class":41},[32,7815,7816,7818,7820,7822],{"class":34,"line":90},[32,7817,7263],{"class":5257},[32,7819,5269],{"class":41},[32,7821,7268],{"class":175},[32,7823,547],{"class":41},[32,7825,7826,7828,7830,7832],{"class":34,"line":99},[32,7827,7275],{"class":5257},[32,7829,5269],{"class":41},[32,7831,7643],{"class":175},[32,7833,547],{"class":41},[32,7835,7836,7838],{"class":34,"line":106},[32,7837,5258],{"class":5257},[32,7839,5261],{"class":41},[32,7841,7842,7844,7846,7849],{"class":34,"line":114},[32,7843,7656],{"class":5257},[32,7845,5269],{"class":41},[32,7847,7848],{"class":175},"\"webpack --mode development --watch\"",[32,7850,547],{"class":41},[32,7852,7853,7856,7858,7861],{"class":34,"line":120},[32,7854,7855],{"class":5257},"    \"start\"",[32,7857,5269],{"class":41},[32,7859,7860],{"class":175},"\"webpack --mode development\"",[32,7862,547],{"class":41},[32,7864,7865,7868,7870],{"class":34,"line":127},[32,7866,7867],{"class":5257},"    \"deploy\"",[32,7869,5269],{"class":41},[32,7871,7872],{"class":175},"\"webpack --mode production\"\n",[32,7874,7875],{"class":34,"line":132},[32,7876,5639],{"class":41},[32,7878,7879,7881,7883,7885],{"class":34,"line":141},[32,7880,7330],{"class":5257},[32,7882,5269],{"class":41},[32,7884,7268],{"class":175},[32,7886,547],{"class":41},[32,7888,7889,7891,7893,7895],{"class":34,"line":147},[32,7890,7341],{"class":5257},[32,7892,5269],{"class":41},[32,7894,7346],{"class":175},[32,7896,547],{"class":41},[32,7898,7899,7901],{"class":34,"line":275},[32,7900,7353],{"class":5257},[32,7902,5261],{"class":41},[32,7904,7905,7908,7910,7913],{"class":34,"line":282},[32,7906,7907],{"class":5257},"    \"@babel\u002Fcore\"",[32,7909,5269],{"class":41},[32,7911,7912],{"class":175},"\"^7.0.0\"",[32,7914,547],{"class":41},[32,7916,7917,7920,7922,7924],{"class":34,"line":295},[32,7918,7919],{"class":5257},"    \"@babel\u002Fpreset-env\"",[32,7921,5269],{"class":41},[32,7923,7912],{"class":175},[32,7925,547],{"class":41},[32,7927,7928,7931,7933,7936],{"class":34,"line":605},[32,7929,7930],{"class":5257},"    \"babel-loader\"",[32,7932,5269],{"class":41},[32,7934,7935],{"class":175},"\"^8.0.2\"",[32,7937,547],{"class":41},[32,7939,7940,7942,7944,7947],{"class":34,"line":612},[32,7941,7360],{"class":5257},[32,7943,5269],{"class":41},[32,7945,7946],{"class":175},"\"^4.21.0\"",[32,7948,547],{"class":41},[32,7950,7951,7953,7955],{"class":34,"line":617},[32,7952,7372],{"class":5257},[32,7954,5269],{"class":41},[32,7956,7957],{"class":175},"\"^3.1.2\"\n",[32,7959,7960],{"class":34,"line":644},[32,7961,1203],{"class":41},[32,7963,7964],{"class":34,"line":649},[32,7965,54],{"class":41},[4538,7967,7968,7973,7979],{},[4541,7969,7970,7972],{},[29,7971,7593],{},"：持續編譯不中斷，使用 development 版本。",[4541,7974,7975,7978],{},[29,7976,7977],{},"start","：執行一次編譯，使用 development 版本。",[4541,7980,7981,7984],{},[29,7982,7983],{},"deploy","：執行一次編譯，使用 production 版本。",[11,7986,7987],{},"Development 的程式碼不會被壓縮。",[15,7989,7991],{"id":7990},"javascript-與-babel","JavaScript 與 Babel",[11,7993,7994],{},"安裝 Babel：",[22,7996,7998],{"className":2057,"code":7997,"language":2059,"meta":27,"style":27},"npm install babel-loader @babel\u002Fcore @babel\u002Fpreset-env --save-dev\n",[29,7999,8000],{"__ignoreMap":27},[32,8001,8002,8004,8006,8009,8012,8015],{"class":34,"line":35},[32,8003,4625],{"class":2066},[32,8005,4650],{"class":175},[32,8007,8008],{"class":175}," babel-loader",[32,8010,8011],{"class":175}," @babel\u002Fcore",[32,8013,8014],{"class":175}," @babel\u002Fpreset-env",[32,8016,7066],{"class":351},[6426,8018,8019,8025,8031],{},[4541,8020,8021,8024],{},[29,8022,8023],{},"babel-loader","：讓 Webpack 判讀並轉換檔案。",[4541,8026,8027,8030],{},[29,8028,8029],{},"@babel\u002Fcore","：提供 Babel 編譯用的 API。",[4541,8032,8033,8036],{},[29,8034,8035],{},"@babel\u002Fpreset-env","：使用新版 JavaScript 語法時，不必逐一設定需要轉換的語法。",[11,8038,8039,5240],{},[29,8040,7089],{},[22,8042,8044],{"className":24,"code":8043,"language":26,"meta":27,"style":27},"var path = require('path');\n\nmodule.exports = {\n  context: path.resolve(__dirname, 'js'),\n  entry: {\n    index: '.\u002Findex.js',\n  },\n  output: {\n    path: path.resolve(__dirname, 'js'),\n    filename: '.\u002Findex.bundle.js',\n  },\n  module: {\n    rules: [\n      {\n        test: \u002F\\.(js)$\u002F,\n        exclude: \u002F(node_modules)\u002F,\n        use: {\n          loader: 'babel-loader',\n          options: {\n            presets: ['@babel\u002Fpreset-env'],\n          },\n        },\n      },\n    ],\n  },\n};\n",[29,8045,8046,8062,8066,8078,8091,8096,8105,8109,8113,8125,8134,8138,8143,8148,8153,8172,8182,8187,8197,8202,8213,8218,8223,8227,8232,8236],{"__ignoreMap":27},[32,8047,8048,8050,8052,8054,8056,8058,8060],{"class":34,"line":35},[32,8049,166],{"class":38},[32,8051,7431],{"class":41},[32,8053,172],{"class":38},[32,8055,7114],{"class":217},[32,8057,477],{"class":41},[32,8059,7119],{"class":175},[32,8061,230],{"class":41},[32,8063,8064],{"class":34,"line":45},[32,8065,103],{"emptyLinePlaceholder":102},[32,8067,8068,8070,8072,8074,8076],{"class":34,"line":51},[32,8069,7130],{"class":351},[32,8071,1278],{"class":41},[32,8073,7135],{"class":351},[32,8075,894],{"class":38},[32,8077,703],{"class":41},[32,8079,8080,8082,8084,8086,8089],{"class":34,"line":90},[32,8081,7530],{"class":41},[32,8083,7172],{"class":217},[32,8085,7175],{"class":41},[32,8087,8088],{"class":175},"'js'",[32,8090,5101],{"class":41},[32,8092,8093],{"class":34,"line":99},[32,8094,8095],{"class":41},"  entry: {\n",[32,8097,8098,8101,8103],{"class":34,"line":106},[32,8099,8100],{"class":41},"    index: ",[32,8102,7147],{"class":175},[32,8104,547],{"class":41},[32,8106,8107],{"class":34,"line":114},[32,8108,5639],{"class":41},[32,8110,8111],{"class":34,"line":120},[32,8112,7154],{"class":41},[32,8114,8115,8117,8119,8121,8123],{"class":34,"line":127},[32,8116,7169],{"class":41},[32,8118,7172],{"class":217},[32,8120,7175],{"class":41},[32,8122,8088],{"class":175},[32,8124,5101],{"class":41},[32,8126,8127,8129,8132],{"class":34,"line":132},[32,8128,7159],{"class":41},[32,8130,8131],{"class":175},"'.\u002Findex.bundle.js'",[32,8133,547],{"class":41},[32,8135,8136],{"class":34,"line":141},[32,8137,5639],{"class":41},[32,8139,8140],{"class":34,"line":147},[32,8141,8142],{"class":41},"  module: {\n",[32,8144,8145],{"class":34,"line":275},[32,8146,8147],{"class":41},"    rules: [\n",[32,8149,8150],{"class":34,"line":282},[32,8151,8152],{"class":41},"      {\n",[32,8154,8155,8158,8161,8163,8166,8168,8170],{"class":34,"line":295},[32,8156,8157],{"class":41},"        test:",[32,8159,8160],{"class":175}," \u002F",[32,8162,1272],{"class":1265},[32,8164,8165],{"class":175},"(js)",[32,8167,755],{"class":38},[32,8169,1275],{"class":175},[32,8171,547],{"class":41},[32,8173,8174,8177,8180],{"class":34,"line":605},[32,8175,8176],{"class":41},"        exclude:",[32,8178,8179],{"class":175}," \u002F(node_modules)\u002F",[32,8181,547],{"class":41},[32,8183,8184],{"class":34,"line":612},[32,8185,8186],{"class":41},"        use: {\n",[32,8188,8189,8192,8195],{"class":34,"line":617},[32,8190,8191],{"class":41},"          loader: ",[32,8193,8194],{"class":175},"'babel-loader'",[32,8196,547],{"class":41},[32,8198,8199],{"class":34,"line":644},[32,8200,8201],{"class":41},"          options: {\n",[32,8203,8204,8207,8210],{"class":34,"line":649},[32,8205,8206],{"class":41},"            presets: [",[32,8208,8209],{"class":175},"'@babel\u002Fpreset-env'",[32,8211,8212],{"class":41},"],\n",[32,8214,8215],{"class":34,"line":671},[32,8216,8217],{"class":41},"          },\n",[32,8219,8220],{"class":34,"line":690},[32,8221,8222],{"class":41},"        },\n",[32,8224,8225],{"class":34,"line":696},[32,8226,4500],{"class":41},[32,8228,8229],{"class":34,"line":706},[32,8230,8231],{"class":41},"    ],\n",[32,8233,8234],{"class":34,"line":721},[32,8235,5639],{"class":41},[32,8237,8238],{"class":34,"line":728},[32,8239,7189],{"class":41},[11,8241,5134,8242,8244],{},[29,8243,7093],{}," 使用 ES6 語法測試：",[22,8246,8248],{"className":24,"code":8247,"language":26,"meta":27,"style":27},"const Name = ['Mike', 'Jacky', 'Andy', 'Scars'];\nName.forEach((obj, idx) => console.log(`${idx} => ${obj}`));\n",[29,8249,8250,8283],{"__ignoreMap":27},[32,8251,8252,8254,8257,8259,8262,8265,8267,8270,8272,8275,8277,8280],{"class":34,"line":35},[32,8253,6617],{"class":38},[32,8255,8256],{"class":351}," Name",[32,8258,894],{"class":38},[32,8260,8261],{"class":41}," [",[32,8263,8264],{"class":175},"'Mike'",[32,8266,635],{"class":41},[32,8268,8269],{"class":175},"'Jacky'",[32,8271,635],{"class":41},[32,8273,8274],{"class":175},"'Andy'",[32,8276,635],{"class":41},[32,8278,8279],{"class":175},"'Scars'",[32,8281,8282],{"class":41},"];\n",[32,8284,8285,8288,8291,8294,8297,8299,8302,8304,8306,8309,8311,8313,8316,8318,8321,8323,8326],{"class":34,"line":45},[32,8286,8287],{"class":41},"Name.",[32,8289,8290],{"class":217},"forEach",[32,8292,8293],{"class":41},"((",[32,8295,8296],{"class":903},"obj",[32,8298,635],{"class":41},[32,8300,8301],{"class":903},"idx",[32,8303,483],{"class":41},[32,8305,5090],{"class":38},[32,8307,8308],{"class":41}," console.",[32,8310,5197],{"class":217},[32,8312,477],{"class":41},[32,8314,8315],{"class":175},"`${",[32,8317,8301],{"class":41},[32,8319,8320],{"class":175},"} => ${",[32,8322,8296],{"class":41},[32,8324,8325],{"class":175},"}`",[32,8327,8328],{"class":41},"));\n",[11,8330,8331],{},"執行：",[22,8333,8334],{"className":2057,"code":7735,"language":2059,"meta":27,"style":27},[29,8335,8336],{"__ignoreMap":27},[32,8337,8338,8340,8342],{"class":34,"line":35},[32,8339,4625],{"class":2066},[32,8341,4743],{"class":175},[32,8343,7746],{"class":175},[11,8345,8346,8347,8349,8350,8352,8353,8355],{},"編譯結果會把 ",[29,8348,6617],{}," 轉成 ",[29,8351,166],{},"、箭頭函式轉成 ",[29,8354,665],{},"，字串模板也會組回一般字串，代表程式已編譯成 ES5。",[11,8357,8358,8359,8362],{},"正式上專案前要執行 ",[29,8360,8361],{},"npm run deploy","，讓 production 編譯壓縮及最佳化程式碼。",[11,8364,8365],{},"Babel 不只轉換新版 JavaScript，也可以轉換 React 的 JSX 與 TypeScript 等語法。",[15,8367,4536],{"id":4536},[4538,8369,8370,8377,8384],{},[4541,8371,8372],{},[412,8373,8376],{"href":8374,"rel":8375},"https:\u002F\u002Fwww.cnblogs.com\u002Fzaking\u002Fp\u002F8586458.html",[416],"Webpack 配置參考",[4541,8378,8379],{},[412,8380,8383],{"href":8381,"rel":8382},"https:\u002F\u002Ffrontenddev.org\u002Farticle\u002Fcoolie-pk-battle-with-webpack-1-js-file-consolidation-and-compression.html",[416],"JavaScript 檔案合併與壓縮",[4541,8385,8386],{},[412,8387,8390],{"href":8388,"rel":8389},"https:\u002F\u002Fmedium.com\u002F@Mike_Cheng1208\u002F%E4%BB%80%E9%BA%BC%E6%98%AFwebpack-%E4%BD%A0%E9%9C%80%E8%A6%81webpack%E5%97%8E-2d8f9658241d",[416],"什麼是 webpack？你需要 webpack 嗎",[368,8392,8393],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .swgif, html code.shiki .swgif{--shiki-default:#005CC5;--shiki-dark:#7EE787}html pre.shiki code .sw7DY, html code.shiki .sw7DY{--shiki-default:#005CC5;--shiki-dark:#FF7B72}html pre.shiki code .sh9l7, html code.shiki .sh9l7{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#7EE787;--shiki-dark-font-weight:bold}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}",{"title":27,"searchDepth":51,"depth":51,"links":8395},[8396,8397,8398,8399,8400,8401],{"id":7042,"depth":45,"text":7043},{"id":7403,"depth":45,"text":7403},{"id":7585,"depth":45,"text":7586},{"id":7749,"depth":45,"text":7750},{"id":7990,"depth":45,"text":7991},{"id":4536,"depth":45,"text":4536},"2018 年整理的 Webpack 4 基本配置、路徑、watch、mode 與 Babel 設定。",{},"\u002Fposts\u002Fwebpack4-config-notes","2018-10-24",[],{"title":7037,"description":8402},"posts\u002F20181024.webpack4-config-notes",[8410,4850,390],"Webpack","uL2rRwQqtYziOo7WpITS_ymdjiSa8cXB_x7hz13upWk",{"id":8413,"title":8414,"body":8415,"category":378,"description":10509,"draft":380,"extension":381,"image":382,"meta":10510,"navigation":102,"path":10511,"publishedAt":10512,"relatedExperiments":10513,"seo":10514,"stem":10515,"tags":10516,"updatedAt":392,"__hash__":10518},"posts\u002Fposts\u002F20181029.vue2-project-kit.md","Vue CLI、Bootstrap 與常用套件安裝筆記",{"type":8,"value":8416,"toc":10488},[8417,8420,8422,8424,8437,8471,8491,8495,8498,8515,8521,8524,8535,8538,8567,8570,8598,8600,8612,8616,8660,8663,8730,8733,8750,8753,8780,8785,8809,8813,8832,8836,8899,8905,9019,9023,9039,9043,9052,9106,9109,9142,9145,9148,9165,9169,9234,9239,9347,9354,9357,9363,9366,9533,9536,9546,9549,9565,9612,9776,9780,9794,9798,9830,9833,9918,9924,9927,10021,10024,10030,10069,10072,10183,10186,10193,10209,10213,10245,10248,10280,10284,10290,10295,10371,10376,10398,10405,10409,10415,10418,10439,10442,10485],[11,8418,8419],{},"這邊記錄手動安裝vuecli，\n第三方套件要往上放，先安裝 Node.js。",[15,8421,6249],{"id":6248},[11,8423,6252],{},[4538,8425,8426,8431,8435],{},[4541,8427,6257,8428],{},[412,8429,6262],{"href":6260,"rel":8430},[416],[4541,8432,6265,8433],{},[29,8434,6268],{},[4541,8436,6271],{},[22,8438,8439],{"className":2057,"code":6274,"language":2059,"meta":27,"style":27},[29,8440,8441,8447,8455,8463],{"__ignoreMap":27},[32,8442,8443,8445],{"class":34,"line":35},[32,8444,6281],{"class":2066},[32,8446,6284],{"class":175},[32,8448,8449,8451,8453],{"class":34,"line":45},[32,8450,6281],{"class":2066},[32,8452,6291],{"class":175},[32,8454,6294],{"class":175},[32,8456,8457,8459,8461],{"class":34,"line":51},[32,8458,6281],{"class":2066},[32,8460,4650],{"class":175},[32,8462,6303],{"class":175},[32,8464,8465,8467,8469],{"class":34,"line":90},[32,8466,6281],{"class":2066},[32,8468,6310],{"class":175},[32,8470,6303],{"class":175},[4538,8472,8473,8477,8481,8485,8489],{},[4541,8474,8475,6320],{},[29,8476,6319],{},[4541,8478,8479,6326],{},[29,8480,6325],{},[4541,8482,8483,6332],{},[29,8484,6331],{},[4541,8486,8487,6338],{},[29,8488,6337],{},[4541,8490,6341],{},[15,8492,8494],{"id":8493},"安裝-vue-cli","安裝 Vue CLI",[11,8496,8497],{},"全域安裝一次：",[22,8499,8501],{"className":2057,"code":8500,"language":2059,"meta":27,"style":27},"npm i -g vue-cli\n",[29,8502,8503],{"__ignoreMap":27},[32,8504,8505,8507,8510,8512],{"class":34,"line":35},[32,8506,4625],{"class":2066},[32,8508,8509],{"class":175}," i",[32,8511,4653],{"class":351},[32,8513,8514],{"class":175}," vue-cli\n",[11,8516,8517,8520],{},[29,8518,8519],{},"-g"," 代表全域安裝。",[11,8522,8523],{},"查看模板清單：",[22,8525,8527],{"className":2057,"code":8526,"language":2059,"meta":27,"style":27},"vue list\n",[29,8528,8529],{"__ignoreMap":27},[32,8530,8531,8533],{"class":34,"line":35},[32,8532,4112],{"class":2066},[32,8534,6284],{"class":175},[11,8536,8537],{},"空資料夾可以選擇下列模板：",[4538,8539,8540,8545,8550,8555,8561],{},[4541,8541,8542],{},[29,8543,8544],{},"browserify",[4541,8546,8547],{},[29,8548,8549],{},"browserify-simple",[4541,8551,8552],{},[29,8553,8554],{},"pwa",[4541,8556,8557,8560],{},[29,8558,8559],{},"webpack","：主要模板",[4541,8562,8563,8566],{},[29,8564,8565],{},"webpack-simple","：基本架構",[11,8568,8569],{},"如果要使用 SCSS，設定過程要選擇 Yes。",[22,8571,8573],{"className":2057,"code":8572,"language":2059,"meta":27,"style":27},"vue init webpack 資料夾名稱\nvue init webpack-simple 資料夾名稱\n",[29,8574,8575,8587],{"__ignoreMap":27},[32,8576,8577,8579,8582,8584],{"class":34,"line":35},[32,8578,4112],{"class":2066},[32,8580,8581],{"class":175}," init",[32,8583,7060],{"class":175},[32,8585,8586],{"class":175}," 資料夾名稱\n",[32,8588,8589,8591,8593,8596],{"class":34,"line":45},[32,8590,4112],{"class":2066},[32,8592,8581],{"class":175},[32,8594,8595],{"class":175}," webpack-simple",[32,8597,8586],{"class":175},[11,8599,6344],{},[22,8601,8603],{"className":2057,"code":8602,"language":2059,"meta":27,"style":27},"vue -V\n",[29,8604,8605],{"__ignoreMap":27},[32,8606,8607,8609],{"class":34,"line":35},[32,8608,4112],{"class":2066},[32,8610,8611],{"class":351}," -V\n",[15,8613,8615],{"id":8614},"安裝-sass-與-bootstrap","安裝 Sass 與 Bootstrap",[22,8617,8619],{"className":2057,"code":8618,"language":2059,"meta":27,"style":27},"npm install bootstrap node-sass sass-loader --save\nnpm install --save jquery\nnpm install popper.js\n",[29,8620,8621,8639,8651],{"__ignoreMap":27},[32,8622,8623,8625,8627,8630,8633,8636],{"class":34,"line":35},[32,8624,4625],{"class":2066},[32,8626,4650],{"class":175},[32,8628,8629],{"class":175}," bootstrap",[32,8631,8632],{"class":175}," node-sass",[32,8634,8635],{"class":175}," sass-loader",[32,8637,8638],{"class":351}," --save\n",[32,8640,8641,8643,8645,8648],{"class":34,"line":45},[32,8642,4625],{"class":2066},[32,8644,4650],{"class":175},[32,8646,8647],{"class":351}," --save",[32,8649,8650],{"class":175}," jquery\n",[32,8652,8653,8655,8657],{"class":34,"line":51},[32,8654,4625],{"class":2066},[32,8656,4650],{"class":175},[32,8658,8659],{"class":175}," popper.js\n",[11,8661,8662],{},"測試 SCSS：",[22,8664,8667],{"className":8665,"code":8666,"language":4112,"meta":27,"style":27},"language-vue shiki shiki-themes github-light github-dark-default","\u003Cstyle lang=\"scss\">\n$color: #000;\n\nbody {\n  background-color: $color;\n}\n\u003C\u002Fstyle>\n",[29,8668,8669,8685,8697,8701,8707,8718,8722],{"__ignoreMap":27},[32,8670,8671,8673,8675,8678,8680,8683],{"class":34,"line":35},[32,8672,4046],{"class":41},[32,8674,368],{"class":4049},[32,8676,8677],{"class":4053}," lang",[32,8679,172],{"class":41},[32,8681,8682],{"class":175},"\"scss\"",[32,8684,4062],{"class":41},[32,8686,8687,8690,8692,8695],{"class":34,"line":45},[32,8688,8689],{"class":903},"$color",[32,8691,5269],{"class":5049},[32,8693,8694],{"class":351},"#000",[32,8696,96],{"class":41},[32,8698,8699],{"class":34,"line":51},[32,8700,103],{"emptyLinePlaceholder":102},[32,8702,8703,8705],{"class":34,"line":90},[32,8704,5495],{"class":4049},[32,8706,703],{"class":41},[32,8708,8709,8712,8714,8716],{"class":34,"line":99},[32,8710,8711],{"class":351},"  background-color",[32,8713,5269],{"class":41},[32,8715,8689],{"class":903},[32,8717,96],{"class":41},[32,8719,8720],{"class":34,"line":106},[32,8721,54],{"class":41},[32,8723,8724,8726,8728],{"class":34,"line":114},[32,8725,4105],{"class":41},[32,8727,368],{"class":4049},[32,8729,4062],{"class":41},[11,8731,8732],{},"引入 Bootstrap：",[22,8734,8738],{"className":8735,"code":8736,"language":8737,"meta":27,"style":27},"language-scss shiki shiki-themes github-light github-dark-default","@import '~bootstrap\u002Fscss\u002Fbootstrap';\n","scss",[29,8739,8740],{"__ignoreMap":27},[32,8741,8742,8745,8748],{"class":34,"line":35},[32,8743,8744],{"class":38},"@import",[32,8746,8747],{"class":175}," '~bootstrap\u002Fscss\u002Fbootstrap'",[32,8749,96],{"class":41},[11,8751,8752],{},"如果要指定當時使用的 Bootstrap 4 版本：",[22,8754,8756],{"className":2057,"code":8755,"language":2059,"meta":27,"style":27},"npm install --save jquery popper.js\nnpm install bootstrap@4.0.0-beta.3\n",[29,8757,8758,8771],{"__ignoreMap":27},[32,8759,8760,8762,8764,8766,8769],{"class":34,"line":35},[32,8761,4625],{"class":2066},[32,8763,4650],{"class":175},[32,8765,8647],{"class":351},[32,8767,8768],{"class":175}," jquery",[32,8770,8659],{"class":175},[32,8772,8773,8775,8777],{"class":34,"line":45},[32,8774,4625],{"class":2066},[32,8776,4650],{"class":175},[32,8778,8779],{"class":175}," bootstrap@4.0.0-beta.3\n",[11,8781,5134,8782,8784],{},[29,8783,5137],{}," 引入 Bootstrap 的 SCSS 與 JavaScript 模組：",[22,8786,8788],{"className":24,"code":8787,"language":26,"meta":27,"style":27},"import 'bootstrap\u002Fscss\u002Fbootstrap.scss';\nimport 'bootstrap';\n",[29,8789,8790,8800],{"__ignoreMap":27},[32,8791,8792,8795,8798],{"class":34,"line":35},[32,8793,8794],{"class":38},"import",[32,8796,8797],{"class":175}," 'bootstrap\u002Fscss\u002Fbootstrap.scss'",[32,8799,96],{"class":41},[32,8801,8802,8804,8807],{"class":34,"line":45},[32,8803,8794],{"class":38},[32,8805,8806],{"class":175}," 'bootstrap'",[32,8808,96],{"class":41},[15,8810,8812],{"id":8811},"axios-與-vue-axios","axios 與 vue-axios",[22,8814,8816],{"className":2057,"code":8815,"language":2059,"meta":27,"style":27},"npm install --save axios vue-axios\n",[29,8817,8818],{"__ignoreMap":27},[32,8819,8820,8822,8824,8826,8829],{"class":34,"line":35},[32,8821,4625],{"class":2066},[32,8823,4650],{"class":175},[32,8825,8647],{"class":351},[32,8827,8828],{"class":175}," axios",[32,8830,8831],{"class":175}," vue-axios\n",[11,8833,5134,8834,7419],{},[29,8835,5137],{},[22,8837,8839],{"className":24,"code":8838,"language":26,"meta":27,"style":27},"import Vue from 'vue';\nimport axios from 'axios';\nimport VueAxios from 'vue-axios';\n\nVue.use(VueAxios, axios);\n",[29,8840,8841,8856,8870,8884,8888],{"__ignoreMap":27},[32,8842,8843,8845,8848,8851,8854],{"class":34,"line":35},[32,8844,8794],{"class":38},[32,8846,8847],{"class":41}," Vue ",[32,8849,8850],{"class":38},"from",[32,8852,8853],{"class":175}," 'vue'",[32,8855,96],{"class":41},[32,8857,8858,8860,8863,8865,8868],{"class":34,"line":45},[32,8859,8794],{"class":38},[32,8861,8862],{"class":41}," axios ",[32,8864,8850],{"class":38},[32,8866,8867],{"class":175}," 'axios'",[32,8869,96],{"class":41},[32,8871,8872,8874,8877,8879,8882],{"class":34,"line":51},[32,8873,8794],{"class":38},[32,8875,8876],{"class":41}," VueAxios ",[32,8878,8850],{"class":38},[32,8880,8881],{"class":175}," 'vue-axios'",[32,8883,96],{"class":41},[32,8885,8886],{"class":34,"line":90},[32,8887,103],{"emptyLinePlaceholder":102},[32,8889,8890,8893,8896],{"class":34,"line":99},[32,8891,8892],{"class":41},"Vue.",[32,8894,8895],{"class":217},"use",[32,8897,8898],{"class":41},"(VueAxios, axios);\n",[11,8900,8901,8902,5240],{},"測試資料可使用 ",[29,8903,8904],{},"https:\u002F\u002Frandomuser.me\u002Fapi\u002F",[22,8906,8908],{"className":24,"code":8907,"language":26,"meta":27,"style":27},"created() {\n  const url = 'https:\u002F\u002Frandomuser.me\u002Fapi\u002F';\n\n  this.axios.get(url).then((response) => {\n    console.log(response.data);\n  });\n\n  this.$http.get(url).then((response) => {\n    console.log(response.data);\n  });\n}\n",[29,8909,8910,8916,8930,8934,8962,8972,8976,8980,9003,9011,9015],{"__ignoreMap":27},[32,8911,8912,8914],{"class":34,"line":35},[32,8913,5187],{"class":217},[32,8915,4221],{"class":41},[32,8917,8918,8920,8923,8925,8928],{"class":34,"line":45},[32,8919,4157],{"class":38},[32,8921,8922],{"class":351}," url",[32,8924,894],{"class":38},[32,8926,8927],{"class":175}," 'https:\u002F\u002Frandomuser.me\u002Fapi\u002F'",[32,8929,96],{"class":41},[32,8931,8932],{"class":34,"line":51},[32,8933,103],{"emptyLinePlaceholder":102},[32,8935,8936,8939,8942,8945,8948,8951,8953,8956,8958,8960],{"class":34,"line":90},[32,8937,8938],{"class":351},"  this",[32,8940,8941],{"class":41},".axios.",[32,8943,8944],{"class":217},"get",[32,8946,8947],{"class":41},"(url).",[32,8949,8950],{"class":217},"then",[32,8952,8293],{"class":41},[32,8954,8955],{"class":903},"response",[32,8957,483],{"class":41},[32,8959,5090],{"class":38},[32,8961,703],{"class":41},[32,8963,8964,8967,8969],{"class":34,"line":99},[32,8965,8966],{"class":41},"    console.",[32,8968,5197],{"class":217},[32,8970,8971],{"class":41},"(response.data);\n",[32,8973,8974],{"class":34,"line":106},[32,8975,693],{"class":41},[32,8977,8978],{"class":34,"line":114},[32,8979,103],{"emptyLinePlaceholder":102},[32,8981,8982,8984,8987,8989,8991,8993,8995,8997,8999,9001],{"class":34,"line":120},[32,8983,8938],{"class":351},[32,8985,8986],{"class":41},".$http.",[32,8988,8944],{"class":217},[32,8990,8947],{"class":41},[32,8992,8950],{"class":217},[32,8994,8293],{"class":41},[32,8996,8955],{"class":903},[32,8998,483],{"class":41},[32,9000,5090],{"class":38},[32,9002,703],{"class":41},[32,9004,9005,9007,9009],{"class":34,"line":127},[32,9006,8966],{"class":41},[32,9008,5197],{"class":217},[32,9010,8971],{"class":41},[32,9012,9013],{"class":34,"line":132},[32,9014,693],{"class":41},[32,9016,9017],{"class":34,"line":141},[32,9018,54],{"class":41},[151,9020,9022],{"id":9021},"相關連結參考","相關連結參考：",[4538,9024,9025,9032],{},[4541,9026,9027],{},[412,9028,9031],{"href":9029,"rel":9030},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fvue-axios",[416],"vue-axios",[4541,9033,9034,3775],{},[412,9035,9038],{"href":9036,"rel":9037},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10188510",[416],"iT 邦幫忙文章",[15,9040,9042],{"id":9041},"設定-api-路徑","設定 API 路徑",[11,9044,9045,9046,7090,9049,5240],{},"設定 ",[29,9047,9048],{},"config\u002Fdev.env.js",[29,9050,9051],{},"config\u002Fprod.env.js",[22,9053,9055],{"className":24,"code":9054,"language":26,"meta":27,"style":27},"module.exports = merge(prodEnv, {\n  NODE_ENV: '\"development\"',\n  APIPATH: '\"https:\u002F\u002Fxxx.xxx.xxx\u002F\"',\n  CUSTOMPATH: '\"adminUser\"',\n});\n",[29,9056,9057,9072,9082,9092,9102],{"__ignoreMap":27},[32,9058,9059,9061,9063,9065,9067,9069],{"class":34,"line":35},[32,9060,7130],{"class":351},[32,9062,1278],{"class":41},[32,9064,7135],{"class":351},[32,9066,894],{"class":38},[32,9068,3324],{"class":217},[32,9070,9071],{"class":41},"(prodEnv, {\n",[32,9073,9074,9077,9080],{"class":34,"line":45},[32,9075,9076],{"class":41},"  NODE_ENV: ",[32,9078,9079],{"class":175},"'\"development\"'",[32,9081,547],{"class":41},[32,9083,9084,9087,9090],{"class":34,"line":51},[32,9085,9086],{"class":41},"  APIPATH: ",[32,9088,9089],{"class":175},"'\"https:\u002F\u002Fxxx.xxx.xxx\u002F\"'",[32,9091,547],{"class":41},[32,9093,9094,9097,9100],{"class":34,"line":90},[32,9095,9096],{"class":41},"  CUSTOMPATH: ",[32,9098,9099],{"class":175},"'\"adminUser\"'",[32,9101,547],{"class":41},[32,9103,9104],{"class":34,"line":99},[32,9105,792],{"class":41},[11,9107,9108],{},"設定完成後要重啟 Vue CLI。在需要使用的頁面輸入：",[22,9110,9112],{"className":24,"code":9111,"language":26,"meta":27,"style":27},"const url = `${process.env.APIPATH}\u002Fadmin\u002Fsignin`;\n",[29,9113,9114],{"__ignoreMap":27},[32,9115,9116,9118,9120,9122,9125,9128,9130,9132,9134,9137,9140],{"class":34,"line":35},[32,9117,6617],{"class":38},[32,9119,8922],{"class":351},[32,9121,894],{"class":38},[32,9123,9124],{"class":175}," `${",[32,9126,9127],{"class":41},"process",[32,9129,1278],{"class":175},[32,9131,5162],{"class":41},[32,9133,1278],{"class":175},[32,9135,9136],{"class":351},"APIPATH",[32,9138,9139],{"class":175},"}\u002Fadmin\u002Fsignin`",[32,9141,96],{"class":41},[15,9143,4841],{"id":9144},"vue-router",[11,9146,9147],{},"如果沒有安裝 Vue Router：",[22,9149,9151],{"className":2057,"code":9150,"language":2059,"meta":27,"style":27},"npm i -s vue-router\n",[29,9152,9153],{"__ignoreMap":27},[32,9154,9155,9157,9159,9162],{"class":34,"line":35},[32,9156,4625],{"class":2066},[32,9158,8509],{"class":175},[32,9160,9161],{"class":351}," -s",[32,9163,9164],{"class":175}," vue-router\n",[11,9166,9167,5240],{},[29,9168,5137],{},[22,9170,9172],{"className":24,"code":9171,"language":26,"meta":27,"style":27},"import router from '.\u002Frouter';\n\nnew Vue({\n  el: '#app',\n  router,\n  components: { App },\n  template: '\u003CApp\u002F>',\n});\n",[29,9173,9174,9188,9192,9201,9210,9215,9220,9230],{"__ignoreMap":27},[32,9175,9176,9178,9181,9183,9186],{"class":34,"line":35},[32,9177,8794],{"class":38},[32,9179,9180],{"class":41}," router ",[32,9182,8850],{"class":38},[32,9184,9185],{"class":175}," '.\u002Frouter'",[32,9187,96],{"class":41},[32,9189,9190],{"class":34,"line":45},[32,9191,103],{"emptyLinePlaceholder":102},[32,9193,9194,9197,9199],{"class":34,"line":51},[32,9195,9196],{"class":38},"new",[32,9198,4168],{"class":217},[32,9200,1143],{"class":41},[32,9202,9203,9206,9208],{"class":34,"line":90},[32,9204,9205],{"class":41},"  el: ",[32,9207,4178],{"class":175},[32,9209,547],{"class":41},[32,9211,9212],{"class":34,"line":99},[32,9213,9214],{"class":41},"  router,\n",[32,9216,9217],{"class":34,"line":106},[32,9218,9219],{"class":41},"  components: { App },\n",[32,9221,9222,9225,9228],{"class":34,"line":114},[32,9223,9224],{"class":41},"  template: ",[32,9226,9227],{"class":175},"'\u003CApp\u002F>'",[32,9229,547],{"class":41},[32,9231,9232],{"class":34,"line":120},[32,9233,792],{"class":41},[11,9235,9236,5240],{},[29,9237,9238],{},"router\u002Findex.js",[22,9240,9242],{"className":24,"code":9241,"language":26,"meta":27,"style":27},"import Router from 'vue-router';\nimport login from '@\u002Fcomponents\u002Fpages\u002Flogin';\n\nVue.use(Router);\n\nexport default new Router({\n  routes: [\n    {\n      path: '\u002F',\n      name: 'xxx',\n      component: xxx,\n    },\n  ],\n});\n",[29,9243,9244,9258,9272,9276,9285,9289,9301,9305,9309,9317,9326,9331,9335,9341],{"__ignoreMap":27},[32,9245,9246,9248,9251,9253,9256],{"class":34,"line":35},[32,9247,8794],{"class":38},[32,9249,9250],{"class":41}," Router ",[32,9252,8850],{"class":38},[32,9254,9255],{"class":175}," 'vue-router'",[32,9257,96],{"class":41},[32,9259,9260,9262,9265,9267,9270],{"class":34,"line":45},[32,9261,8794],{"class":38},[32,9263,9264],{"class":41}," login ",[32,9266,8850],{"class":38},[32,9268,9269],{"class":175}," '@\u002Fcomponents\u002Fpages\u002Flogin'",[32,9271,96],{"class":41},[32,9273,9274],{"class":34,"line":51},[32,9275,103],{"emptyLinePlaceholder":102},[32,9277,9278,9280,9282],{"class":34,"line":90},[32,9279,8892],{"class":41},[32,9281,8895],{"class":217},[32,9283,9284],{"class":41},"(Router);\n",[32,9286,9287],{"class":34,"line":99},[32,9288,103],{"emptyLinePlaceholder":102},[32,9290,9291,9293,9295,9297,9299],{"class":34,"line":106},[32,9292,5038],{"class":38},[32,9294,5041],{"class":38},[32,9296,4165],{"class":38},[32,9298,5046],{"class":217},[32,9300,1143],{"class":5049},[32,9302,9303],{"class":34,"line":114},[32,9304,5054],{"class":41},[32,9306,9307],{"class":34,"line":120},[32,9308,5059],{"class":41},[32,9310,9311,9313,9315],{"class":34,"line":127},[32,9312,5064],{"class":41},[32,9314,5067],{"class":175},[32,9316,547],{"class":41},[32,9318,9319,9321,9324],{"class":34,"line":132},[32,9320,5074],{"class":41},[32,9322,9323],{"class":175},"'xxx'",[32,9325,547],{"class":41},[32,9327,9328],{"class":34,"line":141},[32,9329,9330],{"class":41},"      component: xxx,\n",[32,9332,9333],{"class":34,"line":147},[32,9334,4204],{"class":41},[32,9336,9337,9339],{"class":34,"line":275},[32,9338,5110],{"class":41},[32,9340,547],{"class":5049},[32,9342,9343,9345],{"class":34,"line":282},[32,9344,5117],{"class":5049},[32,9346,96],{"class":41},[11,9348,9349,9350,9353],{},"元件使用 ",[29,9351,9352],{},"\u003Crouter-view\u002F>"," 顯示路由內容。",[151,9355,9356],{"id":9356},"導航守衛",[11,9358,9359,9360,3775],{},"導航守衛用來驗證使用者是否需要登入，在路由加入 ",[29,9361,9362],{},"meta: { requiresAuth: true }",[11,9364,9365],{},"檢查權限：",[22,9367,9369],{"className":24,"code":9368,"language":26,"meta":27,"style":27},"router.beforeEach((to, from, next) => {\n  if (to.meta.requiresAuth) {\n    const api = `${process.env.APIPATH}\u002Fapi\u002Fuser\u002Fcheck`;\n\n    axios.post(api).then((response) => {\n      if (response.data.success) {\n        next();\n      } else {\n        next({\n          path: '\u002Flogin',\n        });\n      }\n    });\n  } else {\n    next();\n  }\n});\n",[29,9370,9371,9398,9405,9432,9436,9459,9466,9473,9482,9488,9498,9502,9506,9510,9518,9525,9529],{"__ignoreMap":27},[32,9372,9373,9376,9379,9381,9383,9385,9387,9389,9392,9394,9396],{"class":34,"line":35},[32,9374,9375],{"class":41},"router.",[32,9377,9378],{"class":217},"beforeEach",[32,9380,8293],{"class":41},[32,9382,6416],{"class":903},[32,9384,635],{"class":41},[32,9386,8850],{"class":903},[32,9388,635],{"class":41},[32,9390,9391],{"class":903},"next",[32,9393,483],{"class":41},[32,9395,5090],{"class":38},[32,9397,703],{"class":41},[32,9399,9400,9402],{"class":34,"line":45},[32,9401,1021],{"class":38},[32,9403,9404],{"class":41}," (to.meta.requiresAuth) {\n",[32,9406,9407,9410,9413,9415,9417,9419,9421,9423,9425,9427,9430],{"class":34,"line":51},[32,9408,9409],{"class":38},"    const",[32,9411,9412],{"class":351}," api",[32,9414,894],{"class":38},[32,9416,9124],{"class":175},[32,9418,9127],{"class":41},[32,9420,1278],{"class":175},[32,9422,5162],{"class":41},[32,9424,1278],{"class":175},[32,9426,9136],{"class":351},[32,9428,9429],{"class":175},"}\u002Fapi\u002Fuser\u002Fcheck`",[32,9431,96],{"class":41},[32,9433,9434],{"class":34,"line":90},[32,9435,103],{"emptyLinePlaceholder":102},[32,9437,9438,9441,9444,9447,9449,9451,9453,9455,9457],{"class":34,"line":99},[32,9439,9440],{"class":41},"    axios.",[32,9442,9443],{"class":217},"post",[32,9445,9446],{"class":41},"(api).",[32,9448,8950],{"class":217},[32,9450,8293],{"class":41},[32,9452,8955],{"class":903},[32,9454,483],{"class":41},[32,9456,5090],{"class":38},[32,9458,703],{"class":41},[32,9460,9461,9463],{"class":34,"line":106},[32,9462,1071],{"class":38},[32,9464,9465],{"class":41}," (response.data.success) {\n",[32,9467,9468,9471],{"class":34,"line":114},[32,9469,9470],{"class":217},"        next",[32,9472,687],{"class":41},[32,9474,9475,9478,9480],{"class":34,"line":120},[32,9476,9477],{"class":41},"      } ",[32,9479,565],{"class":38},[32,9481,703],{"class":41},[32,9483,9484,9486],{"class":34,"line":127},[32,9485,9470],{"class":217},[32,9487,1143],{"class":41},[32,9489,9490,9493,9496],{"class":34,"line":132},[32,9491,9492],{"class":41},"          path: ",[32,9494,9495],{"class":175},"'\u002Flogin'",[32,9497,547],{"class":41},[32,9499,9500],{"class":34,"line":141},[32,9501,1188],{"class":41},[32,9503,9504],{"class":34,"line":147},[32,9505,1193],{"class":41},[32,9507,9508],{"class":34,"line":275},[32,9509,1198],{"class":41},[32,9511,9512,9514,9516],{"class":34,"line":282},[32,9513,5911],{"class":41},[32,9515,565],{"class":38},[32,9517,703],{"class":41},[32,9519,9520,9523],{"class":34,"line":295},[32,9521,9522],{"class":217},"    next",[32,9524,687],{"class":41},[32,9526,9527],{"class":34,"line":605},[32,9528,1203],{"class":41},[32,9530,9531],{"class":34,"line":612},[32,9532,792],{"class":41},[11,9534,9535],{},"當時的筆記是：頁面第一次無法觸發時，必須點選下一頁才會執行。",[11,9537,9538,9541,9542,9545],{},[29,9539,9540],{},"axios"," 可以直接使用；",[29,9543,9544],{},"this.$http"," 要在 Vue 元件內使用。",[15,9547,9548],{"id":9548},"vue-loading-overlay",[22,9550,9552],{"className":2057,"code":9551,"language":2059,"meta":27,"style":27},"npm install vue-loading-overlay --save\n",[29,9553,9554],{"__ignoreMap":27},[32,9555,9556,9558,9560,9563],{"class":34,"line":35},[32,9557,4625],{"class":2066},[32,9559,4650],{"class":175},[32,9561,9562],{"class":175}," vue-loading-overlay",[32,9564,8638],{"class":351},[22,9566,9568],{"className":24,"code":9567,"language":26,"meta":27,"style":27},"import Loading from 'vue-loading-overlay';\nimport 'vue-loading-overlay\u002Fdist\u002Fvue-loading.min.css';\n\nVue.component('Loading', Loading);\n",[29,9569,9570,9584,9593,9597],{"__ignoreMap":27},[32,9571,9572,9574,9577,9579,9582],{"class":34,"line":35},[32,9573,8794],{"class":38},[32,9575,9576],{"class":41}," Loading ",[32,9578,8850],{"class":38},[32,9580,9581],{"class":175}," 'vue-loading-overlay'",[32,9583,96],{"class":41},[32,9585,9586,9588,9591],{"class":34,"line":45},[32,9587,8794],{"class":38},[32,9589,9590],{"class":175}," 'vue-loading-overlay\u002Fdist\u002Fvue-loading.min.css'",[32,9592,96],{"class":41},[32,9594,9595],{"class":34,"line":51},[32,9596,103],{"emptyLinePlaceholder":102},[32,9598,9599,9601,9604,9606,9609],{"class":34,"line":90},[32,9600,8892],{"class":41},[32,9602,9603],{"class":217},"component",[32,9605,477],{"class":41},[32,9607,9608],{"class":175},"'Loading'",[32,9610,9611],{"class":41},", Loading);\n",[22,9613,9615],{"className":8665,"code":9614,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cloading\n      :active.sync=\"isLoading\"\n      :can-cancel=\"true\"\n      :on-cancel=\"onCancel\"\n      :is-full-page=\"fullPage\"\n    \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  data() {\n    return {\n      isLoading: false,\n    };\n  },\n};\n\u003C\u002Fscript>\n",[29,9616,9617,9626,9634,9642,9652,9662,9672,9682,9687,9696,9704,9708,9716,9724,9733,9739,9749,9754,9761,9768],{"__ignoreMap":27},[32,9618,9619,9621,9624],{"class":34,"line":35},[32,9620,4046],{"class":41},[32,9622,9623],{"class":4049},"template",[32,9625,4062],{"class":41},[32,9627,9628,9630,9632],{"class":34,"line":45},[32,9629,4067],{"class":41},[32,9631,4050],{"class":4049},[32,9633,4062],{"class":41},[32,9635,9636,9639],{"class":34,"line":51},[32,9637,9638],{"class":41},"    \u003C",[32,9640,9641],{"class":4049},"loading\n",[32,9643,9644,9647,9649],{"class":34,"line":90},[32,9645,9646],{"class":4053},"      :active.sync",[32,9648,172],{"class":41},[32,9650,9651],{"class":175},"\"isLoading\"\n",[32,9653,9654,9657,9659],{"class":34,"line":99},[32,9655,9656],{"class":4053},"      :can-cancel",[32,9658,172],{"class":41},[32,9660,9661],{"class":175},"\"true\"\n",[32,9663,9664,9667,9669],{"class":34,"line":106},[32,9665,9666],{"class":4053},"      :on-cancel",[32,9668,172],{"class":41},[32,9670,9671],{"class":175},"\"onCancel\"\n",[32,9673,9674,9677,9679],{"class":34,"line":114},[32,9675,9676],{"class":4053},"      :is-full-page",[32,9678,172],{"class":41},[32,9680,9681],{"class":175},"\"fullPage\"\n",[32,9683,9684],{"class":34,"line":120},[32,9685,9686],{"class":41},"    \u002F>\n",[32,9688,9689,9692,9694],{"class":34,"line":127},[32,9690,9691],{"class":41},"  \u003C\u002F",[32,9693,4050],{"class":4049},[32,9695,4062],{"class":41},[32,9697,9698,9700,9702],{"class":34,"line":132},[32,9699,4105],{"class":41},[32,9701,9623],{"class":4049},[32,9703,4062],{"class":41},[32,9705,9706],{"class":34,"line":141},[32,9707,103],{"emptyLinePlaceholder":102},[32,9709,9710,9712,9714],{"class":34,"line":147},[32,9711,4046],{"class":41},[32,9713,4125],{"class":4049},[32,9715,4062],{"class":41},[32,9717,9718,9720,9722],{"class":34,"line":275},[32,9719,5038],{"class":38},[32,9721,5041],{"class":38},[32,9723,703],{"class":5049},[32,9725,9726,9729,9731],{"class":34,"line":282},[32,9727,9728],{"class":217},"  data",[32,9730,6075],{"class":5049},[32,9732,5252],{"class":41},[32,9734,9735,9737],{"class":34,"line":295},[32,9736,971],{"class":38},[32,9738,703],{"class":41},[32,9740,9741,9744,9747],{"class":34,"line":605},[32,9742,9743],{"class":41},"      isLoading: ",[32,9745,9746],{"class":351},"false",[32,9748,547],{"class":41},[32,9750,9751],{"class":34,"line":612},[32,9752,9753],{"class":41},"    };\n",[32,9755,9756,9759],{"class":34,"line":617},[32,9757,9758],{"class":41},"  }",[32,9760,547],{"class":5049},[32,9762,9763,9766],{"class":34,"line":644},[32,9764,9765],{"class":5049},"}",[32,9767,96],{"class":41},[32,9769,9770,9772,9774],{"class":34,"line":649},[32,9771,4105],{"class":41},[32,9773,4125],{"class":4049},[32,9775,4062],{"class":41},[15,9777,9779],{"id":9778},"vee-validate","Vee Validate",[22,9781,9783],{"className":2057,"code":9782,"language":2059,"meta":27,"style":27},"npm install vee-validate\n",[29,9784,9785],{"__ignoreMap":27},[32,9786,9787,9789,9791],{"class":34,"line":35},[32,9788,4625],{"class":2066},[32,9790,4650],{"class":175},[32,9792,9793],{"class":175}," vee-validate\n",[11,9795,5134,9796,7419],{},[29,9797,5137],{},[22,9799,9801],{"className":24,"code":9800,"language":26,"meta":27,"style":27},"import VeeValidate from 'vee-validate';\n\nVue.use(VeeValidate);\n",[29,9802,9803,9817,9821],{"__ignoreMap":27},[32,9804,9805,9807,9810,9812,9815],{"class":34,"line":35},[32,9806,8794],{"class":38},[32,9808,9809],{"class":41}," VeeValidate ",[32,9811,8850],{"class":38},[32,9813,9814],{"class":175}," 'vee-validate'",[32,9816,96],{"class":41},[32,9818,9819],{"class":34,"line":45},[32,9820,103],{"emptyLinePlaceholder":102},[32,9822,9823,9825,9827],{"class":34,"line":51},[32,9824,8892],{"class":41},[32,9826,8895],{"class":217},[32,9828,9829],{"class":41},"(VeeValidate);\n",[11,9831,9832],{},"姓名欄位判斷：",[22,9834,9836],{"className":4038,"code":9835,"language":4034,"meta":27,"style":27},"\u003Cinput\n  type=\"text\"\n  name=\"name\"\n  :class=\"{ 'is-invalid': errors.has('name') }\"\n  v-validate=\"'required'\"\n>\n\u003Cspan class=\"text-danger\" v-if=\"errors.has('name')\">姓名必須輸入\u003C\u002Fspan>\n",[29,9837,9838,9845,9855,9865,9875,9885,9889],{"__ignoreMap":27},[32,9839,9840,9842],{"class":34,"line":35},[32,9841,4046],{"class":41},[32,9843,9844],{"class":4049},"input\n",[32,9846,9847,9850,9852],{"class":34,"line":45},[32,9848,9849],{"class":4053},"  type",[32,9851,172],{"class":41},[32,9853,9854],{"class":175},"\"text\"\n",[32,9856,9857,9860,9862],{"class":34,"line":51},[32,9858,9859],{"class":4053},"  name",[32,9861,172],{"class":41},[32,9863,9864],{"class":175},"\"name\"\n",[32,9866,9867,9870,9872],{"class":34,"line":90},[32,9868,9869],{"class":4053},"  :class",[32,9871,172],{"class":41},[32,9873,9874],{"class":175},"\"{ 'is-invalid': errors.has('name') }\"\n",[32,9876,9877,9880,9882],{"class":34,"line":99},[32,9878,9879],{"class":4053},"  v-validate",[32,9881,172],{"class":41},[32,9883,9884],{"class":175},"\"'required'\"\n",[32,9886,9887],{"class":34,"line":106},[32,9888,4062],{"class":41},[32,9890,9891,9893,9895,9898,9900,9903,9906,9908,9911,9914,9916],{"class":34,"line":114},[32,9892,4046],{"class":41},[32,9894,32],{"class":4049},[32,9896,9897],{"class":4053}," class",[32,9899,172],{"class":41},[32,9901,9902],{"class":175},"\"text-danger\"",[32,9904,9905],{"class":4053}," v-if",[32,9907,172],{"class":41},[32,9909,9910],{"class":175},"\"errors.has('name')\"",[32,9912,9913],{"class":41},">姓名必須輸入\u003C\u002F",[32,9915,32],{"class":4049},[32,9917,4062],{"class":41},[11,9919,9920,9923],{},[29,9921,9922],{},"v-validate=\"'required'\""," 代表必須輸入。欄位點選後沒有輸入，再移出欄位時會顯示錯誤。",[11,9925,9926],{},"Email 欄位判斷：",[22,9928,9930],{"className":4038,"code":9929,"language":4034,"meta":27,"style":27},"\u003Cinput\n  type=\"text\"\n  name=\"email\"\n  v-model=\"form.user.email\"\n  :class=\"{ 'is-invalid': errors.has('email') }\"\n  v-validate=\"'required|email'\"\n>\n\u003Cspan class=\"text-danger\" v-if=\"errors.has('email')\">\n  {{ errors.first('email') }}\n\u003C\u002Fspan>\n",[29,9931,9932,9938,9946,9955,9965,9974,9983,9987,10008,10013],{"__ignoreMap":27},[32,9933,9934,9936],{"class":34,"line":35},[32,9935,4046],{"class":41},[32,9937,9844],{"class":4049},[32,9939,9940,9942,9944],{"class":34,"line":45},[32,9941,9849],{"class":4053},[32,9943,172],{"class":41},[32,9945,9854],{"class":175},[32,9947,9948,9950,9952],{"class":34,"line":51},[32,9949,9859],{"class":4053},[32,9951,172],{"class":41},[32,9953,9954],{"class":175},"\"email\"\n",[32,9956,9957,9960,9962],{"class":34,"line":90},[32,9958,9959],{"class":4053},"  v-model",[32,9961,172],{"class":41},[32,9963,9964],{"class":175},"\"form.user.email\"\n",[32,9966,9967,9969,9971],{"class":34,"line":99},[32,9968,9869],{"class":4053},[32,9970,172],{"class":41},[32,9972,9973],{"class":175},"\"{ 'is-invalid': errors.has('email') }\"\n",[32,9975,9976,9978,9980],{"class":34,"line":106},[32,9977,9879],{"class":4053},[32,9979,172],{"class":41},[32,9981,9982],{"class":175},"\"'required|email'\"\n",[32,9984,9985],{"class":34,"line":114},[32,9986,4062],{"class":41},[32,9988,9989,9991,9993,9995,9997,9999,10001,10003,10006],{"class":34,"line":120},[32,9990,4046],{"class":41},[32,9992,32],{"class":4049},[32,9994,9897],{"class":4053},[32,9996,172],{"class":41},[32,9998,9902],{"class":175},[32,10000,9905],{"class":4053},[32,10002,172],{"class":41},[32,10004,10005],{"class":175},"\"errors.has('email')\"",[32,10007,4062],{"class":41},[32,10009,10010],{"class":34,"line":127},[32,10011,10012],{"class":41},"  {{ errors.first('email') }}\n",[32,10014,10015,10017,10019],{"class":34,"line":132},[32,10016,4105],{"class":41},[32,10018,32],{"class":4049},[32,10020,4062],{"class":41},[151,10022,10023],{"id":10023},"驗證語系",[11,10025,10026,10027,3775],{},"語系路徑：",[29,10028,10029],{},"node_modules\u002Fvee-validate\u002Fdist\u002Flocale\u002F",[22,10031,10033],{"className":24,"code":10032,"language":26,"meta":27,"style":27},"import zhTWValidate from 'vee-validate\u002Fdist\u002Flocale\u002Fzh_TW';\n\nVeeValidate.Validator.localize('zh_TW', zhTWValidate);\n",[29,10034,10035,10049,10053],{"__ignoreMap":27},[32,10036,10037,10039,10042,10044,10047],{"class":34,"line":35},[32,10038,8794],{"class":38},[32,10040,10041],{"class":41}," zhTWValidate ",[32,10043,8850],{"class":38},[32,10045,10046],{"class":175}," 'vee-validate\u002Fdist\u002Flocale\u002Fzh_TW'",[32,10048,96],{"class":41},[32,10050,10051],{"class":34,"line":45},[32,10052,103],{"emptyLinePlaceholder":102},[32,10054,10055,10058,10061,10063,10066],{"class":34,"line":51},[32,10056,10057],{"class":41},"VeeValidate.Validator.",[32,10059,10060],{"class":217},"localize",[32,10062,477],{"class":41},[32,10064,10065],{"class":175},"'zh_TW'",[32,10067,10068],{"class":41},", zhTWValidate);\n",[151,10070,10071],{"id":10071},"表單送出前驗證",[22,10073,10075],{"className":24,"code":10074,"language":26,"meta":27,"style":27},"this.$validator.validate().then((result) => {\n  if (result) {\n    this.$http.post(url, { data: order }).then((res) => {\n      console.log('訂單已建立', res);\n    });\n  } else {\n    console.log('未完成');\n  }\n});\n",[29,10076,10077,10103,10110,10135,10150,10154,10162,10175,10179],{"__ignoreMap":27},[32,10078,10079,10081,10084,10087,10090,10092,10094,10097,10099,10101],{"class":34,"line":35},[32,10080,1083],{"class":351},[32,10082,10083],{"class":41},".$validator.",[32,10085,10086],{"class":217},"validate",[32,10088,10089],{"class":41},"().",[32,10091,8950],{"class":217},[32,10093,8293],{"class":41},[32,10095,10096],{"class":903},"result",[32,10098,483],{"class":41},[32,10100,5090],{"class":38},[32,10102,703],{"class":41},[32,10104,10105,10107],{"class":34,"line":45},[32,10106,1021],{"class":38},[32,10108,10109],{"class":41}," (result) {\n",[32,10111,10112,10115,10117,10119,10122,10124,10126,10129,10131,10133],{"class":34,"line":51},[32,10113,10114],{"class":351},"    this",[32,10116,8986],{"class":41},[32,10118,9443],{"class":217},[32,10120,10121],{"class":41},"(url, { data: order }).",[32,10123,8950],{"class":217},[32,10125,8293],{"class":41},[32,10127,10128],{"class":903},"res",[32,10130,483],{"class":41},[32,10132,5090],{"class":38},[32,10134,703],{"class":41},[32,10136,10137,10140,10142,10144,10147],{"class":34,"line":90},[32,10138,10139],{"class":41},"      console.",[32,10141,5197],{"class":217},[32,10143,477],{"class":41},[32,10145,10146],{"class":175},"'訂單已建立'",[32,10148,10149],{"class":41},", res);\n",[32,10151,10152],{"class":34,"line":99},[32,10153,1198],{"class":41},[32,10155,10156,10158,10160],{"class":34,"line":106},[32,10157,5911],{"class":41},[32,10159,565],{"class":38},[32,10161,703],{"class":41},[32,10163,10164,10166,10168,10170,10173],{"class":34,"line":114},[32,10165,8966],{"class":41},[32,10167,5197],{"class":217},[32,10169,477],{"class":41},[32,10171,10172],{"class":175},"'未完成'",[32,10174,230],{"class":41},[32,10176,10177],{"class":34,"line":120},[32,10178,1203],{"class":41},[32,10180,10181],{"class":34,"line":127},[32,10182,792],{"class":41},[15,10184,4844],{"id":10185},"vuex",[11,10187,10188,10189,10192],{},"先新增 ",[29,10190,10191],{},"store.js","，再安裝 Vuex：",[22,10194,10196],{"className":2057,"code":10195,"language":2059,"meta":27,"style":27},"npm i -s vuex\n",[29,10197,10198],{"__ignoreMap":27},[32,10199,10200,10202,10204,10206],{"class":34,"line":35},[32,10201,4625],{"class":2066},[32,10203,8509],{"class":175},[32,10205,9161],{"class":351},[32,10207,10208],{"class":175}," vuex\n",[11,10210,10211,5240],{},[29,10212,5137],{},[22,10214,10216],{"className":24,"code":10215,"language":26,"meta":27,"style":27},"import Vuex, { Store } from 'vuex';\n\nVue.use(Vuex);\n",[29,10217,10218,10232,10236],{"__ignoreMap":27},[32,10219,10220,10222,10225,10227,10230],{"class":34,"line":35},[32,10221,8794],{"class":38},[32,10223,10224],{"class":41}," Vuex, { Store } ",[32,10226,8850],{"class":38},[32,10228,10229],{"class":175}," 'vuex'",[32,10231,96],{"class":41},[32,10233,10234],{"class":34,"line":45},[32,10235,103],{"emptyLinePlaceholder":102},[32,10237,10238,10240,10242],{"class":34,"line":51},[32,10239,8892],{"class":41},[32,10241,8895],{"class":217},[32,10243,10244],{"class":41},"(Vuex);\n",[11,10246,10247],{},"元件：",[22,10249,10251],{"className":24,"code":10250,"language":26,"meta":27,"style":27},"import store from '.\u002Fstore.js';\nimport { mapState } from 'vuex';\n",[29,10252,10253,10267],{"__ignoreMap":27},[32,10254,10255,10257,10260,10262,10265],{"class":34,"line":35},[32,10256,8794],{"class":38},[32,10258,10259],{"class":41}," store ",[32,10261,8850],{"class":38},[32,10263,10264],{"class":175}," '.\u002Fstore.js'",[32,10266,96],{"class":41},[32,10268,10269,10271,10274,10276,10278],{"class":34,"line":45},[32,10270,8794],{"class":38},[32,10272,10273],{"class":41}," { mapState } ",[32,10275,8850],{"class":38},[32,10277,10229],{"class":175},[32,10279,96],{"class":41},[15,10281,10283],{"id":10282},"scss-架構","SCSS 架構",[22,10285,10288],{"className":10286,"code":10287,"language":426,"meta":27},[424],"app.scss              統一引入自訂樣式與 Bootstrap\n_customBootstrap.scss 統一調整 Bootstrap 風格\n",[29,10289,10287],{"__ignoreMap":27},[11,10291,10292,5240],{},[29,10293,10294],{},"app.scss",[22,10296,10298],{"className":8735,"code":10297,"language":8737,"meta":27,"style":27},"@import 'variable';\n@import 'mixin';\n@import 'reset';\n@import 'extend';\n@import 'layout';\n\n\u002F\u002F third-party\n@import 'customBootstrap';\n@import '~bootstrap\u002Fscss\u002Fbootstrap';\n",[29,10299,10300,10309,10318,10327,10336,10345,10349,10354,10363],{"__ignoreMap":27},[32,10301,10302,10304,10307],{"class":34,"line":35},[32,10303,8744],{"class":38},[32,10305,10306],{"class":175}," 'variable'",[32,10308,96],{"class":41},[32,10310,10311,10313,10316],{"class":34,"line":45},[32,10312,8744],{"class":38},[32,10314,10315],{"class":175}," 'mixin'",[32,10317,96],{"class":41},[32,10319,10320,10322,10325],{"class":34,"line":51},[32,10321,8744],{"class":38},[32,10323,10324],{"class":175}," 'reset'",[32,10326,96],{"class":41},[32,10328,10329,10331,10334],{"class":34,"line":90},[32,10330,8744],{"class":38},[32,10332,10333],{"class":175}," 'extend'",[32,10335,96],{"class":41},[32,10337,10338,10340,10343],{"class":34,"line":99},[32,10339,8744],{"class":38},[32,10341,10342],{"class":175}," 'layout'",[32,10344,96],{"class":41},[32,10346,10347],{"class":34,"line":106},[32,10348,103],{"emptyLinePlaceholder":102},[32,10350,10351],{"class":34,"line":114},[32,10352,10353],{"class":608},"\u002F\u002F third-party\n",[32,10355,10356,10358,10361],{"class":34,"line":120},[32,10357,8744],{"class":38},[32,10359,10360],{"class":175}," 'customBootstrap'",[32,10362,96],{"class":41},[32,10364,10365,10367,10369],{"class":34,"line":127},[32,10366,8744],{"class":38},[32,10368,8747],{"class":175},[32,10370,96],{"class":41},[11,10372,10373,10374,5240],{},"程式進入點只要引入 Bootstrap 與 ",[29,10375,10294],{},[22,10377,10379],{"className":24,"code":10378,"language":26,"meta":27,"style":27},"import 'bootstrap';\nimport '.\u002Fassets\u002Fcss\u002Fapp.scss';\n",[29,10380,10381,10389],{"__ignoreMap":27},[32,10382,10383,10385,10387],{"class":34,"line":35},[32,10384,8794],{"class":38},[32,10386,8806],{"class":175},[32,10388,96],{"class":41},[32,10390,10391,10393,10396],{"class":34,"line":45},[32,10392,8794],{"class":38},[32,10394,10395],{"class":175}," '.\u002Fassets\u002Fcss\u002Fapp.scss'",[32,10397,96],{"class":41},[11,10399,10400,10401,3775],{},"參考：",[412,10402,10283],{"href":10403,"rel":10404},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10186760",[416],[15,10406,10408],{"id":10407},"vue-cli-專案結構","Vue CLI 專案結構",[22,10410,10413],{"className":10411,"code":10412,"language":426,"meta":27},[424],"main.js         程式進入點\nrouter\u002Findex.js Router 設定檔\n*.vue           分頁與元件\n",[29,10414,10412],{"__ignoreMap":27},[11,10416,10417],{},"安裝完成後：",[22,10419,10421],{"className":2057,"code":10420,"language":2059,"meta":27,"style":27},"npm i\nnpm run dev\n",[29,10422,10423,10430],{"__ignoreMap":27},[32,10424,10425,10427],{"class":34,"line":35},[32,10426,4625],{"class":2066},[32,10428,10429],{"class":175}," i\n",[32,10431,10432,10434,10436],{"class":34,"line":45},[32,10433,4625],{"class":2066},[32,10435,4743],{"class":175},[32,10437,10438],{"class":175}," dev\n",[15,10440,10441],{"id":10441},"其他筆記",[4538,10443,10444,10454,10458,10464,10473,10476],{},[4541,10445,10446,10447,10450,10451],{},"終止命令提示字元：",[29,10448,10449],{},"Ctrl+C"," 或 ",[29,10452,10453],{},"Ctrl+\u002F",[4541,10455,10456,6679],{},[29,10457,6678],{},[4541,10459,10460,10461],{},"開啟 VS Code 終端機：",[29,10462,10463],{},"Ctrl+`",[4541,10465,10466,10467,10469,10470],{},"Webpack 的 ",[29,10468,7172],{}," 可以省略副檔名，路徑可以使用 ",[29,10471,10472],{},"@\u002F",[4541,10474,10475],{},"圖片小於 10KB 會壓縮成 Base64，大於 10KB 則以圖檔顯示",[4541,10477,10478,10480,10481,10484],{},[29,10479,7093],{}," 依執行環境設定，",[29,10482,10483],{},"host"," 可以替換成要運行的 IP",[368,10486,10487],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}",{"title":27,"searchDepth":51,"depth":51,"links":10489},[10490,10491,10492,10493,10496,10497,10500,10501,10505,10506,10507,10508],{"id":6248,"depth":45,"text":6249},{"id":8493,"depth":45,"text":8494},{"id":8614,"depth":45,"text":8615},{"id":8811,"depth":45,"text":8812,"children":10494},[10495],{"id":9021,"depth":51,"text":9022},{"id":9041,"depth":45,"text":9042},{"id":9144,"depth":45,"text":4841,"children":10498},[10499],{"id":9356,"depth":51,"text":9356},{"id":9548,"depth":45,"text":9548},{"id":9778,"depth":45,"text":9779,"children":10502},[10503,10504],{"id":10023,"depth":51,"text":10023},{"id":10071,"depth":51,"text":10071},{"id":10185,"depth":45,"text":4844},{"id":10282,"depth":45,"text":10283},{"id":10407,"depth":45,"text":10408},{"id":10441,"depth":45,"text":10441},"2018 年整理的 Vue CLI、Vue Router、Vuex、axios、Bootstrap 4 與表單驗證套件安裝筆記。",{},"\u002Fposts\u002Fvue2-project-kit","2018-10-29",[],{"title":8414,"description":10509},"posts\u002F20181029.vue2-project-kit",[4113,4844,9540,10517,4572],"Bootstrap","ukHYg73OuRjyb1jgyStTmLmg0B_Vkx6i9OCkWEzX5H4",{"id":10520,"title":10521,"body":10522,"category":378,"description":10704,"draft":380,"extension":381,"image":382,"meta":10705,"navigation":102,"path":10706,"publishedAt":10707,"relatedExperiments":10708,"seo":10709,"stem":10710,"tags":10711,"updatedAt":392,"__hash__":10713},"posts\u002Fposts\u002F20190315.legacy-url-parsing.md","使用 location.href 取得網址片段",{"type":8,"value":10523,"toc":10702},[10524,10527,10537,10692,10699],[10525,10526],"hr",{},[11,10528,10529,10530,10533,10534,10536],{},"先透過 ",[29,10531,10532],{},"location.href"," 取得目前頁面的完整網址，再使用 ",[29,10535,1275],{}," 分割字串，取得指定位置的內容：",[22,10538,10540],{"className":24,"code":10539,"language":26,"meta":27,"style":27},"var url = location.href;\n\nif (url.indexOf('\u002F') != -1) {\n  var ary1 = url.split('\u002F');\n\n  ary1[5] == undefined ? (num = 'u001') : (num = ary1[5].split('='));\n\n  var ary2 = num.toString();\n  num = ary2;\n}\n",[29,10541,10542,10554,10558,10581,10602,10606,10657,10661,10678,10688],{"__ignoreMap":27},[32,10543,10544,10546,10549,10551],{"class":34,"line":35},[32,10545,166],{"class":38},[32,10547,10548],{"class":41}," url ",[32,10550,172],{"class":38},[32,10552,10553],{"class":41}," location.href;\n",[32,10555,10556],{"class":34,"line":45},[32,10557,103],{"emptyLinePlaceholder":102},[32,10559,10560,10562,10565,10567,10569,10571,10573,10575,10577,10579],{"class":34,"line":51},[32,10561,17],{"class":38},[32,10563,10564],{"class":41}," (url.",[32,10566,1106],{"class":217},[32,10568,477],{"class":41},[32,10570,5067],{"class":175},[32,10572,483],{"class":41},[32,10574,1116],{"class":38},[32,10576,1119],{"class":38},[32,10578,6544],{"class":351},[32,10580,520],{"class":41},[32,10582,10583,10585,10588,10590,10593,10596,10598,10600],{"class":34,"line":90},[32,10584,888],{"class":38},[32,10586,10587],{"class":41}," ary1 ",[32,10589,172],{"class":38},[32,10591,10592],{"class":41}," url.",[32,10594,10595],{"class":217},"split",[32,10597,477],{"class":41},[32,10599,5067],{"class":175},[32,10601,230],{"class":41},[32,10603,10604],{"class":34,"line":99},[32,10605,103],{"emptyLinePlaceholder":102},[32,10607,10608,10611,10614,10617,10619,10622,10624,10627,10629,10632,10634,10636,10638,10640,10643,10645,10648,10650,10652,10655],{"class":34,"line":106},[32,10609,10610],{"class":41},"  ary1[",[32,10612,10613],{"class":351},"5",[32,10615,10616],{"class":41},"] ",[32,10618,5867],{"class":38},[32,10620,10621],{"class":351}," undefined",[32,10623,355],{"class":38},[32,10625,10626],{"class":41}," (num ",[32,10628,172],{"class":38},[32,10630,10631],{"class":175}," 'u001'",[32,10633,483],{"class":41},[32,10635,322],{"class":38},[32,10637,10626],{"class":41},[32,10639,172],{"class":38},[32,10641,10642],{"class":41}," ary1[",[32,10644,10613],{"class":351},[32,10646,10647],{"class":41},"].",[32,10649,10595],{"class":217},[32,10651,477],{"class":41},[32,10653,10654],{"class":175},"'='",[32,10656,8328],{"class":41},[32,10658,10659],{"class":34,"line":114},[32,10660,103],{"emptyLinePlaceholder":102},[32,10662,10663,10665,10668,10670,10673,10676],{"class":34,"line":120},[32,10664,888],{"class":38},[32,10666,10667],{"class":41}," ary2 ",[32,10669,172],{"class":38},[32,10671,10672],{"class":41}," num.",[32,10674,10675],{"class":217},"toString",[32,10677,687],{"class":41},[32,10679,10680,10683,10685],{"class":34,"line":127},[32,10681,10682],{"class":41},"  num ",[32,10684,172],{"class":38},[32,10686,10687],{"class":41}," ary2;\n",[32,10689,10690],{"class":34,"line":132},[32,10691,54],{"class":41},[11,10693,10694,10695,10698],{},"這種寫法會依賴網址分割後的固定位置，例如 ",[29,10696,10697],{},"ary1[5]","。\n如果網址結構改變，就可能取得錯誤的內容。",[368,10700,10701],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":10703},[],"2019 年使用 location.href 搭配 split() 取得網址片段的程式碼筆記，並補充較新的寫法。",{},"\u002Fposts\u002Flegacy-url-parsing","2019-03-15",[],{"title":10521,"description":10704},"posts\u002F20190315.legacy-url-parsing",[390,10712],"URL","cmNtF4IogsayA72J8LWjxUPCgBJZ72VPUplK0nhEYcI",{"id":10715,"title":10716,"body":10717,"category":378,"description":10819,"draft":380,"extension":381,"image":382,"meta":10820,"navigation":102,"path":10821,"publishedAt":10822,"relatedExperiments":10823,"seo":10824,"stem":10825,"tags":10826,"updatedAt":10829,"__hash__":10830},"posts\u002Fposts\u002F20200203.es6-var-let-const.md","JavaScript ES6：var、let 與 const",{"type":8,"value":10718,"toc":10813},[10719,10730,10734,10739,10746,10750,10758,10764,10772,10778,10782,10787,10793,10796,10802,10805],[11,10720,10721,10722,3750,10724,7090,10727,10729],{},"這邊記錄 ",[29,10723,166],{},[29,10725,10726],{},"let",[29,10728,6617],{}," 變數之間差異。",[15,10731,10733],{"id":10732},"var-宣告","var 宣告",[11,10735,4675,10736,10738],{},[29,10737,166],{}," 宣告變數時，會先在記憶體裡面存取空間。",[11,10740,10741],{},[10742,10743],"img",{"alt":10744,"src":10745},"開發者工具使用 var 宣告 test 變數，宣告結果顯示 undefined","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F01.webp",[15,10747,10749],{"id":10748},"var-與-let-的作用域","var 與 let 的作用域",[11,10751,10752,10754,10755,10757],{},[29,10753,166],{}," 在 function 裡宣告，作用域是 function scope；",[29,10756,10726],{}," 的作用域是 block。",[11,10759,10760],{},[10742,10761],{"alt":10762,"src":10763},"var 與 let 在 if 區塊中的作用域比較，var 會影響外層變數，let 不會","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F02.webp",[11,10765,10766,10767,7090,10769,10771],{},"下面比較 ",[29,10768,166],{},[29,10770,10726],{}," 在迴圈裡的差異。",[11,10773,10774],{},[10742,10775],{"alt":10776,"src":10777},"for 迴圈分別使用 var 與 let，var 成為全域變數並輸出 10，let 依序輸出 0 到 9","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F03.webp",[15,10779,10781],{"id":10780},"const-常數","const 常數",[11,10783,10784,10786],{},[29,10785,6617],{}," 宣告的變數不能被更換。",[11,10788,10789],{},[10742,10790],{"alt":10791,"src":10792},"重新指定 const 變數時出現 Assignment to constant variable 錯誤","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F04.webp",[11,10794,10795],{},"物件本身是傳參考而不是傳值，因此物件內的屬性仍然可以修改。",[11,10797,10798],{},[10742,10799],{"alt":10800,"src":10801},"const 宣告物件後修改 a2 屬性，物件內容由 456 變成 222","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F05.webp",[15,10803,10804],{"id":10804},"結論",[11,10806,10807,10808,10810,10811,3775],{},"作用域預設使用 ",[29,10809,6617],{},"，需要重新賦值時才使用 ",[29,10812,10726],{},{"title":27,"searchDepth":51,"depth":51,"links":10814},[10815,10816,10817,10818],{"id":10732,"depth":45,"text":10733},{"id":10748,"depth":45,"text":10749},{"id":10780,"depth":45,"text":10781},{"id":10804,"depth":45,"text":10804},"2020 年整理的 var、let 與 const 變數宣告及作用域筆記。",{},"\u002Fposts\u002Fes6-var-let-const","2020-02-03",[],{"title":10716,"description":10819},"posts\u002F20200203.es6-var-let-const",[390,10827,10828],"ES6","變數宣告","2026-08-06","3yvA0FjmicBouy6o7wc7PCuHBY_Eba7xxCZizBvAL8g",{"id":10832,"title":10833,"body":10834,"category":378,"description":10921,"draft":380,"extension":381,"image":382,"meta":10922,"navigation":102,"path":10923,"publishedAt":10924,"relatedExperiments":10925,"seo":10926,"stem":10927,"tags":10928,"updatedAt":10829,"__hash__":10930},"posts\u002Fposts\u002F20200205.es6-destructuring.md","JavaScript ES6：解構賦值",{"type":8,"value":10835,"toc":10914},[10836,10839,10842,10845,10851,10854,10857,10863,10866,10872,10875,10878,10884,10887,10893,10896,10899,10905,10908],[11,10837,10838],{},"解構賦值是將右邊的值賦予給左邊的變數，有點像鏡射的概念。\n如果左右兩邊數量不同，右邊多餘的值不會進行賦值。",[15,10840,10841],{"id":10841},"陣列解構",[11,10843,10844],{},"範例：將陣列裡的值賦予變數。逗號之間沒有變數時，會跳過該位置。",[11,10846,10847],{},[10742,10848],{"alt":10849,"src":10850},"陣列解構依序取得值、只取前兩個值，以及用空位跳過中間元素","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F01.webp",[15,10852,10853],{"id":10853},"交換變數",[11,10855,10856],{},"解構賦值可以直接交換變數，不需要第三個暫存變數。",[11,10858,10859],{},[10742,10860],{"alt":10861,"src":10862},"使用陣列解構交換 aa 與 bb，輸出結果由 aa bb 變成 bb aa","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F02.webp",[15,10864,10865],{"id":10865},"拆解字串",[11,10867,10868],{},[10742,10869],{"alt":10870,"src":10871},"將 hello 字串解構成五個字元並逐一輸出","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F03.webp",[15,10873,10874],{"id":10874},"物件解構",[11,10876,10877],{},"可以取出物件其中一個值，也可以指定新的變數名稱。",[11,10879,10880],{},[10742,10881],{"alt":10882,"src":10883},"從物件取出 aa 屬性，並示範將 aa 改名成 gg","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F04.webp",[11,10885,10886],{},"物件與陣列也能一起解構。",[11,10888,10889],{},[10742,10890],{"alt":10891,"src":10892},"同時解構物件的 ll 屬性與 tt 陣列第二個元素，輸出 test 與 bb","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F05.webp",[15,10894,10895],{"id":10895},"預設值",[11,10897,10898],{},"陣列解構可以設定預設值。",[11,10900,10901],{},[10742,10902],{"alt":10903,"src":10904},"陣列只有 cc 一個值時，testa 取得 cc，testb 使用預設值 bb","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F06.webp",[11,10906,10907],{},"物件解構改名時也能設定預設值。",[11,10909,10910],{},[10742,10911],{"alt":10912,"src":10913},"從空物件解構 testc 並改名為 ming，最後使用預設值 aa","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F07.webp",{"title":27,"searchDepth":51,"depth":51,"links":10915},[10916,10917,10918,10919,10920],{"id":10841,"depth":45,"text":10841},{"id":10853,"depth":45,"text":10853},{"id":10865,"depth":45,"text":10865},{"id":10874,"depth":45,"text":10874},{"id":10895,"depth":45,"text":10895},"2020 年整理的陣列、字串與物件解構賦值筆記。",{},"\u002Fposts\u002Fes6-destructuring","2020-02-05",[],{"title":10833,"description":10921},"posts\u002F20200205.es6-destructuring",[390,10827,10929],"解構賦值","3eZqGwKLbvymn70nkehs7tumY0sH9ooYT1dyONm1nDA",{"id":10932,"title":10933,"body":10934,"category":378,"description":11557,"draft":380,"extension":381,"image":382,"meta":11558,"navigation":102,"path":11559,"publishedAt":11560,"relatedExperiments":11561,"seo":11562,"stem":11563,"tags":11564,"updatedAt":10829,"__hash__":11566},"posts\u002Fposts\u002F20200206.es6-arrow-functions.md","JavaScript ES6：箭頭函式",{"type":8,"value":10935,"toc":11547},[10936,10939,10947,11054,11057,11110,11113,11196,11199,11232,11235,11241,11278,11282,11288,11291,11298,11365,11368,11371,11475,11479,11482,11515,11533,11535,11544],[15,10937,10938],{"id":10938},"語法簡寫",[4538,10940,10941,10944],{},[4541,10942,10943],{},"參數只有一個時可以省略小括號。",[4541,10945,10946],{},"內容只有一行並回傳時，可以簡寫成一行。",[22,10948,10950],{"className":24,"code":10949,"language":26,"meta":27,"style":27},"var double = function (x) {\n  return x * 2;\n};\n\nconst double = (x) => {\n  return x * 2;\n};\n\nconst shortDouble = x => x * 2;\n",[29,10951,10952,10970,10985,10989,10993,11011,11023,11027,11031],{"__ignoreMap":27},[32,10953,10954,10956,10959,10961,10963,10965,10968],{"class":34,"line":35},[32,10955,166],{"class":38},[32,10957,10958],{"class":217}," double",[32,10960,894],{"class":38},[32,10962,897],{"class":38},[32,10964,900],{"class":41},[32,10966,10967],{"class":903},"x",[32,10969,520],{"class":41},[32,10971,10972,10975,10978,10980,10983],{"class":34,"line":45},[32,10973,10974],{"class":38},"  return",[32,10976,10977],{"class":41}," x ",[32,10979,6078],{"class":38},[32,10981,10982],{"class":351}," 2",[32,10984,96],{"class":41},[32,10986,10987],{"class":34,"line":51},[32,10988,7189],{"class":41},[32,10990,10991],{"class":34,"line":90},[32,10992,103],{"emptyLinePlaceholder":102},[32,10994,10995,10997,10999,11001,11003,11005,11007,11009],{"class":34,"line":99},[32,10996,6617],{"class":38},[32,10998,10958],{"class":217},[32,11000,894],{"class":38},[32,11002,900],{"class":41},[32,11004,10967],{"class":903},[32,11006,483],{"class":41},[32,11008,5090],{"class":38},[32,11010,703],{"class":41},[32,11012,11013,11015,11017,11019,11021],{"class":34,"line":106},[32,11014,10974],{"class":38},[32,11016,10977],{"class":41},[32,11018,6078],{"class":38},[32,11020,10982],{"class":351},[32,11022,96],{"class":41},[32,11024,11025],{"class":34,"line":114},[32,11026,7189],{"class":41},[32,11028,11029],{"class":34,"line":120},[32,11030,103],{"emptyLinePlaceholder":102},[32,11032,11033,11035,11038,11040,11043,11046,11048,11050,11052],{"class":34,"line":127},[32,11034,6617],{"class":38},[32,11036,11037],{"class":217}," shortDouble",[32,11039,894],{"class":38},[32,11041,11042],{"class":903}," x",[32,11044,11045],{"class":38}," =>",[32,11047,10977],{"class":41},[32,11049,6078],{"class":38},[32,11051,10982],{"class":351},[32,11053,96],{"class":41},[11,11055,11056],{},"只有一個參數時可以省略小括號；有兩個參數時要保留：",[22,11058,11060],{"className":24,"code":11059,"language":26,"meta":27,"style":27},"const double = x => x * 2;\nconst add = (x, y) => x + y;\n",[29,11061,11062,11082],{"__ignoreMap":27},[32,11063,11064,11066,11068,11070,11072,11074,11076,11078,11080],{"class":34,"line":35},[32,11065,6617],{"class":38},[32,11067,10958],{"class":217},[32,11069,894],{"class":38},[32,11071,11042],{"class":903},[32,11073,11045],{"class":38},[32,11075,10977],{"class":41},[32,11077,6078],{"class":38},[32,11079,10982],{"class":351},[32,11081,96],{"class":41},[32,11083,11084,11086,11088,11090,11092,11094,11096,11099,11101,11103,11105,11107],{"class":34,"line":45},[32,11085,6617],{"class":38},[32,11087,2493],{"class":217},[32,11089,894],{"class":38},[32,11091,900],{"class":41},[32,11093,10967],{"class":903},[32,11095,635],{"class":41},[32,11097,11098],{"class":903},"y",[32,11100,483],{"class":41},[32,11102,5090],{"class":38},[32,11104,10977],{"class":41},[32,11106,224],{"class":38},[32,11108,11109],{"class":41}," y;\n",[11,11111,11112],{},"陣列方法的 ES5 與 ES6 寫法：",[22,11114,11116],{"className":24,"code":11115,"language":26,"meta":27,"style":27},"\u002F\u002F ES5\narr.map(function (elm, idx) {\n  return elm + idx;\n});\n\n\u002F\u002F ES6\narr.map((elm, idx) => elm + idx);\n",[29,11117,11118,11123,11146,11158,11162,11166,11171],{"__ignoreMap":27},[32,11119,11120],{"class":34,"line":35},[32,11121,11122],{"class":608},"\u002F\u002F ES5\n",[32,11124,11125,11128,11131,11133,11135,11137,11140,11142,11144],{"class":34,"line":45},[32,11126,11127],{"class":41},"arr.",[32,11129,11130],{"class":217},"map",[32,11132,477],{"class":41},[32,11134,665],{"class":38},[32,11136,900],{"class":41},[32,11138,11139],{"class":903},"elm",[32,11141,635],{"class":41},[32,11143,8301],{"class":903},[32,11145,520],{"class":41},[32,11147,11148,11150,11153,11155],{"class":34,"line":51},[32,11149,10974],{"class":38},[32,11151,11152],{"class":41}," elm ",[32,11154,224],{"class":38},[32,11156,11157],{"class":41}," idx;\n",[32,11159,11160],{"class":34,"line":90},[32,11161,792],{"class":41},[32,11163,11164],{"class":34,"line":99},[32,11165,103],{"emptyLinePlaceholder":102},[32,11167,11168],{"class":34,"line":106},[32,11169,11170],{"class":608},"\u002F\u002F ES6\n",[32,11172,11173,11175,11177,11179,11181,11183,11185,11187,11189,11191,11193],{"class":34,"line":114},[32,11174,11127],{"class":41},[32,11176,11130],{"class":217},[32,11178,8293],{"class":41},[32,11180,11139],{"class":903},[32,11182,635],{"class":41},[32,11184,8301],{"class":903},[32,11186,483],{"class":41},[32,11188,5090],{"class":38},[32,11190,11152],{"class":41},[32,11192,224],{"class":38},[32,11194,11195],{"class":41}," idx);\n",[11,11197,11198],{},"事件監聽：",[22,11200,11202],{"className":24,"code":11201,"language":26,"meta":27,"style":27},"btn.addEventListener('click', () => console.log(10));\n",[29,11203,11204],{"__ignoreMap":27},[32,11205,11206,11209,11211,11213,11216,11219,11221,11223,11225,11227,11230],{"class":34,"line":35},[32,11207,11208],{"class":41},"btn.",[32,11210,5517],{"class":217},[32,11212,477],{"class":41},[32,11214,11215],{"class":175},"'click'",[32,11217,11218],{"class":41},", () ",[32,11220,5090],{"class":38},[32,11222,8308],{"class":41},[32,11224,5197],{"class":217},[32,11226,477],{"class":41},[32,11228,11229],{"class":351},"10",[32,11231,8328],{"class":41},[15,11233,11234],{"id":11234},"自動綁定",[11,11236,11237,11238,11240],{},"箭頭函式內部的 ",[29,11239,1083],{}," 與外部相同。",[22,11242,11244],{"className":24,"code":11243,"language":26,"meta":27,"style":27},"const a = () => {\n  console.log(this);\n};\n",[29,11245,11246,11262,11274],{"__ignoreMap":27},[32,11247,11248,11250,11253,11255,11258,11260],{"class":34,"line":35},[32,11249,6617],{"class":38},[32,11251,11252],{"class":217}," a",[32,11254,894],{"class":38},[32,11256,11257],{"class":41}," () ",[32,11259,5090],{"class":38},[32,11261,703],{"class":41},[32,11263,11264,11266,11268,11270,11272],{"class":34,"line":45},[32,11265,5194],{"class":41},[32,11267,5197],{"class":217},[32,11269,477],{"class":41},[32,11271,1083],{"class":351},[32,11273,230],{"class":41},[32,11275,11276],{"class":34,"line":51},[32,11277,7189],{"class":41},[15,11279,11281],{"id":11280},"一般函式的-this","一般函式的 this",[11,11283,11284,11285,11287],{},"一般函式的 ",[29,11286,1083],{}," 由函式呼叫方式決定。",[151,11289,11290],{"id":11290},"直接執行",[11,11292,11293,11294,11297],{},"直接執行時指向 ",[29,11295,11296],{},"window","（global）：",[22,11299,11301],{"className":24,"code":11300,"language":26,"meta":27,"style":27},"var name = 'hello';\n\nvar sayMyName = function () {\n  console.log(this.name);\n};\n\nsayMyName(); \u002F\u002F global.hello\n",[29,11302,11303,11316,11320,11333,11346,11350,11354],{"__ignoreMap":27},[32,11304,11305,11307,11309,11311,11314],{"class":34,"line":35},[32,11306,166],{"class":38},[32,11308,169],{"class":41},[32,11310,172],{"class":38},[32,11312,11313],{"class":175}," 'hello'",[32,11315,96],{"class":41},[32,11317,11318],{"class":34,"line":45},[32,11319,103],{"emptyLinePlaceholder":102},[32,11321,11322,11324,11327,11329,11331],{"class":34,"line":51},[32,11323,166],{"class":38},[32,11325,11326],{"class":217}," sayMyName",[32,11328,894],{"class":38},[32,11330,897],{"class":38},[32,11332,668],{"class":41},[32,11334,11335,11337,11339,11341,11343],{"class":34,"line":90},[32,11336,5194],{"class":41},[32,11338,5197],{"class":217},[32,11340,477],{"class":41},[32,11342,1083],{"class":351},[32,11344,11345],{"class":41},".name);\n",[32,11347,11348],{"class":34,"line":99},[32,11349,7189],{"class":41},[32,11351,11352],{"class":34,"line":106},[32,11353,103],{"emptyLinePlaceholder":102},[32,11355,11356,11359,11362],{"class":34,"line":114},[32,11357,11358],{"class":217},"sayMyName",[32,11360,11361],{"class":41},"(); ",[32,11363,11364],{"class":608},"\u002F\u002F global.hello\n",[151,11366,11367],{"id":11367},"作為物件的成員函式",[11,11369,11370],{},"作為物件的成員函式執行時，指向該物件：",[22,11372,11374],{"className":24,"code":11373,"language":26,"meta":27,"style":27},"var name = 'hello';\n\nvar sayMyName = function () {\n  console.log(this.name);\n};\n\nvar teacher = {\n  name: 'white',\n};\n\nteacher.sayMyName = sayMyName;\nteacher.sayMyName(); \u002F\u002F white\n",[29,11375,11376,11388,11392,11404,11416,11420,11424,11435,11445,11449,11453,11463],{"__ignoreMap":27},[32,11377,11378,11380,11382,11384,11386],{"class":34,"line":35},[32,11379,166],{"class":38},[32,11381,169],{"class":41},[32,11383,172],{"class":38},[32,11385,11313],{"class":175},[32,11387,96],{"class":41},[32,11389,11390],{"class":34,"line":45},[32,11391,103],{"emptyLinePlaceholder":102},[32,11393,11394,11396,11398,11400,11402],{"class":34,"line":51},[32,11395,166],{"class":38},[32,11397,11326],{"class":217},[32,11399,894],{"class":38},[32,11401,897],{"class":38},[32,11403,668],{"class":41},[32,11405,11406,11408,11410,11412,11414],{"class":34,"line":90},[32,11407,5194],{"class":41},[32,11409,5197],{"class":217},[32,11411,477],{"class":41},[32,11413,1083],{"class":351},[32,11415,11345],{"class":41},[32,11417,11418],{"class":34,"line":99},[32,11419,7189],{"class":41},[32,11421,11422],{"class":34,"line":106},[32,11423,103],{"emptyLinePlaceholder":102},[32,11425,11426,11428,11431,11433],{"class":34,"line":114},[32,11427,166],{"class":38},[32,11429,11430],{"class":41}," teacher ",[32,11432,172],{"class":38},[32,11434,703],{"class":41},[32,11436,11437,11440,11443],{"class":34,"line":120},[32,11438,11439],{"class":41},"  name: ",[32,11441,11442],{"class":175},"'white'",[32,11444,547],{"class":41},[32,11446,11447],{"class":34,"line":127},[32,11448,7189],{"class":41},[32,11450,11451],{"class":34,"line":132},[32,11452,103],{"emptyLinePlaceholder":102},[32,11454,11455,11458,11460],{"class":34,"line":141},[32,11456,11457],{"class":41},"teacher.sayMyName ",[32,11459,172],{"class":38},[32,11461,11462],{"class":41}," sayMyName;\n",[32,11464,11465,11468,11470,11472],{"class":34,"line":147},[32,11466,11467],{"class":41},"teacher.",[32,11469,11358],{"class":217},[32,11471,11361],{"class":41},[32,11473,11474],{"class":608},"\u002F\u002F white\n",[151,11476,11478],{"id":11477},"作為-dom-的監聽函式","作為 DOM 的監聽函式",[11,11480,11481],{},"作為 DOM 的監聽函式執行時，指向該 DOM：",[22,11483,11485],{"className":4038,"code":11484,"language":4034,"meta":27,"style":27},"\u003Cbutton id=\"btn\" name=\"God damn right\">Response\u003C\u002Fbutton>\n",[29,11486,11487],{"__ignoreMap":27},[32,11488,11489,11491,11494,11496,11498,11501,11503,11505,11508,11511,11513],{"class":34,"line":35},[32,11490,4046],{"class":41},[32,11492,11493],{"class":4049},"button",[32,11495,4054],{"class":4053},[32,11497,172],{"class":41},[32,11499,11500],{"class":175},"\"btn\"",[32,11502,5668],{"class":4053},[32,11504,172],{"class":41},[32,11506,11507],{"class":175},"\"God damn right\"",[32,11509,11510],{"class":41},">Response\u003C\u002F",[32,11512,11493],{"class":4049},[32,11514,4062],{"class":41},[22,11516,11518],{"className":24,"code":11517,"language":26,"meta":27,"style":27},"btn.addEventListener('click', sayMyName);\n",[29,11519,11520],{"__ignoreMap":27},[32,11521,11522,11524,11526,11528,11530],{"class":34,"line":35},[32,11523,11208],{"class":41},[32,11525,5517],{"class":217},[32,11527,477],{"class":41},[32,11529,11215],{"class":175},[32,11531,11532],{"class":41},", sayMyName);\n",[15,11534,2004],{"id":2003},[11,11536,11537,11538,11540,11541,11543],{},"箭頭函式的語法與 ",[29,11539,1083],{}," 規則沒有改變。需要依呼叫者取得 ",[29,11542,1083],{}," 的物件方法或 DOM 監聽器，仍要留意是否適合使用一般函式。",[368,11545,11546],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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 .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":11548},[11549,11550,11551,11556],{"id":10938,"depth":45,"text":10938},{"id":11234,"depth":45,"text":11234},{"id":11280,"depth":45,"text":11281,"children":11552},[11553,11554,11555],{"id":11290,"depth":51,"text":11290},{"id":11367,"depth":51,"text":11367},{"id":11477,"depth":51,"text":11478},{"id":2003,"depth":45,"text":2004},"2020 年整理的箭頭函式簡寫方式與 this 綁定筆記。",{},"\u002Fposts\u002Fes6-arrow-functions","2020-02-06",[],{"title":10933,"description":11557},"posts\u002F20200206.es6-arrow-functions",[390,10827,11565,1083],"箭頭函式","ET-V7Wwr3RvHTnz33yXdaif4tVHMmUow5CFJvL-td8Y",{"id":11568,"title":11569,"body":11570,"category":378,"description":11592,"draft":380,"extension":381,"image":382,"meta":11593,"navigation":102,"path":11594,"publishedAt":11595,"relatedExperiments":11596,"seo":11597,"stem":11598,"tags":11599,"updatedAt":6716,"__hash__":11601},"posts\u002Fposts\u002F20200228.google-fonts-embed.md","Google Fonts 引用筆記",{"type":8,"value":11571,"toc":11589},[11572,11575,11584,11586],[11,11573,11574],{},"這邊記錄網頁需要字型時，可以從哪邊引用：",[4538,11576,11577],{},[4541,11578,11579],{},[412,11580,11583],{"href":11581,"rel":11582},"https:\u002F\u002Ffonts.google.com\u002F",[416],"Google Fonts",[15,11585,2004],{"id":2003},[11,11587,11588],{},"Google Fonts 現在仍可使用，但若在意載入效能與訪客請求會連到第三方網域，可以改成自架字型。相關做法整理在《現在引用網頁字型的做法》。",{"title":27,"searchDepth":51,"depth":51,"links":11590},[11591],{"id":2003,"depth":45,"text":2004},"2020 年記錄網頁需要字型時，可以從 Google Fonts 取得引用方式。",{},"\u002Fposts\u002Fgoogle-fonts-embed","2020-02-28",[],{"title":11569,"description":11592},"posts\u002F20200228.google-fonts-embed",[1757,11583,11600],"字型","vo42ZtA9vW9kyb7P771zblsxG2jjuM6gtyGqjWX-8Rw",{"id":11603,"title":11604,"body":11605,"category":378,"description":11641,"draft":380,"extension":381,"image":382,"meta":11642,"navigation":102,"path":11643,"publishedAt":11644,"relatedExperiments":11645,"seo":11646,"stem":11647,"tags":11648,"updatedAt":10829,"__hash__":11649},"posts\u002Fposts\u002F20200310.box-sizing-border-box.md","CSS box-sizing 筆記",{"type":8,"value":11606,"toc":11638},[11607,11612,11625,11631,11633],[11,11608,10721,11609,3775],{},[29,11610,11611],{},"box-sizing",[11,11613,11614,11617,11618,11621,11622,11624],{},[29,11615,11616],{},"box-sizing: border-box"," 可以把 padding 與 border 計入設定的 ",[29,11619,11620],{},"width","／",[29,11623,6762],{},"，避免元素的實際尺寸向外增加。",[11,11626,11627],{},[10742,11628],{"alt":11629,"src":11630},"兩個相同寬高、邊框與內距的方塊，未設定 box-sizing 的方塊較大，設定 border-box 的方塊維持 50px","\u002Fimages\u002Fposts\u002Fbox-sizing-border-box\u002F01.webp",[15,11632,2004],{"id":2003},[11,11634,11635,11637],{},[29,11636,11616],{}," 現在仍普遍使用，通常會連同偽元素一起設為全域規則。",{"title":27,"searchDepth":51,"depth":51,"links":11639},[11640],{"id":2003,"depth":45,"text":2004},"2020 年記錄 box-sizing 如何讓 padding 與 border 計入元素設定的寬高。",{},"\u002Fposts\u002Fbox-sizing-border-box","2020-03-10",[],{"title":11604,"description":11641},"posts\u002F20200310.box-sizing-border-box",[1757],"Hsa5G1waJHX12ORw72prX8uMREyZxjDlCeZ-YBv8OMM",{"id":11651,"title":11652,"body":11653,"category":378,"description":12307,"draft":380,"extension":381,"image":382,"meta":12308,"navigation":102,"path":12309,"publishedAt":11644,"relatedExperiments":12310,"seo":12311,"stem":12312,"tags":12313,"updatedAt":10829,"__hash__":12315},"posts\u002Fposts\u002F20200310.scss-icon-sprite-map.md","用 SCSS 的 Map 與 @each 統一管理背景圖示",{"type":8,"value":11654,"toc":12299},[11655,11662,11666,11799,11807,11811,11996,12016,12019,12033,12235,12243,12246,12253,12259,12261,12278,12280,12296],[11,11656,11657,11658,11661],{},"網站圖示如果是一批各自獨立的 PNG 檔案（而不是圖示字型或 SVG），每個圖示又要處理 hover／normal 兩種狀態，手動幫每一個圖示各寫一段 CSS 很容易漏東漏西。\n這篇整理當時用 SCSS 的 map 加 ",[29,11659,11660],{},"@each"," 迴圈批次產生的做法。",[15,11663,11665],{"id":11664},"用-map-存圖示路徑","用 map 存圖示路徑",[22,11667,11669],{"className":8735,"code":11668,"language":8737,"meta":27,"style":27},"$icon-name: 'bookmark', 'avatar', 'chat', 'page', 'stars', 'focus';\n\n$iconImageGroup: (\n  'bookmark-hover': '..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-hover.png',\n  'bookmark-normal': '..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-normal.png',\n  'stars-hover': '..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-hover.png',\n  'stars-normal': '..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-normal.png',\n  'focus-hover': '\u002F_img\u002F_icon\u002Ficon_focus_hover.png',\n  'focus-normal': '\u002F_img\u002F_icon\u002Ficon_focus_normal.png',\n);\n",[29,11670,11671,11708,11712,11720,11732,11744,11756,11768,11780,11792],{"__ignoreMap":27},[32,11672,11673,11676,11678,11681,11683,11686,11688,11691,11693,11696,11698,11701,11703,11706],{"class":34,"line":35},[32,11674,11675],{"class":903},"$icon-name",[32,11677,5269],{"class":5049},[32,11679,11680],{"class":175},"'bookmark'",[32,11682,635],{"class":5049},[32,11684,11685],{"class":175},"'avatar'",[32,11687,635],{"class":5049},[32,11689,11690],{"class":175},"'chat'",[32,11692,635],{"class":5049},[32,11694,11695],{"class":175},"'page'",[32,11697,635],{"class":5049},[32,11699,11700],{"class":175},"'stars'",[32,11702,635],{"class":5049},[32,11704,11705],{"class":175},"'focus'",[32,11707,96],{"class":41},[32,11709,11710],{"class":34,"line":45},[32,11711,103],{"emptyLinePlaceholder":102},[32,11713,11714,11717],{"class":34,"line":51},[32,11715,11716],{"class":903},"$iconImageGroup",[32,11718,11719],{"class":5049},": (\n",[32,11721,11722,11725,11727,11730],{"class":34,"line":90},[32,11723,11724],{"class":175},"  'bookmark-hover'",[32,11726,5269],{"class":5049},[32,11728,11729],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-hover.png'",[32,11731,547],{"class":5049},[32,11733,11734,11737,11739,11742],{"class":34,"line":99},[32,11735,11736],{"class":175},"  'bookmark-normal'",[32,11738,5269],{"class":5049},[32,11740,11741],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-normal.png'",[32,11743,547],{"class":5049},[32,11745,11746,11749,11751,11754],{"class":34,"line":106},[32,11747,11748],{"class":175},"  'stars-hover'",[32,11750,5269],{"class":5049},[32,11752,11753],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-hover.png'",[32,11755,547],{"class":5049},[32,11757,11758,11761,11763,11766],{"class":34,"line":114},[32,11759,11760],{"class":175},"  'stars-normal'",[32,11762,5269],{"class":5049},[32,11764,11765],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-normal.png'",[32,11767,547],{"class":5049},[32,11769,11770,11773,11775,11778],{"class":34,"line":120},[32,11771,11772],{"class":175},"  'focus-hover'",[32,11774,5269],{"class":5049},[32,11776,11777],{"class":175},"'\u002F_img\u002F_icon\u002Ficon_focus_hover.png'",[32,11779,547],{"class":5049},[32,11781,11782,11785,11787,11790],{"class":34,"line":127},[32,11783,11784],{"class":175},"  'focus-normal'",[32,11786,5269],{"class":5049},[32,11788,11789],{"class":175},"'\u002F_img\u002F_icon\u002Ficon_focus_normal.png'",[32,11791,547],{"class":5049},[32,11793,11794,11797],{"class":34,"line":132},[32,11795,11796],{"class":5049},")",[32,11798,96],{"class":41},[11,11800,11801,11803,11804,11806],{},[29,11802,11675],{}," 是一份圖示名稱清單，",[29,11805,11716],{}," 是一個 map（SCSS 的鍵值對結構），把每個圖示 hover／normal 兩種狀態各自對應到一個圖檔路徑。",[15,11808,11810],{"id":11809},"用-each-批次產生-class","用 @each 批次產生 class",[22,11812,11814],{"className":8735,"code":11813,"language":8737,"meta":27,"style":27},"@each $name in $icon-name {\n  &.icon-#{$name} {\n    width: 26px;\n    height: 24px;\n    padding: 0px !important;\n    background: url(map-get($iconImageGroup, $name + '-normal'));\n    background-repeat: no-repeat;\n    background-position: center center;\n    transition: 0.3s;\n    margin-right: 2px;\n    display: inline-block;\n  }\n}\n",[29,11815,11816,11830,11843,11858,11872,11889,11920,11932,11947,11962,11976,11988,11992],{"__ignoreMap":27},[32,11817,11818,11820,11823,11825,11828],{"class":34,"line":35},[32,11819,11660],{"class":38},[32,11821,11822],{"class":903}," $name",[32,11824,5527],{"class":38},[32,11826,11827],{"class":903}," $icon-name",[32,11829,703],{"class":41},[32,11831,11832,11835,11838,11841],{"class":34,"line":45},[32,11833,11834],{"class":4049},"  &",[32,11836,11837],{"class":4053},".icon-",[32,11839,11840],{"class":903},"#{$name}",[32,11842,703],{"class":41},[32,11844,11845,11848,11850,11853,11856],{"class":34,"line":51},[32,11846,11847],{"class":351},"    width",[32,11849,5269],{"class":41},[32,11851,11852],{"class":351},"26",[32,11854,11855],{"class":38},"px",[32,11857,96],{"class":41},[32,11859,11860,11863,11865,11868,11870],{"class":34,"line":90},[32,11861,11862],{"class":351},"    height",[32,11864,5269],{"class":41},[32,11866,11867],{"class":351},"24",[32,11869,11855],{"class":38},[32,11871,96],{"class":41},[32,11873,11874,11877,11879,11882,11884,11887],{"class":34,"line":99},[32,11875,11876],{"class":351},"    padding",[32,11878,5269],{"class":41},[32,11880,11881],{"class":351},"0",[32,11883,11855],{"class":38},[32,11885,11886],{"class":38}," !important",[32,11888,96],{"class":41},[32,11890,11891,11894,11896,11899,11901,11904,11906,11908,11910,11913,11915,11918],{"class":34,"line":106},[32,11892,11893],{"class":351},"    background",[32,11895,5269],{"class":41},[32,11897,11898],{"class":351},"url",[32,11900,477],{"class":41},[32,11902,11903],{"class":351},"map-get",[32,11905,477],{"class":41},[32,11907,11716],{"class":903},[32,11909,635],{"class":41},[32,11911,11912],{"class":903},"$name",[32,11914,1799],{"class":38},[32,11916,11917],{"class":175}," '-normal'",[32,11919,8328],{"class":41},[32,11921,11922,11925,11927,11930],{"class":34,"line":114},[32,11923,11924],{"class":351},"    background-repeat",[32,11926,5269],{"class":41},[32,11928,11929],{"class":351},"no-repeat",[32,11931,96],{"class":41},[32,11933,11934,11937,11939,11942,11945],{"class":34,"line":120},[32,11935,11936],{"class":351},"    background-position",[32,11938,5269],{"class":41},[32,11940,11941],{"class":351},"center",[32,11943,11944],{"class":351}," center",[32,11946,96],{"class":41},[32,11948,11949,11952,11954,11957,11960],{"class":34,"line":127},[32,11950,11951],{"class":351},"    transition",[32,11953,5269],{"class":41},[32,11955,11956],{"class":351},"0.3",[32,11958,11959],{"class":38},"s",[32,11961,96],{"class":41},[32,11963,11964,11967,11969,11972,11974],{"class":34,"line":132},[32,11965,11966],{"class":351},"    margin-right",[32,11968,5269],{"class":41},[32,11970,11971],{"class":351},"2",[32,11973,11855],{"class":38},[32,11975,96],{"class":41},[32,11977,11978,11981,11983,11986],{"class":34,"line":141},[32,11979,11980],{"class":351},"    display",[32,11982,5269],{"class":41},[32,11984,11985],{"class":351},"inline-block",[32,11987,96],{"class":41},[32,11989,11990],{"class":34,"line":147},[32,11991,1203],{"class":41},[32,11993,11994],{"class":34,"line":275},[32,11995,54],{"class":41},[11,11997,11998,12001,12002,12004,12005,3750,12008,12011,12012,12015],{},[29,11999,12000],{},"@each $name in $icon-name"," 會把清單裡的每個名稱輪流帶入迴圈，",[29,12003,11840],{}," 是字串插值，讓 class 名稱依名稱動態產生（",[29,12006,12007],{},".icon-bookmark",[29,12009,12010],{},".icon-avatar","……），",[29,12013,12014],{},"map-get()"," 則依名稱去 map 裡查對應的圖檔路徑。\n六個圖示的樣式規則就這樣一次產生完，之後要加第七個圖示，只需要在兩份清單裡各加一筆。",[15,12017,12018],{"id":12018},"依名稱做例外處理",[11,12020,12021,12022,11621,12025,12028,12029,12032],{},"不是每個圖示都遵循同一套規則，某些圖示需要額外的狀態 class（例如 ",[29,12023,12024],{},"bookmark",[29,12026,12027],{},"unbookmark"," 兩種狀態各自的樣式），可以用 ",[29,12030,12031],{},"@if"," 針對特定名稱加規則：",[22,12034,12036],{"className":8735,"code":12035,"language":8737,"meta":27,"style":27},"@each $name in $icon-name {\n  &.icon-#{$name} {\n    \u002F\u002F 通用規則...\n\n    @if ($name == 'bookmark') {\n      &.bookmark {\n        cursor: pointer;\n        background: url(map-get($iconImageGroup, 'bookmark-hover'));\n        width: 22px;\n        height: 32px;\n      }\n      &.unbookmark {\n        width: 22px;\n        height: 32px;\n        background: url(map-get($iconImageGroup, 'bookmark-normal'));\n      }\n    }\n  }\n}\n",[29,12037,12038,12050,12060,12065,12069,12085,12095,12107,12131,12145,12159,12163,12172,12184,12196,12219,12223,12227,12231],{"__ignoreMap":27},[32,12039,12040,12042,12044,12046,12048],{"class":34,"line":35},[32,12041,11660],{"class":38},[32,12043,11822],{"class":903},[32,12045,5527],{"class":38},[32,12047,11827],{"class":903},[32,12049,703],{"class":41},[32,12051,12052,12054,12056,12058],{"class":34,"line":45},[32,12053,11834],{"class":4049},[32,12055,11837],{"class":4053},[32,12057,11840],{"class":903},[32,12059,703],{"class":41},[32,12061,12062],{"class":34,"line":51},[32,12063,12064],{"class":608},"    \u002F\u002F 通用規則...\n",[32,12066,12067],{"class":34,"line":90},[32,12068,103],{"emptyLinePlaceholder":102},[32,12070,12071,12074,12076,12078,12081,12083],{"class":34,"line":99},[32,12072,12073],{"class":38},"    @if",[32,12075,900],{"class":41},[32,12077,11912],{"class":903},[32,12079,12080],{"class":41}," == ",[32,12082,11680],{"class":175},[32,12084,520],{"class":41},[32,12086,12087,12090,12093],{"class":34,"line":106},[32,12088,12089],{"class":4049},"      &",[32,12091,12092],{"class":4053},".bookmark",[32,12094,703],{"class":41},[32,12096,12097,12100,12102,12105],{"class":34,"line":114},[32,12098,12099],{"class":4049},"        cursor",[32,12101,5269],{"class":41},[32,12103,12104],{"class":351},"pointer",[32,12106,96],{"class":41},[32,12108,12109,12112,12114,12116,12118,12120,12122,12124,12126,12129],{"class":34,"line":120},[32,12110,12111],{"class":351},"        background",[32,12113,5269],{"class":41},[32,12115,11898],{"class":351},[32,12117,477],{"class":41},[32,12119,11903],{"class":351},[32,12121,477],{"class":41},[32,12123,11716],{"class":903},[32,12125,635],{"class":41},[32,12127,12128],{"class":175},"'bookmark-hover'",[32,12130,8328],{"class":41},[32,12132,12133,12136,12138,12141,12143],{"class":34,"line":127},[32,12134,12135],{"class":351},"        width",[32,12137,5269],{"class":41},[32,12139,12140],{"class":351},"22",[32,12142,11855],{"class":38},[32,12144,96],{"class":41},[32,12146,12147,12150,12152,12155,12157],{"class":34,"line":132},[32,12148,12149],{"class":351},"        height",[32,12151,5269],{"class":41},[32,12153,12154],{"class":351},"32",[32,12156,11855],{"class":38},[32,12158,96],{"class":41},[32,12160,12161],{"class":34,"line":141},[32,12162,1193],{"class":41},[32,12164,12165,12167,12170],{"class":34,"line":147},[32,12166,12089],{"class":4049},[32,12168,12169],{"class":4053},".unbookmark",[32,12171,703],{"class":41},[32,12173,12174,12176,12178,12180,12182],{"class":34,"line":275},[32,12175,12135],{"class":351},[32,12177,5269],{"class":41},[32,12179,12140],{"class":351},[32,12181,11855],{"class":38},[32,12183,96],{"class":41},[32,12185,12186,12188,12190,12192,12194],{"class":34,"line":282},[32,12187,12149],{"class":351},[32,12189,5269],{"class":41},[32,12191,12154],{"class":351},[32,12193,11855],{"class":38},[32,12195,96],{"class":41},[32,12197,12198,12200,12202,12204,12206,12208,12210,12212,12214,12217],{"class":34,"line":295},[32,12199,12111],{"class":351},[32,12201,5269],{"class":41},[32,12203,11898],{"class":351},[32,12205,477],{"class":41},[32,12207,11903],{"class":351},[32,12209,477],{"class":41},[32,12211,11716],{"class":903},[32,12213,635],{"class":41},[32,12215,12216],{"class":175},"'bookmark-normal'",[32,12218,8328],{"class":41},[32,12220,12221],{"class":34,"line":605},[32,12222,1193],{"class":41},[32,12224,12225],{"class":34,"line":612},[32,12226,5591],{"class":41},[32,12228,12229],{"class":34,"line":617},[32,12230,1203],{"class":41},[32,12232,12233],{"class":34,"line":644},[32,12234,54],{"class":41},[11,12236,12237,12239,12240,12242],{},[29,12238,12031],{}," 在迴圈內部依當下的 ",[29,12241,11912],{}," 值判斷，只有名稱符合條件時才會加上額外的巢狀規則，其餘圖示不受影響。",[15,12244,12245],{"id":12245},"這個做法的代價",[11,12247,12248,12252],{},[12249,12250,12251],"strong",{},"每個圖示、每種狀態都是一個獨立的圖檔請求","。hover 狀態要切換圖片，代表瀏覽器要先把 hover 版本的圖也下載下來（或是遇到滑鼠移上去才臨時載入，反而有延遲閃爍的問題），圖示數量一多，請求數跟著往上疊。",[11,12254,12255,12258],{},[12249,12256,12257],{},"顏色調整要重新出圖","。網站要換色系、或同一個圖示要在不同背景色上呈現不同顏色，PNG 圖示沒辦法用 CSS 調色，只能請設計重新出一版圖檔。",[15,12260,2004],{"id":2003},[11,12262,12263,12266,12267,12269,12270,12273,12274,12277],{},[12249,12264,12265],{},"這套「用資料結構驅動批次產生樣式」的思路本身沒有過時","，SCSS 的 map／",[29,12268,11660],{}," 現在同樣好用。真正被取代的是",[12249,12271,12272],{},"用一堆獨立 PNG 檔案管理圖示","這件事——現在多半用 SVG 圖示元件，一份圖示可以用 ",[29,12275,12276],{},"currentColor"," 直接吃 CSS 的文字顏色，不需要為了換色重新出圖，也不用為了 hover 狀態多準備一張圖。整理在《SVG 圖示元件：取代背景圖示與圖示字型》。",[15,12279,4536],{"id":4536},[4538,12281,12282,12289],{},[4541,12283,12284],{},[412,12285,12288],{"href":12286,"rel":12287},"https:\u002F\u002Fsass-lang.com\u002Fdocumentation\u002Fvalues\u002Fmaps\u002F",[416],"Sass 官方文件：Maps",[4541,12290,12291],{},[412,12292,12295],{"href":12293,"rel":12294},"https:\u002F\u002Fsass-lang.com\u002Fdocumentation\u002Fat-rules\u002Fcontrol\u002Feach\u002F",[416],"Sass 官方文件：@each",[368,12297,12298],{},"html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}",{"title":27,"searchDepth":51,"depth":51,"links":12300},[12301,12302,12303,12304,12305,12306],{"id":11664,"depth":45,"text":11665},{"id":11809,"depth":45,"text":11810},{"id":12018,"depth":45,"text":12018},{"id":12245,"depth":45,"text":12245},{"id":2003,"depth":45,"text":2004},{"id":4536,"depth":45,"text":4536},"整理用 SCSS 的 map 資料結構搭配 @each 迴圈，批次產生一組背景圖示 class 的做法，同一份清單同時管理 hover／normal 兩種狀態各自對應的圖檔路徑。這個做法現在多半被 SVG 圖示元件取代，整理在新的一篇。",{},"\u002Fposts\u002Fscss-icon-sprite-map",[],{"title":11652,"description":12307},"posts\u002F20200310.scss-icon-sprite-map",[12314,1757,4847],"SCSS","qNGNDDRHUx-7vcZ7tskko8SwRuReYeSbdJwM-WwT7Vk",{"id":12317,"title":12318,"body":12319,"category":378,"description":12537,"draft":380,"extension":381,"image":382,"meta":12538,"navigation":102,"path":12539,"publishedAt":12540,"relatedExperiments":12541,"seo":12542,"stem":12543,"tags":12544,"updatedAt":10829,"__hash__":12545},"posts\u002Fposts\u002F20200311.html5-meta-basics.md","HTML5 基本 meta 資訊筆記",{"type":8,"value":12320,"toc":12534},[12321,12516,12518,12531],[22,12322,12324],{"className":4038,"code":12323,"language":4034,"meta":27,"style":27},"\u003C!DOCTYPE html>\n\u003Chtml lang=\"en\">\n\u003Chead>\n  \u003Cmeta charset=\"UTF-8\">\n  \u003Cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"> \u003C!-- 行動裝置必須加 -->\n  \u003Cmeta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\"> \u003C!-- 將瀏覽器更新到 IE Edge -->\n  \u003Ctitle>Yahoo 新聞\u003C\u002Ftitle>\n\u003C\u002Fhead>\n\u003Cbody>\n  \u003Ch1>標題\u003C\u002Fh1>\n  \u003Cp>段落段落\u003C\u002Fp>\n  \u003Cp>段落段落\u003C\u002Fp>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[29,12325,12326,12339,12354,12363,12379,12405,12431,12445,12453,12461,12475,12488,12500,12508],{"__ignoreMap":27},[32,12327,12328,12331,12334,12337],{"class":34,"line":35},[32,12329,12330],{"class":41},"\u003C!",[32,12332,12333],{"class":4049},"DOCTYPE",[32,12335,12336],{"class":4053}," html",[32,12338,4062],{"class":41},[32,12340,12341,12343,12345,12347,12349,12352],{"class":34,"line":45},[32,12342,4046],{"class":41},[32,12344,4034],{"class":4049},[32,12346,8677],{"class":4053},[32,12348,172],{"class":41},[32,12350,12351],{"class":175},"\"en\"",[32,12353,4062],{"class":41},[32,12355,12356,12358,12361],{"class":34,"line":51},[32,12357,4046],{"class":41},[32,12359,12360],{"class":4049},"head",[32,12362,4062],{"class":41},[32,12364,12365,12367,12369,12372,12374,12377],{"class":34,"line":90},[32,12366,4067],{"class":41},[32,12368,5665],{"class":4049},[32,12370,12371],{"class":4053}," charset",[32,12373,172],{"class":41},[32,12375,12376],{"class":175},"\"UTF-8\"",[32,12378,4062],{"class":41},[32,12380,12381,12383,12385,12387,12389,12392,12394,12396,12399,12402],{"class":34,"line":99},[32,12382,4067],{"class":41},[32,12384,5665],{"class":4049},[32,12386,5668],{"class":4053},[32,12388,172],{"class":41},[32,12390,12391],{"class":175},"\"viewport\"",[32,12393,5676],{"class":4053},[32,12395,172],{"class":41},[32,12397,12398],{"class":175},"\"width=device-width,initial-scale=1.0\"",[32,12400,12401],{"class":41},"> ",[32,12403,12404],{"class":608},"\u003C!-- 行動裝置必須加 -->\n",[32,12406,12407,12409,12411,12414,12416,12419,12421,12423,12426,12428],{"class":34,"line":106},[32,12408,4067],{"class":41},[32,12410,5665],{"class":4049},[32,12412,12413],{"class":4053}," http-equiv",[32,12415,172],{"class":41},[32,12417,12418],{"class":175},"\"X-UA-Compatible\"",[32,12420,5676],{"class":4053},[32,12422,172],{"class":41},[32,12424,12425],{"class":175},"\"ie=edge\"",[32,12427,12401],{"class":41},[32,12429,12430],{"class":608},"\u003C!-- 將瀏覽器更新到 IE Edge -->\n",[32,12432,12433,12435,12438,12441,12443],{"class":34,"line":114},[32,12434,4067],{"class":41},[32,12436,12437],{"class":4049},"title",[32,12439,12440],{"class":41},">Yahoo 新聞\u003C\u002F",[32,12442,12437],{"class":4049},[32,12444,4062],{"class":41},[32,12446,12447,12449,12451],{"class":34,"line":120},[32,12448,4105],{"class":41},[32,12450,12360],{"class":4049},[32,12452,4062],{"class":41},[32,12454,12455,12457,12459],{"class":34,"line":127},[32,12456,4046],{"class":41},[32,12458,5495],{"class":4049},[32,12460,4062],{"class":41},[32,12462,12463,12465,12468,12471,12473],{"class":34,"line":132},[32,12464,4067],{"class":41},[32,12466,12467],{"class":4049},"h1",[32,12469,12470],{"class":41},">標題\u003C\u002F",[32,12472,12467],{"class":4049},[32,12474,4062],{"class":41},[32,12476,12477,12479,12481,12484,12486],{"class":34,"line":141},[32,12478,4067],{"class":41},[32,12480,11],{"class":4049},[32,12482,12483],{"class":41},">段落段落\u003C\u002F",[32,12485,11],{"class":4049},[32,12487,4062],{"class":41},[32,12489,12490,12492,12494,12496,12498],{"class":34,"line":147},[32,12491,4067],{"class":41},[32,12493,11],{"class":4049},[32,12495,12483],{"class":41},[32,12497,11],{"class":4049},[32,12499,4062],{"class":41},[32,12501,12502,12504,12506],{"class":34,"line":275},[32,12503,4105],{"class":41},[32,12505,5495],{"class":4049},[32,12507,4062],{"class":41},[32,12509,12510,12512,12514],{"class":34,"line":282},[32,12511,4105],{"class":41},[32,12513,4034],{"class":4049},[32,12515,4062],{"class":41},[15,12517,2004],{"id":2003},[11,12519,12520,7090,12523,12526,12527,12530],{},[29,12521,12522],{},"charset",[29,12524,12525],{},"viewport"," 現在仍是基本設定；",[29,12528,12529],{},"X-UA-Compatible"," 是給 Internet Explorer 的舊設定，新專案已不需要。現行頁面資訊可參考《現在的 HTML meta 標籤怎麼寫》。",[368,12532,12533],{},"html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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);}",{"title":27,"searchDepth":51,"depth":51,"links":12535},[12536],{"id":2003,"depth":45,"text":2004},"2020 年留下的 HTML5 頁面骨架與基本 meta 標籤。",{},"\u002Fposts\u002Fhtml5-meta-basics","2020-03-11",[],{"title":12318,"description":12537},"posts\u002F20200311.html5-meta-basics",[4035,5665],"TcHYP9NY4iyRlNma-aQwG2M9mErLhsU1swF2Gz9k80w",{"id":12547,"title":12548,"body":12549,"category":378,"description":12634,"draft":380,"extension":381,"image":382,"meta":12635,"navigation":102,"path":12636,"publishedAt":12637,"relatedExperiments":12638,"seo":12639,"stem":12640,"tags":12641,"updatedAt":10829,"__hash__":12643},"posts\u002Fposts\u002F20200313.bootstrap-modal-scrollbar-fix.md","Bootstrap Modal 捲軸變動修正",{"type":8,"value":12550,"toc":12631},[12551,12558,12561,12619,12621,12628],[11,12552,12553,12554,12557],{},"使用 Bootstrap 的 Modal 元件時，如果頁面 Header 設為 ",[29,12555,12556],{},"position: fixed","，會發現開啟 Modal 時捲軸與版面發生變動。",[11,12559,12560],{},"當時使用以下 CSS 修正：",[22,12562,12564],{"className":5412,"code":12563,"language":1140,"meta":27,"style":27},"body,\nbody.swal2-shown,\nbody.modal-open {\n  overflow: inherit;\n  padding-right: inherit !important;\n}\n",[29,12565,12566,12572,12581,12590,12602,12615],{"__ignoreMap":27},[32,12567,12568,12570],{"class":34,"line":35},[32,12569,5495],{"class":4049},[32,12571,547],{"class":41},[32,12573,12574,12576,12579],{"class":34,"line":45},[32,12575,5495],{"class":4049},[32,12577,12578],{"class":4053},".swal2-shown",[32,12580,547],{"class":41},[32,12582,12583,12585,12588],{"class":34,"line":51},[32,12584,5495],{"class":4049},[32,12586,12587],{"class":4053},".modal-open",[32,12589,703],{"class":41},[32,12591,12592,12595,12597,12600],{"class":34,"line":90},[32,12593,12594],{"class":351},"  overflow",[32,12596,5269],{"class":41},[32,12598,12599],{"class":351},"inherit",[32,12601,96],{"class":41},[32,12603,12604,12607,12609,12611,12613],{"class":34,"line":99},[32,12605,12606],{"class":351},"  padding-right",[32,12608,5269],{"class":41},[32,12610,12599],{"class":351},[32,12612,11886],{"class":38},[32,12614,96],{"class":41},[32,12616,12617],{"class":34,"line":106},[32,12618,54],{"class":41},[15,12620,2004],{"id":2003},[11,12622,12623,12624,12627],{},"這段覆蓋規則會取消套件原本的捲動鎖定與捲軸寬度補償，只適合當時的版面情境。新專案若不依賴 Bootstrap Modal，也可以考慮瀏覽器原生的 ",[29,12625,12626],{},"dialog"," 元素。",[368,12629,12630],{},"html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}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);}",{"title":27,"searchDepth":51,"depth":51,"links":12632},[12633],{"id":2003,"depth":45,"text":2004},"2020 年記錄 Bootstrap Modal 與 fixed Header 一起使用時的捲軸修正方式。",{},"\u002Fposts\u002Fbootstrap-modal-scrollbar-fix","2020-03-13",[],{"title":12548,"description":12634},"posts\u002F20200313.bootstrap-modal-scrollbar-fix",[10517,1757,12642],"Modal","EVd-qtpdp1Yhv-cXjxVDZ4ceK7-IiK6TUgid-9-YIgU",{"id":12645,"title":12646,"body":12647,"category":4012,"description":12803,"draft":380,"extension":381,"image":382,"meta":12804,"navigation":102,"path":12805,"publishedAt":12806,"relatedExperiments":12807,"seo":12808,"stem":12809,"tags":12810,"updatedAt":10829,"__hash__":12813},"posts\u002Fposts\u002F20200315.github-first-push.md","專案上傳 GitHub 前的初始化流程",{"type":8,"value":12648,"toc":12797},[12649,12652,12656,12659,12665,12668,12674,12680,12683,12686,12692,12695,12705,12711,12714,12734,12737,12743,12747,12750,12756,12759,12765,12772,12778,12780,12794],[11,12650,12651],{},"這邊記錄專案上傳 GitHub 前會先做的動作。",[15,12653,12655],{"id":12654},"在-github-建立專案","在 GitHub 建立專案",[11,12657,12658],{},"進到 GitHub，點選右上角新增專案。",[11,12660,12661],{},[10742,12662],{"alt":12663,"src":12664},"GitHub 右上角的新增選單，New repository 選項用紅框標示","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F01.png",[11,12666,12667],{},"填寫專案名稱並選擇是否公開。",[11,12669,12670],{},[10742,12671],{"alt":12672,"src":12673},"GitHub 的 Create a new repository 表單，可填寫專案名稱並選擇 Public 或 Private","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F02.png",[11,12675,12676],{},[10742,12677],{"alt":12678,"src":12679},"GitHub 建立空倉庫後顯示的 command line 初始化指令","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F03.png",[15,12681,12682],{"id":12682},"本機初始化",[11,12684,12685],{},"開啟 PowerShell，將路徑切換到要上傳的專案並查看檔案清單。",[11,12687,12688],{},[10742,12689],{"alt":12690,"src":12691},"PowerShell 使用 ls 顯示專案資料夾中的檔案與目錄","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F04.png",[11,12693,12694],{},"初始化 Git：",[22,12696,12697],{"className":2057,"code":2381,"language":2059,"meta":27,"style":27},[29,12698,12699],{"__ignoreMap":27},[32,12700,12701,12703],{"class":34,"line":35},[32,12702,2126],{"class":2066},[32,12704,2390],{"class":175},[11,12706,12707],{},[10742,12708],{"alt":12709,"src":12710},"PowerShell 執行 git init，顯示 Initialized empty Git repository","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F05.png",[11,12712,12713],{},"告訴本機資料夾要連到哪個 GitHub 倉庫：",[22,12715,12717],{"className":2057,"code":12716,"language":2059,"meta":27,"style":27},"git remote add origin https:\u002F\u002Fgithub.com\u002F帳號\u002F專案名稱.git\n",[29,12718,12719],{"__ignoreMap":27},[32,12720,12721,12723,12726,12728,12731],{"class":34,"line":35},[32,12722,2126],{"class":2066},[32,12724,12725],{"class":175}," remote",[32,12727,2493],{"class":175},[32,12729,12730],{"class":175}," origin",[32,12732,12733],{"class":175}," https:\u002F\u002Fgithub.com\u002F帳號\u002F專案名稱.git\n",[11,12735,12736],{},"沒有任何錯誤或其他訊息出現，就代表設定成功。",[11,12738,12739],{},[10742,12740],{"alt":12741,"src":12742},"PowerShell 執行 git remote add origin，成功時沒有其他訊息","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F06.png",[15,12744,12746],{"id":12745},"使用-github-desktop","使用 GitHub Desktop",[11,12748,12749],{},"開啟 GitHub Desktop。",[11,12751,12752],{},[10742,12753],{"alt":12754,"src":12755},"GitHub Desktop 的 File 選單，Add local repository 選項被選取","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F07.png",[11,12757,12758],{},"選擇已建立、準備上傳的專案。",[11,12760,12761],{},[10742,12762],{"alt":12763,"src":12764},"GitHub Desktop 的 Add local repository 視窗，可選擇本機專案路徑","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F08.png",[11,12766,12767,12768,12771],{},"新增 ",[29,12769,12770],{},"CHANGELOG.md","，填寫 commit 訊息後提交並 push。",[11,12773,12774],{},[10742,12775],{"alt":12776,"src":12777},"GitHub Desktop 顯示專案變更，提交訊息欄位填寫初始化 Laravel 專案","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F09.png",[15,12779,2004],{"id":2003},[11,12781,12782,12783,12786,12787,12789,12790,12793],{},"初始化、設定 remote、commit 與 push 的流程沒有改變；現在 GitHub 新倉庫的預設分支通常是 ",[29,12784,12785],{},"main","，舊截圖則仍顯示 ",[29,12788,3753],{},"。常用指令可參考《",[412,12791,12792],{"href":4015},"Git 常用指令整理","》。",[368,12795,12796],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":12798},[12799,12800,12801,12802],{"id":12654,"depth":45,"text":12655},{"id":12682,"depth":45,"text":12682},{"id":12745,"depth":45,"text":12746},{"id":2003,"depth":45,"text":2004},"2020 年記錄建立 GitHub 倉庫、本機初始化並用 GitHub Desktop 完成第一次提交的流程。",{},"\u002Fposts\u002Fgithub-first-push","2020-03-15",[],{"title":12646,"description":12803},"posts\u002F20200315.github-first-push",[4021,12811,12812],"GitHub","GitHub Desktop","w1rx37B0l7tYN3oI2p6GNhHrDvSJgFmqR0LK532n4fk",{"id":12815,"title":12816,"body":12817,"category":378,"description":12881,"draft":380,"extension":381,"image":382,"meta":12882,"navigation":102,"path":12883,"publishedAt":12884,"relatedExperiments":12885,"seo":12886,"stem":12887,"tags":12888,"updatedAt":10829,"__hash__":12889},"posts\u002Fposts\u002F20200316.css-reset-normalize.md","CSS Reset 與 Normalize.css 筆記",{"type":8,"value":12818,"toc":12875},[12819,12822,12826,12838,12842,12851,12854,12861,12867,12869],[11,12820,12821],{},"開始製作專案時，習慣先將瀏覽器的預設樣式清空，以免撰寫 CSS 時出現不一致。\n清空方式很多，也可以自己手寫，這邊記錄當時常用的兩種選擇。",[15,12823,12825],{"id":12824},"reset-css","Reset CSS",[4538,12827,12828,12831],{},[4541,12829,12830],{},"會將不同瀏覽器的預設樣式清空。",[4541,12832,12833],{},[412,12834,12837],{"href":12835,"rel":12836},"https:\u002F\u002Fmeyerweb.com\u002Feric\u002Ftools\u002Fcss\u002Freset\u002F",[416],"Eric Meyer 的 Reset CSS",[15,12839,12841],{"id":12840},"normalizecss","Normalize.css",[4538,12843,12844],{},[4541,12845,12846,12847],{},"會保留部分預設樣式，並清除瀏覽器之間多餘或不一致的設定。當時較常使用這一套，Bootstrap 也有採用。\n",[412,12848,12841],{"href":12849,"rel":12850},"https:\u002F\u002Fnecolas.github.io\u002Fnormalize.css\u002F",[416],[15,12852,12853],{"id":12853},"使用方式",[11,12855,12856,12857,12860],{},"選擇一套習慣的方案，下載後可以直接把 CSS 檔改成 ",[29,12858,12859],{},"_xxx.scss","，再匯入主要的 SCSS 檔案。",[11,12862,12863],{},[10742,12864],{"alt":12865,"src":12866},"SCSS 入口檔使用 import 引入 normalize、animate、變數與 mixin 等檔案","\u002Fimages\u002Fposts\u002Fcss-reset-normalize\u002F01.webp",[15,12868,2004],{"id":2003},[11,12870,12871,12872,12874],{},"這兩套方案仍可使用；現代瀏覽器也可以搭配更精簡的 reset，整理在《現在的 CSS Reset》。Sass 的 ",[29,12873,8744],{}," 已有新的模組寫法，這篇保留當時的專案結構。",{"title":27,"searchDepth":51,"depth":51,"links":12876},[12877,12878,12879,12880],{"id":12824,"depth":45,"text":12825},{"id":12840,"depth":45,"text":12841},{"id":12853,"depth":45,"text":12853},{"id":2003,"depth":45,"text":2004},"2020 年整理的 CSS Reset、Normalize.css 與 Sass 引入方式。",{},"\u002Fposts\u002Fcss-reset-normalize","2020-03-16",[],{"title":12816,"description":12881},"posts\u002F20200316.css-reset-normalize",[1757,12314,12841],"2tIswfoUUD1KKmVrMk9YL5eph33bYXiugPlZQdwWGdI",{"id":12891,"title":12892,"body":12893,"category":378,"description":12997,"draft":380,"extension":381,"image":382,"meta":12998,"navigation":102,"path":12999,"publishedAt":13000,"relatedExperiments":13001,"seo":13002,"stem":13003,"tags":13004,"updatedAt":10829,"__hash__":13005},"posts\u002Fposts\u002F20200317.sass-scss-syntax-basics.md","關於 Sass／SCSS：兩種語法與專案架構",{"type":8,"value":12894,"toc":12991},[12895,12898,12902,12905,12908,12914,12920,12924,12927,12933,12939,12942,12948,12954,12960,12973,12975,12988],[11,12896,12897],{},"Sass／SCSS 是用來管理 CSS 的工具與程式語言，透過編譯工具轉成瀏覽器看得懂的 CSS。SCSS 是 Sass 3 引入的新語法，兩種寫法有些不同，但執行順序都是由上而下。",[15,12899,12901],{"id":12900},"sass-與-scss-寫法","Sass 與 SCSS 寫法",[11,12903,12904],{},"兩者最大的表面差異，是 Sass 省略了分號與大括號。Sass 寫起來較簡潔，但內容很多時只靠縮排會比較難分辨段落。",[11,12906,12907],{},"下面的 SCSS 與 Sass 寫法沒有功能差異，會編譯成相同的 CSS。",[11,12909,12910],{},[10742,12911],{"alt":12912,"src":12913},"SCSS 使用大括號與分號撰寫巢狀 nav，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F01.webp",[11,12915,12916],{},[10742,12917],{"alt":12918,"src":12919},"Sass 使用縮排撰寫相同的 nav 樣式，右側顯示相同的編譯結果","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F02.webp",[15,12921,12923],{"id":12922},"mixin-寫法","mixin 寫法",[11,12925,12926],{},"Mixin 在 SCSS 與 Sass 中的寫法不同。",[11,12928,12929],{},[10742,12930],{"alt":12931,"src":12932},"SCSS 使用 @mixin 與 @include 定義 transform，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F03.webp",[11,12934,12935],{},[10742,12936],{"alt":12937,"src":12938},"Sass 使用等號與加號定義及呼叫 transform mixin，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F04.webp",[15,12940,12941],{"id":12941},"專案架構",[11,12943,12944,12945,12947],{},"當時用 ",[29,12946,8744],{}," 組成的簡單架構：",[22,12949,12952],{"className":12950,"code":12951,"language":426,"meta":27},[424],"_variable.scss   \u002F\u002F 變數\n_normalize.scss  \u002F\u002F 保持乾淨的網站\n_mixin.scss      \u002F\u002F mixin\n_header.scss     \u002F\u002F header、footer 等\n_page1.scss      \u002F\u002F 分頁\n_page2.scss\n_all.scss        \u002F\u002F 所有檔案 import 到這裡\n",[29,12953,12951],{"__ignoreMap":27},[11,12955,12956,12959],{},[29,12957,12958],{},"_all.scss"," 內的寫法：",[22,12961,12963],{"className":8735,"code":12962,"language":8737,"meta":27,"style":27},"@import 'variable';\n",[29,12964,12965],{"__ignoreMap":27},[32,12966,12967,12969,12971],{"class":34,"line":35},[32,12968,8744],{"class":38},[32,12970,10306],{"class":175},[32,12972,96],{"class":41},[15,12974,2004],{"id":2003},[11,12976,12977,12978,7090,12981,12984,12985,12987],{},"SCSS 仍是常見語法，但 Sass 官方已用 ",[29,12979,12980],{},"@use",[29,12982,12983],{},"@forward"," 取代舊式 ",[29,12986,8744],{}," 架構；現行模組方式整理在《Sass 的 @use 與 @forward》。",[368,12989,12990],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}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);}",{"title":27,"searchDepth":51,"depth":51,"links":12992},[12993,12994,12995,12996],{"id":12900,"depth":45,"text":12901},{"id":12922,"depth":45,"text":12923},{"id":12941,"depth":45,"text":12941},{"id":2003,"depth":45,"text":2004},"2020 年整理的 Sass、SCSS 語法差異、mixin 與 import 專案結構。",{},"\u002Fposts\u002Fsass-scss-syntax-basics","2020-03-17",[],{"title":12892,"description":12997},"posts\u002F20200317.sass-scss-syntax-basics",[4847,12314],"j87ORCDJiqkqsXGX6jbLhz0Q_PZRE4jOpg2Kq20V0ck",{"id":13007,"title":13008,"body":13009,"category":378,"description":13415,"draft":380,"extension":381,"image":382,"meta":13416,"navigation":102,"path":13417,"publishedAt":13418,"relatedExperiments":13419,"seo":13420,"stem":13421,"tags":13422,"updatedAt":10829,"__hash__":13423},"posts\u002Fposts\u002F20200318.css-methodologies-smacss-oocss-bem.md","CSS 架構方法論：SMACSS、OOCSS、BEM",{"type":8,"value":13010,"toc":13402},[13011,13014,13018,13021,13033,13036,13115,13124,13190,13197,13201,13204,13212,13232,13256,13260,13264,13275,13282,13293,13300,13314,13317,13388,13394,13396,13399],[11,13012,13013],{},"Modular CSS 的目的是讓程式碼易懂、可重用，進而有效率地開發及維護。",[15,13015,13017],{"id":13016},"smacss","SMACSS",[11,13019,13020],{},"SMACSS（Scalable and Modular Architecture for CSS）具有結構規範與命名規則，將 CSS 結構分類，並讓 CSS 與 HTML 分離。",[4538,13022,13023,13026],{},[4541,13024,13025],{},"作者：Jonathan Snook",[4541,13027,13028,13029],{},"網站：",[412,13030,13017],{"href":13031,"rel":13032},"http:\u002F\u002Fsmacss.com\u002F",[416],[11,13034,13035],{},"分類方式：",[4538,13037,13038,13058,13075,13092,13109],{},[4541,13039,13040,13043,13044],{},[12249,13041,13042],{},"Base","：基底\n",[4538,13045,13046,13049,13052],{},[4541,13047,13048],{},"CSS Reset",[4541,13050,13051],{},"CSS Normalize",[4541,13053,13054,13055],{},"不應該使用 ",[29,13056,13057],{},"!important",[4541,13059,13060,13063,13064],{},[12249,13061,13062],{},"Layout","：圖層\n",[4538,13065,13066,13069,13072],{},[4541,13067,13068],{},"Header",[4541,13070,13071],{},"Sidebar",[4541,13073,13074],{},"Content",[4541,13076,13077,13080,13081],{},[12249,13078,13079],{},"Module","：模組\n",[4538,13082,13083,13086,13089],{},[4541,13084,13085],{},"Tabs",[4541,13087,13088],{},"Button",[4541,13090,13091],{},"List",[4541,13093,13094,13097,13098],{},[12249,13095,13096],{},"State","：狀態\n",[4538,13099,13100,13103,13106],{},[4541,13101,13102],{},"Disabled State",[4541,13104,13105],{},"Default State",[4541,13107,13108],{},"Active State",[4541,13110,13111,13114],{},[12249,13112,13113],{},"Theme","：頁面上可單獨存在並可重複使用的元件",[11,13116,13117,13118,3750,13121,3775],{},"定義 Module 時，應避免使用 ID 或標籤名稱作為選擇器。子模組以原模組名稱加連字號作為名稱，例如 ",[29,13119,13120],{},".mod-header",[29,13122,13123],{},".mod-body",[22,13125,13127],{"className":4038,"code":13126,"language":4034,"meta":27,"style":27},"\u003Cdiv class=\"fld\">\n  \u003Cp class=\"fld-name\">\u003C\u002Fp>\n  \u003Cp class=\"fld-item\">\u003C\u002Fp>\n\u003C\u002Fdiv>\n",[29,13128,13129,13144,13163,13182],{"__ignoreMap":27},[32,13130,13131,13133,13135,13137,13139,13142],{"class":34,"line":35},[32,13132,4046],{"class":41},[32,13134,4050],{"class":4049},[32,13136,9897],{"class":4053},[32,13138,172],{"class":41},[32,13140,13141],{"class":175},"\"fld\"",[32,13143,4062],{"class":41},[32,13145,13146,13148,13150,13152,13154,13157,13159,13161],{"class":34,"line":45},[32,13147,4067],{"class":41},[32,13149,11],{"class":4049},[32,13151,9897],{"class":4053},[32,13153,172],{"class":41},[32,13155,13156],{"class":175},"\"fld-name\"",[32,13158,4136],{"class":41},[32,13160,11],{"class":4049},[32,13162,4062],{"class":41},[32,13164,13165,13167,13169,13171,13173,13176,13178,13180],{"class":34,"line":51},[32,13166,4067],{"class":41},[32,13168,11],{"class":4049},[32,13170,9897],{"class":4053},[32,13172,172],{"class":41},[32,13174,13175],{"class":175},"\"fld-item\"",[32,13177,4136],{"class":41},[32,13179,11],{"class":4049},[32,13181,4062],{"class":41},[32,13183,13184,13186,13188],{"class":34,"line":90},[32,13185,4105],{"class":41},[32,13187,4050],{"class":4049},[32,13189,4062],{"class":41},[11,13191,10400,13192],{},[412,13193,13196],{"href":13194,"rel":13195},"https:\u002F\u002Fwww.slideshare.net\u002Fkurotanshi\u002Fcss-oocss-smacss-bem",[416],"CSS：OOCSS、SMACSS、BEM",[15,13198,13200],{"id":13199},"oocss","OOCSS",[11,13202,13203],{},"OOCSS（Object Oriented CSS）最典型的框架例子是 Bootstrap。",[4538,13205,13206,13209],{},[4541,13207,13208],{},"結構與外觀分離：與樣式有關的部分要獨立出來。",[4541,13210,13211],{},"容器與內容分離，例如格線系統 Grid System。",[22,13213,13215],{"className":5412,"code":13214,"language":1140,"meta":27,"style":27},".container .grid_1\n.container .grid_2\n",[29,13216,13217,13225],{"__ignoreMap":27},[32,13218,13219,13222],{"class":34,"line":35},[32,13220,13221],{"class":4053},".container",[32,13223,13224],{"class":4053}," .grid_1\n",[32,13226,13227,13229],{"class":34,"line":45},[32,13228,13221],{"class":4053},[32,13230,13231],{"class":4053}," .grid_2\n",[22,13233,13235],{"className":4038,"code":13234,"language":4034,"meta":27,"style":27},"\u003Cbutton class=\"btn btn-small btn-primary\">\u003C\u002Fbutton>\n",[29,13236,13237],{"__ignoreMap":27},[32,13238,13239,13241,13243,13245,13247,13250,13252,13254],{"class":34,"line":35},[32,13240,4046],{"class":41},[32,13242,11493],{"class":4049},[32,13244,9897],{"class":4053},[32,13246,172],{"class":41},[32,13248,13249],{"class":175},"\"btn btn-small btn-primary\"",[32,13251,4136],{"class":41},[32,13253,11493],{"class":4049},[32,13255,4062],{"class":41},[15,13257,13259],{"id":13258},"bem","BEM",[151,13261,13263],{"id":13262},"block區塊","Block（區塊）",[4538,13265,13266,13269,13272],{},[4541,13267,13268],{},"在頁面上獨立存在並可重複使用的元件。",[4541,13270,13271],{},"如同 SMACSS 的 Module、Layout。",[4541,13273,13274],{},"每個 Block 都是獨立存在。",[151,13276,13278,13279],{"id":13277},"element元素__","Element（元素）",[29,13280,13281],{},"__",[4538,13283,13284,13287,13290],{},[4541,13285,13286],{},"Block 的一部分，也就是子元件。",[4541,13288,13289],{},"無法獨立於 Block 之外。",[4541,13291,13292],{},"有些 Block 可能沒有 Element。",[151,13294,13296,13297],{"id":13295},"modifier修飾符","Modifier（修飾符）",[29,13298,13299],{},"--",[4538,13301,13302,13305,13308,13311],{},[4541,13303,13304],{},"用來修改樣式。",[4541,13306,13307],{},"定義 Block 或 Element 的狀態或屬性。",[4541,13309,13310],{},"類似 SMACSS 的 State。",[4541,13312,13313],{},"同一個 Block 或 Element 可以同時存在多組 Modifier。",[15,13315,13316],{"id":13316},"命名筆記",[4538,13318,13319,13322,13346,13361,13370,13376,13379,13382,13385],{},[4541,13320,13321],{},"階層不要超過五層。",[4541,13323,13324,13325,3750,13328,3750,13331,3750,13334,3750,13337,3750,13340,3750,13343,3775],{},"前綴詞：",[29,13326,13327],{},".l-layout",[29,13329,13330],{},".e-element",[29,13332,13333],{},".p-page",[29,13335,13336],{},".h-helper",[29,13338,13339],{},".col-",[29,13341,13342],{},".fas",[29,13344,13345],{},".fa-icon",[4541,13347,13348,13349,3750,13352,3750,13355,3750,13358,3775],{},"Element：",[29,13350,13351],{},".button__icon",[29,13353,13354],{},".text-field__label",[29,13356,13357],{},".heading__title",[29,13359,13360],{},".menu__item",[4541,13362,13363,13364,3750,13367,3775],{},"Modifier：",[29,13365,13366],{},".button_active",[29,13368,13369],{},".text-field_editable",[4541,13371,13372,13373,3775],{},"當時 CSS 通常使用小駝峰寫法，例如 ",[29,13374,13375],{},".bookList",[4541,13377,13378],{},"依照開發規範選擇命名方式，重點是保持一致。",[4541,13380,13381],{},"可以使用 BEM 設計模式與命名規範。",[4541,13383,13384],{},"拋棄語意命名方式，改以工具性質命名（SMACSS）。",[4541,13386,13387],{},"多參考其他框架，了解不同命名方式。",[11,13389,13390,13391,3775],{},"良好的 CSS 架構：",[12249,13392,13393],{},"可預測 → 可複用 → 可維護 → 可延展",[15,13395,2004],{"id":2003},[11,13397,13398],{},"這些方法論仍可用在全域 CSS；元件 scoped style、CSS Modules 與 utility-first CSS 則提供了不同的作用域與命名方式，整理在《Scoped Style 與 Utility-First CSS》。",[368,13400,13401],{},"html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":13403},[13404,13405,13406,13413,13414],{"id":13016,"depth":45,"text":13017},{"id":13199,"depth":45,"text":13200},{"id":13258,"depth":45,"text":13259,"children":13407},[13408,13409,13411],{"id":13262,"depth":51,"text":13263},{"id":13277,"depth":51,"text":13410},"Element（元素）__",{"id":13295,"depth":51,"text":13412},"Modifier（修飾符）--",{"id":13316,"depth":45,"text":13316},{"id":2003,"depth":45,"text":2004},"2020 年整理的 SMACSS、OOCSS、BEM 分類與命名筆記。",{},"\u002Fposts\u002Fcss-methodologies-smacss-oocss-bem","2020-03-18",[],{"title":13008,"description":13415},"posts\u002F20200318.css-methodologies-smacss-oocss-bem",[1757,13259,13017,13200],"x5xxmylpKKc2860imGPWbwo0ArnzP-siL-1cFC3Rhqk",{"id":13425,"title":13426,"body":13427,"category":378,"description":13611,"draft":380,"extension":381,"image":382,"meta":13612,"navigation":102,"path":13613,"publishedAt":13614,"relatedExperiments":13615,"seo":13616,"stem":13617,"tags":13618,"updatedAt":10829,"__hash__":13620},"posts\u002Fposts\u002F20200319.css-scss-team-standard.md","2020 年 CSS／Sass 規範與檢核表",{"type":8,"value":13428,"toc":13606},[13429,13432,13533,13536,13598,13600],[15,13430,13431],{"id":13431},"規範",[13433,13434,13435,13448],"table",{},[13436,13437,13438],"thead",{},[13439,13440,13441,13445],"tr",{},[13442,13443,13444],"th",{},"項次",[13442,13446,13447],{},"規範敘述",[13449,13450,13451,13459,13466,13474,13482,13489,13501,13508,13519,13526],"tbody",{},[13439,13452,13453,13456],{},[13454,13455,6544],"td",{},[13454,13457,13458],{},"類別階層以不超過四層為原則",[13439,13460,13461,13463],{},[13454,13462,11971],{},[13454,13464,13465],{},"不使用 ID，一律使用 class；ID 通常只用於唯一值與錨點定位",[13439,13467,13468,13471],{},[13454,13469,13470],{},"3",[13454,13472,13473],{},"使用 OOCSS 建立類別工具庫",[13439,13475,13476,13479],{},[13454,13477,13478],{},"4",[13454,13480,13481],{},"排版結構以 BEM 開發",[13439,13483,13484,13486],{},[13454,13485,10613],{},[13454,13487,13488],{},"導入 Bootstrap 4 的 Grid System",[13439,13490,13491,13494],{},[13454,13492,13493],{},"6",[13454,13495,13496,13497,13500],{},"使用 Sass ",[29,13498,13499],{},"for"," 管理擴充元件",[13439,13502,13503,13505],{},[13454,13504,1269],{},[13454,13506,13507],{},"一律採用小駝峰式命名",[13439,13509,13510,13512],{},[13454,13511,1031],{},[13454,13513,13514,13515,13518],{},"第三方插件在 Sass 的 ",[29,13516,13517],{},"vendor"," 分類中引入",[13439,13520,13521,13523],{},[13454,13522,1043],{},[13454,13524,13525],{},"使用 REM 或 vmin 單位",[13439,13527,13528,13530],{},[13454,13529,11229],{},[13454,13531,13532],{},"使用 flexbox 進行元件布局",[15,13534,13535],{"id":13535},"檢核表",[13433,13537,13538,13548],{},[13436,13539,13540],{},[13439,13541,13542,13545],{},[13442,13543,13544],{},"項目",[13442,13546,13547],{},"敘述",[13449,13549,13550,13558,13566,13574,13582,13590],{},[13439,13551,13552,13555],{},[13454,13553,13554],{},"網頁相容性",[13454,13556,13557],{},"檢查各大瀏覽器版本，例如 Chrome、Firefox、Edge",[13439,13559,13560,13563],{},[13454,13561,13562],{},"螢幕解析度",[13454,13564,13565],{},"可自行設定 1920、1440、1280、1024、768、414、370、320 等尺寸；使用 Bootstrap 時改用 BS4 的 breakpoints",[13439,13567,13568,13571],{},[13454,13569,13570],{},"可讀性",[13454,13572,13573],{},"class 的連字號、底線與駝峰寫法要有一致規則，並統一縮排與註解",[13439,13575,13576,13579],{},[13454,13577,13578],{},"可擴充性",[13454,13580,13581],{},"具備元件化設計觀念（BEM 或自訂規則），不輕易影響主體架構與 JS hooks",[13439,13583,13584,13587],{},[13454,13585,13586],{},"可重用性",[13454,13588,13589],{},"自訂 class 可在多處使用（OOCSS），不重複套用多餘 CSS",[13439,13591,13592,13595],{},[13454,13593,13594],{},"可維護性",[13454,13596,13597],{},"Sass import 結構清晰易懂，整體風格一致",[15,13599,2004],{"id":2003},[11,13601,13602,13603,13605],{},"這份規範保留的是當時的團隊約定，其中 Bootstrap 4 Grid、Sass ",[29,13604,8744],{}," 與命名方式不必直接套用到新專案。現代元件樣式與 utility-first 的取捨可參考《Scoped Style 與 Utility-First CSS》。",{"title":27,"searchDepth":51,"depth":51,"links":13607},[13608,13609,13610],{"id":13431,"depth":45,"text":13431},{"id":13535,"depth":45,"text":13535},{"id":2003,"depth":45,"text":2004},"2020 年留下的 CSS／Sass 團隊規範、相容性與維護性檢核表。",{},"\u002Fposts\u002Fcss-scss-team-standard","2020-03-19",[],{"title":13426,"description":13611},"posts\u002F20200319.css-scss-team-standard",[1757,4847,13619],"團隊規範","68E2Iy1aYISP0Sw0Ue3P9da2cVL8hpuctfU36c2zjsc",{"id":13622,"title":13623,"body":13624,"category":378,"description":13658,"draft":380,"extension":381,"image":382,"meta":13659,"navigation":102,"path":13660,"publishedAt":13661,"relatedExperiments":13662,"seo":13663,"stem":13664,"tags":13665,"updatedAt":10829,"__hash__":13668},"posts\u002Fposts\u002F20200320.ios-momentum-scrolling.md","iOS 捲動順暢設定：-webkit-overflow-scrolling",{"type":8,"value":13625,"toc":13655},[13626,13629,13644,13646,13652],[11,13627,13628],{},"若要在 iOS 讓區塊的捲軸滾動順暢，可以使用以下語法：",[22,13630,13632],{"className":5412,"code":13631,"language":1140,"meta":27,"style":27},"overflow: auto;\n-webkit-overflow-scrolling: touch;\n",[29,13633,13634,13639],{"__ignoreMap":27},[32,13635,13636],{"class":34,"line":35},[32,13637,13638],{"class":41},"overflow: auto;\n",[32,13640,13641],{"class":34,"line":45},[32,13642,13643],{"class":41},"-webkit-overflow-scrolling: touch;\n",[15,13645,2004],{"id":2003},[11,13647,13648,13649,3775],{},"這是早期 iOS Safari 的非標準設定。新版 Safari 已預設提供慣性捲動，新專案通常不需要再加入 ",[29,13650,13651],{},"-webkit-overflow-scrolling: touch",[368,13653,13654],{},"html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}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);}",{"title":27,"searchDepth":51,"depth":51,"links":13656},[13657],{"id":2003,"depth":45,"text":2004},"2020 年記錄 iOS 可捲動區塊啟用慣性捲動的 CSS。",{},"\u002Fposts\u002Fios-momentum-scrolling","2020-03-20",[],{"title":13623,"description":13658},"posts\u002F20200320.ios-momentum-scrolling",[1757,13666,13667],"iOS","Safari","dHIBq5EBemZqS3COAUSR8IkMlYhqdXZWNmbLJCzZeSc",{"id":13670,"title":13671,"body":13672,"category":378,"description":14263,"draft":380,"extension":381,"image":382,"meta":14264,"navigation":102,"path":14265,"publishedAt":14266,"relatedExperiments":14267,"seo":14268,"stem":14269,"tags":14270,"updatedAt":14272,"__hash__":14273},"posts\u002Fposts\u002F20200323.scss-color-map.md","用 SCSS 的 Map 建立一份共用色票",{"type":8,"value":13673,"toc":14258},[13674,13677,13681,13690,13893,13896,13899,13902,14051,14054,14201,14204,14250,14252,14255],[11,13675,13676],{},"撰寫 SCSS 時，顏色怎麼命名是一種考驗。這邊分享當時常用的兩種整理方式。",[15,13678,13680],{"id":13679},"擴充-bootstrap-的顏色工具類別","擴充 Bootstrap 的顏色工具類別",[11,13682,13683,13684,13689],{},"因為自己常用 Bootstrap，所以會沿用它的顏色工具類別規範。可以先定義顏色；如果要以顏色名稱命名，我習慣把色碼貼到 ",[412,13685,13688],{"href":13686,"rel":13687},"http:\u002F\u002Fchir.ag\u002Fprojects\u002Fname-that-color\u002F",[416],"Name That Color"," 查詢名稱。",[22,13691,13693],{"className":8735,"code":13692,"language":8737,"meta":27,"style":27},"$colorGroup: (\n  \"supernova\": #fecc00,\n  \"fiord\": #4c596c,\n  \"black\": #000,\n  \"alto\": #dbdbdb,\n  \"dustyGray\": #999,\n  \"gray\": #7f7f7f,\n);\n\n@each $name, $color in $colorGroup {\n  .bg-#{$name} {\n    background: $color;\n  }\n\n  .text-#{$name} {\n    color: $color !important;\n  }\n\n  .border-#{$name} {\n    border: 1px solid $color;\n  }\n}\n",[29,13694,13695,13702,13714,13726,13737,13749,13761,13773,13779,13783,13800,13809,13819,13823,13827,13836,13849,13853,13857,13866,13885,13889],{"__ignoreMap":27},[32,13696,13697,13700],{"class":34,"line":35},[32,13698,13699],{"class":903},"$colorGroup",[32,13701,11719],{"class":5049},[32,13703,13704,13707,13709,13712],{"class":34,"line":45},[32,13705,13706],{"class":175},"  \"supernova\"",[32,13708,5269],{"class":5049},[32,13710,13711],{"class":351},"#fecc00",[32,13713,547],{"class":5049},[32,13715,13716,13719,13721,13724],{"class":34,"line":51},[32,13717,13718],{"class":175},"  \"fiord\"",[32,13720,5269],{"class":5049},[32,13722,13723],{"class":351},"#4c596c",[32,13725,547],{"class":5049},[32,13727,13728,13731,13733,13735],{"class":34,"line":90},[32,13729,13730],{"class":175},"  \"black\"",[32,13732,5269],{"class":5049},[32,13734,8694],{"class":351},[32,13736,547],{"class":5049},[32,13738,13739,13742,13744,13747],{"class":34,"line":99},[32,13740,13741],{"class":175},"  \"alto\"",[32,13743,5269],{"class":5049},[32,13745,13746],{"class":351},"#dbdbdb",[32,13748,547],{"class":5049},[32,13750,13751,13754,13756,13759],{"class":34,"line":106},[32,13752,13753],{"class":175},"  \"dustyGray\"",[32,13755,5269],{"class":5049},[32,13757,13758],{"class":351},"#999",[32,13760,547],{"class":5049},[32,13762,13763,13766,13768,13771],{"class":34,"line":114},[32,13764,13765],{"class":175},"  \"gray\"",[32,13767,5269],{"class":5049},[32,13769,13770],{"class":351},"#7f7f7f",[32,13772,547],{"class":5049},[32,13774,13775,13777],{"class":34,"line":120},[32,13776,11796],{"class":5049},[32,13778,96],{"class":41},[32,13780,13781],{"class":34,"line":127},[32,13782,103],{"emptyLinePlaceholder":102},[32,13784,13785,13787,13789,13791,13793,13795,13798],{"class":34,"line":132},[32,13786,11660],{"class":38},[32,13788,11822],{"class":903},[32,13790,635],{"class":41},[32,13792,8689],{"class":903},[32,13794,5527],{"class":38},[32,13796,13797],{"class":903}," $colorGroup",[32,13799,703],{"class":41},[32,13801,13802,13805,13807],{"class":34,"line":141},[32,13803,13804],{"class":4053},"  .bg-",[32,13806,11840],{"class":903},[32,13808,703],{"class":41},[32,13810,13811,13813,13815,13817],{"class":34,"line":147},[32,13812,11893],{"class":351},[32,13814,5269],{"class":41},[32,13816,8689],{"class":903},[32,13818,96],{"class":41},[32,13820,13821],{"class":34,"line":275},[32,13822,1203],{"class":41},[32,13824,13825],{"class":34,"line":282},[32,13826,103],{"emptyLinePlaceholder":102},[32,13828,13829,13832,13834],{"class":34,"line":295},[32,13830,13831],{"class":4053},"  .text-",[32,13833,11840],{"class":903},[32,13835,703],{"class":41},[32,13837,13838,13841,13843,13845,13847],{"class":34,"line":605},[32,13839,13840],{"class":351},"    color",[32,13842,5269],{"class":41},[32,13844,8689],{"class":903},[32,13846,11886],{"class":38},[32,13848,96],{"class":41},[32,13850,13851],{"class":34,"line":612},[32,13852,1203],{"class":41},[32,13854,13855],{"class":34,"line":617},[32,13856,103],{"emptyLinePlaceholder":102},[32,13858,13859,13862,13864],{"class":34,"line":644},[32,13860,13861],{"class":4053},"  .border-",[32,13863,11840],{"class":903},[32,13865,703],{"class":41},[32,13867,13868,13871,13873,13875,13877,13880,13883],{"class":34,"line":649},[32,13869,13870],{"class":351},"    border",[32,13872,5269],{"class":41},[32,13874,6544],{"class":351},[32,13876,11855],{"class":38},[32,13878,13879],{"class":351}," solid",[32,13881,13882],{"class":903}," $color",[32,13884,96],{"class":41},[32,13886,13887],{"class":34,"line":671},[32,13888,1203],{"class":41},[32,13890,13891],{"class":34,"line":690},[32,13892,54],{"class":41},[11,13894,13895],{},"SCSS 編譯完成後，就可以直接使用產生出來的 class。",[15,13897,13898],{"id":13898},"依區塊整理顏色",[11,13900,13901],{},"區塊需要的顏色可以直接使用色碼，或引用已經命名的顏色。例如 footer 可以另外整理一份 map：",[22,13903,13905],{"className":8735,"code":13904,"language":8737,"meta":27,"style":27},"$footerGroup: (\n  \"menu-title-color\": map-get($colorGroup, \"nobel\"),\n  \"menu-normal-color\": map-get($colorGroup, \"doveGray\"),\n  \"menu-hover-color\": map-get($colorGroup, \"treePoppy\"),\n  \"bottom-bg-color\": map-get($colorGroup, \"shark\"),\n  \"privacy-text-color\": map-get($colorGroup, \"doveGray\"),\n  \"border-color\": map-get($colorGroup, \"alto\"),\n  \"footer-bg\": white,\n);\n",[29,13906,13907,13914,13934,13954,13974,13994,14013,14033,14045],{"__ignoreMap":27},[32,13908,13909,13912],{"class":34,"line":35},[32,13910,13911],{"class":903},"$footerGroup",[32,13913,11719],{"class":5049},[32,13915,13916,13919,13921,13923,13925,13927,13929,13932],{"class":34,"line":45},[32,13917,13918],{"class":175},"  \"menu-title-color\"",[32,13920,5269],{"class":5049},[32,13922,11903],{"class":351},[32,13924,477],{"class":5049},[32,13926,13699],{"class":903},[32,13928,635],{"class":5049},[32,13930,13931],{"class":175},"\"nobel\"",[32,13933,5101],{"class":5049},[32,13935,13936,13939,13941,13943,13945,13947,13949,13952],{"class":34,"line":51},[32,13937,13938],{"class":175},"  \"menu-normal-color\"",[32,13940,5269],{"class":5049},[32,13942,11903],{"class":351},[32,13944,477],{"class":5049},[32,13946,13699],{"class":903},[32,13948,635],{"class":5049},[32,13950,13951],{"class":175},"\"doveGray\"",[32,13953,5101],{"class":5049},[32,13955,13956,13959,13961,13963,13965,13967,13969,13972],{"class":34,"line":90},[32,13957,13958],{"class":175},"  \"menu-hover-color\"",[32,13960,5269],{"class":5049},[32,13962,11903],{"class":351},[32,13964,477],{"class":5049},[32,13966,13699],{"class":903},[32,13968,635],{"class":5049},[32,13970,13971],{"class":175},"\"treePoppy\"",[32,13973,5101],{"class":5049},[32,13975,13976,13979,13981,13983,13985,13987,13989,13992],{"class":34,"line":99},[32,13977,13978],{"class":175},"  \"bottom-bg-color\"",[32,13980,5269],{"class":5049},[32,13982,11903],{"class":351},[32,13984,477],{"class":5049},[32,13986,13699],{"class":903},[32,13988,635],{"class":5049},[32,13990,13991],{"class":175},"\"shark\"",[32,13993,5101],{"class":5049},[32,13995,13996,13999,14001,14003,14005,14007,14009,14011],{"class":34,"line":106},[32,13997,13998],{"class":175},"  \"privacy-text-color\"",[32,14000,5269],{"class":5049},[32,14002,11903],{"class":351},[32,14004,477],{"class":5049},[32,14006,13699],{"class":903},[32,14008,635],{"class":5049},[32,14010,13951],{"class":175},[32,14012,5101],{"class":5049},[32,14014,14015,14018,14020,14022,14024,14026,14028,14031],{"class":34,"line":114},[32,14016,14017],{"class":175},"  \"border-color\"",[32,14019,5269],{"class":5049},[32,14021,11903],{"class":351},[32,14023,477],{"class":5049},[32,14025,13699],{"class":903},[32,14027,635],{"class":5049},[32,14029,14030],{"class":175},"\"alto\"",[32,14032,5101],{"class":5049},[32,14034,14035,14038,14040,14043],{"class":34,"line":120},[32,14036,14037],{"class":175},"  \"footer-bg\"",[32,14039,5269],{"class":5049},[32,14041,14042],{"class":351},"white",[32,14044,547],{"class":5049},[32,14046,14047,14049],{"class":34,"line":127},[32,14048,11796],{"class":5049},[32,14050,96],{"class":41},[11,14052,14053],{},"社群圖示也可以直接用色碼命名：",[22,14055,14057],{"className":8735,"code":14056,"language":8737,"meta":27,"style":27},"$socialGroup: (\n  \"users\": #2ab1f3,\n  \"fb\": #3b5998,\n  \"twitter\": #1da1f2,\n  \"ig\": linear-gradient(45deg, #f09433 0%, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888 100%),\n  \"telegram\": #0088cc,\n  \"youtube\": #cd201f,\n);\n",[29,14058,14059,14066,14078,14090,14102,14171,14183,14195],{"__ignoreMap":27},[32,14060,14061,14064],{"class":34,"line":35},[32,14062,14063],{"class":903},"$socialGroup",[32,14065,11719],{"class":5049},[32,14067,14068,14071,14073,14076],{"class":34,"line":45},[32,14069,14070],{"class":175},"  \"users\"",[32,14072,5269],{"class":5049},[32,14074,14075],{"class":351},"#2ab1f3",[32,14077,547],{"class":5049},[32,14079,14080,14083,14085,14088],{"class":34,"line":51},[32,14081,14082],{"class":175},"  \"fb\"",[32,14084,5269],{"class":5049},[32,14086,14087],{"class":351},"#3b5998",[32,14089,547],{"class":5049},[32,14091,14092,14095,14097,14100],{"class":34,"line":90},[32,14093,14094],{"class":175},"  \"twitter\"",[32,14096,5269],{"class":5049},[32,14098,14099],{"class":351},"#1da1f2",[32,14101,547],{"class":5049},[32,14103,14104,14107,14109,14112,14114,14117,14120,14122,14125,14127,14130,14132,14135,14138,14140,14142,14145,14147,14149,14151,14154,14157,14159,14161,14164,14167,14169],{"class":34,"line":99},[32,14105,14106],{"class":175},"  \"ig\"",[32,14108,5269],{"class":5049},[32,14110,14111],{"class":351},"linear-gradient",[32,14113,477],{"class":5049},[32,14115,14116],{"class":351},"45",[32,14118,14119],{"class":38},"deg",[32,14121,635],{"class":5049},[32,14123,14124],{"class":351},"#f09433",[32,14126,1523],{"class":351},[32,14128,14129],{"class":38},"%",[32,14131,635],{"class":5049},[32,14133,14134],{"class":351},"#e6683c",[32,14136,14137],{"class":351}," 25",[32,14139,14129],{"class":38},[32,14141,635],{"class":5049},[32,14143,14144],{"class":351},"#dc2743",[32,14146,6868],{"class":351},[32,14148,14129],{"class":38},[32,14150,635],{"class":5049},[32,14152,14153],{"class":351},"#cc2366",[32,14155,14156],{"class":351}," 75",[32,14158,14129],{"class":38},[32,14160,635],{"class":5049},[32,14162,14163],{"class":351},"#bc1888",[32,14165,14166],{"class":351}," 100",[32,14168,14129],{"class":38},[32,14170,5101],{"class":5049},[32,14172,14173,14176,14178,14181],{"class":34,"line":106},[32,14174,14175],{"class":175},"  \"telegram\"",[32,14177,5269],{"class":5049},[32,14179,14180],{"class":351},"#0088cc",[32,14182,547],{"class":5049},[32,14184,14185,14188,14190,14193],{"class":34,"line":114},[32,14186,14187],{"class":175},"  \"youtube\"",[32,14189,5269],{"class":5049},[32,14191,14192],{"class":351},"#cd201f",[32,14194,547],{"class":5049},[32,14196,14197,14199],{"class":34,"line":120},[32,14198,11796],{"class":5049},[32,14200,96],{"class":41},[11,14202,14203],{},"調用方式：",[22,14205,14207],{"className":8735,"code":14206,"language":8737,"meta":27,"style":27},"footer {\n  .footer-area {\n    background: map-get($footerGroup, \"footer-bg\");\n  }\n}\n",[29,14208,14209,14216,14223,14242,14246],{"__ignoreMap":27},[32,14210,14211,14214],{"class":34,"line":35},[32,14212,14213],{"class":4049},"footer",[32,14215,703],{"class":41},[32,14217,14218,14221],{"class":34,"line":45},[32,14219,14220],{"class":4053},"  .footer-area",[32,14222,703],{"class":41},[32,14224,14225,14227,14229,14231,14233,14235,14237,14240],{"class":34,"line":51},[32,14226,11893],{"class":351},[32,14228,5269],{"class":41},[32,14230,11903],{"class":351},[32,14232,477],{"class":41},[32,14234,13911],{"class":903},[32,14236,635],{"class":41},[32,14238,14239],{"class":175},"\"footer-bg\"",[32,14241,230],{"class":41},[32,14243,14244],{"class":34,"line":90},[32,14245,1203],{"class":41},[32,14247,14248],{"class":34,"line":99},[32,14249,54],{"class":41},[15,14251,2004],{"id":2003},[11,14253,14254],{},"集中管理顏色的想法仍然適用。需要在瀏覽器執行期間切換主題時，現在通常會改用 CSS 自訂屬性；SCSS map 仍適合編譯期的批次產生工作。",[368,14256,14257],{},"html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}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 .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}",{"title":27,"searchDepth":51,"depth":51,"links":14259},[14260,14261,14262],{"id":13679,"depth":45,"text":13680},{"id":13898,"depth":45,"text":13898},{"id":2003,"depth":45,"text":2004},"記錄用顏色名稱整理 SCSS 色票，再以 @each 產生背景、文字與邊框工具類別的做法。",{},"\u002Fposts\u002Fscss-color-map","2020-03-23",[],{"title":13671,"description":14263},"posts\u002F20200323.scss-color-map",[12314,1757,14271],"色彩系統","2026-08-25","YJSmUPoEz2pBgp0FJo38-UtMcfLdNODoBcDCCgdFucg",{"id":14275,"title":14276,"body":14277,"category":378,"description":14538,"draft":380,"extension":381,"image":382,"meta":14539,"navigation":102,"path":14540,"publishedAt":14541,"relatedExperiments":14542,"seo":14543,"stem":14544,"tags":14545,"updatedAt":14272,"__hash__":14547},"posts\u002Fposts\u002F20200328.webkit-scrollbar-styling.md","::-webkit-scrollbar 捲軸樣式調整整理",{"type":8,"value":14278,"toc":14533},[14279,14286,14289,14373,14376,14444,14514,14516,14530],[11,14280,14281,14282,14285],{},"最近在調整 scrollbar 時，發現自己對捲軸還有許多不了解的地方。當時也遇到頁面嵌入 Android WebView 後，單純使用 ",[29,14283,14284],{},"overflow: scroll","，捲軸反而消失的情況，因此爬文整理了一份記錄。",[15,14287,14288],{"id":14288},"捲軸偽元素",[13433,14290,14291,14301],{},[13436,14292,14293],{},[13439,14294,14295,14298],{},[13442,14296,14297],{},"偽元素",[13442,14299,14300],{},"對應部位",[13449,14302,14303,14313,14323,14333,14343,14353,14363],{},[13439,14304,14305,14310],{},[13454,14306,14307],{},[29,14308,14309],{},"::-webkit-scrollbar",[13454,14311,14312],{},"整條捲軸",[13439,14314,14315,14320],{},[13454,14316,14317],{},[29,14318,14319],{},"::-webkit-scrollbar-thumb",[13454,14321,14322],{},"可以上下或左右移動的滑塊",[13439,14324,14325,14330],{},[13454,14326,14327],{},[29,14328,14329],{},"::-webkit-scrollbar-track",[13454,14331,14332],{},"裝著滑塊的軌道",[13439,14334,14335,14340],{},[13454,14336,14337],{},[29,14338,14339],{},"::-webkit-scrollbar-button",[13454,14341,14342],{},"軌道兩端的按鈕",[13439,14344,14345,14350],{},[13454,14346,14347],{},[29,14348,14349],{},"::-webkit-scrollbar-track-piece",[13454,14351,14352],{},"內層軌道",[13439,14354,14355,14360],{},[13454,14356,14357],{},[29,14358,14359],{},"::-webkit-scrollbar-corner",[13454,14361,14362],{},"兩條捲軸的交會處",[13439,14364,14365,14370],{},[13454,14366,14367],{},[29,14368,14369],{},"::-webkit-resizer",[13454,14371,14372],{},"交會處用來調整元素大小的控制元件",[15,14374,14375],{"id":14375},"偽類別",[4538,14377,14378,14384,14390,14396,14402,14408,14414,14420,14426,14432,14438],{},[4541,14379,14380,14383],{},[29,14381,14382],{},":horizontal","：水平方向的捲軸",[4541,14385,14386,14389],{},[29,14387,14388],{},":vertical","：垂直方向的捲軸",[4541,14391,14392,14395],{},[29,14393,14394],{},":decrement","：遞減方向的按鈕或軌道區塊",[4541,14397,14398,14401],{},[29,14399,14400],{},":increment","：遞增方向的按鈕或軌道區塊",[4541,14403,14404,14407],{},[29,14405,14406],{},":start","：位於滑塊前方的物件",[4541,14409,14410,14413],{},[29,14411,14412],{},":end","：位於滑塊後方的物件",[4541,14415,14416,14419],{},[29,14417,14418],{},":double-button","：軌道末端有一對按鈕",[4541,14421,14422,14425],{},[29,14423,14424],{},":single-button","：軌道末端只有一個按鈕",[4541,14427,14428,14431],{},[29,14429,14430],{},":no-button","：軌道末端沒有按鈕",[4541,14433,14434,14437],{},[29,14435,14436],{},":corner-present","：捲軸角落存在",[4541,14439,14440,14443],{},[29,14441,14442],{},":window-inactive","：包含捲軸的視窗未取得焦點",[22,14445,14447],{"className":5412,"code":14446,"language":1140,"meta":27,"style":27},"::-webkit-scrollbar-track-piece:start {\n  \u002F* 捲軸上半邊或左半邊 *\u002F\n}\n\n::-webkit-scrollbar-thumb:window-inactive {\n  \u002F* 焦點不在目前視窗時的滑塊 *\u002F\n}\n\n::-webkit-scrollbar-button:horizontal:decrement:hover {\n  \u002F* 滑鼠移到水平捲軸遞減按鈕時 *\u002F\n}\n",[29,14448,14449,14456,14461,14465,14469,14480,14485,14489,14493,14505,14510],{"__ignoreMap":27},[32,14450,14451,14453],{"class":34,"line":35},[32,14452,14349],{"class":4053},[32,14454,14455],{"class":41},":start {\n",[32,14457,14458],{"class":34,"line":45},[32,14459,14460],{"class":608},"  \u002F* 捲軸上半邊或左半邊 *\u002F\n",[32,14462,14463],{"class":34,"line":51},[32,14464,54],{"class":41},[32,14466,14467],{"class":34,"line":90},[32,14468,103],{"emptyLinePlaceholder":102},[32,14470,14471,14473,14475,14478],{"class":34,"line":99},[32,14472,14319],{"class":4053},[32,14474,322],{"class":41},[32,14476,14477],{"class":4049},"window-inactive",[32,14479,703],{"class":41},[32,14481,14482],{"class":34,"line":106},[32,14483,14484],{"class":608},"  \u002F* 焦點不在目前視窗時的滑塊 *\u002F\n",[32,14486,14487],{"class":34,"line":114},[32,14488,54],{"class":41},[32,14490,14491],{"class":34,"line":120},[32,14492,103],{"emptyLinePlaceholder":102},[32,14494,14495,14497,14500,14503],{"class":34,"line":127},[32,14496,14339],{"class":4053},[32,14498,14499],{"class":41},":horizontal:decrement",[32,14501,14502],{"class":4053},":hover",[32,14504,703],{"class":41},[32,14506,14507],{"class":34,"line":132},[32,14508,14509],{"class":608},"  \u002F* 滑鼠移到水平捲軸遞減按鈕時 *\u002F\n",[32,14511,14512],{"class":34,"line":141},[32,14513,54],{"class":41},[15,14515,2004],{"id":2003},[11,14517,14518,14519,14522,14523,7090,14526,14529],{},"這組 ",[29,14520,14521],{},"::-webkit-scrollbar-*"," 寫法並非完整的跨瀏覽器標準。現在也有 ",[29,14524,14525],{},"scrollbar-width",[29,14527,14528],{},"scrollbar-color"," 等標準屬性可用，但能調整的細節較少；實作前仍要確認目標瀏覽器。",[368,14531,14532],{},"html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}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);}",{"title":27,"searchDepth":51,"depth":51,"links":14534},[14535,14536,14537],{"id":14288,"depth":45,"text":14288},{"id":14375,"depth":45,"text":14375},{"id":2003,"depth":45,"text":2004},"記錄 WebKit 捲軸偽元素、偽類別，以及 Android WebView 中捲軸消失的問題。",{},"\u002Fposts\u002Fwebkit-scrollbar-styling","2020-03-28",[],{"title":14276,"description":14538},"posts\u002F20200328.webkit-scrollbar-styling",[1757,14546],"捲軸","NeeVFr1G44Vfqvgs6KgYlJNTRnGYyJlmS3Ds0a2g-jo",{"id":14549,"title":14550,"body":14551,"category":378,"description":14973,"draft":380,"extension":381,"image":382,"meta":14974,"navigation":102,"path":14975,"publishedAt":14976,"relatedExperiments":14977,"seo":14978,"stem":14979,"tags":14980,"updatedAt":14272,"__hash__":14982},"posts\u002Fposts\u002F20200329.jquery-scroll-animation.md","jQuery 版本的捲動進場動畫：手動比對 offset 與 scrollTop",{"type":8,"value":14552,"toc":14967},[14553,14556,14560,14651,14654,14799,14802,14955,14957,14964],[11,14554,14555],{},"今天練習 EDM 時想整理一下程式碼，免得每次想不起來都要翻找很久。",[15,14557,14559],{"id":14558},"頁面-resize-與-scroll","頁面 resize 與 scroll",[22,14561,14563],{"className":24,"code":14562,"language":26,"meta":27,"style":27},"$(window)\n  .resize(function () {\n    $(window)\n      .on(\"scroll\", function () {\n        \u002F\u002F do something...\n      })\n      .trigger(\"scroll\");\n  })\n  .trigger(\"resize\");\n",[29,14564,14565,14572,14585,14591,14610,14615,14620,14633,14638],{"__ignoreMap":27},[32,14566,14567,14569],{"class":34,"line":35},[32,14568,755],{"class":217},[32,14570,14571],{"class":41},"(window)\n",[32,14573,14574,14577,14579,14581,14583],{"class":34,"line":45},[32,14575,14576],{"class":41},"  .",[32,14578,6728],{"class":217},[32,14580,477],{"class":41},[32,14582,665],{"class":38},[32,14584,668],{"class":41},[32,14586,14587,14589],{"class":34,"line":51},[32,14588,674],{"class":217},[32,14590,14571],{"class":41},[32,14592,14593,14596,14599,14601,14604,14606,14608],{"class":34,"line":90},[32,14594,14595],{"class":41},"      .",[32,14597,14598],{"class":217},"on",[32,14600,477],{"class":41},[32,14602,14603],{"class":175},"\"scroll\"",[32,14605,635],{"class":41},[32,14607,665],{"class":38},[32,14609,668],{"class":41},[32,14611,14612],{"class":34,"line":99},[32,14613,14614],{"class":608},"        \u002F\u002F do something...\n",[32,14616,14617],{"class":34,"line":106},[32,14618,14619],{"class":41},"      })\n",[32,14621,14622,14624,14627,14629,14631],{"class":34,"line":114},[32,14623,14595],{"class":41},[32,14625,14626],{"class":217},"trigger",[32,14628,477],{"class":41},[32,14630,14603],{"class":175},[32,14632,230],{"class":41},[32,14634,14635],{"class":34,"line":120},[32,14636,14637],{"class":41},"  })\n",[32,14639,14640,14642,14644,14646,14649],{"class":34,"line":127},[32,14641,14576],{"class":41},[32,14643,14626],{"class":217},[32,14645,477],{"class":41},[32,14647,14648],{"class":175},"\"resize\"",[32,14650,230],{"class":41},[15,14652,14653],{"id":14653},"捲軸判斷並加入一次性動畫",[22,14655,14657],{"className":24,"code":14656,"language":26,"meta":27,"style":27},"var item = $(this);\nvar windowTop = $(window).scrollTop() + $(window).height();\nvar pageTop = item.offset().top;\n\nif (windowTop >= pageTop) {\n  if (item.hasClass(\"no-gutters\")) {\n    item.addClass(\"animate__animated animate__bounceInRight\");\n  } else {\n    item.addClass(\"animate__animated animate__bounceInLeft\");\n  }\n}\n",[29,14658,14659,14676,14704,14722,14726,14738,14755,14770,14778,14791,14795],{"__ignoreMap":27},[32,14660,14661,14663,14666,14668,14670,14672,14674],{"class":34,"line":35},[32,14662,166],{"class":38},[32,14664,14665],{"class":41}," item ",[32,14667,172],{"class":38},[32,14669,6756],{"class":217},[32,14671,477],{"class":41},[32,14673,1083],{"class":351},[32,14675,230],{"class":41},[32,14677,14678,14680,14683,14685,14687,14689,14692,14694,14696,14698,14700,14702],{"class":34,"line":45},[32,14679,166],{"class":38},[32,14681,14682],{"class":41}," windowTop ",[32,14684,172],{"class":38},[32,14686,6756],{"class":217},[32,14688,6759],{"class":41},[32,14690,14691],{"class":217},"scrollTop",[32,14693,6075],{"class":41},[32,14695,224],{"class":38},[32,14697,6756],{"class":217},[32,14699,6759],{"class":41},[32,14701,6762],{"class":217},[32,14703,687],{"class":41},[32,14705,14706,14708,14711,14713,14716,14719],{"class":34,"line":51},[32,14707,166],{"class":38},[32,14709,14710],{"class":41}," pageTop ",[32,14712,172],{"class":38},[32,14714,14715],{"class":41}," item.",[32,14717,14718],{"class":217},"offset",[32,14720,14721],{"class":41},"().top;\n",[32,14723,14724],{"class":34,"line":90},[32,14725,103],{"emptyLinePlaceholder":102},[32,14727,14728,14730,14733,14735],{"class":34,"line":99},[32,14729,17],{"class":38},[32,14731,14732],{"class":41}," (windowTop ",[32,14734,348],{"class":38},[32,14736,14737],{"class":41}," pageTop) {\n",[32,14739,14740,14742,14745,14748,14750,14753],{"class":34,"line":106},[32,14741,1021],{"class":38},[32,14743,14744],{"class":41}," (item.",[32,14746,14747],{"class":217},"hasClass",[32,14749,477],{"class":41},[32,14751,14752],{"class":175},"\"no-gutters\"",[32,14754,1046],{"class":41},[32,14756,14757,14760,14763,14765,14768],{"class":34,"line":114},[32,14758,14759],{"class":41},"    item.",[32,14761,14762],{"class":217},"addClass",[32,14764,477],{"class":41},[32,14766,14767],{"class":175},"\"animate__animated animate__bounceInRight\"",[32,14769,230],{"class":41},[32,14771,14772,14774,14776],{"class":34,"line":120},[32,14773,5911],{"class":41},[32,14775,565],{"class":38},[32,14777,703],{"class":41},[32,14779,14780,14782,14784,14786,14789],{"class":34,"line":127},[32,14781,14759],{"class":41},[32,14783,14762],{"class":217},[32,14785,477],{"class":41},[32,14787,14788],{"class":175},"\"animate__animated animate__bounceInLeft\"",[32,14790,230],{"class":41},[32,14792,14793],{"class":34,"line":132},[32,14794,1203],{"class":41},[32,14796,14797],{"class":34,"line":141},[32,14798,54],{"class":41},[15,14800,14801],{"id":14801},"進入與離開時切換狀態",[22,14803,14805],{"className":24,"code":14804,"language":26,"meta":27,"style":27},"$(selector).each(function () {\n  var bottomOfObject = $(this).offset().top + $(this).outerHeight() \u002F 8;\n  var bottomOfWindow = $(window).scrollTop() + $(window).height();\n\n  bottomOfWindow > bottomOfObject\n    ? $(this).addClass(\"active\")\n    : $(this).removeClass(\"active\");\n});\n",[29,14806,14807,14822,14866,14893,14897,14907,14929,14951],{"__ignoreMap":27},[32,14808,14809,14811,14814,14816,14818,14820],{"class":34,"line":35},[32,14810,755],{"class":217},[32,14812,14813],{"class":41},"(selector).",[32,14815,1060],{"class":217},[32,14817,477],{"class":41},[32,14819,665],{"class":38},[32,14821,668],{"class":41},[32,14823,14824,14826,14829,14831,14833,14835,14837,14839,14841,14844,14846,14848,14850,14852,14854,14857,14859,14861,14864],{"class":34,"line":45},[32,14825,888],{"class":38},[32,14827,14828],{"class":41}," bottomOfObject ",[32,14830,172],{"class":38},[32,14832,6756],{"class":217},[32,14834,477],{"class":41},[32,14836,1083],{"class":351},[32,14838,533],{"class":41},[32,14840,14718],{"class":217},[32,14842,14843],{"class":41},"().top ",[32,14845,224],{"class":38},[32,14847,6756],{"class":217},[32,14849,477],{"class":41},[32,14851,1083],{"class":351},[32,14853,533],{"class":41},[32,14855,14856],{"class":217},"outerHeight",[32,14858,6075],{"class":41},[32,14860,1275],{"class":38},[32,14862,14863],{"class":351}," 8",[32,14865,96],{"class":41},[32,14867,14868,14870,14873,14875,14877,14879,14881,14883,14885,14887,14889,14891],{"class":34,"line":51},[32,14869,888],{"class":38},[32,14871,14872],{"class":41}," bottomOfWindow ",[32,14874,172],{"class":38},[32,14876,6756],{"class":217},[32,14878,6759],{"class":41},[32,14880,14691],{"class":217},[32,14882,6075],{"class":41},[32,14884,224],{"class":38},[32,14886,6756],{"class":217},[32,14888,6759],{"class":41},[32,14890,6762],{"class":217},[32,14892,687],{"class":41},[32,14894,14895],{"class":34,"line":90},[32,14896,103],{"emptyLinePlaceholder":102},[32,14898,14899,14902,14904],{"class":34,"line":99},[32,14900,14901],{"class":41},"  bottomOfWindow ",[32,14903,1615],{"class":38},[32,14905,14906],{"class":41}," bottomOfObject\n",[32,14908,14909,14912,14914,14916,14918,14920,14922,14924,14927],{"class":34,"line":106},[32,14910,14911],{"class":38},"    ?",[32,14913,6756],{"class":217},[32,14915,477],{"class":41},[32,14917,1083],{"class":351},[32,14919,533],{"class":41},[32,14921,14762],{"class":217},[32,14923,477],{"class":41},[32,14925,14926],{"class":175},"\"active\"",[32,14928,515],{"class":41},[32,14930,14931,14934,14936,14938,14940,14942,14945,14947,14949],{"class":34,"line":114},[32,14932,14933],{"class":38},"    :",[32,14935,6756],{"class":217},[32,14937,477],{"class":41},[32,14939,1083],{"class":351},[32,14941,533],{"class":41},[32,14943,14944],{"class":217},"removeClass",[32,14946,477],{"class":41},[32,14948,14926],{"class":175},[32,14950,230],{"class":41},[32,14952,14953],{"class":34,"line":120},[32,14954,792],{"class":41},[15,14956,2004],{"id":2003},[11,14958,14959,14960,14963],{},"這是當時以 jQuery 手動計算位置的寫法。現在遇到「元素進入可視範圍」的需求，通常會優先使用 ",[29,14961,14962],{},"IntersectionObserver","，不必在每次捲動時重算所有元素的位置。",[368,14965,14966],{},"html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":14968},[14969,14970,14971,14972],{"id":14558,"depth":45,"text":14559},{"id":14653,"depth":45,"text":14653},{"id":14801,"depth":45,"text":14801},{"id":2003,"depth":45,"text":2004},"記錄用 jQuery 監聽 resize 與 scroll，再依元素位置加入動畫 class 的寫法。",{},"\u002Fposts\u002Fjquery-scroll-animation","2020-03-29",[],{"title":14550,"description":14973},"posts\u002F20200329.jquery-scroll-animation",[2040,390,14981],"捲動動畫","SgwH9egrcyK0AYuZztTnRlCg1PQgmxmQtRol6VoCdfM",{"id":14984,"title":14985,"body":14986,"category":378,"description":15038,"draft":380,"extension":381,"image":382,"meta":15039,"navigation":102,"path":15040,"publishedAt":15041,"relatedExperiments":15042,"seo":15043,"stem":15044,"tags":15045,"updatedAt":14272,"__hash__":15046},"posts\u002Fposts\u002F20200408.node-sass-sass-loader.md","安裝 node-sass 與 sass-loader",{"type":8,"value":14987,"toc":15035},[14988,14998,15017,15019,15032],[11,14989,14990,14991,7090,14994,14997],{},"記錄安裝 ",[29,14992,14993],{},"node-sass",[29,14995,14996],{},"sass-loader"," 的指令：",[22,14999,15001],{"className":2057,"code":15000,"language":2059,"meta":27,"style":27},"npm install --save-dev node-sass sass-loader\n",[29,15002,15003],{"__ignoreMap":27},[32,15004,15005,15007,15009,15012,15014],{"class":34,"line":35},[32,15006,4625],{"class":2066},[32,15008,4650],{"class":175},[32,15010,15011],{"class":351}," --save-dev",[32,15013,8632],{"class":175},[32,15015,15016],{"class":175}," sass-loader\n",[15,15018,2004],{"id":2003},[11,15020,15021,15022,15024,15025,15028,15029,15031],{},"這是舊版 webpack 專案的安裝方式。",[29,15023,14993],{}," 已停止維護，現在應改用 Dart Sass 的 ",[29,15026,15027],{},"sass"," 套件；",[29,15030,14996],{}," 的版本也要配合 webpack 與專案環境選擇。",[368,15033,15034],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":15036},[15037],{"id":2003,"depth":45,"text":2004},"記錄 2020 年在 webpack 專案安裝 node-sass 與 sass-loader 的指令。",{},"\u002Fposts\u002Fnode-sass-sass-loader","2020-04-08",[],{"title":14985,"description":15038},"posts\u002F20200408.node-sass-sass-loader",[4847,8410],"RhcGkZNSYiEhScMx4U2B0pHa_i0OdaHgSSfmoz0PYBc",{"id":15048,"title":15049,"body":15050,"category":378,"description":15187,"draft":380,"extension":381,"image":382,"meta":15188,"navigation":102,"path":15189,"publishedAt":15190,"relatedExperiments":15191,"seo":15192,"stem":15193,"tags":15194,"updatedAt":14272,"__hash__":15196},"posts\u002Fposts\u002F20200410.nuxt-layout-usage.md","Nuxt Layout 使用方式（Nuxt 2）",{"type":8,"value":15051,"toc":15184},[15052,15055,15069,15121,15124,15169,15171,15181],[11,15053,15054],{},"這邊記錄 Nuxt 2 Layout 的使用方式。",[11,15056,15057,15058,15061,15062,15064,15065,15068],{},"先在 ",[29,15059,15060],{},"layouts"," 資料夾新增一個 ",[29,15063,5141],{}," 檔案，版面結構可以參照 ",[29,15066,15067],{},"default.vue","，再自行增加需要的節點：",[22,15070,15072],{"className":8665,"code":15071,"language":4112,"meta":27,"style":27},"\u003C!-- layouts\u002Fanimation.vue -->\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cnuxt \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,15073,15074,15079,15087,15095,15105,15113],{"__ignoreMap":27},[32,15075,15076],{"class":34,"line":35},[32,15077,15078],{"class":608},"\u003C!-- layouts\u002Fanimation.vue -->\n",[32,15080,15081,15083,15085],{"class":34,"line":45},[32,15082,4046],{"class":41},[32,15084,9623],{"class":4049},[32,15086,4062],{"class":41},[32,15088,15089,15091,15093],{"class":34,"line":51},[32,15090,4067],{"class":41},[32,15092,4050],{"class":4049},[32,15094,4062],{"class":41},[32,15096,15097,15099,15102],{"class":34,"line":90},[32,15098,9638],{"class":41},[32,15100,15101],{"class":4049},"nuxt",[32,15103,15104],{"class":41}," \u002F>\n",[32,15106,15107,15109,15111],{"class":34,"line":99},[32,15108,9691],{"class":41},[32,15110,4050],{"class":4049},[32,15112,4062],{"class":41},[32,15114,15115,15117,15119],{"class":34,"line":106},[32,15116,4105],{"class":41},[32,15118,9623],{"class":4049},[32,15120,4062],{"class":41},[11,15122,15123],{},"使用時，在 page 設定 layout 的名稱，就可以沿用剛建立的版面：",[22,15125,15127],{"className":8665,"code":15126,"language":4112,"meta":27,"style":27},"\u003Cscript>\nexport default {\n  layout: \"animation\",\n};\n\u003C\u002Fscript>\n",[29,15128,15129,15137,15145,15155,15161],{"__ignoreMap":27},[32,15130,15131,15133,15135],{"class":34,"line":35},[32,15132,4046],{"class":41},[32,15134,4125],{"class":4049},[32,15136,4062],{"class":41},[32,15138,15139,15141,15143],{"class":34,"line":45},[32,15140,5038],{"class":38},[32,15142,5041],{"class":38},[32,15144,703],{"class":5049},[32,15146,15147,15150,15153],{"class":34,"line":51},[32,15148,15149],{"class":41},"  layout: ",[32,15151,15152],{"class":175},"\"animation\"",[32,15154,547],{"class":5049},[32,15156,15157,15159],{"class":34,"line":90},[32,15158,9765],{"class":5049},[32,15160,96],{"class":41},[32,15162,15163,15165,15167],{"class":34,"line":99},[32,15164,4105],{"class":41},[32,15166,4125],{"class":4049},[32,15168,4062],{"class":41},[15,15170,2004],{"id":2003},[11,15172,15173,15174,15177,15178,3775],{},"這是 Nuxt 2 的寫法。Nuxt 3 之後改用 ",[29,15175,15176],{},"definePageMeta({ layout: \"animation\" })"," 指定版面，layout 裡承載頁面內容的元件也改為 ",[29,15179,15180],{},"\u003CNuxtPage \u002F>",[368,15182,15183],{},"html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}",{"title":27,"searchDepth":51,"depth":51,"links":15185},[15186],{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 layouts 資料夾新增版面，並由頁面指定 layout 名稱的方式。",{},"\u002Fposts\u002Fnuxt-layout-usage","2020-04-10",[],{"title":15049,"description":15187},"posts\u002F20200410.nuxt-layout-usage",[15195,4113],"Nuxt","u8aeEbxhr2ovGilbohetIjqn_ERFRvbtXlPZFwUCv4c",{"id":15198,"title":15199,"body":15200,"category":378,"description":15387,"draft":380,"extension":381,"image":382,"meta":15388,"navigation":102,"path":15389,"publishedAt":15390,"relatedExperiments":15391,"seo":15392,"stem":15393,"tags":15394,"updatedAt":14272,"__hash__":15396},"posts\u002Fposts\u002F20200413.js-sort-filter-arrow.md","JavaScript sort 與 filter 搭配箭頭函式的範例",{"type":8,"value":15201,"toc":15384},[15202,15354,15362,15364,15381],[22,15203,15205],{"className":24,"code":15204,"language":26,"meta":27,"style":27},"var shopData = [\n  { name: \"美商博帝 120G SSD\", price: 638 },\n  { name: \"SanDisk 120G SSD\", price: 599 },\n  { name: \"美光 MX500 250G SSD\", price: 1499 },\n];\n\n\u002F\u002F 使用 sort 依價格排序\nvar result = shopData.sort((a, b) => a.price - b.price);\n\n\u002F\u002F 過濾出價格低於 600 的商品\nvar result2 = shopData.filter((shop) => shop.price \u003C 600);\n",[29,15206,15207,15219,15236,15250,15264,15268,15272,15277,15312,15316,15321],{"__ignoreMap":27},[32,15208,15209,15211,15214,15216],{"class":34,"line":35},[32,15210,166],{"class":38},[32,15212,15213],{"class":41}," shopData ",[32,15215,172],{"class":38},[32,15217,15218],{"class":41}," [\n",[32,15220,15221,15224,15227,15230,15233],{"class":34,"line":45},[32,15222,15223],{"class":41},"  { name: ",[32,15225,15226],{"class":175},"\"美商博帝 120G SSD\"",[32,15228,15229],{"class":41},", price: ",[32,15231,15232],{"class":351},"638",[32,15234,15235],{"class":41}," },\n",[32,15237,15238,15240,15243,15245,15248],{"class":34,"line":51},[32,15239,15223],{"class":41},[32,15241,15242],{"class":175},"\"SanDisk 120G SSD\"",[32,15244,15229],{"class":41},[32,15246,15247],{"class":351},"599",[32,15249,15235],{"class":41},[32,15251,15252,15254,15257,15259,15262],{"class":34,"line":90},[32,15253,15223],{"class":41},[32,15255,15256],{"class":175},"\"美光 MX500 250G SSD\"",[32,15258,15229],{"class":41},[32,15260,15261],{"class":351},"1499",[32,15263,15235],{"class":41},[32,15265,15266],{"class":34,"line":99},[32,15267,8282],{"class":41},[32,15269,15270],{"class":34,"line":106},[32,15271,103],{"emptyLinePlaceholder":102},[32,15273,15274],{"class":34,"line":114},[32,15275,15276],{"class":608},"\u002F\u002F 使用 sort 依價格排序\n",[32,15278,15279,15281,15283,15285,15288,15291,15293,15295,15297,15300,15302,15304,15307,15309],{"class":34,"line":120},[32,15280,166],{"class":38},[32,15282,340],{"class":41},[32,15284,172],{"class":38},[32,15286,15287],{"class":41}," shopData.",[32,15289,15290],{"class":217},"sort",[32,15292,8293],{"class":41},[32,15294,412],{"class":903},[32,15296,635],{"class":41},[32,15298,15299],{"class":903},"b",[32,15301,483],{"class":41},[32,15303,5090],{"class":38},[32,15305,15306],{"class":41}," a.price ",[32,15308,6628],{"class":38},[32,15310,15311],{"class":41}," b.price);\n",[32,15313,15314],{"class":34,"line":127},[32,15315,103],{"emptyLinePlaceholder":102},[32,15317,15318],{"class":34,"line":132},[32,15319,15320],{"class":608},"\u002F\u002F 過濾出價格低於 600 的商品\n",[32,15322,15323,15325,15328,15330,15332,15335,15337,15340,15342,15344,15347,15349,15352],{"class":34,"line":141},[32,15324,166],{"class":38},[32,15326,15327],{"class":41}," result2 ",[32,15329,172],{"class":38},[32,15331,15287],{"class":41},[32,15333,15334],{"class":217},"filter",[32,15336,8293],{"class":41},[32,15338,15339],{"class":903},"shop",[32,15341,483],{"class":41},[32,15343,5090],{"class":38},[32,15345,15346],{"class":41}," shop.price ",[32,15348,4046],{"class":38},[32,15350,15351],{"class":351}," 600",[32,15353,230],{"class":41},[11,15355,15356,15357],{},"參考資料：",[412,15358,15361],{"href":15359,"rel":15360},"http:\u002F\u002Fwww.eion.com.tw\u002FBlogger\u002F?Pid=1170",[416],"JavaScript 陣列 sort 與 filter",[15,15363,2004],{"id":2003},[11,15365,15366,15369,15370,15373,15374,15377,15378,3775],{},[29,15367,15368],{},"sort()"," 會直接改動原陣列，",[29,15371,15372],{},"filter()"," 則會回傳新陣列。若要保留 ",[29,15375,15376],{},"shopData"," 原本的順序，應先複製再排序，或在支援的環境使用 ",[29,15379,15380],{},"toSorted()",[368,15382,15383],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}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);}",{"title":27,"searchDepth":51,"depth":51,"links":15385},[15386],{"id":2003,"depth":45,"text":2004},"用商品清單記錄 sort 排序與 filter 篩選的箭頭函式寫法。",{},"\u002Fposts\u002Fjs-sort-filter-arrow","2020-04-13",[],{"title":15199,"description":15387},"posts\u002F20200413.js-sort-filter-arrow",[390,15395],"陣列方法","KlMJihJy4_nL2HbxAW6Jn_kYFCEjjUBqe9YCdhiL3tI",{"id":15398,"title":15399,"body":15400,"category":378,"description":16947,"draft":380,"extension":381,"image":382,"meta":16948,"navigation":102,"path":16949,"publishedAt":16950,"relatedExperiments":16951,"seo":16952,"stem":16953,"tags":16954,"updatedAt":16956,"__hash__":16957},"posts\u002Fposts\u002F20200419.js-prototype-inheritance.md","JavaScript 物件導向：建構函式、prototype 與繼承三步驟",{"type":8,"value":15401,"toc":16929},[15402,15405,15408,15422,15425,15429,15492,15495,15709,15718,15752,15756,15776,15780,15852,15878,15882,15885,15891,15897,15900,15904,16023,16053,16057,16106,16137,16158,16162,16183,16211,16215,16548,16566,16570,16573,16577,16580,16667,16671,16674,16782,16786,16792,16875,16878,16891,16908,16910,16926],[11,15403,15404],{},"物件導向的核心想法很單純：把情境裡的東西包裝成物件。步驟大致是：把情境描述成物件、定義這些物件的屬性跟行為、讓物件之間互動。",[11,15406,15407],{},"用「人」跟「香蕉」這兩個物件當例子：",[4538,15409,15410,15416],{},[4541,15411,15412,15415],{},[12249,15413,15414],{},"人","：屬性是名字、年齡、有的物品；行為是打招呼、走路、接收物品",[4541,15417,15418,15421],{},[12249,15419,15420],{},"香蕉","：屬性是名字、價格、味道；行為是剝皮、攻擊別人（比喻用，實際不會真的攻擊）",[11,15423,15424],{},"這篇整理 ES5 時代用建構函式手刻這套邏輯的完整流程。",[15,15426,15428],{"id":15427},"封裝把屬性跟方法包進一個建構函式","封裝：把屬性跟方法包進一個建構函式",[22,15430,15432],{"className":24,"code":15431,"language":26,"meta":27,"style":27},"var Ticket = function (初始值) {\n  this.屬性 = 初始值;\n  this.方法 = function () {\n    \u002F\u002F 這裡面可以用 this.屬性 跟 this.方法\n  };\n};\n",[29,15433,15434,15452,15464,15479,15484,15488],{"__ignoreMap":27},[32,15435,15436,15438,15441,15443,15445,15447,15450],{"class":34,"line":35},[32,15437,166],{"class":38},[32,15439,15440],{"class":217}," Ticket",[32,15442,894],{"class":38},[32,15444,897],{"class":38},[32,15446,900],{"class":41},[32,15448,15449],{"class":903},"初始值",[32,15451,520],{"class":41},[32,15453,15454,15456,15459,15461],{"class":34,"line":45},[32,15455,8938],{"class":351},[32,15457,15458],{"class":41},".屬性 ",[32,15460,172],{"class":38},[32,15462,15463],{"class":41}," 初始值;\n",[32,15465,15466,15468,15470,15473,15475,15477],{"class":34,"line":51},[32,15467,8938],{"class":351},[32,15469,1278],{"class":41},[32,15471,15472],{"class":217},"方法",[32,15474,894],{"class":38},[32,15476,897],{"class":38},[32,15478,668],{"class":41},[32,15480,15481],{"class":34,"line":90},[32,15482,15483],{"class":608},"    \u002F\u002F 這裡面可以用 this.屬性 跟 this.方法\n",[32,15485,15486],{"class":34,"line":99},[32,15487,1007],{"class":41},[32,15489,15490],{"class":34,"line":106},[32,15491,7189],{"class":41},[11,15493,15494],{},"用一個實際例子——一張票券，有價格、折扣、固定手續費，還有算總價跟印出描述的方法：",[22,15496,15498],{"className":24,"code":15497,"language":26,"meta":27,"style":27},"var Ticket = function (init_price, init_discount) {\n  \u002F\u002F 初始化\n  this.price = init_price;\n  this.type = 'student';\n  this.discount = init_discount;\n  this.fee = 30;\n\n  this.get_price = function () {\n    \u002F\u002F this 參照物件本體的資訊\n    return this.price * this.discount + this.fee;\n  };\n\n  this.get_description = function () {\n    console.log('這張票是' + this.type + '票，有' + this.discount * 10 + '折扣，共' + this.get_price() + '元');\n  };\n};\n",[29,15499,15500,15522,15527,15539,15553,15565,15579,15583,15598,15603,15624,15628,15632,15647,15701,15705],{"__ignoreMap":27},[32,15501,15502,15504,15506,15508,15510,15512,15515,15517,15520],{"class":34,"line":35},[32,15503,166],{"class":38},[32,15505,15440],{"class":217},[32,15507,894],{"class":38},[32,15509,897],{"class":38},[32,15511,900],{"class":41},[32,15513,15514],{"class":903},"init_price",[32,15516,635],{"class":41},[32,15518,15519],{"class":903},"init_discount",[32,15521,520],{"class":41},[32,15523,15524],{"class":34,"line":45},[32,15525,15526],{"class":608},"  \u002F\u002F 初始化\n",[32,15528,15529,15531,15534,15536],{"class":34,"line":51},[32,15530,8938],{"class":351},[32,15532,15533],{"class":41},".price ",[32,15535,172],{"class":38},[32,15537,15538],{"class":41}," init_price;\n",[32,15540,15541,15543,15546,15548,15551],{"class":34,"line":90},[32,15542,8938],{"class":351},[32,15544,15545],{"class":41},".type ",[32,15547,172],{"class":38},[32,15549,15550],{"class":175}," 'student'",[32,15552,96],{"class":41},[32,15554,15555,15557,15560,15562],{"class":34,"line":99},[32,15556,8938],{"class":351},[32,15558,15559],{"class":41},".discount ",[32,15561,172],{"class":38},[32,15563,15564],{"class":41}," init_discount;\n",[32,15566,15567,15569,15572,15574,15577],{"class":34,"line":106},[32,15568,8938],{"class":351},[32,15570,15571],{"class":41},".fee ",[32,15573,172],{"class":38},[32,15575,15576],{"class":351}," 30",[32,15578,96],{"class":41},[32,15580,15581],{"class":34,"line":114},[32,15582,103],{"emptyLinePlaceholder":102},[32,15584,15585,15587,15589,15592,15594,15596],{"class":34,"line":120},[32,15586,8938],{"class":351},[32,15588,1278],{"class":41},[32,15590,15591],{"class":217},"get_price",[32,15593,894],{"class":38},[32,15595,897],{"class":38},[32,15597,668],{"class":41},[32,15599,15600],{"class":34,"line":127},[32,15601,15602],{"class":608},"    \u002F\u002F this 參照物件本體的資訊\n",[32,15604,15605,15607,15609,15611,15613,15615,15617,15619,15621],{"class":34,"line":132},[32,15606,971],{"class":38},[32,15608,4234],{"class":351},[32,15610,15533],{"class":41},[32,15612,6078],{"class":38},[32,15614,4234],{"class":351},[32,15616,15559],{"class":41},[32,15618,224],{"class":38},[32,15620,4234],{"class":351},[32,15622,15623],{"class":41},".fee;\n",[32,15625,15626],{"class":34,"line":141},[32,15627,1007],{"class":41},[32,15629,15630],{"class":34,"line":147},[32,15631,103],{"emptyLinePlaceholder":102},[32,15633,15634,15636,15638,15641,15643,15645],{"class":34,"line":275},[32,15635,8938],{"class":351},[32,15637,1278],{"class":41},[32,15639,15640],{"class":217},"get_description",[32,15642,894],{"class":38},[32,15644,897],{"class":38},[32,15646,668],{"class":41},[32,15648,15649,15651,15653,15655,15658,15660,15662,15664,15666,15669,15671,15673,15675,15677,15679,15681,15684,15686,15688,15690,15692,15694,15696,15699],{"class":34,"line":282},[32,15650,8966],{"class":41},[32,15652,5197],{"class":217},[32,15654,477],{"class":41},[32,15656,15657],{"class":175},"'這張票是'",[32,15659,1799],{"class":38},[32,15661,4234],{"class":351},[32,15663,15545],{"class":41},[32,15665,224],{"class":38},[32,15667,15668],{"class":175}," '票，有'",[32,15670,1799],{"class":38},[32,15672,4234],{"class":351},[32,15674,15559],{"class":41},[32,15676,6078],{"class":38},[32,15678,4472],{"class":351},[32,15680,1799],{"class":38},[32,15682,15683],{"class":175}," '折扣，共'",[32,15685,1799],{"class":38},[32,15687,4234],{"class":351},[32,15689,1278],{"class":41},[32,15691,15591],{"class":217},[32,15693,6075],{"class":41},[32,15695,224],{"class":38},[32,15697,15698],{"class":175}," '元'",[32,15700,230],{"class":41},[32,15702,15703],{"class":34,"line":295},[32,15704,1007],{"class":41},[32,15706,15707],{"class":34,"line":605},[32,15708,7189],{"class":41},[11,15710,15711,15714,15715,15717],{},[12249,15712,15713],{},"建立實體物件","時用 ",[29,15716,9196],{},"，傳進去的參數對應建構函式裡的初始值：",[22,15719,15721],{"className":24,"code":15720,"language":26,"meta":27,"style":27},"var myticket = new Ticket(500, 0.5); \u002F\u002F 產生時，傳進物件價格跟折扣\n",[29,15722,15723],{"__ignoreMap":27},[32,15724,15725,15727,15730,15732,15734,15736,15738,15741,15743,15746,15749],{"class":34,"line":35},[32,15726,166],{"class":38},[32,15728,15729],{"class":41}," myticket ",[32,15731,172],{"class":38},[32,15733,4165],{"class":38},[32,15735,15440],{"class":217},[32,15737,477],{"class":41},[32,15739,15740],{"class":351},"500",[32,15742,635],{"class":41},[32,15744,15745],{"class":351},"0.5",[32,15747,15748],{"class":41},"); ",[32,15750,15751],{"class":608},"\u002F\u002F 產生時，傳進物件價格跟折扣\n",[15,15753,15755],{"id":15754},"這樣寫的問題每個實體都各自複製一份方法","這樣寫的問題：每個實體都各自複製一份方法",[11,15757,15758,15759,3750,15761,15763,15764,15767,15768,15771,15772,15775],{},"上面的寫法裡，",[29,15760,15591],{},[29,15762,15640],{}," 這兩個方法是寫在建構函式",[12249,15765,15766],{},"內部","的，代表每次 ",[29,15769,15770],{},"new Ticket(...)","，這兩個方法都會被",[12249,15773,15774],{},"重新建立一次、各自佔一份記憶體","——就算兩張票券的邏輯完全一樣，也是兩份獨立的函式物件。",[15,15777,15779],{"id":15778},"共用函式掛在-prototype-上","共用函式：掛在 prototype 上",[22,15781,15783],{"className":24,"code":15782,"language":26,"meta":27,"style":27},"var Ticket = function (初始值) {\n  this.屬性 = 初始值;\n};\n\n\u002F\u002F 共用函數\nTicket.prototype.方法 = function () {\n  \u002F\u002F 其中可使用 this.屬性 跟 this.方法\n};\n",[29,15784,15785,15801,15811,15815,15819,15824,15843,15848],{"__ignoreMap":27},[32,15786,15787,15789,15791,15793,15795,15797,15799],{"class":34,"line":35},[32,15788,166],{"class":38},[32,15790,15440],{"class":217},[32,15792,894],{"class":38},[32,15794,897],{"class":38},[32,15796,900],{"class":41},[32,15798,15449],{"class":903},[32,15800,520],{"class":41},[32,15802,15803,15805,15807,15809],{"class":34,"line":45},[32,15804,8938],{"class":351},[32,15806,15458],{"class":41},[32,15808,172],{"class":38},[32,15810,15463],{"class":41},[32,15812,15813],{"class":34,"line":51},[32,15814,7189],{"class":41},[32,15816,15817],{"class":34,"line":90},[32,15818,103],{"emptyLinePlaceholder":102},[32,15820,15821],{"class":34,"line":99},[32,15822,15823],{"class":608},"\u002F\u002F 共用函數\n",[32,15825,15826,15829,15831,15833,15835,15837,15839,15841],{"class":34,"line":106},[32,15827,15828],{"class":351},"Ticket",[32,15830,1278],{"class":41},[32,15832,1585],{"class":351},[32,15834,1278],{"class":41},[32,15836,15472],{"class":217},[32,15838,894],{"class":38},[32,15840,897],{"class":38},[32,15842,668],{"class":41},[32,15844,15845],{"class":34,"line":114},[32,15846,15847],{"class":608},"  \u002F\u002F 其中可使用 this.屬性 跟 this.方法\n",[32,15849,15850],{"class":34,"line":120},[32,15851,7189],{"class":41},[11,15853,15854,15855,15857,15858,15861,15862,15864,15865,15867,15868,15870,15871,15873,15874,15877],{},"放在 ",[29,15856,1585],{}," 裡的東西",[12249,15859,15860],{},"不會被複製進每一個物件","，物件本身只會有一個參考連到 ",[29,15863,1585],{},"；存取屬性或方法時，先在物件自己身上找，找不到才會往上到 ",[29,15866,1585],{}," 找。這代表不管 ",[29,15869,9196],{}," 出幾個實體，",[29,15872,1585],{}," 上的方法永遠只有",[12249,15875,15876],{},"一份","，多個實體共用同一份參考。",[15,15879,15881],{"id":15880},"繼承類別之間的延續","繼承：類別之間的延續",[11,15883,15884],{},"先定義一個比較上層、比較抽象的類別「生物」，再讓「狗」繼承它：",[22,15886,15889],{"className":15887,"code":15888,"language":426,"meta":27},[424],"生物 (Creature)：名字、生命長度、移動、吃東西\n狗 (Dog)：品種、喜歡吃的東西、吠叫、攻擊\n",[29,15890,15888],{"__ignoreMap":27},[11,15892,15893,15894,3775],{},"「狗」除了自己的專屬屬性（品種、吠叫），也應該擁有「生物」共通的那些（名字、吃東西）——這就是繼承要解決的問題：",[12249,15895,15896],{},"避免每個子類別都要重新定義一次共通的部分",[11,15898,15899],{},"繼承的完整步驟分三步：",[151,15901,15903],{"id":15902},"步驟一建立時呼叫母類別的建構子","步驟一：建立時呼叫母類別的建構子",[22,15905,15907],{"className":24,"code":15906,"language":26,"meta":27,"style":27},"var Creature = function (name, lifespan) {\n  this.name = name;\n  this.lifespan = lifespan;\n};\n\nvar Dog = function (name, lifespan, breed) {\n  Creature.call(this, name, lifespan); \u002F\u002F 呼叫母類別，針對母類別進行初始化\n  this.breed = breed;\n};\n",[29,15908,15909,15932,15944,15956,15960,15964,15990,16007,16019],{"__ignoreMap":27},[32,15910,15911,15913,15916,15918,15920,15922,15925,15927,15930],{"class":34,"line":35},[32,15912,166],{"class":38},[32,15914,15915],{"class":217}," Creature",[32,15917,894],{"class":38},[32,15919,897],{"class":38},[32,15921,900],{"class":41},[32,15923,15924],{"class":903},"name",[32,15926,635],{"class":41},[32,15928,15929],{"class":903},"lifespan",[32,15931,520],{"class":41},[32,15933,15934,15936,15939,15941],{"class":34,"line":45},[32,15935,8938],{"class":351},[32,15937,15938],{"class":41},".name ",[32,15940,172],{"class":38},[32,15942,15943],{"class":41}," name;\n",[32,15945,15946,15948,15951,15953],{"class":34,"line":51},[32,15947,8938],{"class":351},[32,15949,15950],{"class":41},".lifespan ",[32,15952,172],{"class":38},[32,15954,15955],{"class":41}," lifespan;\n",[32,15957,15958],{"class":34,"line":90},[32,15959,7189],{"class":41},[32,15961,15962],{"class":34,"line":99},[32,15963,103],{"emptyLinePlaceholder":102},[32,15965,15966,15968,15971,15973,15975,15977,15979,15981,15983,15985,15988],{"class":34,"line":106},[32,15967,166],{"class":38},[32,15969,15970],{"class":217}," Dog",[32,15972,894],{"class":38},[32,15974,897],{"class":38},[32,15976,900],{"class":41},[32,15978,15924],{"class":903},[32,15980,635],{"class":41},[32,15982,15929],{"class":903},[32,15984,635],{"class":41},[32,15986,15987],{"class":903},"breed",[32,15989,520],{"class":41},[32,15991,15992,15995,15997,15999,16001,16004],{"class":34,"line":114},[32,15993,15994],{"class":41},"  Creature.",[32,15996,1596],{"class":217},[32,15998,477],{"class":41},[32,16000,1083],{"class":351},[32,16002,16003],{"class":41},", name, lifespan); ",[32,16005,16006],{"class":608},"\u002F\u002F 呼叫母類別，針對母類別進行初始化\n",[32,16008,16009,16011,16014,16016],{"class":34,"line":120},[32,16010,8938],{"class":351},[32,16012,16013],{"class":41},".breed ",[32,16015,172],{"class":38},[32,16017,16018],{"class":41}," breed;\n",[32,16020,16021],{"class":34,"line":127},[32,16022,7189],{"class":41},[11,16024,16025,16028,16029,16032,16033,16035,16036,16039,16040,16043,16044,16046,16047,16049,16050,16052],{},[29,16026,16027],{},"Creature.call(this, name, lifespan)"," 的意思是「借用 ",[29,16030,16031],{},"Creature"," 這個建構函式，但讓它的 ",[29,16034,1083],{}," 指向現在正在建立的 ",[29,16037,16038],{},"Dog"," 實體」——這一步只處理",[12249,16041,16042],{},"屬性","的繼承，",[29,16045,16031],{}," 建構子裡對 ",[29,16048,1083],{}," 做的初始化，會套用在正在建立的這個 ",[29,16051,16038],{}," 物件上。",[151,16054,16056],{"id":16055},"步驟二讓子類別的-prototype-接上母類別的-prototype","步驟二：讓子類別的 prototype 接上母類別的 prototype",[22,16058,16060],{"className":24,"code":16059,"language":26,"meta":27,"style":27},"Dog.prototype = Object.create(Creature.prototype);\nDog.prototype.constructor = Dog;\n",[29,16061,16062,16088],{"__ignoreMap":27},[32,16063,16064,16066,16068,16070,16072,16075,16078,16080,16082,16084,16086],{"class":34,"line":35},[32,16065,16038],{"class":351},[32,16067,1278],{"class":41},[32,16069,1585],{"class":351},[32,16071,894],{"class":38},[32,16073,16074],{"class":41}," Object.",[32,16076,16077],{"class":217},"create",[32,16079,477],{"class":41},[32,16081,16031],{"class":351},[32,16083,1278],{"class":41},[32,16085,1585],{"class":351},[32,16087,230],{"class":41},[32,16089,16090,16092,16094,16096,16098,16101,16103],{"class":34,"line":45},[32,16091,16038],{"class":351},[32,16093,1278],{"class":41},[32,16095,1585],{"class":351},[32,16097,1278],{"class":41},[32,16099,16100],{"class":351},"constructor",[32,16102,894],{"class":38},[32,16104,16105],{"class":41}," Dog;\n",[11,16107,16108,16111,16112,16115,16116,16119,16120,16123,16124,16126,16127,16129,16130,16133,16134,16136],{},[29,16109,16110],{},"Object.create(Creature.prototype)"," 建立一個",[12249,16113,16114],{},"空的中繼物件","，這個物件的原型鏈往上連到 ",[29,16117,16118],{},"Creature.prototype","，再把它指派給 ",[29,16121,16122],{},"Dog.prototype","。這一步做完之後，",[29,16125,16038],{}," 的實體如果在自己身上跟 ",[29,16128,16122],{}," 都找不到某個方法，會",[12249,16131,16132],{},"再往上一層","去 ",[29,16135,16118],{}," 找。",[11,16138,16139,16142,16143,16146,16147,16149,16150,16153,16154,16157],{},[12249,16140,16141],{},"只做步驟一不夠","：步驟一只繼承了「屬性」（建構子裡 ",[29,16144,16145],{},"this.xxx = xxx"," 那些），母類別掛在 ",[29,16148,1585],{}," 上的",[12249,16151,16152],{},"共用方法","沒有被繼承到，因為步驟一的 ",[29,16155,16156],{},"call()"," 只是借用建構函式執行了一次，不會動到原型鏈的連結，這正是需要步驟二的原因。",[151,16159,16161],{"id":16160},"步驟三把建構函式指回自己","步驟三：把建構函式指回自己",[22,16163,16165],{"className":24,"code":16164,"language":26,"meta":27,"style":27},"Dog.prototype.constructor = Dog;\n",[29,16166,16167],{"__ignoreMap":27},[32,16168,16169,16171,16173,16175,16177,16179,16181],{"class":34,"line":35},[32,16170,16038],{"class":351},[32,16172,1278],{"class":41},[32,16174,1585],{"class":351},[32,16176,1278],{"class":41},[32,16178,16100],{"class":351},[32,16180,894],{"class":38},[32,16182,16105],{"class":41},[11,16184,16185,16186,16189,16190,16192,16193,16195,16196,16198,16199,16201,16202,16205,16206,16208,16209,3775],{},"步驟二用 ",[29,16187,16188],{},"Object.create()"," 整個換掉了 ",[29,16191,16122],{},"，這個新物件的 ",[29,16194,16100],{}," 屬性預設會指向 ",[29,16197,16031],{},"（因為它是從 ",[29,16200,16118],{}," 複製結構過來的），不修正的話，",[29,16203,16204],{},"someDogInstance.constructor"," 會誤指到 ",[29,16207,16031],{},"，這一步負責把它導正回 ",[29,16210,16038],{},[15,16212,16214],{"id":16213},"完整範例人的繼承","完整範例：人的繼承",[22,16216,16218],{"className":24,"code":16217,"language":26,"meta":27,"style":27},"\u002F\u002F 母類別\nvar Person = function (name, age) {\n  this.name = name;\n  this.age = age;\n};\n\nPerson.prototype.sayHello = function () {\n  console.log('hello i am ' + this.name);\n};\n\n\u002F\u002F 子類別：Worker 繼承 Person\nvar Worker = function (name, age, job) {\n  Person.call(this, name, age); \u002F\u002F 步驟一：呼叫母類別初始化\n  this.job = job; \u002F\u002F 設定自己的額外屬性\n};\n\nWorker.prototype = Object.create(Person.prototype); \u002F\u002F 步驟二：接上原型鏈\nWorker.prototype.constructor = Worker; \u002F\u002F 步驟三：建構函式指回自己\n\nWorker.prototype.tellJob = function () {\n  \u002F\u002F Worker 自己的共用方法\n  console.log('I am a ' + this.job);\n};\n\nvar henry = new Worker('Henry', 30, 'Teacher');\nhenry.sayHello(); \u002F\u002F hello i am Henry ← 繼承自 Person.prototype\nhenry.tellJob(); \u002F\u002F I am a Teacher   ← Worker 自己的方法\n",[29,16219,16220,16225,16247,16257,16269,16273,16277,16297,16314,16318,16322,16327,16353,16370,16385,16389,16393,16421,16441,16445,16464,16469,16487,16491,16495,16525,16537],{"__ignoreMap":27},[32,16221,16222],{"class":34,"line":35},[32,16223,16224],{"class":608},"\u002F\u002F 母類別\n",[32,16226,16227,16229,16232,16234,16236,16238,16240,16242,16245],{"class":34,"line":45},[32,16228,166],{"class":38},[32,16230,16231],{"class":217}," Person",[32,16233,894],{"class":38},[32,16235,897],{"class":38},[32,16237,900],{"class":41},[32,16239,15924],{"class":903},[32,16241,635],{"class":41},[32,16243,16244],{"class":903},"age",[32,16246,520],{"class":41},[32,16248,16249,16251,16253,16255],{"class":34,"line":51},[32,16250,8938],{"class":351},[32,16252,15938],{"class":41},[32,16254,172],{"class":38},[32,16256,15943],{"class":41},[32,16258,16259,16261,16264,16266],{"class":34,"line":90},[32,16260,8938],{"class":351},[32,16262,16263],{"class":41},".age ",[32,16265,172],{"class":38},[32,16267,16268],{"class":41}," age;\n",[32,16270,16271],{"class":34,"line":99},[32,16272,7189],{"class":41},[32,16274,16275],{"class":34,"line":106},[32,16276,103],{"emptyLinePlaceholder":102},[32,16278,16279,16282,16284,16286,16288,16291,16293,16295],{"class":34,"line":114},[32,16280,16281],{"class":351},"Person",[32,16283,1278],{"class":41},[32,16285,1585],{"class":351},[32,16287,1278],{"class":41},[32,16289,16290],{"class":217},"sayHello",[32,16292,894],{"class":38},[32,16294,897],{"class":38},[32,16296,668],{"class":41},[32,16298,16299,16301,16303,16305,16308,16310,16312],{"class":34,"line":120},[32,16300,5194],{"class":41},[32,16302,5197],{"class":217},[32,16304,477],{"class":41},[32,16306,16307],{"class":175},"'hello i am '",[32,16309,1799],{"class":38},[32,16311,4234],{"class":351},[32,16313,11345],{"class":41},[32,16315,16316],{"class":34,"line":127},[32,16317,7189],{"class":41},[32,16319,16320],{"class":34,"line":132},[32,16321,103],{"emptyLinePlaceholder":102},[32,16323,16324],{"class":34,"line":141},[32,16325,16326],{"class":608},"\u002F\u002F 子類別：Worker 繼承 Person\n",[32,16328,16329,16331,16334,16336,16338,16340,16342,16344,16346,16348,16351],{"class":34,"line":147},[32,16330,166],{"class":38},[32,16332,16333],{"class":217}," Worker",[32,16335,894],{"class":38},[32,16337,897],{"class":38},[32,16339,900],{"class":41},[32,16341,15924],{"class":903},[32,16343,635],{"class":41},[32,16345,16244],{"class":903},[32,16347,635],{"class":41},[32,16349,16350],{"class":903},"job",[32,16352,520],{"class":41},[32,16354,16355,16358,16360,16362,16364,16367],{"class":34,"line":275},[32,16356,16357],{"class":41},"  Person.",[32,16359,1596],{"class":217},[32,16361,477],{"class":41},[32,16363,1083],{"class":351},[32,16365,16366],{"class":41},", name, age); ",[32,16368,16369],{"class":608},"\u002F\u002F 步驟一：呼叫母類別初始化\n",[32,16371,16372,16374,16377,16379,16382],{"class":34,"line":282},[32,16373,8938],{"class":351},[32,16375,16376],{"class":41},".job ",[32,16378,172],{"class":38},[32,16380,16381],{"class":41}," job; ",[32,16383,16384],{"class":608},"\u002F\u002F 設定自己的額外屬性\n",[32,16386,16387],{"class":34,"line":295},[32,16388,7189],{"class":41},[32,16390,16391],{"class":34,"line":605},[32,16392,103],{"emptyLinePlaceholder":102},[32,16394,16395,16398,16400,16402,16404,16406,16408,16410,16412,16414,16416,16418],{"class":34,"line":612},[32,16396,16397],{"class":351},"Worker",[32,16399,1278],{"class":41},[32,16401,1585],{"class":351},[32,16403,894],{"class":38},[32,16405,16074],{"class":41},[32,16407,16077],{"class":217},[32,16409,477],{"class":41},[32,16411,16281],{"class":351},[32,16413,1278],{"class":41},[32,16415,1585],{"class":351},[32,16417,15748],{"class":41},[32,16419,16420],{"class":608},"\u002F\u002F 步驟二：接上原型鏈\n",[32,16422,16423,16425,16427,16429,16431,16433,16435,16438],{"class":34,"line":617},[32,16424,16397],{"class":351},[32,16426,1278],{"class":41},[32,16428,1585],{"class":351},[32,16430,1278],{"class":41},[32,16432,16100],{"class":351},[32,16434,894],{"class":38},[32,16436,16437],{"class":41}," Worker; ",[32,16439,16440],{"class":608},"\u002F\u002F 步驟三：建構函式指回自己\n",[32,16442,16443],{"class":34,"line":644},[32,16444,103],{"emptyLinePlaceholder":102},[32,16446,16447,16449,16451,16453,16455,16458,16460,16462],{"class":34,"line":649},[32,16448,16397],{"class":351},[32,16450,1278],{"class":41},[32,16452,1585],{"class":351},[32,16454,1278],{"class":41},[32,16456,16457],{"class":217},"tellJob",[32,16459,894],{"class":38},[32,16461,897],{"class":38},[32,16463,668],{"class":41},[32,16465,16466],{"class":34,"line":671},[32,16467,16468],{"class":608},"  \u002F\u002F Worker 自己的共用方法\n",[32,16470,16471,16473,16475,16477,16480,16482,16484],{"class":34,"line":690},[32,16472,5194],{"class":41},[32,16474,5197],{"class":217},[32,16476,477],{"class":41},[32,16478,16479],{"class":175},"'I am a '",[32,16481,1799],{"class":38},[32,16483,4234],{"class":351},[32,16485,16486],{"class":41},".job);\n",[32,16488,16489],{"class":34,"line":696},[32,16490,7189],{"class":41},[32,16492,16493],{"class":34,"line":706},[32,16494,103],{"emptyLinePlaceholder":102},[32,16496,16497,16499,16502,16504,16506,16508,16510,16513,16515,16518,16520,16523],{"class":34,"line":721},[32,16498,166],{"class":38},[32,16500,16501],{"class":41}," henry ",[32,16503,172],{"class":38},[32,16505,4165],{"class":38},[32,16507,16333],{"class":217},[32,16509,477],{"class":41},[32,16511,16512],{"class":175},"'Henry'",[32,16514,635],{"class":41},[32,16516,16517],{"class":351},"30",[32,16519,635],{"class":41},[32,16521,16522],{"class":175},"'Teacher'",[32,16524,230],{"class":41},[32,16526,16527,16530,16532,16534],{"class":34,"line":728},[32,16528,16529],{"class":41},"henry.",[32,16531,16290],{"class":217},[32,16533,11361],{"class":41},[32,16535,16536],{"class":608},"\u002F\u002F hello i am Henry ← 繼承自 Person.prototype\n",[32,16538,16539,16541,16543,16545],{"class":34,"line":737},[32,16540,16529],{"class":41},[32,16542,16457],{"class":217},[32,16544,11361],{"class":41},[32,16546,16547],{"class":608},"\u002F\u002F I am a Teacher   ← Worker 自己的方法\n",[11,16549,16550,16553,16554,16557,16558,16561,16562,16565],{},[29,16551,16552],{},"henry.sayHello()"," 這個方法沒有寫在 ",[29,16555,16556],{},"Worker.prototype"," 上，",[29,16559,16560],{},"henry"," 自己身上也沒有，會一路往上找到 ",[29,16563,16564],{},"Person.prototype"," 才找到——這就是原型鏈繼承實際運作的樣子。",[15,16567,16569],{"id":16568},"順便記的-es6-物件寫法","順便記的 ES6 物件寫法",[11,16571,16572],{},"練習物件導向的過程中，也整理了幾個 ES6 讓物件字面量寫起來更精簡的語法，跟上面的繼承主題不算同一件事，但當時是一起記的。",[151,16574,16576],{"id":16575},"物件縮寫object-shorthand","物件縮寫（Object Shorthand）",[11,16578,16579],{},"屬性值剛好跟一個同名變數對應時，可以省略冒號跟重複的名稱：",[22,16581,16583],{"className":24,"code":16582,"language":26,"meta":27,"style":27},"\u002F\u002F 完整寫法\nfunction makePoint(x, y) {\n  return {\n    x: x,\n    y: y,\n  };\n}\n\n\u002F\u002F 縮寫\nfunction makePoint(x, y) {\n  return { x, y };\n}\n",[29,16584,16585,16590,16607,16613,16618,16623,16627,16631,16635,16640,16656,16663],{"__ignoreMap":27},[32,16586,16587],{"class":34,"line":35},[32,16588,16589],{"class":608},"\u002F\u002F 完整寫法\n",[32,16591,16592,16594,16597,16599,16601,16603,16605],{"class":34,"line":45},[32,16593,665],{"class":38},[32,16595,16596],{"class":217}," makePoint",[32,16598,477],{"class":41},[32,16600,10967],{"class":903},[32,16602,635],{"class":41},[32,16604,11098],{"class":903},[32,16606,520],{"class":41},[32,16608,16609,16611],{"class":34,"line":51},[32,16610,10974],{"class":38},[32,16612,703],{"class":41},[32,16614,16615],{"class":34,"line":90},[32,16616,16617],{"class":41},"    x: x,\n",[32,16619,16620],{"class":34,"line":99},[32,16621,16622],{"class":41},"    y: y,\n",[32,16624,16625],{"class":34,"line":106},[32,16626,1007],{"class":41},[32,16628,16629],{"class":34,"line":114},[32,16630,54],{"class":41},[32,16632,16633],{"class":34,"line":120},[32,16634,103],{"emptyLinePlaceholder":102},[32,16636,16637],{"class":34,"line":127},[32,16638,16639],{"class":608},"\u002F\u002F 縮寫\n",[32,16641,16642,16644,16646,16648,16650,16652,16654],{"class":34,"line":132},[32,16643,665],{"class":38},[32,16645,16596],{"class":217},[32,16647,477],{"class":41},[32,16649,10967],{"class":903},[32,16651,635],{"class":41},[32,16653,11098],{"class":903},[32,16655,520],{"class":41},[32,16657,16658,16660],{"class":34,"line":141},[32,16659,10974],{"class":38},[32,16661,16662],{"class":41}," { x, y };\n",[32,16664,16665],{"class":34,"line":147},[32,16666,54],{"class":41},[151,16668,16670],{"id":16669},"計算屬性computed-property-names","計算屬性（Computed Property Names）",[11,16672,16673],{},"屬性名稱需要動態決定時，用中括號包住運算式：",[22,16675,16677],{"className":24,"code":16676,"language":26,"meta":27,"style":27},"function createObject(key, value) {\n  const obj = {\n    [key + '1']: value, \u002F\u002F 動態決定屬性名稱\n  };\n  return obj;\n}\n\ncreateObject('name', 'John'); \u002F\u002F { name1: 'John' }\ncreateObject('legs', 4); \u002F\u002F { legs1: 4 }\n",[29,16678,16679,16698,16709,16725,16729,16736,16740,16744,16764],{"__ignoreMap":27},[32,16680,16681,16683,16686,16688,16691,16693,16696],{"class":34,"line":35},[32,16682,665],{"class":38},[32,16684,16685],{"class":217}," createObject",[32,16687,477],{"class":41},[32,16689,16690],{"class":903},"key",[32,16692,635],{"class":41},[32,16694,16695],{"class":903},"value",[32,16697,520],{"class":41},[32,16699,16700,16702,16705,16707],{"class":34,"line":45},[32,16701,4157],{"class":38},[32,16703,16704],{"class":351}," obj",[32,16706,894],{"class":38},[32,16708,703],{"class":41},[32,16710,16711,16714,16716,16719,16722],{"class":34,"line":51},[32,16712,16713],{"class":41},"    [key ",[32,16715,224],{"class":38},[32,16717,16718],{"class":175}," '1'",[32,16720,16721],{"class":41},"]: value, ",[32,16723,16724],{"class":608},"\u002F\u002F 動態決定屬性名稱\n",[32,16726,16727],{"class":34,"line":90},[32,16728,1007],{"class":41},[32,16730,16731,16733],{"class":34,"line":99},[32,16732,10974],{"class":38},[32,16734,16735],{"class":41}," obj;\n",[32,16737,16738],{"class":34,"line":106},[32,16739,54],{"class":41},[32,16741,16742],{"class":34,"line":114},[32,16743,103],{"emptyLinePlaceholder":102},[32,16745,16746,16749,16751,16754,16756,16759,16761],{"class":34,"line":120},[32,16747,16748],{"class":217},"createObject",[32,16750,477],{"class":41},[32,16752,16753],{"class":175},"'name'",[32,16755,635],{"class":41},[32,16757,16758],{"class":175},"'John'",[32,16760,15748],{"class":41},[32,16762,16763],{"class":608},"\u002F\u002F { name1: 'John' }\n",[32,16765,16766,16768,16770,16773,16775,16777,16779],{"class":34,"line":127},[32,16767,16748],{"class":217},[32,16769,477],{"class":41},[32,16771,16772],{"class":175},"'legs'",[32,16774,635],{"class":41},[32,16776,13478],{"class":351},[32,16778,15748],{"class":41},[32,16780,16781],{"class":608},"\u002F\u002F { legs1: 4 }\n",[151,16783,16785],{"id":16784},"函式縮寫method-shorthand","函式縮寫（Method Shorthand）",[11,16787,16788,16789,5240],{},"物件裡的方法不用再寫 ",[29,16790,16791],{},"key: function () {}",[22,16793,16795],{"className":24,"code":16794,"language":26,"meta":27,"style":27},"\u002F\u002F 完整寫法\nconst options = {\n  name: 'Options',\n  created: function () {},\n};\n\n\u002F\u002F ES6 縮寫\nconst options = {\n  name: 'Options',\n  created() {},\n};\n",[29,16796,16797,16801,16812,16821,16833,16837,16841,16846,16856,16864,16871],{"__ignoreMap":27},[32,16798,16799],{"class":34,"line":35},[32,16800,16589],{"class":608},[32,16802,16803,16805,16808,16810],{"class":34,"line":45},[32,16804,6617],{"class":38},[32,16806,16807],{"class":351}," options",[32,16809,894],{"class":38},[32,16811,703],{"class":41},[32,16813,16814,16816,16819],{"class":34,"line":51},[32,16815,11439],{"class":41},[32,16817,16818],{"class":175},"'Options'",[32,16820,547],{"class":41},[32,16822,16823,16826,16828,16830],{"class":34,"line":90},[32,16824,16825],{"class":217},"  created",[32,16827,5269],{"class":41},[32,16829,665],{"class":38},[32,16831,16832],{"class":41}," () {},\n",[32,16834,16835],{"class":34,"line":99},[32,16836,7189],{"class":41},[32,16838,16839],{"class":34,"line":106},[32,16840,103],{"emptyLinePlaceholder":102},[32,16842,16843],{"class":34,"line":114},[32,16844,16845],{"class":608},"\u002F\u002F ES6 縮寫\n",[32,16847,16848,16850,16852,16854],{"class":34,"line":120},[32,16849,6617],{"class":38},[32,16851,16807],{"class":351},[32,16853,894],{"class":38},[32,16855,703],{"class":41},[32,16857,16858,16860,16862],{"class":34,"line":127},[32,16859,11439],{"class":41},[32,16861,16818],{"class":175},[32,16863,547],{"class":41},[32,16865,16866,16868],{"class":34,"line":132},[32,16867,16825],{"class":217},[32,16869,16870],{"class":41},"() {},\n",[32,16872,16873],{"class":34,"line":141},[32,16874,7189],{"class":41},[15,16876,16877],{"id":16877},"現在還適用嗎",[11,16879,16880,16883,16884,16887,16888,16890],{},[12249,16881,16882],{},"原型鏈這套底層機制到現在完全沒變","，",[29,16885,16886],{},"class"," 語法（ES6 就有）背後運作的原理就是這篇整理的 ",[29,16889,1585],{}," 鏈接，不是另一套全新的東西。物件縮寫、計算屬性、函式縮寫這幾個 ES6 寫法現在也還是日常寫法，沒有過時。",[11,16892,16893,16894,16897,16898,16900,16901,16903,16904,16907],{},"真正變的是",[12249,16895,16896],{},"手刻繼承這件事的人","——現在幾乎沒有人會再手寫 ",[29,16899,16188],{}," 加修正 ",[29,16902,16100],{}," 這三步驟，",[29,16905,16906],{},"class extends"," 把這一整套樣板程式碼包裝起來，寫法更接近其他物件導向語言、也更不容易漏掉某一步。整理在《ES6 Class：prototype 繼承的語法糖》。",[15,16909,4536],{"id":4536},[4538,16911,16912,16919],{},[4541,16913,16914],{},[412,16915,16918],{"href":16916,"rel":16917},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FInheritance_and_the_prototype_chain",[416],"MDN：繼承與原型鏈",[4541,16920,16921],{},[412,16922,16925],{"href":16923,"rel":16924},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FObject\u002Fcreate",[416],"MDN：Object.create()",[368,16927,16928],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}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 .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}",{"title":27,"searchDepth":51,"depth":51,"links":16930},[16931,16932,16933,16934,16939,16940,16945,16946],{"id":15427,"depth":45,"text":15428},{"id":15754,"depth":45,"text":15755},{"id":15778,"depth":45,"text":15779},{"id":15880,"depth":45,"text":15881,"children":16935},[16936,16937,16938],{"id":15902,"depth":51,"text":15903},{"id":16055,"depth":51,"text":16056},{"id":16160,"depth":51,"text":16161},{"id":16213,"depth":45,"text":16214},{"id":16568,"depth":45,"text":16569,"children":16941},[16942,16943,16944],{"id":16575,"depth":51,"text":16576},{"id":16669,"depth":51,"text":16670},{"id":16784,"depth":51,"text":16785},{"id":16877,"depth":45,"text":16877},{"id":4536,"depth":45,"text":4536},"整理 ES5 時代用建構函式加 prototype 手刻物件導向的完整流程——封裝屬性與方法、共用函式為什麼要掛在 prototype 上、以及繼承的三個步驟（call 借用母類別建構子、Object.create 接上原型鏈、修正 constructor 指向），並附上物件縮寫與計算屬性這兩個順便學到的 ES6 寫法。",{},"\u002Fposts\u002Fjs-prototype-inheritance","2020-04-19",[],{"title":15399,"description":16947},"posts\u002F20200419.js-prototype-inheritance",[390,16955,1585],"物件導向","2026-08-19","I__C0RwVSthzWrbGPTNo4Q9ErBM_ZjfZSQQKSCNHGdI",{"id":16959,"title":16960,"body":16961,"category":4012,"description":17352,"draft":380,"extension":381,"image":382,"meta":17353,"navigation":102,"path":17354,"publishedAt":17355,"relatedExperiments":17356,"seo":17357,"stem":17358,"tags":17359,"updatedAt":14272,"__hash__":17360},"posts\u002Fposts\u002F20200420.vuex-todos-example.md","Vuex 上課筆記：用一個 todos 範例串起 state、mutation、action",{"type":8,"value":16962,"toc":17349},[16963,16966,16988,16991,17149,17203,17216,17341,17343,17346],[11,16964,16965],{},"上課筆記。Vuex 的四個元素：",[4538,16967,16968,16973,16978,16983],{},[4541,16969,16970],{},[29,16971,16972],{},"state",[4541,16974,16975],{},[29,16976,16977],{},"mutation",[4541,16979,16980],{},[29,16981,16982],{},"getter",[4541,16984,16985],{},[29,16986,16987],{},"action",[11,16989,16990],{},"當時以 todos 做的 store 練習：",[22,16992,16994],{"className":24,"code":16993,"language":26,"meta":27,"style":27},"export default new Vuex.Store({\n  state: {\n    todos: [],\n  },\n  mutations: {\n    setTodos(state, value) {\n      state.todos = value;\n    },\n  },\n  actions: {\n    loadTodos(context) {\n      axios.get(\"https:\u002F\u002Fjsonplaceholder.typicode.com\u002Ftodos\").then((res) => {\n        context.commit(\"setTodos\", res.data);\n      });\n    },\n  },\n});\n",[29,16995,16996,17014,17019,17024,17030,17035,17050,17060,17064,17070,17075,17086,17112,17128,17133,17137,17143],{"__ignoreMap":27},[32,16997,16998,17000,17002,17004,17007,17009,17012],{"class":34,"line":35},[32,16999,5038],{"class":38},[32,17001,5041],{"class":38},[32,17003,4165],{"class":38},[32,17005,17006],{"class":41}," Vuex",[32,17008,1278],{"class":5049},[32,17010,17011],{"class":217},"Store",[32,17013,1143],{"class":5049},[32,17015,17016],{"class":34,"line":45},[32,17017,17018],{"class":41},"  state: {\n",[32,17020,17021],{"class":34,"line":51},[32,17022,17023],{"class":41},"    todos: [],\n",[32,17025,17026,17028],{"class":34,"line":90},[32,17027,9758],{"class":41},[32,17029,547],{"class":5049},[32,17031,17032],{"class":34,"line":99},[32,17033,17034],{"class":41},"  mutations: {\n",[32,17036,17037,17040,17042,17044,17046,17048],{"class":34,"line":106},[32,17038,17039],{"class":217},"    setTodos",[32,17041,477],{"class":41},[32,17043,16972],{"class":903},[32,17045,635],{"class":41},[32,17047,16695],{"class":903},[32,17049,520],{"class":41},[32,17051,17052,17055,17057],{"class":34,"line":114},[32,17053,17054],{"class":41},"      state.todos ",[32,17056,172],{"class":38},[32,17058,17059],{"class":41}," value;\n",[32,17061,17062],{"class":34,"line":120},[32,17063,4204],{"class":41},[32,17065,17066,17068],{"class":34,"line":127},[32,17067,9758],{"class":41},[32,17069,547],{"class":5049},[32,17071,17072],{"class":34,"line":132},[32,17073,17074],{"class":41},"  actions: {\n",[32,17076,17077,17080,17082,17084],{"class":34,"line":141},[32,17078,17079],{"class":217},"    loadTodos",[32,17081,477],{"class":41},[32,17083,7449],{"class":903},[32,17085,520],{"class":41},[32,17087,17088,17091,17093,17095,17098,17100,17102,17104,17106,17108,17110],{"class":34,"line":147},[32,17089,17090],{"class":41},"      axios.",[32,17092,8944],{"class":217},[32,17094,477],{"class":41},[32,17096,17097],{"class":175},"\"https:\u002F\u002Fjsonplaceholder.typicode.com\u002Ftodos\"",[32,17099,533],{"class":41},[32,17101,8950],{"class":217},[32,17103,8293],{"class":41},[32,17105,10128],{"class":903},[32,17107,483],{"class":41},[32,17109,5090],{"class":38},[32,17111,703],{"class":41},[32,17113,17114,17117,17120,17122,17125],{"class":34,"line":275},[32,17115,17116],{"class":41},"        context.",[32,17118,17119],{"class":217},"commit",[32,17121,477],{"class":41},[32,17123,17124],{"class":175},"\"setTodos\"",[32,17126,17127],{"class":41},", res.data);\n",[32,17129,17130],{"class":34,"line":282},[32,17131,17132],{"class":41},"      });\n",[32,17134,17135],{"class":34,"line":295},[32,17136,4204],{"class":41},[32,17138,17139,17141],{"class":34,"line":605},[32,17140,9758],{"class":41},[32,17142,547],{"class":5049},[32,17144,17145,17147],{"class":34,"line":612},[32,17146,5117],{"class":5049},[32,17148,96],{"class":41},[22,17150,17152],{"className":24,"code":17151,"language":26,"meta":27,"style":27},"store.dispatch(\"loadTodos\");\nstore.commit(\"setTodos\", [1, 2, 3, 4, 5]);\n",[29,17153,17154,17169],{"__ignoreMap":27},[32,17155,17156,17159,17162,17164,17167],{"class":34,"line":35},[32,17157,17158],{"class":41},"store.",[32,17160,17161],{"class":217},"dispatch",[32,17163,477],{"class":41},[32,17165,17166],{"class":175},"\"loadTodos\"",[32,17168,230],{"class":41},[32,17170,17171,17173,17175,17177,17179,17182,17184,17186,17188,17190,17192,17194,17196,17198,17200],{"class":34,"line":45},[32,17172,17158],{"class":41},[32,17174,17119],{"class":217},[32,17176,477],{"class":41},[32,17178,17124],{"class":175},[32,17180,17181],{"class":41},", [",[32,17183,6544],{"class":351},[32,17185,635],{"class":41},[32,17187,11971],{"class":351},[32,17189,635],{"class":41},[32,17191,13470],{"class":351},[32,17193,635],{"class":41},[32,17195,13478],{"class":351},[32,17197,635],{"class":41},[32,17199,10613],{"class":351},[32,17201,17202],{"class":41},"]);\n",[11,17204,17205,17206,3750,17209,7090,17212,17215],{},"元件裡可以用 ",[29,17207,17208],{},"mapState",[29,17210,17211],{},"mapMutations",[29,17213,17214],{},"mapActions"," 取用：",[22,17217,17219],{"className":24,"code":17218,"language":26,"meta":27,"style":27},"import { mapState, mapMutations, mapActions } from \"vuex\";\n\nexport default {\n  computed: {\n    ...mapState([\"todos\"]),\n  },\n  mounted() {\n    this.loadTodos();\n  },\n  methods: {\n    ...mapMutations([\"setTodos\"]),\n    ...mapActions([\"loadTodos\"]),\n  },\n};\n",[29,17220,17221,17235,17239,17247,17252,17268,17274,17283,17294,17300,17305,17317,17329,17335],{"__ignoreMap":27},[32,17222,17223,17225,17228,17230,17233],{"class":34,"line":35},[32,17224,8794],{"class":38},[32,17226,17227],{"class":41}," { mapState, mapMutations, mapActions } ",[32,17229,8850],{"class":38},[32,17231,17232],{"class":175}," \"vuex\"",[32,17234,96],{"class":41},[32,17236,17237],{"class":34,"line":45},[32,17238,103],{"emptyLinePlaceholder":102},[32,17240,17241,17243,17245],{"class":34,"line":51},[32,17242,5038],{"class":38},[32,17244,5041],{"class":38},[32,17246,703],{"class":5049},[32,17248,17249],{"class":34,"line":90},[32,17250,17251],{"class":41},"  computed: {\n",[32,17253,17254,17257,17259,17262,17265],{"class":34,"line":99},[32,17255,17256],{"class":38},"    ...",[32,17258,17208],{"class":217},[32,17260,17261],{"class":41},"([",[32,17263,17264],{"class":175},"\"todos\"",[32,17266,17267],{"class":41},"]),\n",[32,17269,17270,17272],{"class":34,"line":106},[32,17271,9758],{"class":41},[32,17273,547],{"class":5049},[32,17275,17276,17279,17281],{"class":34,"line":114},[32,17277,17278],{"class":217},"  mounted",[32,17280,6075],{"class":5049},[32,17282,5252],{"class":41},[32,17284,17285,17287,17289,17292],{"class":34,"line":120},[32,17286,10114],{"class":351},[32,17288,1278],{"class":41},[32,17290,17291],{"class":217},"loadTodos",[32,17293,687],{"class":41},[32,17295,17296,17298],{"class":34,"line":127},[32,17297,9758],{"class":41},[32,17299,547],{"class":5049},[32,17301,17302],{"class":34,"line":132},[32,17303,17304],{"class":41},"  methods: {\n",[32,17306,17307,17309,17311,17313,17315],{"class":34,"line":141},[32,17308,17256],{"class":38},[32,17310,17211],{"class":217},[32,17312,17261],{"class":41},[32,17314,17124],{"class":175},[32,17316,17267],{"class":41},[32,17318,17319,17321,17323,17325,17327],{"class":34,"line":147},[32,17320,17256],{"class":38},[32,17322,17214],{"class":217},[32,17324,17261],{"class":41},[32,17326,17166],{"class":175},[32,17328,17267],{"class":41},[32,17330,17331,17333],{"class":34,"line":275},[32,17332,9758],{"class":41},[32,17334,547],{"class":5049},[32,17336,17337,17339],{"class":34,"line":282},[32,17338,9765],{"class":5049},[32,17340,96],{"class":41},[15,17342,2004],{"id":2003},[11,17344,17345],{},"原文主要是課堂截圖，整理時只把其中的核心範例轉成文字。這是 Vue 2／Vuex 3 時期的寫法；新專案應依目前使用的 Vue 狀態管理方案調整。",[368,17347,17348],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":17350},[17351],{"id":2003,"depth":45,"text":2004},"上課時以 todos 練習 Vuex state、mutation、action 與 getter 的筆記。",{},"\u002Fposts\u002Fvuex-todos-example","2020-04-20",[],{"title":16960,"description":17352},"posts\u002F20200420.vuex-todos-example",[4844,4113],"kHfrC62F2Q3ZZKDhiUgEjW41PKyS-93pMQylWDN0Tno",{"id":17362,"title":17363,"body":17364,"category":378,"description":17582,"draft":380,"extension":381,"image":382,"meta":17583,"navigation":102,"path":17584,"publishedAt":17585,"relatedExperiments":17586,"seo":17587,"stem":17588,"tags":17589,"updatedAt":14272,"__hash__":17593},"posts\u002Fposts\u002F20200421.threejs-basics.md","Three.js 基礎入門：場景、光源、材質、攝影機",{"type":8,"value":17365,"toc":17579},[17366,17369,17372,17375,17389,17392,17545,17551,17567,17569,17576],[11,17367,17368],{},"這邊是當時的 Three.js 學習筆記。",[11,17370,17371],{},"Three.js 可以先理解成舞台，加上「畫面要怎麼被看到」。它可以搭配 SVG、CSS 或 WebGL 等渲染方式。",[11,17373,17374],{},"基本組成包括：",[4538,17376,17377,17380,17383,17386],{},[4541,17378,17379],{},"場景（scene）",[4541,17381,17382],{},"渲染器（renderer）",[4541,17384,17385],{},"攝影機（camera）",[4541,17387,17388],{},"物件、光源與材質",[11,17390,17391],{},"建立攝影機時，要設定大小、長寬比與其他參數，再設定位置以及要朝哪個方向觀看。",[22,17393,17395],{"className":24,"code":17394,"language":26,"meta":27,"style":27},"var scene = new THREE.Scene();\nvar camera = new THREE.PerspectiveCamera(\n  75,\n  window.innerWidth \u002F window.innerHeight,\n  0.1,\n  1000,\n);\nvar renderer = new THREE.WebGLRenderer();\n\nrenderer.setSize(window.innerWidth, window.innerHeight);\ndocument.body.appendChild(renderer.domElement);\n\ncamera.position.z = 5;\nrenderer.render(scene, camera);\n",[29,17396,17397,17418,17438,17445,17455,17462,17469,17473,17493,17497,17508,17519,17523,17535],{"__ignoreMap":27},[32,17398,17399,17401,17404,17406,17408,17411,17413,17416],{"class":34,"line":35},[32,17400,166],{"class":38},[32,17402,17403],{"class":41}," scene ",[32,17405,172],{"class":38},[32,17407,4165],{"class":38},[32,17409,17410],{"class":351}," THREE",[32,17412,1278],{"class":41},[32,17414,17415],{"class":217},"Scene",[32,17417,687],{"class":41},[32,17419,17420,17422,17425,17427,17429,17431,17433,17436],{"class":34,"line":45},[32,17421,166],{"class":38},[32,17423,17424],{"class":41}," camera ",[32,17426,172],{"class":38},[32,17428,4165],{"class":38},[32,17430,17410],{"class":351},[32,17432,1278],{"class":41},[32,17434,17435],{"class":217},"PerspectiveCamera",[32,17437,539],{"class":41},[32,17439,17440,17443],{"class":34,"line":51},[32,17441,17442],{"class":351},"  75",[32,17444,547],{"class":41},[32,17446,17447,17450,17452],{"class":34,"line":90},[32,17448,17449],{"class":41},"  window.innerWidth ",[32,17451,1275],{"class":38},[32,17453,17454],{"class":41}," window.innerHeight,\n",[32,17456,17457,17460],{"class":34,"line":99},[32,17458,17459],{"class":351},"  0.1",[32,17461,547],{"class":41},[32,17463,17464,17467],{"class":34,"line":106},[32,17465,17466],{"class":351},"  1000",[32,17468,547],{"class":41},[32,17470,17471],{"class":34,"line":114},[32,17472,230],{"class":41},[32,17474,17475,17477,17480,17482,17484,17486,17488,17491],{"class":34,"line":120},[32,17476,166],{"class":38},[32,17478,17479],{"class":41}," renderer ",[32,17481,172],{"class":38},[32,17483,4165],{"class":38},[32,17485,17410],{"class":351},[32,17487,1278],{"class":41},[32,17489,17490],{"class":217},"WebGLRenderer",[32,17492,687],{"class":41},[32,17494,17495],{"class":34,"line":127},[32,17496,103],{"emptyLinePlaceholder":102},[32,17498,17499,17502,17505],{"class":34,"line":132},[32,17500,17501],{"class":41},"renderer.",[32,17503,17504],{"class":217},"setSize",[32,17506,17507],{"class":41},"(window.innerWidth, window.innerHeight);\n",[32,17509,17510,17513,17516],{"class":34,"line":141},[32,17511,17512],{"class":41},"document.body.",[32,17514,17515],{"class":217},"appendChild",[32,17517,17518],{"class":41},"(renderer.domElement);\n",[32,17520,17521],{"class":34,"line":147},[32,17522,103],{"emptyLinePlaceholder":102},[32,17524,17525,17528,17530,17533],{"class":34,"line":275},[32,17526,17527],{"class":41},"camera.position.z ",[32,17529,172],{"class":38},[32,17531,17532],{"class":351}," 5",[32,17534,96],{"class":41},[32,17536,17537,17539,17542],{"class":34,"line":282},[32,17538,17501],{"class":41},[32,17540,17541],{"class":217},"render",[32,17543,17544],{"class":41},"(scene, camera);\n",[11,17546,17547,17550],{},[29,17548,17549],{},"Group"," 是一個空的 3D 群組物件，可以把多個物件放在一起轉動。",[4538,17552,17553,17560],{},[4541,17554,17555],{},[412,17556,17559],{"href":17557,"rel":17558},"https:\u002F\u002Fthreejs.org\u002F",[416],"Three.js 官方網站",[4541,17561,17562],{},[412,17563,17566],{"href":17564,"rel":17565},"https:\u002F\u002Fcodepen.io\u002Frockayumitw\u002Fpen\u002FZEWLWqx?editors=0110",[416],"當時的 CodePen 練習",[15,17568,2004],{"id":2003},[11,17570,17571,17572,17575],{},"原文主要由十二張課堂截圖組成，以上只保留可辨認的核心摘要。範例是 2020 年以全域 ",[29,17573,17574],{},"THREE"," 物件使用的寫法；目前專案通常透過 ESM 匯入套件，API 也應以使用版本的官方文件為準。",[368,17577,17578],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":17580},[17581],{"id":2003,"depth":45,"text":2004},"2020 年學習 Three.js 時，對場景、渲染器、攝影機與物件群組留下的課堂筆記。",{},"\u002Fposts\u002Fthreejs-basics","2020-04-21",[],{"title":17363,"description":17582},"posts\u002F20200421.threejs-basics",[17590,17591,17592],"Three.js","WebGL","3D","hppoQn98BEFIxDg7ZZ3M-NTMF0d0V8IVOpV-QahYbsA",{"id":17595,"title":17596,"body":17597,"category":4012,"description":17862,"draft":380,"extension":381,"image":382,"meta":17863,"navigation":102,"path":17864,"publishedAt":17585,"relatedExperiments":17865,"seo":17866,"stem":17867,"tags":17868,"updatedAt":14272,"__hash__":17869},"posts\u002Fposts\u002F20200421.vuex-syntax-cheatsheet.md","Vuex API 語法速查：安裝、state、mutations、actions、getters、modules",{"type":8,"value":17598,"toc":17857},[17599,17611,17614,17626,17629,17645,17649,17777,17780,17799,17802,17841,17849,17851,17854],[11,17600,17601,17602,17605,17606,3750,17608,17610],{},"元件可以透過 ",[29,17603,17604],{},"$store"," 取用 Vuex，也可以使用 ",[29,17607,17208],{},[29,17609,17214],{}," 等輔助函式。要使用這些方法，必須先在最上層注入 store。",[11,17612,17613],{},"拿到新的專案後，先安裝相依套件：",[22,17615,17617],{"className":2057,"code":17616,"language":2059,"meta":27,"style":27},"npm install\n",[29,17618,17619],{"__ignoreMap":27},[32,17620,17621,17623],{"class":34,"line":35},[32,17622,4625],{"class":2066},[32,17624,17625],{"class":175}," install\n",[11,17627,17628],{},"如果還沒有安裝 Vuex：",[22,17630,17632],{"className":2057,"code":17631,"language":2059,"meta":27,"style":27},"npm install vuex --save\n",[29,17633,17634],{"__ignoreMap":27},[32,17635,17636,17638,17640,17643],{"class":34,"line":35},[32,17637,4625],{"class":2066},[32,17639,4650],{"class":175},[32,17641,17642],{"class":175}," vuex",[32,17644,8638],{"class":351},[15,17646,17648],{"id":17647},"建立-store","建立 store",[22,17650,17652],{"className":24,"code":17651,"language":26,"meta":27,"style":27},"\u002F\u002F src\u002Fstore\u002Findex.js\nimport Vue from \"vue\";\nimport Vuex from \"vuex\";\n\nVue.use(Vuex);\n\nexport default new Vuex.Store({\n  state: {},\n  actions: {\n    updateLoading(context, status) {\n      \u002F\u002F context 是 Vuex 傳入的內容\n      \u002F\u002F status 是外部傳入的 payload\n    },\n  },\n  mutations: {},\n});\n",[29,17653,17654,17659,17672,17685,17689,17697,17701,17717,17724,17728,17744,17749,17754,17758,17764,17771],{"__ignoreMap":27},[32,17655,17656],{"class":34,"line":35},[32,17657,17658],{"class":608},"\u002F\u002F src\u002Fstore\u002Findex.js\n",[32,17660,17661,17663,17665,17667,17670],{"class":34,"line":45},[32,17662,8794],{"class":38},[32,17664,8847],{"class":41},[32,17666,8850],{"class":38},[32,17668,17669],{"class":175}," \"vue\"",[32,17671,96],{"class":41},[32,17673,17674,17676,17679,17681,17683],{"class":34,"line":51},[32,17675,8794],{"class":38},[32,17677,17678],{"class":41}," Vuex ",[32,17680,8850],{"class":38},[32,17682,17232],{"class":175},[32,17684,96],{"class":41},[32,17686,17687],{"class":34,"line":90},[32,17688,103],{"emptyLinePlaceholder":102},[32,17690,17691,17693,17695],{"class":34,"line":99},[32,17692,8892],{"class":41},[32,17694,8895],{"class":217},[32,17696,10244],{"class":41},[32,17698,17699],{"class":34,"line":106},[32,17700,103],{"emptyLinePlaceholder":102},[32,17702,17703,17705,17707,17709,17711,17713,17715],{"class":34,"line":114},[32,17704,5038],{"class":38},[32,17706,5041],{"class":38},[32,17708,4165],{"class":38},[32,17710,17006],{"class":41},[32,17712,1278],{"class":5049},[32,17714,17011],{"class":217},[32,17716,1143],{"class":5049},[32,17718,17719,17722],{"class":34,"line":120},[32,17720,17721],{"class":41},"  state: {}",[32,17723,547],{"class":5049},[32,17725,17726],{"class":34,"line":127},[32,17727,17074],{"class":41},[32,17729,17730,17733,17735,17737,17739,17742],{"class":34,"line":132},[32,17731,17732],{"class":217},"    updateLoading",[32,17734,477],{"class":41},[32,17736,7449],{"class":903},[32,17738,635],{"class":41},[32,17740,17741],{"class":903},"status",[32,17743,520],{"class":41},[32,17745,17746],{"class":34,"line":141},[32,17747,17748],{"class":608},"      \u002F\u002F context 是 Vuex 傳入的內容\n",[32,17750,17751],{"class":34,"line":147},[32,17752,17753],{"class":608},"      \u002F\u002F status 是外部傳入的 payload\n",[32,17755,17756],{"class":34,"line":275},[32,17757,4204],{"class":41},[32,17759,17760,17762],{"class":34,"line":282},[32,17761,9758],{"class":41},[32,17763,547],{"class":5049},[32,17765,17766,17769],{"class":34,"line":295},[32,17767,17768],{"class":41},"  mutations: {}",[32,17770,547],{"class":5049},[32,17772,17773,17775],{"class":34,"line":605},[32,17774,5117],{"class":5049},[32,17776,96],{"class":41},[11,17778,17779],{},"當時的理解是：",[4538,17781,17782,17787,17793],{},[4541,17783,17784,17786],{},[29,17785,16972],{},"：保存狀態",[4541,17788,17789,17792],{},[29,17790,17791],{},"actions","：放實際操作與 AJAX 等非同步行為，不直接修改 state",[4541,17794,17795,17798],{},[29,17796,17797],{},"mutations","：實際修改 state，名稱通常以大寫常數表示",[15,17800,17801],{"id":17801},"注入根元件",[22,17803,17805],{"className":24,"code":17804,"language":26,"meta":27,"style":27},"import store from \".\u002Fstore\";\n\nnew Vue({\n  store,\n});\n",[29,17806,17807,17820,17824,17832,17837],{"__ignoreMap":27},[32,17808,17809,17811,17813,17815,17818],{"class":34,"line":35},[32,17810,8794],{"class":38},[32,17812,10259],{"class":41},[32,17814,8850],{"class":38},[32,17816,17817],{"class":175}," \".\u002Fstore\"",[32,17819,96],{"class":41},[32,17821,17822],{"class":34,"line":45},[32,17823,103],{"emptyLinePlaceholder":102},[32,17825,17826,17828,17830],{"class":34,"line":51},[32,17827,9196],{"class":38},[32,17829,4168],{"class":217},[32,17831,1143],{"class":41},[32,17833,17834],{"class":34,"line":90},[32,17835,17836],{"class":41},"  store,\n",[32,17838,17839],{"class":34,"line":99},[32,17840,792],{"class":41},[11,17842,17843,17844],{},"資料來源：",[412,17845,17848],{"href":17846,"rel":17847},"https:\u002F\u002Fvuex.vuejs.org\u002Fzh\u002Fapi\u002F",[416],"Vuex API（封存文件）",[15,17850,2004],{"id":2003},[11,17852,17853],{},"這是 Vue 2／Vuex 3 時期的速記，原文沒有完整涵蓋標題列出的每個 API。Vuex 仍可維護既有專案，但新專案的安裝與狀態管理方式應依目前框架版本選擇。",[368,17855,17856],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}",{"title":27,"searchDepth":51,"depth":51,"links":17858},[17859,17860,17861],{"id":17647,"depth":45,"text":17648},{"id":17801,"depth":45,"text":17801},{"id":2003,"depth":45,"text":2004},"記錄 Vue 2 專案安裝、注入 Vuex，以及 state、actions、mutations 的基本分工。",{},"\u002Fposts\u002Fvuex-syntax-cheatsheet",[],{"title":17596,"description":17862},"posts\u002F20200421.vuex-syntax-cheatsheet",[4844,4113],"3YZkXJ9yDHbvYb8LHZS0LAR8P87af1ojiLIOs7VldQE",{"id":17871,"title":17872,"body":17873,"category":378,"description":17952,"draft":380,"extension":381,"image":382,"meta":17953,"navigation":102,"path":17954,"publishedAt":17955,"relatedExperiments":17956,"seo":17957,"stem":17958,"tags":17959,"updatedAt":14272,"__hash__":17960},"posts\u002Fposts\u002F20200429.nuxt-axios-module.md","Nuxt 安裝 @nuxtjs\u002Faxios 模組",{"type":8,"value":17874,"toc":17949},[17875,17878,17892,17899,17931,17933,17946],[11,17876,17877],{},"這邊記錄 Nuxt 2 安裝 axios 模組。",[22,17879,17881],{"className":2057,"code":17880,"language":2059,"meta":27,"style":27},"npm install @nuxtjs\u002Faxios\n",[29,17882,17883],{"__ignoreMap":27},[32,17884,17885,17887,17889],{"class":34,"line":35},[32,17886,4625],{"class":2066},[32,17888,4650],{"class":175},[32,17890,17891],{"class":175}," @nuxtjs\u002Faxios\n",[11,17893,17894,17895,17898],{},"接著在 ",[29,17896,17897],{},"nuxt.config.js"," 註冊：",[22,17900,17902],{"className":24,"code":17901,"language":26,"meta":27,"style":27},"export default {\n  modules: [\"@nuxtjs\u002Faxios\"],\n};\n",[29,17903,17904,17912,17925],{"__ignoreMap":27},[32,17905,17906,17908,17910],{"class":34,"line":35},[32,17907,5038],{"class":38},[32,17909,5041],{"class":38},[32,17911,703],{"class":5049},[32,17913,17914,17917,17920,17923],{"class":34,"line":45},[32,17915,17916],{"class":41},"  modules: [",[32,17918,17919],{"class":175},"\"@nuxtjs\u002Faxios\"",[32,17921,17922],{"class":41},"]",[32,17924,547],{"class":5049},[32,17926,17927,17929],{"class":34,"line":51},[32,17928,9765],{"class":5049},[32,17930,96],{"class":41},[15,17932,2004],{"id":2003},[11,17934,17935,17936,17939,17940,10450,17943,3775],{},"這是 Nuxt 2 的舊模組。",[29,17937,17938],{},"@nuxtjs\u002Faxios"," 已停止維護，Nuxt 3 之後通常改用內建的 ",[29,17941,17942],{},"useFetch()",[29,17944,17945],{},"$fetch()",[368,17947,17948],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}",{"title":27,"searchDepth":51,"depth":51,"links":17950},[17951],{"id":2003,"depth":45,"text":2004},"記錄 2020 年在 Nuxt 2 專案安裝並註冊 @nuxtjs\u002Faxios 的方式。",{},"\u002Fposts\u002Fnuxt-axios-module","2020-04-29",[],{"title":17872,"description":17952},"posts\u002F20200429.nuxt-axios-module",[15195,9540],"fAIXo4zAF_lIyN9CXjmGbK9O2PWGsKGY5it8Z9NNWz0",{"id":17962,"title":17963,"body":17964,"category":378,"description":18033,"draft":380,"extension":381,"image":382,"meta":18034,"navigation":102,"path":18035,"publishedAt":18036,"relatedExperiments":18037,"seo":18038,"stem":18039,"tags":18040,"updatedAt":14272,"__hash__":18042},"posts\u002Fposts\u002F20200729.chrome-focus-outline.md","消除 Chrome 按鈕的黑色外框",{"type":8,"value":17965,"toc":18030},[17966,17969,18015,18017,18028],[11,17967,17968],{},"最近 Chrome 更新後，點選按鈕時會出現黑色外框。當時確認加入以下 CSS 後就會消失：",[22,17970,17972],{"className":5412,"code":17971,"language":1140,"meta":27,"style":27},"*,\n*:focus,\n*:hover {\n  outline: none !important;\n}\n",[29,17973,17974,17980,17989,17997,18011],{"__ignoreMap":27},[32,17975,17976,17978],{"class":34,"line":35},[32,17977,6078],{"class":4049},[32,17979,547],{"class":41},[32,17981,17982,17984,17987],{"class":34,"line":45},[32,17983,6078],{"class":4049},[32,17985,17986],{"class":4053},":focus",[32,17988,547],{"class":41},[32,17990,17991,17993,17995],{"class":34,"line":51},[32,17992,6078],{"class":4049},[32,17994,14502],{"class":4053},[32,17996,703],{"class":41},[32,17998,17999,18002,18004,18007,18009],{"class":34,"line":90},[32,18000,18001],{"class":351},"  outline",[32,18003,5269],{"class":41},[32,18005,18006],{"class":351},"none",[32,18008,11886],{"class":38},[32,18010,96],{"class":41},[32,18012,18013],{"class":34,"line":99},[32,18014,54],{"class":41},[15,18016,2004],{"id":2003},[11,18018,18019,18020,18023,18024,18027],{},"這段全域移除 ",[29,18021,18022],{},"outline"," 的做法不應沿用。外框是鍵盤操作的重要焦點提示；若要調整外觀，應保留清楚可辨認的 ",[29,18025,18026],{},":focus-visible"," 樣式，而不是把所有元素的焦點指示全部關掉。",[368,18029,12630],{},{"title":27,"searchDepth":51,"depth":51,"links":18031},[18032],{"id":2003,"depth":45,"text":2004},"記錄 Chrome 更新後，當時用全域 outline none 移除按鈕焦點外框的寫法。",{},"\u002Fposts\u002Fchrome-focus-outline","2020-07-29",[],{"title":17963,"description":18033},"posts\u002F20200729.chrome-focus-outline",[1757,18041],"Chrome","Qu8MDMfEuWxGqI3dsyfYBU45VG9icLrAPfxQqM14e1Y",{"id":18044,"title":18045,"body":18046,"category":378,"description":18737,"draft":380,"extension":381,"image":382,"meta":18738,"navigation":102,"path":18739,"publishedAt":18740,"relatedExperiments":18741,"seo":18742,"stem":18743,"tags":18744,"updatedAt":14272,"__hash__":18745},"posts\u002Fposts\u002F20200820.js-array-methods.md","JavaScript 陣列方法整理：forEach、map、filter、find、some、every、sort、reduce",{"type":8,"value":18047,"toc":18718},[18048,18055,18066,18108,18115,18125,18206,18209,18256,18262,18275,18319,18326,18331,18420,18427,18476,18483,18532,18538,18613,18620,18623,18704,18706,18715],[15,18049,18051,18054],{"id":18050},"foreach對每個元素執行動作",[29,18052,18053],{},"forEach()","：對每個元素執行動作",[4538,18056,18057,18060,18063],{},[4541,18058,18059],{},"將陣列元素逐一帶入函式",[4541,18061,18062],{},"不會產生新的陣列",[4541,18064,18065],{},"如果元素是物件，可以在函式裡修改物件內容",[22,18067,18069],{"className":24,"code":18068,"language":26,"meta":27,"style":27},"books.forEach(function (book) {\n  book.total = book.discount * book.price;\n});\n",[29,18070,18071,18089,18104],{"__ignoreMap":27},[32,18072,18073,18076,18078,18080,18082,18084,18087],{"class":34,"line":35},[32,18074,18075],{"class":41},"books.",[32,18077,8290],{"class":217},[32,18079,477],{"class":41},[32,18081,665],{"class":38},[32,18083,900],{"class":41},[32,18085,18086],{"class":903},"book",[32,18088,520],{"class":41},[32,18090,18091,18094,18096,18099,18101],{"class":34,"line":45},[32,18092,18093],{"class":41},"  book.total ",[32,18095,172],{"class":38},[32,18097,18098],{"class":41}," book.discount ",[32,18100,6078],{"class":38},[32,18102,18103],{"class":41}," book.price;\n",[32,18105,18106],{"class":34,"line":51},[32,18107,792],{"class":41},[15,18109,18111,18114],{"id":18110},"map把執行結果存到新陣列",[29,18112,18113],{},"map()","：把執行結果存到新陣列",[4538,18116,18117,18119,18122],{},[4541,18118,18059],{},[4541,18120,18121],{},"將回傳結果組成另一個陣列",[4541,18123,18124],{},"常用於抽取或轉換必要資訊",[22,18126,18128],{"className":24,"code":18127,"language":26,"meta":27,"style":27},"var numbers = [1, 2, 3, 4, 5, 6];\nvar squared = numbers.map(function (number) {\n  return number * number;\n});\n",[29,18129,18130,18165,18190,18202],{"__ignoreMap":27},[32,18131,18132,18134,18137,18139,18141,18143,18145,18147,18149,18151,18153,18155,18157,18159,18161,18163],{"class":34,"line":35},[32,18133,166],{"class":38},[32,18135,18136],{"class":41}," numbers ",[32,18138,172],{"class":38},[32,18140,8261],{"class":41},[32,18142,6544],{"class":351},[32,18144,635],{"class":41},[32,18146,11971],{"class":351},[32,18148,635],{"class":41},[32,18150,13470],{"class":351},[32,18152,635],{"class":41},[32,18154,13478],{"class":351},[32,18156,635],{"class":41},[32,18158,10613],{"class":351},[32,18160,635],{"class":41},[32,18162,13493],{"class":351},[32,18164,8282],{"class":41},[32,18166,18167,18169,18172,18174,18177,18179,18181,18183,18185,18188],{"class":34,"line":45},[32,18168,166],{"class":38},[32,18170,18171],{"class":41}," squared ",[32,18173,172],{"class":38},[32,18175,18176],{"class":41}," numbers.",[32,18178,11130],{"class":217},[32,18180,477],{"class":41},[32,18182,665],{"class":38},[32,18184,900],{"class":41},[32,18186,18187],{"class":903},"number",[32,18189,520],{"class":41},[32,18191,18192,18194,18197,18199],{"class":34,"line":51},[32,18193,10974],{"class":38},[32,18195,18196],{"class":41}," number ",[32,18198,6078],{"class":38},[32,18200,18201],{"class":41}," number;\n",[32,18203,18204],{"class":34,"line":90},[32,18205,792],{"class":41},[11,18207,18208],{},"物件轉換範例：",[22,18210,18212],{"className":24,"code":18211,"language":26,"meta":27,"style":27},"function convert(obj) {\n  return {\n    name: obj.name,\n    total: obj.price * obj.discount,\n  };\n}\n",[29,18213,18214,18227,18233,18238,18248,18252],{"__ignoreMap":27},[32,18215,18216,18218,18221,18223,18225],{"class":34,"line":35},[32,18217,665],{"class":38},[32,18219,18220],{"class":217}," convert",[32,18222,477],{"class":41},[32,18224,8296],{"class":903},[32,18226,520],{"class":41},[32,18228,18229,18231],{"class":34,"line":45},[32,18230,10974],{"class":38},[32,18232,703],{"class":41},[32,18234,18235],{"class":34,"line":51},[32,18236,18237],{"class":41},"    name: obj.name,\n",[32,18239,18240,18243,18245],{"class":34,"line":90},[32,18241,18242],{"class":41},"    total: obj.price ",[32,18244,6078],{"class":38},[32,18246,18247],{"class":41}," obj.discount,\n",[32,18249,18250],{"class":34,"line":99},[32,18251,1007],{"class":41},[32,18253,18254],{"class":34,"line":106},[32,18255,54],{"class":41},[15,18257,18259,18261],{"id":18258},"filter留下符合條件的元素",[29,18260,15372],{},"：留下符合條件的元素",[4538,18263,18264,18272],{},[4541,18265,18266,18267,11621,18269,18271],{},"依函式回傳的 ",[29,18268,6206],{},[29,18270,9746],{}," 決定是否保留",[4541,18273,18274],{},"回傳新的陣列",[22,18276,18278],{"className":24,"code":18277,"language":26,"meta":27,"style":27},"var result = numbers.filter(function (number) {\n  return number > 3;\n});\n",[29,18279,18280,18302,18315],{"__ignoreMap":27},[32,18281,18282,18284,18286,18288,18290,18292,18294,18296,18298,18300],{"class":34,"line":35},[32,18283,166],{"class":38},[32,18285,340],{"class":41},[32,18287,172],{"class":38},[32,18289,18176],{"class":41},[32,18291,15334],{"class":217},[32,18293,477],{"class":41},[32,18295,665],{"class":38},[32,18297,900],{"class":41},[32,18299,18187],{"class":903},[32,18301,520],{"class":41},[32,18303,18304,18306,18308,18310,18313],{"class":34,"line":45},[32,18305,10974],{"class":38},[32,18307,18196],{"class":41},[32,18309,1615],{"class":38},[32,18311,18312],{"class":351}," 3",[32,18314,96],{"class":41},[32,18316,18317],{"class":34,"line":51},[32,18318,792],{"class":41},[15,18320,18322,18325],{"id":18321},"find找到第一個符合條件的元素",[29,18323,18324],{},"find()","：找到第一個符合條件的元素",[4538,18327,18328],{},[4541,18329,18330],{},"回傳第一個符合條件的元素，不是陣列",[22,18332,18334],{"className":24,"code":18333,"language":26,"meta":27,"style":27},"var dnaList = [\"ATC\", \"AGC\", \"AAA\", \"TTG\"];\nvar result = dnaList.find(function (dna) {\n  return dna.indexOf(\"TG\") > -1;\n});\n",[29,18335,18336,18367,18392,18416],{"__ignoreMap":27},[32,18337,18338,18340,18343,18345,18347,18350,18352,18355,18357,18360,18362,18365],{"class":34,"line":35},[32,18339,166],{"class":38},[32,18341,18342],{"class":41}," dnaList ",[32,18344,172],{"class":38},[32,18346,8261],{"class":41},[32,18348,18349],{"class":175},"\"ATC\"",[32,18351,635],{"class":41},[32,18353,18354],{"class":175},"\"AGC\"",[32,18356,635],{"class":41},[32,18358,18359],{"class":175},"\"AAA\"",[32,18361,635],{"class":41},[32,18363,18364],{"class":175},"\"TTG\"",[32,18366,8282],{"class":41},[32,18368,18369,18371,18373,18375,18378,18381,18383,18385,18387,18390],{"class":34,"line":45},[32,18370,166],{"class":38},[32,18372,340],{"class":41},[32,18374,172],{"class":38},[32,18376,18377],{"class":41}," dnaList.",[32,18379,18380],{"class":217},"find",[32,18382,477],{"class":41},[32,18384,665],{"class":38},[32,18386,900],{"class":41},[32,18388,18389],{"class":903},"dna",[32,18391,520],{"class":41},[32,18393,18394,18396,18399,18401,18403,18406,18408,18410,18412,18414],{"class":34,"line":51},[32,18395,10974],{"class":38},[32,18397,18398],{"class":41}," dna.",[32,18400,1106],{"class":217},[32,18402,477],{"class":41},[32,18404,18405],{"class":175},"\"TG\"",[32,18407,483],{"class":41},[32,18409,1615],{"class":38},[32,18411,1119],{"class":38},[32,18413,6544],{"class":351},[32,18415,96],{"class":41},[32,18417,18418],{"class":34,"line":90},[32,18419,792],{"class":41},[15,18421,18423,18426],{"id":18422},"some是否有元素符合條件",[29,18424,18425],{},"some()","：是否有元素符合條件",[22,18428,18430],{"className":24,"code":18429,"language":26,"meta":27,"style":27},"var hasEven = numbers.some(function (number) {\n  return number % 2 === 0;\n});\n",[29,18431,18432,18456,18472],{"__ignoreMap":27},[32,18433,18434,18436,18439,18441,18443,18446,18448,18450,18452,18454],{"class":34,"line":35},[32,18435,166],{"class":38},[32,18437,18438],{"class":41}," hasEven ",[32,18440,172],{"class":38},[32,18442,18176],{"class":41},[32,18444,18445],{"class":217},"some",[32,18447,477],{"class":41},[32,18449,665],{"class":38},[32,18451,900],{"class":41},[32,18453,18187],{"class":903},[32,18455,520],{"class":41},[32,18457,18458,18460,18462,18464,18466,18468,18470],{"class":34,"line":45},[32,18459,10974],{"class":38},[32,18461,18196],{"class":41},[32,18463,14129],{"class":38},[32,18465,10982],{"class":351},[32,18467,994],{"class":38},[32,18469,1523],{"class":351},[32,18471,96],{"class":41},[32,18473,18474],{"class":34,"line":51},[32,18475,792],{"class":41},[15,18477,18479,18482],{"id":18478},"every是否所有元素都符合條件",[29,18480,18481],{},"every()","：是否所有元素都符合條件",[22,18484,18486],{"className":24,"code":18485,"language":26,"meta":27,"style":27},"var allEven = numbers.every(function (number) {\n  return number % 2 === 0;\n});\n",[29,18487,18488,18512,18528],{"__ignoreMap":27},[32,18489,18490,18492,18495,18497,18499,18502,18504,18506,18508,18510],{"class":34,"line":35},[32,18491,166],{"class":38},[32,18493,18494],{"class":41}," allEven ",[32,18496,172],{"class":38},[32,18498,18176],{"class":41},[32,18500,18501],{"class":217},"every",[32,18503,477],{"class":41},[32,18505,665],{"class":38},[32,18507,900],{"class":41},[32,18509,18187],{"class":903},[32,18511,520],{"class":41},[32,18513,18514,18516,18518,18520,18522,18524,18526],{"class":34,"line":45},[32,18515,10974],{"class":38},[32,18517,18196],{"class":41},[32,18519,14129],{"class":38},[32,18521,10982],{"class":351},[32,18523,994],{"class":38},[32,18525,1523],{"class":351},[32,18527,96],{"class":41},[32,18529,18530],{"class":34,"line":51},[32,18531,792],{"class":41},[15,18533,18535,18537],{"id":18534},"sort依比較函式排序",[29,18536,15368],{},"：依比較函式排序",[22,18539,18541],{"className":24,"code":18540,"language":26,"meta":27,"style":27},"var members = [{ year: 27 }, { year: 14 }, { year: 50 }];\n\nmembers.sort(function (a, b) {\n  return a.year - b.year;\n});\n",[29,18542,18543,18572,18576,18597,18609],{"__ignoreMap":27},[32,18544,18545,18547,18550,18552,18555,18558,18561,18564,18566,18569],{"class":34,"line":35},[32,18546,166],{"class":38},[32,18548,18549],{"class":41}," members ",[32,18551,172],{"class":38},[32,18553,18554],{"class":41}," [{ year: ",[32,18556,18557],{"class":351},"27",[32,18559,18560],{"class":41}," }, { year: ",[32,18562,18563],{"class":351},"14",[32,18565,18560],{"class":41},[32,18567,18568],{"class":351},"50",[32,18570,18571],{"class":41}," }];\n",[32,18573,18574],{"class":34,"line":45},[32,18575,103],{"emptyLinePlaceholder":102},[32,18577,18578,18581,18583,18585,18587,18589,18591,18593,18595],{"class":34,"line":51},[32,18579,18580],{"class":41},"members.",[32,18582,15290],{"class":217},[32,18584,477],{"class":41},[32,18586,665],{"class":38},[32,18588,900],{"class":41},[32,18590,412],{"class":903},[32,18592,635],{"class":41},[32,18594,15299],{"class":903},[32,18596,520],{"class":41},[32,18598,18599,18601,18604,18606],{"class":34,"line":90},[32,18600,10974],{"class":38},[32,18602,18603],{"class":41}," a.year ",[32,18605,6628],{"class":38},[32,18607,18608],{"class":41}," b.year;\n",[32,18610,18611],{"class":34,"line":99},[32,18612,792],{"class":41},[15,18614,18616,18619],{"id":18615},"reduce依規則縮減陣列",[29,18617,18618],{},"reduce()","：依規則縮減陣列",[11,18621,18622],{},"每次取出一個值，和暫存結果一起運算；可以用在加總、分類或組合字串。",[22,18624,18626],{"className":24,"code":18625,"language":26,"meta":27,"style":27},"var books = [{ price: 10 }, { price: 20 }, { price: 30 }];\nvar total = books.reduce(function (sum, book) {\n  return sum + book.price;\n}, 0);\n",[29,18627,18628,18654,18684,18695],{"__ignoreMap":27},[32,18629,18630,18632,18635,18637,18640,18642,18645,18648,18650,18652],{"class":34,"line":35},[32,18631,166],{"class":38},[32,18633,18634],{"class":41}," books ",[32,18636,172],{"class":38},[32,18638,18639],{"class":41}," [{ price: ",[32,18641,11229],{"class":351},[32,18643,18644],{"class":41}," }, { price: ",[32,18646,18647],{"class":351},"20",[32,18649,18644],{"class":41},[32,18651,16517],{"class":351},[32,18653,18571],{"class":41},[32,18655,18656,18658,18661,18663,18666,18669,18671,18673,18675,18678,18680,18682],{"class":34,"line":45},[32,18657,166],{"class":38},[32,18659,18660],{"class":41}," total ",[32,18662,172],{"class":38},[32,18664,18665],{"class":41}," books.",[32,18667,18668],{"class":217},"reduce",[32,18670,477],{"class":41},[32,18672,665],{"class":38},[32,18674,900],{"class":41},[32,18676,18677],{"class":903},"sum",[32,18679,635],{"class":41},[32,18681,18086],{"class":903},[32,18683,520],{"class":41},[32,18685,18686,18688,18691,18693],{"class":34,"line":51},[32,18687,10974],{"class":38},[32,18689,18690],{"class":41}," sum ",[32,18692,224],{"class":38},[32,18694,18103],{"class":41},[32,18696,18697,18700,18702],{"class":34,"line":90},[32,18698,18699],{"class":41},"}, ",[32,18701,11881],{"class":351},[32,18703,230],{"class":41},[15,18705,2004],{"id":2003},[11,18707,18708,18709,18711,18712,18714],{},"原筆記中的 ",[29,18710,15368],{}," 比較函式回傳布林值，這不符合比較函式應回傳負數、零或正數的規則，整理時改成數值相減。",[29,18713,15368],{}," 會直接改變原陣列；其餘方法是否改到原資料，也取決於 callback 裡有沒有修改物件。",[368,18716,18717],{},"html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}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 .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}",{"title":27,"searchDepth":51,"depth":51,"links":18719},[18720,18722,18724,18726,18728,18730,18732,18734,18736],{"id":18050,"depth":45,"text":18721},"forEach()：對每個元素執行動作",{"id":18110,"depth":45,"text":18723},"map()：把執行結果存到新陣列",{"id":18258,"depth":45,"text":18725},"filter()：留下符合條件的元素",{"id":18321,"depth":45,"text":18727},"find()：找到第一個符合條件的元素",{"id":18422,"depth":45,"text":18729},"some()：是否有元素符合條件",{"id":18478,"depth":45,"text":18731},"every()：是否所有元素都符合條件",{"id":18534,"depth":45,"text":18733},"sort()：依比較函式排序",{"id":18615,"depth":45,"text":18735},"reduce()：依規則縮減陣列",{"id":2003,"depth":45,"text":2004},"整理 2020 年學習的八個 JavaScript 陣列方法及簡短範例。",{},"\u002Fposts\u002Fjs-array-methods","2020-08-20",[],{"title":18045,"description":18737},"posts\u002F20200820.js-array-methods",[390,15395],"_ldSkMazg7nH74MRxLeV_Iz3PV2tNbCNe_Pp9O_RDpQ",{"id":18747,"title":18748,"body":18749,"category":4012,"description":19050,"draft":380,"extension":381,"image":382,"meta":19051,"navigation":102,"path":19052,"publishedAt":19053,"relatedExperiments":19054,"seo":19055,"stem":19056,"tags":19057,"updatedAt":14272,"__hash__":19060},"posts\u002Fposts\u002F20200827.http-status-codes.md","HTTP 狀態碼整理：開發時真正會用到的那幾個",{"type":8,"value":18750,"toc":19041},[18751,18758,18762,18776,18780,18830,18834,18878,18882,18968,18972,19010,19013,19029,19031],[11,18752,18753,18754,18757],{},"狀態碼要熟悉。當時先記下 ",[29,18755,18756],{},"302"," 可以用在重新導向，例如 HTTP 轉到 HTTPS，並整理 HTTP 狀態碼的五大分類。",[15,18759,18761],{"id":18760},"_1xx參考資訊","1xx：參考資訊",[4538,18763,18764,18770],{},[4541,18765,18766,18769],{},[29,18767,18768],{},"100 Continue","：繼續",[4541,18771,18772,18775],{},[29,18773,18774],{},"101 Switching Protocols","：切換通訊協定",[15,18777,18779],{"id":18778},"_2xx成功","2xx：成功",[4538,18781,18782,18788,18794,18800,18806,18812,18818,18824],{},[4541,18783,18784,18787],{},[29,18785,18786],{},"200 OK","：請求成功",[4541,18789,18790,18793],{},[29,18791,18792],{},"201 Created","：已建立",[4541,18795,18796,18799],{},[29,18797,18798],{},"202 Accepted","：已接受",[4541,18801,18802,18805],{},[29,18803,18804],{},"203 Non-Authoritative Information","：非授權資訊",[4541,18807,18808,18811],{},[29,18809,18810],{},"204 No Content","：無內容",[4541,18813,18814,18817],{},[29,18815,18816],{},"205 Reset Content","：重設內容",[4541,18819,18820,18823],{},[29,18821,18822],{},"206 Partial Content","：部分內容",[4541,18825,18826,18829],{},[29,18827,18828],{},"207 Multi-Status","：多重狀態（WebDAV）",[15,18831,18833],{"id":18832},"_3xx重新導向","3xx：重新導向",[4538,18835,18836,18842,18848,18854,18860,18866,18872],{},[4541,18837,18838,18841],{},[29,18839,18840],{},"301 Moved Permanently","：資源永久改變網址",[4541,18843,18844,18847],{},[29,18845,18846],{},"302 Found","：資源暫時位於不同網址",[4541,18849,18850,18853],{},[29,18851,18852],{},"303 See Other","：改到另一個網址查看結果，常見於 POST 後改用 GET",[4541,18855,18856,18859],{},[29,18857,18858],{},"304 Not Modified","：內容未變更，可使用本機快取",[4541,18861,18862,18865],{},[29,18863,18864],{},"305 Use Proxy","：需透過指定 Proxy",[4541,18867,18868,18871],{},[29,18869,18870],{},"306","：未使用",[4541,18873,18874,18877],{},[29,18875,18876],{},"307 Temporary Redirect","：暫時重新導向",[15,18879,18881],{"id":18880},"_4xx用戶端錯誤","4xx：用戶端錯誤",[4538,18883,18884,18890,18896,18902,18908,18914,18920,18926,18932,18938,18944,18950,18956,18962],{},[4541,18885,18886,18889],{},[29,18887,18888],{},"400 Bad Request","：錯誤的請求",[4541,18891,18892,18895],{},[29,18893,18894],{},"401 Unauthorized","：需要驗證",[4541,18897,18898,18901],{},[29,18899,18900],{},"403 Forbidden","：禁止存取",[4541,18903,18904,18907],{},[29,18905,18906],{},"404 Not Found","：找不到資源",[4541,18909,18910,18913],{},[29,18911,18912],{},"405 Method Not Allowed","：不允許使用這個 HTTP 方法",[4541,18915,18916,18919],{},[29,18917,18918],{},"406 Not Acceptable","：無法提供用戶端接受的內容",[4541,18921,18922,18925],{},[29,18923,18924],{},"407 Proxy Authentication Required","：需要 Proxy 驗證",[4541,18927,18928,18931],{},[29,18929,18930],{},"412 Precondition Failed","：指定條件失敗",[4541,18933,18934,18937],{},[29,18935,18936],{},"413 Content Too Large","：請求內容太大",[4541,18939,18940,18943],{},[29,18941,18942],{},"414 URI Too Long","：URI 太長",[4541,18945,18946,18949],{},[29,18947,18948],{},"415 Unsupported Media Type","：不支援的媒體類型",[4541,18951,18952,18955],{},[29,18953,18954],{},"416 Range Not Satisfiable","：無法滿足要求的範圍",[4541,18957,18958,18961],{},[29,18959,18960],{},"417 Expectation Failed","：無法滿足 Expect 標頭",[4541,18963,18964,18967],{},[29,18965,18966],{},"423 Locked","：資源已鎖定",[15,18969,18971],{"id":18970},"_5xx伺服器錯誤","5xx：伺服器錯誤",[4538,18973,18974,18980,18986,18992,18998,19004],{},[4541,18975,18976,18979],{},[29,18977,18978],{},"500 Internal Server Error","：內部伺服器錯誤",[4541,18981,18982,18985],{},[29,18983,18984],{},"501 Not Implemented","：伺服器未實作要求的功能",[4541,18987,18988,18991],{},[29,18989,18990],{},"502 Bad Gateway","：閘道或 Proxy 收到無效回應",[4541,18993,18994,18997],{},[29,18995,18996],{},"503 Service Unavailable","：服務無法使用",[4541,18999,19000,19003],{},[29,19001,19002],{},"504 Gateway Timeout","：閘道逾時",[4541,19005,19006,19009],{},[29,19007,19008],{},"505 HTTP Version Not Supported","：不支援的 HTTP 版本",[15,19011,19012],{"id":19012},"當時參考的資料",[4538,19014,19015,19022],{},[4541,19016,19017],{},[412,19018,19021],{"href":19019,"rel":19020},"https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002FHTTP%E7%8A%B6%E6%80%81%E7%A0%81",[416],"HTTP 狀態碼",[4541,19023,19024],{},[412,19025,19028],{"href":19026,"rel":19027},"https:\u002F\u002Fblog.miniasp.com\u002Fpost\u002F2009\u002F01\u002F16\u002FWeb-developer-should-know-about-HTTP-Status-Code",[416],"Web 開發人員應了解的 HTTP 狀態碼",[15,19030,2004],{"id":2003},[11,19032,19033,19034,19037,19038,3775],{},"原稿還列了許多舊版 IIS 專屬的子狀態碼；整理時保留通用代碼，IIS 細節應依實際版本文件查詢。狀態碼的正式名稱與語意也應以現行 HTTP 規格為準，例如 ",[29,19035,19036],{},"413"," 現行名稱是 ",[29,19039,19040],{},"Content Too Large",{"title":27,"searchDepth":51,"depth":51,"links":19042},[19043,19044,19045,19046,19047,19048,19049],{"id":18760,"depth":45,"text":18761},{"id":18778,"depth":45,"text":18779},{"id":18832,"depth":45,"text":18833},{"id":18880,"depth":45,"text":18881},{"id":18970,"depth":45,"text":18971},{"id":19012,"depth":45,"text":19012},{"id":2003,"depth":45,"text":2004},"2020 年學習 HTTP 狀態碼時，留下的五大分類與常見代碼筆記。",{},"\u002Fposts\u002Fhttp-status-codes","2020-08-27",[],{"title":18748,"description":19050},"posts\u002F20200827.http-status-codes",[19058,19059],"HTTP","網路","Ctl9Eib9vFTbSutTM5DvSJaUN0L8dCalHextyjIk_dY",{"id":19062,"title":19063,"body":19064,"category":378,"description":19292,"draft":380,"extension":381,"image":382,"meta":19293,"navigation":102,"path":19294,"publishedAt":19053,"relatedExperiments":19295,"seo":19296,"stem":19297,"tags":19298,"updatedAt":14272,"__hash__":19300},"posts\u002Fposts\u002F20200827.nuxt-middleware-auth.md","Nuxt 2 Middleware：進頁面前做登入驗證",{"type":8,"value":19065,"toc":19286},[19066,19069,19072,19076,19082,19185,19188,19253,19256,19258,19274,19276,19283],[11,19067,19068],{},"最近接觸 Nuxt，覺得有點棘手，所以持續記錄 middleware 的使用方式。",[11,19070,19071],{},"Vue 專案可以使用 Vue Router 的導航守衛；Nuxt 則提供 middleware，在使用者進入頁面前先做篩選與必要驗證。",[15,19073,19075],{"id":19074},"新增-middleware","新增 middleware",[11,19077,5134,19078,19081],{},[29,19079,19080],{},"middleware"," 資料夾新增 JavaScript 檔案：",[22,19083,19085],{"className":24,"code":19084,"language":26,"meta":27,"style":27},"\u002F\u002F middleware\u002Fauth.js\nexport default function ({ route, redirect }) {\n  if (route.meta[0].requiresAuth) {\n    const isAuthenticated = false;\n\n    if (!isAuthenticated) {\n      return redirect(\"\u002F\");\n    }\n  }\n}\n",[29,19086,19087,19092,19116,19128,19142,19146,19158,19173,19177,19181],{"__ignoreMap":27},[32,19088,19089],{"class":34,"line":35},[32,19090,19091],{"class":608},"\u002F\u002F middleware\u002Fauth.js\n",[32,19093,19094,19096,19098,19100,19103,19106,19108,19111,19114],{"class":34,"line":45},[32,19095,5038],{"class":38},[32,19097,5041],{"class":38},[32,19099,897],{"class":38},[32,19101,19102],{"class":5049}," ({ ",[32,19104,19105],{"class":903},"route",[32,19107,635],{"class":5049},[32,19109,19110],{"class":903},"redirect",[32,19112,19113],{"class":5049}," }) ",[32,19115,5252],{"class":41},[32,19117,19118,19120,19123,19125],{"class":34,"line":51},[32,19119,1021],{"class":38},[32,19121,19122],{"class":41}," (route.meta[",[32,19124,11881],{"class":351},[32,19126,19127],{"class":41},"].requiresAuth) {\n",[32,19129,19130,19132,19135,19137,19140],{"class":34,"line":90},[32,19131,9409],{"class":38},[32,19133,19134],{"class":351}," isAuthenticated",[32,19136,894],{"class":38},[32,19138,19139],{"class":351}," false",[32,19141,96],{"class":41},[32,19143,19144],{"class":34,"line":99},[32,19145,103],{"emptyLinePlaceholder":102},[32,19147,19148,19150,19152,19155],{"class":34,"line":106},[32,19149,5554],{"class":38},[32,19151,900],{"class":41},[32,19153,19154],{"class":38},"!",[32,19156,19157],{"class":41},"isAuthenticated) {\n",[32,19159,19160,19163,19166,19168,19171],{"class":34,"line":114},[32,19161,19162],{"class":38},"      return",[32,19164,19165],{"class":217}," redirect",[32,19167,477],{"class":41},[32,19169,19170],{"class":175},"\"\u002F\"",[32,19172,230],{"class":41},[32,19174,19175],{"class":34,"line":120},[32,19176,5591],{"class":41},[32,19178,19179],{"class":34,"line":127},[32,19180,1203],{"class":41},[32,19182,19183],{"class":34,"line":132},[32,19184,54],{"class":41},[15,19186,19187],{"id":19187},"在頁面使用",[22,19189,19191],{"className":8665,"code":19190,"language":4112,"meta":27,"style":27},"\u003Cscript>\nexport default {\n  middleware: \"auth\",\n  meta: {\n    requiresAuth: true,\n  },\n};\n\u003C\u002Fscript>\n",[29,19192,19193,19201,19209,19219,19224,19233,19239,19245],{"__ignoreMap":27},[32,19194,19195,19197,19199],{"class":34,"line":35},[32,19196,4046],{"class":41},[32,19198,4125],{"class":4049},[32,19200,4062],{"class":41},[32,19202,19203,19205,19207],{"class":34,"line":45},[32,19204,5038],{"class":38},[32,19206,5041],{"class":38},[32,19208,703],{"class":5049},[32,19210,19211,19214,19217],{"class":34,"line":51},[32,19212,19213],{"class":41},"  middleware: ",[32,19215,19216],{"class":175},"\"auth\"",[32,19218,547],{"class":5049},[32,19220,19221],{"class":34,"line":90},[32,19222,19223],{"class":41},"  meta: {\n",[32,19225,19226,19229,19231],{"class":34,"line":99},[32,19227,19228],{"class":41},"    requiresAuth: ",[32,19230,6206],{"class":351},[32,19232,547],{"class":41},[32,19234,19235,19237],{"class":34,"line":106},[32,19236,9758],{"class":41},[32,19238,547],{"class":5049},[32,19240,19241,19243],{"class":34,"line":114},[32,19242,9765],{"class":5049},[32,19244,96],{"class":41},[32,19246,19247,19249,19251],{"class":34,"line":120},[32,19248,4105],{"class":41},[32,19250,4125],{"class":4049},[32,19252,4062],{"class":41},[11,19254,19255],{},"沒有通過驗證時，就會導向 middleware 設定的頁面。",[15,19257,19012],{"id":19012},[4538,19259,19260,19267],{},[4541,19261,19262],{},[412,19263,19266],{"href":19264,"rel":19265},"https:\u002F\u002Fhsiangfeng.github.io\u002Fvue\u002F20190816\u002F3627128539\u002F",[416],"Nuxt middleware 使用方式",[4541,19268,19269],{},[412,19270,19273],{"href":19271,"rel":19272},"https:\u002F\u002Fgithub.com\u002Fhsiangfeng\u002FNuxt-routeAuth\u002Ftree\u002Fmaster\u002Fmiddleware",[416],"Nuxt routeAuth 範例",[15,19275,2004],{"id":2003},[11,19277,19278,19279,19282],{},"這是 Nuxt 2 的舊寫法。Nuxt 3 改用 route middleware API，不能直接沿用 ",[29,19280,19281],{},"route.meta[0]","。此外，前端 middleware 只能控制畫面導向，真正受保護的資料與操作仍必須由後端驗證權限。",[368,19284,19285],{},"html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}",{"title":27,"searchDepth":51,"depth":51,"links":19287},[19288,19289,19290,19291],{"id":19074,"depth":45,"text":19075},{"id":19187,"depth":45,"text":19187},{"id":19012,"depth":45,"text":19012},{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 middleware 檔案驗證頁面權限，未通過時重新導向的做法。",{},"\u002Fposts\u002Fnuxt-middleware-auth",[],{"title":19063,"description":19292},"posts\u002F20200827.nuxt-middleware-auth",[15195,19299],"驗證","F_fTLdu7pBcIoVh3ojEudz2B_S1VCD2oUUDbC1yjIzs",{"id":19302,"title":19303,"body":19304,"category":378,"description":19413,"draft":380,"extension":381,"image":382,"meta":19414,"navigation":102,"path":19415,"publishedAt":19416,"relatedExperiments":19417,"seo":19418,"stem":19419,"tags":19420,"updatedAt":14272,"__hash__":19422},"posts\u002Fposts\u002F20200830.nuxt-config-redirect.md","Nuxt 2 設定重新導向：nuxt.config.js 的 extendRoutes",{"type":8,"value":19305,"toc":19410},[19306,19309,19315,19394,19396,19407],[11,19307,19308],{},"這邊記錄 router 重新導向。",[11,19310,19311,19312,19314],{},"可以在 ",[29,19313,17897],{}," 新增重新導向，但比較麻煩的是修改後要重啟伺服器：",[22,19316,19318],{"className":24,"code":19317,"language":26,"meta":27,"style":27},"export default {\n  router: {\n    extendRoutes(routes) {\n      routes.push({\n        path: \"\u002F\",\n        redirect: \"\u002FLogin\",\n      });\n    },\n  },\n};\n",[29,19319,19320,19328,19333,19345,19355,19364,19374,19378,19382,19388],{"__ignoreMap":27},[32,19321,19322,19324,19326],{"class":34,"line":35},[32,19323,5038],{"class":38},[32,19325,5041],{"class":38},[32,19327,703],{"class":5049},[32,19329,19330],{"class":34,"line":45},[32,19331,19332],{"class":41},"  router: {\n",[32,19334,19335,19338,19340,19343],{"class":34,"line":51},[32,19336,19337],{"class":217},"    extendRoutes",[32,19339,477],{"class":41},[32,19341,19342],{"class":903},"routes",[32,19344,520],{"class":41},[32,19346,19347,19350,19353],{"class":34,"line":90},[32,19348,19349],{"class":41},"      routes.",[32,19351,19352],{"class":217},"push",[32,19354,1143],{"class":41},[32,19356,19357,19360,19362],{"class":34,"line":99},[32,19358,19359],{"class":41},"        path: ",[32,19361,19170],{"class":175},[32,19363,547],{"class":41},[32,19365,19366,19369,19372],{"class":34,"line":106},[32,19367,19368],{"class":41},"        redirect: ",[32,19370,19371],{"class":175},"\"\u002FLogin\"",[32,19373,547],{"class":41},[32,19375,19376],{"class":34,"line":114},[32,19377,17132],{"class":41},[32,19379,19380],{"class":34,"line":120},[32,19381,4204],{"class":41},[32,19383,19384,19386],{"class":34,"line":127},[32,19385,9758],{"class":41},[32,19387,547],{"class":5049},[32,19389,19390,19392],{"class":34,"line":132},[32,19391,9765],{"class":5049},[32,19393,96],{"class":41},[15,19395,2004],{"id":2003},[11,19397,19398,19399,19402,19403,19406],{},"這是 Nuxt 2 的 ",[29,19400,19401],{},"extendRoutes"," 寫法。Nuxt 3／4 可依部署需求使用 ",[29,19404,19405],{},"routeRules","、route middleware 或伺服器端路由處理重新導向；應選擇會回傳正確 HTTP 狀態碼、符合 SEO 與快取需求的方式。",[368,19408,19409],{},"html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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);}",{"title":27,"searchDepth":51,"depth":51,"links":19411},[19412],{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 nuxt.config.js 新增重新導向規則，以及修改後要重啟伺服器的情況。",{},"\u002Fposts\u002Fnuxt-config-redirect","2020-08-30",[],{"title":19303,"description":19413},"posts\u002F20200830.nuxt-config-redirect",[15195,19421],"重新導向","8_DfYaO6cgP5oRwnUs-L8BdV_she-Rv4KBQDJtvPaxk",{"id":19424,"title":19425,"body":19426,"category":378,"description":19547,"draft":380,"extension":381,"image":382,"meta":19548,"navigation":102,"path":19549,"publishedAt":19550,"relatedExperiments":19551,"seo":19552,"stem":19553,"tags":19554,"updatedAt":14272,"__hash__":19556},"posts\u002Fposts\u002F20200901.nuxt-cors-proxy-module.md","Nuxt 2 解決 CORS：用 @nuxtjs\u002Fproxy 把 Nuxt 當成代理伺服器",{"type":8,"value":19427,"toc":19543},[19428,19431,19434,19437,19440,19454,19460,19536,19538,19541],[11,19429,19430],{},"這邊記錄使用 axios 串接後端 API 時遇到的 CORS 問題。",[11,19432,19433],{},"CORS（Cross-Origin Resource Sharing，跨來源資源共用）基於瀏覽器的安全性考量，載入其他網域的資源時會受到限制。當後端 API 沒有提供允許跨來源存取的設定時，就必須採取其他方法。",[11,19435,19436],{},"安裝 proxy 後，可以把 Nuxt 的 Web Server 當成 Proxy Server。瀏覽器先向提供網頁的伺服器發出請求，再由它向真正的後端伺服器取得資料。",[15,19438,19439],{"id":19439},"安裝",[22,19441,19443],{"className":2057,"code":19442,"language":2059,"meta":27,"style":27},"npm install @nuxtjs\u002Fproxy\n",[29,19444,19445],{"__ignoreMap":27},[32,19446,19447,19449,19451],{"class":34,"line":35},[32,19448,4625],{"class":2066},[32,19450,4650],{"class":175},[32,19452,19453],{"class":175}," @nuxtjs\u002Fproxy\n",[11,19455,19456,19457,19459],{},"安裝完成後，在 ",[29,19458,17897],{}," 設定：",[22,19461,19463],{"className":24,"code":19462,"language":26,"meta":27,"style":27},"export default {\n  modules: [\"@nuxtjs\u002Fproxy\"],\n  proxy: {\n    \"\u002Fapi\u002F\": {\n      target: \"https:\u002F\u002Fbackend.example.com\",\n      pathRewrite: { \"^\u002Fapi\u002F\": \"\" },\n    },\n  },\n};\n",[29,19464,19465,19473,19484,19489,19496,19506,19520,19524,19530],{"__ignoreMap":27},[32,19466,19467,19469,19471],{"class":34,"line":35},[32,19468,5038],{"class":38},[32,19470,5041],{"class":38},[32,19472,703],{"class":5049},[32,19474,19475,19477,19480,19482],{"class":34,"line":45},[32,19476,17916],{"class":41},[32,19478,19479],{"class":175},"\"@nuxtjs\u002Fproxy\"",[32,19481,17922],{"class":41},[32,19483,547],{"class":5049},[32,19485,19486],{"class":34,"line":51},[32,19487,19488],{"class":41},"  proxy: {\n",[32,19490,19491,19494],{"class":34,"line":90},[32,19492,19493],{"class":175},"    \"\u002Fapi\u002F\"",[32,19495,5261],{"class":41},[32,19497,19498,19501,19504],{"class":34,"line":99},[32,19499,19500],{"class":41},"      target: ",[32,19502,19503],{"class":175},"\"https:\u002F\u002Fbackend.example.com\"",[32,19505,547],{"class":41},[32,19507,19508,19511,19514,19516,19518],{"class":34,"line":106},[32,19509,19510],{"class":41},"      pathRewrite: { ",[32,19512,19513],{"class":175},"\"^\u002Fapi\u002F\"",[32,19515,5269],{"class":41},[32,19517,7268],{"class":175},[32,19519,15235],{"class":41},[32,19521,19522],{"class":34,"line":114},[32,19523,4204],{"class":41},[32,19525,19526,19528],{"class":34,"line":120},[32,19527,9758],{"class":41},[32,19529,547],{"class":5049},[32,19531,19532,19534],{"class":34,"line":127},[32,19533,9765],{"class":5049},[32,19535,96],{"class":41},[15,19537,2004],{"id":2003},[11,19539,19540],{},"這是 Nuxt 2 的模組與設定方式，不能直接套用到 Nuxt 3／4。代理只能轉送事先限定的 API，不應做成接受任意網址的通用 Proxy；若涉及機密金鑰，也只能在伺服器端讀取。",[368,19542,17948],{},{"title":27,"searchDepth":51,"depth":51,"links":19544},[19545,19546],{"id":19439,"depth":45,"text":19439},{"id":2003,"depth":45,"text":2004},"記錄串接後端 API 遇到 CORS 時，安裝 @nuxtjs\u002Fproxy 轉送請求的方式。",{},"\u002Fposts\u002Fnuxt-cors-proxy-module","2020-09-01",[],{"title":19425,"description":19547},"posts\u002F20200901.nuxt-cors-proxy-module",[15195,19555],"CORS","-gRCSDkflIsgshPt_q3XQzrct4u-ZbPTNbM5nSNqPk8",{"id":19558,"title":19559,"body":19560,"category":378,"description":19930,"draft":380,"extension":381,"image":382,"meta":19931,"navigation":102,"path":19932,"publishedAt":19933,"relatedExperiments":19934,"seo":19935,"stem":19936,"tags":19937,"updatedAt":14272,"__hash__":19938},"posts\u002Fposts\u002F20200908.vee-validate-v3-setup.md","vee-validate 表單驗證安裝紀錄（v3，Options API）",{"type":8,"value":19561,"toc":19923},[19562,19565,19568,19584,19590,19714,19717,19720,19774,19777,19784,19850,19853,19856,19862,19868,19908,19915,19917,19920],[11,19563,19564],{},"最近調整驗證表單時使用 vee-validate，遇到一些挫折，研究了幾天，在這邊簡單記錄。",[15,19566,19567],{"id":19567},"安裝與導入",[22,19569,19571],{"className":2057,"code":19570,"language":2059,"meta":27,"style":27},"npm install vee-validate --save\n",[29,19572,19573],{"__ignoreMap":27},[32,19574,19575,19577,19579,19582],{"class":34,"line":35},[32,19576,4625],{"class":2066},[32,19578,4650],{"class":175},[32,19580,19581],{"class":175}," vee-validate",[32,19583,8638],{"class":351},[11,19585,19586,19587,19589],{},"建立 plugin，並在 ",[29,19588,17897],{}," 引入。當時的基本導入方式：",[22,19591,19593],{"className":24,"code":19592,"language":26,"meta":27,"style":27},"import Vue from \"vue\";\nimport {\n  ValidationObserver,\n  ValidationProvider,\n  extend,\n} from \"vee-validate\";\nimport { email, required } from \"vee-validate\u002Fdist\u002Frules\";\n\nextend(\"required\", required);\nextend(\"email\", email);\n\nVue.component(\"ValidationObserver\", ValidationObserver);\nVue.component(\"ValidationProvider\", ValidationProvider);\n",[29,19594,19595,19607,19613,19618,19623,19628,19639,19653,19657,19670,19682,19686,19700],{"__ignoreMap":27},[32,19596,19597,19599,19601,19603,19605],{"class":34,"line":35},[32,19598,8794],{"class":38},[32,19600,8847],{"class":41},[32,19602,8850],{"class":38},[32,19604,17669],{"class":175},[32,19606,96],{"class":41},[32,19608,19609,19611],{"class":34,"line":45},[32,19610,8794],{"class":38},[32,19612,703],{"class":41},[32,19614,19615],{"class":34,"line":51},[32,19616,19617],{"class":41},"  ValidationObserver,\n",[32,19619,19620],{"class":34,"line":90},[32,19621,19622],{"class":41},"  ValidationProvider,\n",[32,19624,19625],{"class":34,"line":99},[32,19626,19627],{"class":41},"  extend,\n",[32,19629,19630,19632,19634,19637],{"class":34,"line":106},[32,19631,562],{"class":41},[32,19633,8850],{"class":38},[32,19635,19636],{"class":175}," \"vee-validate\"",[32,19638,96],{"class":41},[32,19640,19641,19643,19646,19648,19651],{"class":34,"line":114},[32,19642,8794],{"class":38},[32,19644,19645],{"class":41}," { email, required } ",[32,19647,8850],{"class":38},[32,19649,19650],{"class":175}," \"vee-validate\u002Fdist\u002Frules\"",[32,19652,96],{"class":41},[32,19654,19655],{"class":34,"line":120},[32,19656,103],{"emptyLinePlaceholder":102},[32,19658,19659,19662,19664,19667],{"class":34,"line":127},[32,19660,19661],{"class":217},"extend",[32,19663,477],{"class":41},[32,19665,19666],{"class":175},"\"required\"",[32,19668,19669],{"class":41},", required);\n",[32,19671,19672,19674,19676,19679],{"class":34,"line":132},[32,19673,19661],{"class":217},[32,19675,477],{"class":41},[32,19677,19678],{"class":175},"\"email\"",[32,19680,19681],{"class":41},", email);\n",[32,19683,19684],{"class":34,"line":141},[32,19685,103],{"emptyLinePlaceholder":102},[32,19687,19688,19690,19692,19694,19697],{"class":34,"line":147},[32,19689,8892],{"class":41},[32,19691,9603],{"class":217},[32,19693,477],{"class":41},[32,19695,19696],{"class":175},"\"ValidationObserver\"",[32,19698,19699],{"class":41},", ValidationObserver);\n",[32,19701,19702,19704,19706,19708,19711],{"class":34,"line":275},[32,19703,8892],{"class":41},[32,19705,9603],{"class":217},[32,19707,477],{"class":41},[32,19709,19710],{"class":175},"\"ValidationProvider\"",[32,19712,19713],{"class":41},", ValidationProvider);\n",[15,19715,19716],{"id":19716},"欄位驗證",[11,19718,19719],{},"以 Email 為例：",[22,19721,19723],{"className":8665,"code":19722,"language":4112,"meta":27,"style":27},"\u003CValidationProvider rules=\"required|email\" v-slot=\"{ errors }\">\n  \u003Cinput v-model=\"email\" type=\"email\">\n  \u003Cspan>{{ errors[0] }}\u003C\u002Fspan>\n\u003C\u002FValidationProvider>\n",[29,19724,19725,19756,19761,19766],{"__ignoreMap":27},[32,19726,19727,19729,19732,19735,19737,19740,19743,19745,19749,19752,19754],{"class":34,"line":35},[32,19728,4046],{"class":41},[32,19730,19731],{"class":4049},"ValidationProvider",[32,19733,19734],{"class":4053}," rules",[32,19736,172],{"class":41},[32,19738,19739],{"class":175},"\"required|email\"",[32,19741,19742],{"class":4053}," v-slot",[32,19744,172],{"class":41},[32,19746,19748],{"class":19747},"spddc","\"",[32,19750,19751],{"class":41},"{ errors }",[32,19753,19748],{"class":19747},[32,19755,4062],{"class":41},[32,19757,19758],{"class":34,"line":45},[32,19759,19760],{"class":41},"  \u003Cinput v-model=\"email\" type=\"email\">\n",[32,19762,19763],{"class":34,"line":51},[32,19764,19765],{"class":41},"  \u003Cspan>{{ errors[0] }}\u003C\u002Fspan>\n",[32,19767,19768,19770,19772],{"class":34,"line":90},[32,19769,4105],{"class":41},[32,19771,19731],{"class":4049},[32,19773,4062],{"class":41},[15,19775,19776],{"id":19776},"表單送出",[11,19778,19779,19780,19783],{},"引入 ",[29,19781,19782],{},"ValidationObserver","，再把 form 包起來：",[22,19785,19787],{"className":8665,"code":19786,"language":4112,"meta":27,"style":27},"\u003CValidationObserver ref=\"observer\" tag=\"form\" @submit.prevent=\"submit\">\n  \u003C!-- 欄位 -->\n  \u003Cbutton type=\"submit\">送出\u003C\u002Fbutton>\n\u003C\u002FValidationObserver>\n",[29,19788,19789,19832,19837,19842],{"__ignoreMap":27},[32,19790,19791,19793,19795,19798,19800,19803,19806,19808,19811,19814,19817,19819,19822,19824,19826,19828,19830],{"class":34,"line":35},[32,19792,4046],{"class":41},[32,19794,19782],{"class":4049},[32,19796,19797],{"class":4053}," ref",[32,19799,172],{"class":41},[32,19801,19802],{"class":175},"\"observer\"",[32,19804,19805],{"class":4053}," tag",[32,19807,172],{"class":41},[32,19809,19810],{"class":175},"\"form\"",[32,19812,19813],{"class":41}," @",[32,19815,19816],{"class":4053},"submit",[32,19818,1278],{"class":41},[32,19820,19821],{"class":4053},"prevent",[32,19823,172],{"class":41},[32,19825,19748],{"class":19747},[32,19827,19816],{"class":41},[32,19829,19748],{"class":19747},[32,19831,4062],{"class":41},[32,19833,19834],{"class":34,"line":45},[32,19835,19836],{"class":41},"  \u003C!-- 欄位 -->\n",[32,19838,19839],{"class":34,"line":51},[32,19840,19841],{"class":41},"  \u003Cbutton type=\"submit\">送出\u003C\u002Fbutton>\n",[32,19843,19844,19846,19848],{"class":34,"line":90},[32,19845,4105],{"class":41},[32,19847,19782],{"class":4049},[32,19849,4062],{"class":41},[15,19851,19852],{"id":19852},"當時遇到的問題",[11,19854,19855],{},"匯入 validation rules 時遇到：",[22,19857,19860],{"className":19858,"code":19859,"language":426,"meta":27},[424],"Unexpected token export\n",[29,19861,19859],{"__ignoreMap":27},[11,19863,19864,19865,19867],{},"當時在 ",[29,19866,17897],{}," 把 rules 加進轉譯設定：",[22,19869,19871],{"className":24,"code":19870,"language":26,"meta":27,"style":27},"export default {\n  build: {\n    transpile: [\"vee-validate\u002Fdist\u002Frules\"],\n  },\n};\n",[29,19872,19873,19881,19886,19896,19902],{"__ignoreMap":27},[32,19874,19875,19877,19879],{"class":34,"line":35},[32,19876,5038],{"class":38},[32,19878,5041],{"class":38},[32,19880,703],{"class":5049},[32,19882,19883],{"class":34,"line":45},[32,19884,19885],{"class":41},"  build: {\n",[32,19887,19888,19891,19894],{"class":34,"line":51},[32,19889,19890],{"class":41},"    transpile: [",[32,19892,19893],{"class":175},"\"vee-validate\u002Fdist\u002Frules\"",[32,19895,8212],{"class":41},[32,19897,19898,19900],{"class":34,"line":90},[32,19899,9758],{"class":41},[32,19901,547],{"class":5049},[32,19903,19904,19906],{"class":34,"line":99},[32,19905,9765],{"class":5049},[32,19907,96],{"class":41},[11,19909,15356,19910],{},[412,19911,19914],{"href":19912,"rel":19913},"https:\u002F\u002Fvee-validate.logaretm.com\u002Fv3\u002Fguide\u002Fcomponents\u002Fvalidation-observer.html",[416],"vee-validate ValidationObserver",[15,19916,2004],{"id":2003},[11,19918,19919],{},"這是 Nuxt 2、Vue 2 與 vee-validate 3 的舊版寫法。新版 vee-validate 的 API、套件入口與 Nuxt 整合方式不同，不能把這份安裝步驟直接套用到新專案。",[368,19921,19922],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .spddc, html code.shiki .spddc{--shiki-default:#032F62;--shiki-dark:#E6EDF3}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}",{"title":27,"searchDepth":51,"depth":51,"links":19924},[19925,19926,19927,19928,19929],{"id":19567,"depth":45,"text":19567},{"id":19716,"depth":45,"text":19716},{"id":19776,"depth":45,"text":19776},{"id":19852,"depth":45,"text":19852},{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 安裝 vee-validate、驗證欄位與送出表單時遇到的設定問題。",{},"\u002Fposts\u002Fvee-validate-v3-setup","2020-09-08",[],{"title":19559,"description":19930},"posts\u002F20200908.vee-validate-v3-setup",[9778,4113,4572],"3wK4ROVk_XTfdji-uZUdCVyKroNd1vwJ705zXMn5nuA",{"id":19940,"title":19941,"body":19942,"category":378,"description":20135,"draft":380,"extension":381,"image":382,"meta":20136,"navigation":102,"path":20137,"publishedAt":20138,"relatedExperiments":20139,"seo":20140,"stem":20141,"tags":20142,"updatedAt":14272,"__hash__":20145},"posts\u002Fposts\u002F20200910.moment-vue-filter.md","用 moment.js 搭配 Vue 2 全域 filter 做日期格式化",{"type":8,"value":19943,"toc":20130},[19944,19947,19949,19963,19967,19977,20075,20081,20084,20102,20118,20120,20127],[11,19945,19946],{},"這邊記錄 moment 日期格式的使用方式。",[15,19948,19439],{"id":19439},[22,19950,19952],{"className":2057,"code":19951,"language":2059,"meta":27,"style":27},"npm install moment\n",[29,19953,19954],{"__ignoreMap":27},[32,19955,19956,19958,19960],{"class":34,"line":35},[32,19957,4625],{"class":2066},[32,19959,4650],{"class":175},[32,19961,19962],{"class":175}," moment\n",[15,19964,19966],{"id":19965},"建立-filter","建立 filter",[11,19968,7086,19969,19972,19973,19976],{},[29,19970,19971],{},"filter.js","，放在 ",[29,19974,19975],{},"plugins"," 資料夾：",[22,19978,19980],{"className":24,"code":19979,"language":26,"meta":27,"style":27},"import Vue from \"vue\";\nimport moment from \"moment\";\n\nVue.filter(\"dateFormat\", (value, format = \"YYYY-MM-DD\") => {\n  const datetime = moment(value);\n  return datetime.format(format);\n});\n",[29,19981,19982,19994,20008,20012,20044,20059,20071],{"__ignoreMap":27},[32,19983,19984,19986,19988,19990,19992],{"class":34,"line":35},[32,19985,8794],{"class":38},[32,19987,8847],{"class":41},[32,19989,8850],{"class":38},[32,19991,17669],{"class":175},[32,19993,96],{"class":41},[32,19995,19996,19998,20001,20003,20006],{"class":34,"line":45},[32,19997,8794],{"class":38},[32,19999,20000],{"class":41}," moment ",[32,20002,8850],{"class":38},[32,20004,20005],{"class":175}," \"moment\"",[32,20007,96],{"class":41},[32,20009,20010],{"class":34,"line":51},[32,20011,103],{"emptyLinePlaceholder":102},[32,20013,20014,20016,20018,20020,20023,20026,20028,20030,20033,20035,20038,20040,20042],{"class":34,"line":90},[32,20015,8892],{"class":41},[32,20017,15334],{"class":217},[32,20019,477],{"class":41},[32,20021,20022],{"class":175},"\"dateFormat\"",[32,20024,20025],{"class":41},", (",[32,20027,16695],{"class":903},[32,20029,635],{"class":41},[32,20031,20032],{"class":903},"format",[32,20034,894],{"class":38},[32,20036,20037],{"class":175}," \"YYYY-MM-DD\"",[32,20039,483],{"class":41},[32,20041,5090],{"class":38},[32,20043,703],{"class":41},[32,20045,20046,20048,20051,20053,20056],{"class":34,"line":99},[32,20047,4157],{"class":38},[32,20049,20050],{"class":351}," datetime",[32,20052,894],{"class":38},[32,20054,20055],{"class":217}," moment",[32,20057,20058],{"class":41},"(value);\n",[32,20060,20061,20063,20066,20068],{"class":34,"line":106},[32,20062,10974],{"class":38},[32,20064,20065],{"class":41}," datetime.",[32,20067,20032],{"class":217},[32,20069,20070],{"class":41},"(format);\n",[32,20072,20073],{"class":34,"line":114},[32,20074,792],{"class":41},[11,20076,20077,20078,20080],{},"再到 ",[29,20079,17897],{}," 引入這支 plugin。",[11,20082,20083],{},"模板使用方式：",[22,20085,20087],{"className":8665,"code":20086,"language":4112,"meta":27,"style":27},"\u003Cspan>{{ date | dateFormat(\"YYYY-MM-DD\") }}\u003C\u002Fspan>\n",[29,20088,20089],{"__ignoreMap":27},[32,20090,20091,20093,20095,20098,20100],{"class":34,"line":35},[32,20092,4046],{"class":41},[32,20094,32],{"class":4049},[32,20096,20097],{"class":41},">{{ date | dateFormat(\"YYYY-MM-DD\") }}\u003C\u002F",[32,20099,32],{"class":4049},[32,20101,4062],{"class":41},[4538,20103,20104,20111],{},[4541,20105,20106],{},[412,20107,20110],{"href":20108,"rel":20109},"https:\u002F\u002Fmomentjs.com\u002F",[416],"Moment.js",[4541,20112,20113],{},[412,20114,20117],{"href":20115,"rel":20116},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10208995",[416],"當時參考的 Vue filter 文章",[15,20119,2004],{"id":2003},[11,20121,20122,20123,20126],{},"這是 Vue 2 的全域 filter 語法；Vue 3 已移除 filters。Moment.js 目前仍可維護既有專案，但官方將它視為 legacy project，新功能通常會優先考慮原生 ",[29,20124,20125],{},"Intl"," 或其他日期工具。",[368,20128,20129],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}",{"title":27,"searchDepth":51,"depth":51,"links":20131},[20132,20133,20134],{"id":19439,"depth":45,"text":19439},{"id":19965,"depth":45,"text":19966},{"id":2003,"depth":45,"text":2004},"記錄安裝 moment.js，並在 Vue 2 全域 filter 格式化日期的方式。",{},"\u002Fposts\u002Fmoment-vue-filter","2020-09-10",[],{"title":19941,"description":20135},"posts\u002F20200910.moment-vue-filter",[4113,20143,20144],"moment.js","日期","pJQFFOlvHdwLszVBVKiHMzcIVHYF7X8BmVvJDriCvbo",{"id":20147,"title":20148,"body":20149,"category":378,"description":20364,"draft":380,"extension":381,"image":382,"meta":20365,"navigation":102,"path":20366,"publishedAt":20367,"relatedExperiments":20368,"seo":20369,"stem":20370,"tags":20371,"updatedAt":14272,"__hash__":20373},"posts\u002Fposts\u002F20220409.vue-cli4-project-setup.md","vue-cli4 專案建立",{"type":8,"value":20150,"toc":20355},[20151,20154,20157,20171,20176,20179,20182,20188,20191,20197,20200,20203,20209,20212,20218,20221,20227,20230,20236,20239,20247,20253,20258,20264,20267,20273,20276,20282,20285,20291,20294,20296,20306,20309,20353],[15,20152,20153],{"id":20153},"建立流程",[151,20155,20156],{"id":20156},"建立項目指令",[22,20158,20160],{"className":2057,"code":20159,"language":2059,"meta":27,"style":27},"vue create 專案名稱\n",[29,20161,20162],{"__ignoreMap":27},[32,20163,20164,20166,20168],{"class":34,"line":35},[32,20165,4112],{"class":2066},[32,20167,4799],{"class":175},[32,20169,20170],{"class":175}," 專案名稱\n",[2184,20172,20173],{},[11,20174,20175],{},"專案名稱不能有大寫字母。",[151,20177,20178],{"id":20178},"設定項目",[11,20180,20181],{},"選擇最後一個手動選擇：",[11,20183,20184],{},[10742,20185],{"alt":20186,"src":20187},"Vue CLI 4.5.13 的 preset 選單","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F01.png",[11,20189,20190],{},"手動選擇項目：",[11,20192,20193],{},[10742,20194],{"alt":20195,"src":20196},"Vue CLI 的功能勾選清單","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F02.png",[11,20198,20199],{},"Unit Testing 是 Vue.js 官方維護的單元測試套件，可搭配 Jest；Vue CLI 能自動配置所需環境。E2E Testing：",[11,20201,20202],{},"選擇 Vue 3 模式：",[11,20204,20205],{},[10742,20206],{"alt":20207,"src":20208},"Vue CLI 選擇 Vue.js 版本","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F03.png",[11,20210,20211],{},"選擇是否將 hash 模式寫在 router：",[11,20213,20214],{},[10742,20215],{"alt":20216,"src":20217},"Vue CLI 詢問是否使用 history mode","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F04.png",[11,20219,20220],{},"選擇 node-sass：",[11,20222,20223],{},[10742,20224],{"alt":20225,"src":20226},"Vue CLI 選擇 CSS 前處理器","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F05.png",[11,20228,20229],{},"選擇 Airbnb 模式：",[11,20231,20232],{},[10742,20233],{"alt":20234,"src":20235},"Vue CLI 選擇 linter 設定","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F06.png",[11,20237,20238],{},"選擇檢查程式碼的時機，Airbnb 檢查後修正錯誤再提交：",[4538,20240,20241,20244],{},[4541,20242,20243],{},"存檔時檢查",[4541,20245,20246],{},"提交時檢查",[11,20248,20249],{},[10742,20250],{"alt":20251,"src":20252},"Vue CLI 詢問 lint 功能","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F07.png",[11,20254,20255,20256,5240],{},"設定檔放在 ",[29,20257,4945],{},[11,20259,20260],{},[10742,20261],{"alt":20262,"src":20263},"Vue CLI 詢問設定檔放置位置","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F08.png",[11,20265,20266],{},"是否將剛才的設定做為一份預設檔案：",[11,20268,20269],{},[10742,20270],{"alt":20271,"src":20272},"Vue CLI 詢問是否儲存 preset","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F09.png",[11,20274,20275],{},"開始建立：",[11,20277,20278],{},[10742,20279],{"alt":20280,"src":20281},"Vue CLI 開始建立專案","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F10.png",[15,20283,20284],{"id":20284},"遇到的問題",[11,20286,20287],{},[10742,20288],{"alt":20289,"src":20290},"Vue CLI 顯示專案名稱不能有大寫字母","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F11.png",[11,20292,20293],{},"專案名稱不能使用大寫字母。",[15,20295,2004],{"id":2003},[11,20297,20298,20299,20301,20302,20305],{},"這是 2022 年 Vue CLI 4 的互動式建立流程，包含當時的 ",[29,20300,14993],{}," 選項。現在建立 Vue 專案通常會使用官方的 ",[29,20303,20304],{},"create-vue","／Vite 流程；不要直接照舊選項建立新專案。",[15,20307,20308],{"id":20308},"參考相關文件",[4538,20310,20311,20318,20325,20332,20339,20346],{},[4541,20312,20313],{},[412,20314,20317],{"href":20315,"rel":20316},"https:\u002F\u002Fmedium.com\u002Fweb-design-zone\u002F%E4%BD%BF%E7%94%A8vue-cli-%E5%BB%BA%E7%AB%8Bvue-router-%E5%B0%88%E6%A1%88-f37e4b037ef0",[416],"使用 Vue CLI 建立 Vue Router 專案",[4541,20319,20320],{},[412,20321,20324],{"href":20322,"rel":20323},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10277447",[416],"hash 與 history 模式",[4541,20326,20327],{},[412,20328,20331],{"href":20329,"rel":20330},"https:\u002F\u002Fcli.vuejs.org\u002Fzh\u002Fguide\u002Fcreating-a-project.html#vue-create",[416],"Vue CLI 官方文件",[4541,20333,20334],{},[412,20335,20338],{"href":20336,"rel":20337},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10216606",[416],"Vue CLI 3 安裝與建立 Vue 專案",[4541,20340,20341],{},[412,20342,20345],{"href":20343,"rel":20344},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10275591",[416],"Vue Test Utils + Jest",[4541,20347,20348],{},[412,20349,20352],{"href":20350,"rel":20351},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10279077",[416],"Cypress 基本介紹",[368,20354,12796],{},{"title":27,"searchDepth":51,"depth":51,"links":20356},[20357,20361,20362,20363],{"id":20153,"depth":45,"text":20153,"children":20358},[20359,20360],{"id":20156,"depth":51,"text":20156},{"id":20178,"depth":51,"text":20178},{"id":20284,"depth":45,"text":20284},{"id":2003,"depth":45,"text":2004},{"id":20308,"depth":45,"text":20308},"紀錄使用 Vue CLI 4 建立 Vue 專案時的選項。",{},"\u002Fposts\u002Fvue-cli4-project-setup","2022-04-09",[],{"title":20148,"description":20364},"posts\u002F20220409.vue-cli4-project-setup",[5396,20372,4853,4847],"Vue3","6Km4mCJ45YUPFqNKDT1nGh4debzFHpLrodCsFMXv0Bg",{"id":20375,"title":20376,"body":20377,"category":378,"description":22619,"draft":380,"extension":381,"image":382,"meta":22620,"navigation":102,"path":22621,"publishedAt":22622,"relatedExperiments":22623,"seo":22624,"stem":22625,"tags":22626,"updatedAt":14272,"__hash__":22628},"posts\u002Fposts\u002F20240505.pinia-vuex-state-management.md","Pinia \u002F Vuex 狀態管理及差異",{"type":8,"value":20378,"toc":22600},[20379,20382,20385,20389,20396,20399,20434,20437,20440,20443,20466,20470,20473,20476,20502,20505,20610,20617,20619,20623,20637,20641,20731,20735,20752,20757,20791,20794,20798,20801,21159,21168,21171,21448,21452,21458,21517,21528,21553,21557,21568,21948,21956,21959,22144,22150,22154,22157,22162,22328,22333,22513,22527,22530,22533,22536,22563,22566,22568,22571,22574,22597],[11,20380,20381],{},"元件之間要共用資料時，用 props 一層一層傳很快就會受不了。狀態管理就是把這些資料抽出來放在一個共用的地方。",[11,20383,20384],{},"Vue 生態裡先有 Vuex，後來有了 Pinia。這篇整理兩者的差異，以及 Pinia 實際怎麼寫。",[15,20386,20388],{"id":20387},"vuex-概要","Vuex 概要",[11,20390,20391,20392,20395],{},"Vuex 是 Vue 官方早期提供的狀態管理庫，核心是",[12249,20393,20394],{},"集中式存儲","：整個應用共用一棵狀態樹（store），各個元件都能存取或修改同一份狀態。",[11,20397,20398],{},"四個核心概念：",[6426,20400,20401,20407,20419,20428],{},[4541,20402,20403,20406],{},[12249,20404,20405],{},"State（狀態）","：響應式的物件，放應用層級的所有資料。元件透過 getter 讀取。",[4541,20408,20409,5240,20412,20415,20416,20418],{},[12249,20410,20411],{},"Mutation（突變）",[12249,20413,20414],{},"唯一","允許修改狀態的地方，而且必須是同步的。接收 ",[29,20417,16972],{}," 當第一個參數，加上可選的 payload。",[4541,20420,20421,20424,20425,20427],{},[12249,20422,20423],{},"Action（動作）","：處理非同步操作或批次呼叫多個 mutation。接收 ",[29,20426,7449],{}," 物件。",[4541,20429,20430,20433],{},[12249,20431,20432],{},"Module（模組）","：把 store 拆成模組，各自有自己的 state、mutations、actions、getters。",[11,20435,20436],{},"「非同步的事情放 action、真正改狀態的動作放 mutation」這個設計是為了讓每一次狀態變更都可追蹤——Vue DevTools 能列出每一個 mutation，出問題時倒著看就知道狀態是被誰改的。",[151,20438,20439],{"id":20439},"遇到的瓶頸",[11,20441,20442],{},"規模上來之後，這套設計的代價開始浮現：",[4538,20444,20445,20451,20457],{},[4541,20446,20447,20450],{},[12249,20448,20449],{},"模組結構讓狀態分散","在多個模組裡，追蹤與管理變得困難。",[4541,20452,20453,20456],{},[12249,20454,20455],{},"API 冗長","。改一個值要先定義 mutation、再定義 action、再在元件裡 dispatch，中間隔了兩層。",[4541,20458,20459,3775,20462,20465],{},[12249,20460,20461],{},"TypeScript 支援不好",[29,20463,20464],{},"commit('someMutation', payload)"," 是字串，型別推不出來，打錯字要到執行期才會發現。",[15,20467,20469],{"id":20468},"pinia-概要","Pinia 概要",[11,20471,20472],{},"為了解決這些問題，Vue 團隊開發了 Pinia，用來取代 Vuex 的全域資料管理函式庫。",[11,20474,20475],{},"主要特點：",[6426,20477,20478,20484,20490,20496],{},[4541,20479,20480,20483],{},[12249,20481,20482],{},"與 Composition API 緊密整合","：可以用組合式的方式組織與重用邏輯。",[4541,20485,20486,20489],{},[12249,20487,20488],{},"扁平的 store 結構","：每個 store 都是獨立的實例，有自己的 state、getters、actions，不用巢狀模組。",[4541,20491,20492,20495],{},[12249,20493,20494],{},"TypeScript 支援良好","：大量使用型別推斷，不需要額外寫型別包裝。",[4541,20497,20498,20501],{},[12249,20499,20500],{},"輕量","：壓縮後約 1KB，並支援自訂 plugin。",[15,20503,20504],{"id":20504},"兩者的差異",[13433,20506,20507,20518],{},[13436,20508,20509],{},[13439,20510,20511,20513,20515],{},[13442,20512,13544],{},[13442,20514,4844],{},[13442,20516,20517],{},"Pinia",[13449,20519,20520,20534,20548,20559,20575,20586,20599],{},[13439,20521,20522,20525,20528],{},[13454,20523,20524],{},"Mutations",[13454,20526,20527],{},"必須有",[13454,20529,20530,20533],{},[12249,20531,20532],{},"移除","，直接在 action 改 state",[13439,20535,20536,20539,20545],{},[13454,20537,20538],{},"模組 namespace",[13454,20540,20541,20542],{},"要自己設定 ",[29,20543,20544],{},"namespaced",[13454,20546,20547],{},"自動，每個 store 天生獨立",[13439,20549,20550,20553,20556],{},[13454,20551,20552],{},"TypeScript",[13454,20554,20555],{},"需要額外的型別包裝",[13454,20557,20558],{},"型別推斷",[13439,20560,20561,20564,20570],{},[13454,20562,20563],{},"取得 state",[13454,20565,20566,20567,20569],{},"要傳 ",[29,20568,16972],{}," 參數",[13454,20571,20572,20573],{},"直接用 ",[29,20574,1083],{},[13439,20576,20577,20580,20583],{},[13454,20578,20579],{},"SSR",[13454,20581,20582],{},"支援但設定繁瑣",[13454,20584,20585],{},"原生支援",[13439,20587,20588,20591,20594],{},[13454,20589,20590],{},"Nuxt 3",[13454,20592,20593],{},"不支援",[13454,20595,20596],{},[12249,20597,20598],{},"完整支援",[13439,20600,20601,20604,20607],{},[13454,20602,20603],{},"體積",[13454,20605,20606],{},"較大",[13454,20608,20609],{},"約 1KB",[11,20611,20612,20613,20616],{},"最大的差異是",[12249,20614,20615],{},"移除了 Mutations","。少了一層之後寫法簡潔很多，代價是從程式碼上看不出它是 Flux 架構——但實務上，多數人本來就覺得 mutation 這層是多餘的儀式。",[15,20618,19439],{"id":19439},[151,20620,20622],{"id":20621},"vue-專案","Vue 專案",[22,20624,20626],{"className":2057,"code":20625,"language":2059,"meta":27,"style":27},"npm install pinia\n",[29,20627,20628],{"__ignoreMap":27},[32,20629,20630,20632,20634],{"class":34,"line":35},[32,20631,4625],{"class":2066},[32,20633,4650],{"class":175},[32,20635,20636],{"class":175}," pinia\n",[11,20638,20639,5240],{},[29,20640,5137],{},[22,20642,20646],{"className":20643,"code":20644,"language":20645,"meta":27,"style":27},"language-javascript shiki shiki-themes github-light github-dark-default","import { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport App from '.\u002FApp.vue'\n\nconst app = createApp(App)\napp.use(createPinia())\napp.mount('#app')\n","javascript",[29,20647,20648,20660,20672,20684,20688,20703,20718],{"__ignoreMap":27},[32,20649,20650,20652,20655,20657],{"class":34,"line":35},[32,20651,8794],{"class":38},[32,20653,20654],{"class":41}," { createApp } ",[32,20656,8850],{"class":38},[32,20658,20659],{"class":175}," 'vue'\n",[32,20661,20662,20664,20667,20669],{"class":34,"line":45},[32,20663,8794],{"class":38},[32,20665,20666],{"class":41}," { createPinia } ",[32,20668,8850],{"class":38},[32,20670,20671],{"class":175}," 'pinia'\n",[32,20673,20674,20676,20679,20681],{"class":34,"line":51},[32,20675,8794],{"class":38},[32,20677,20678],{"class":41}," App ",[32,20680,8850],{"class":38},[32,20682,20683],{"class":175}," '.\u002FApp.vue'\n",[32,20685,20686],{"class":34,"line":90},[32,20687,103],{"emptyLinePlaceholder":102},[32,20689,20690,20692,20695,20697,20700],{"class":34,"line":99},[32,20691,6617],{"class":38},[32,20693,20694],{"class":351}," app",[32,20696,894],{"class":38},[32,20698,20699],{"class":217}," createApp",[32,20701,20702],{"class":41},"(App)\n",[32,20704,20705,20708,20710,20712,20715],{"class":34,"line":106},[32,20706,20707],{"class":41},"app.",[32,20709,8895],{"class":217},[32,20711,477],{"class":41},[32,20713,20714],{"class":217},"createPinia",[32,20716,20717],{"class":41},"())\n",[32,20719,20720,20722,20725,20727,20729],{"class":34,"line":114},[32,20721,20707],{"class":41},[32,20723,20724],{"class":217},"mount",[32,20726,477],{"class":41},[32,20728,4178],{"class":175},[32,20730,515],{"class":41},[151,20732,20734],{"id":20733},"nuxt-專案","Nuxt 專案",[22,20736,20738],{"className":2057,"code":20737,"language":2059,"meta":27,"style":27},"npm install pinia @pinia\u002Fnuxt\n",[29,20739,20740],{"__ignoreMap":27},[32,20741,20742,20744,20746,20749],{"class":34,"line":35},[32,20743,4625],{"class":2066},[32,20745,4650],{"class":175},[32,20747,20748],{"class":175}," pinia",[32,20750,20751],{"class":175}," @pinia\u002Fnuxt\n",[11,20753,20754,5240],{},[29,20755,20756],{},"nuxt.config.ts",[22,20758,20762],{"className":20759,"code":20760,"language":20761,"meta":27,"style":27},"language-typescript shiki shiki-themes github-light github-dark-default","export default defineNuxtConfig({\n  modules: ['@pinia\u002Fnuxt'],\n})\n","typescript",[29,20763,20764,20775,20786],{"__ignoreMap":27},[32,20765,20766,20768,20770,20773],{"class":34,"line":35},[32,20767,5038],{"class":38},[32,20769,5041],{"class":38},[32,20771,20772],{"class":217}," defineNuxtConfig",[32,20774,1143],{"class":5049},[32,20776,20777,20779,20782,20784],{"class":34,"line":45},[32,20778,17916],{"class":41},[32,20780,20781],{"class":175},"'@pinia\u002Fnuxt'",[32,20783,17922],{"class":41},[32,20785,547],{"class":5049},[32,20787,20788],{"class":34,"line":51},[32,20789,20790],{"class":5049},"})\n",[11,20792,20793],{},"Nuxt 模組會自動處理 SSR 的狀態注水（hydration），不用自己搬狀態。",[15,20795,20797],{"id":20796},"寫法一options-風格","寫法一：Options 風格",[11,20799,20800],{},"跟 Vuex 比較像，適合從 Vuex 搬過來：",[22,20802,20804],{"className":20643,"code":20803,"language":20645,"meta":27,"style":27},"\u002F\u002F src\u002Fstores\u002Fcart.js\nimport { defineStore } from 'pinia'\n\nexport const useCartStore = defineStore('cart', {\n  state: () => ({\n    items: []\n  }),\n  getters: {\n    totalCost(state) {\n      return state.items.reduce(\n        (total, item) => total + item.price * item.quantity,\n        0\n      )\n    }\n  },\n  actions: {\n    addItem(item) {\n      const existingItem = this.items.find((i) => i.id === item.id)\n      if (existingItem) {\n        const newItem = {\n          ...existingItem,\n          quantity: existingItem.quantity + item.quantity\n        }\n        this.items = this.items.map((i) => (i.id === item.id ? newItem : i))\n      } else {\n        this.items.push(item)\n      }\n    },\n    removeItem(itemId) {\n      this.items = this.items.filter((item) => item.id !== itemId)\n    }\n  }\n})\n",[29,20805,20806,20811,20822,20826,20849,20861,20866,20871,20876,20887,20898,20927,20932,20937,20941,20945,20949,20960,20994,21001,21013,21021,21031,21036,21078,21086,21097,21101,21105,21117,21147,21151,21155],{"__ignoreMap":27},[32,20807,20808],{"class":34,"line":35},[32,20809,20810],{"class":608},"\u002F\u002F src\u002Fstores\u002Fcart.js\n",[32,20812,20813,20815,20818,20820],{"class":34,"line":45},[32,20814,8794],{"class":38},[32,20816,20817],{"class":41}," { defineStore } ",[32,20819,8850],{"class":38},[32,20821,20671],{"class":175},[32,20823,20824],{"class":34,"line":51},[32,20825,103],{"emptyLinePlaceholder":102},[32,20827,20828,20830,20833,20836,20838,20841,20843,20846],{"class":34,"line":90},[32,20829,5038],{"class":38},[32,20831,20832],{"class":38}," const",[32,20834,20835],{"class":351}," useCartStore",[32,20837,894],{"class":38},[32,20839,20840],{"class":217}," defineStore",[32,20842,477],{"class":41},[32,20844,20845],{"class":175},"'cart'",[32,20847,20848],{"class":41},", {\n",[32,20850,20851,20854,20856,20858],{"class":34,"line":99},[32,20852,20853],{"class":217},"  state",[32,20855,5087],{"class":41},[32,20857,5090],{"class":38},[32,20859,20860],{"class":41}," ({\n",[32,20862,20863],{"class":34,"line":106},[32,20864,20865],{"class":41},"    items: []\n",[32,20867,20868],{"class":34,"line":114},[32,20869,20870],{"class":41},"  }),\n",[32,20872,20873],{"class":34,"line":120},[32,20874,20875],{"class":41},"  getters: {\n",[32,20877,20878,20881,20883,20885],{"class":34,"line":127},[32,20879,20880],{"class":217},"    totalCost",[32,20882,477],{"class":41},[32,20884,16972],{"class":903},[32,20886,520],{"class":41},[32,20888,20889,20891,20894,20896],{"class":34,"line":132},[32,20890,19162],{"class":38},[32,20892,20893],{"class":41}," state.items.",[32,20895,18668],{"class":217},[32,20897,539],{"class":41},[32,20899,20900,20903,20906,20908,20911,20913,20915,20917,20919,20922,20924],{"class":34,"line":141},[32,20901,20902],{"class":41},"        (",[32,20904,20905],{"class":903},"total",[32,20907,635],{"class":41},[32,20909,20910],{"class":903},"item",[32,20912,483],{"class":41},[32,20914,5090],{"class":38},[32,20916,18660],{"class":41},[32,20918,224],{"class":38},[32,20920,20921],{"class":41}," item.price ",[32,20923,6078],{"class":38},[32,20925,20926],{"class":41}," item.quantity,\n",[32,20928,20929],{"class":34,"line":147},[32,20930,20931],{"class":351},"        0\n",[32,20933,20934],{"class":34,"line":275},[32,20935,20936],{"class":41},"      )\n",[32,20938,20939],{"class":34,"line":282},[32,20940,5591],{"class":41},[32,20942,20943],{"class":34,"line":295},[32,20944,5639],{"class":41},[32,20946,20947],{"class":34,"line":605},[32,20948,17074],{"class":41},[32,20950,20951,20954,20956,20958],{"class":34,"line":612},[32,20952,20953],{"class":217},"    addItem",[32,20955,477],{"class":41},[32,20957,20910],{"class":903},[32,20959,520],{"class":41},[32,20961,20962,20965,20968,20970,20972,20975,20977,20979,20982,20984,20986,20989,20991],{"class":34,"line":617},[32,20963,20964],{"class":38},"      const",[32,20966,20967],{"class":351}," existingItem",[32,20969,894],{"class":38},[32,20971,4234],{"class":351},[32,20973,20974],{"class":41},".items.",[32,20976,18380],{"class":217},[32,20978,8293],{"class":41},[32,20980,20981],{"class":903},"i",[32,20983,483],{"class":41},[32,20985,5090],{"class":38},[32,20987,20988],{"class":41}," i.id ",[32,20990,5560],{"class":38},[32,20992,20993],{"class":41}," item.id)\n",[32,20995,20996,20998],{"class":34,"line":644},[32,20997,1071],{"class":38},[32,20999,21000],{"class":41}," (existingItem) {\n",[32,21002,21003,21006,21009,21011],{"class":34,"line":649},[32,21004,21005],{"class":38},"        const",[32,21007,21008],{"class":351}," newItem",[32,21010,894],{"class":38},[32,21012,703],{"class":41},[32,21014,21015,21018],{"class":34,"line":671},[32,21016,21017],{"class":38},"          ...",[32,21019,21020],{"class":41},"existingItem,\n",[32,21022,21023,21026,21028],{"class":34,"line":690},[32,21024,21025],{"class":41},"          quantity: existingItem.quantity ",[32,21027,224],{"class":38},[32,21029,21030],{"class":41}," item.quantity\n",[32,21032,21033],{"class":34,"line":696},[32,21034,21035],{"class":41},"        }\n",[32,21037,21038,21041,21044,21046,21048,21050,21052,21054,21056,21058,21060,21063,21065,21068,21070,21073,21075],{"class":34,"line":706},[32,21039,21040],{"class":351},"        this",[32,21042,21043],{"class":41},".items ",[32,21045,172],{"class":38},[32,21047,4234],{"class":351},[32,21049,20974],{"class":41},[32,21051,11130],{"class":217},[32,21053,8293],{"class":41},[32,21055,20981],{"class":903},[32,21057,483],{"class":41},[32,21059,5090],{"class":38},[32,21061,21062],{"class":41}," (i.id ",[32,21064,5560],{"class":38},[32,21066,21067],{"class":41}," item.id ",[32,21069,316],{"class":38},[32,21071,21072],{"class":41}," newItem ",[32,21074,322],{"class":38},[32,21076,21077],{"class":41}," i))\n",[32,21079,21080,21082,21084],{"class":34,"line":721},[32,21081,9477],{"class":41},[32,21083,565],{"class":38},[32,21085,703],{"class":41},[32,21087,21088,21090,21092,21094],{"class":34,"line":728},[32,21089,21040],{"class":351},[32,21091,20974],{"class":41},[32,21093,19352],{"class":217},[32,21095,21096],{"class":41},"(item)\n",[32,21098,21099],{"class":34,"line":737},[32,21100,1193],{"class":41},[32,21102,21103],{"class":34,"line":742},[32,21104,4204],{"class":41},[32,21106,21107,21110,21112,21115],{"class":34,"line":747},[32,21108,21109],{"class":217},"    removeItem",[32,21111,477],{"class":41},[32,21113,21114],{"class":903},"itemId",[32,21116,520],{"class":41},[32,21118,21119,21122,21124,21126,21128,21130,21132,21134,21136,21138,21140,21142,21144],{"class":34,"line":752},[32,21120,21121],{"class":351},"      this",[32,21123,21043],{"class":41},[32,21125,172],{"class":38},[32,21127,4234],{"class":351},[32,21129,20974],{"class":41},[32,21131,15334],{"class":217},[32,21133,8293],{"class":41},[32,21135,20910],{"class":903},[32,21137,483],{"class":41},[32,21139,5090],{"class":38},[32,21141,21067],{"class":41},[32,21143,1553],{"class":38},[32,21145,21146],{"class":41}," itemId)\n",[32,21148,21149],{"class":34,"line":773},[32,21150,5591],{"class":41},[32,21152,21153],{"class":34,"line":789},[32,21154,1203],{"class":41},[32,21156,21157],{"class":34,"line":795},[32,21158,20790],{"class":41},[11,21160,21161,21164,21165,21167],{},[29,21162,21163],{},"defineStore"," 的第一個參數 ",[29,21166,20845],{}," 是這個 store 的唯一 ID，DevTools 會用它來標示。",[11,21169,21170],{},"在元件裡使用：",[22,21172,21174],{"className":8665,"code":21173,"language":4112,"meta":27,"style":27},"\u003C!-- src\u002Fcomponents\u002FCart.vue -->\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Ch2>你的購物車\u003C\u002Fh2>\n    \u003Cul>\n      \u003Cli v-for=\"item in items\" :key=\"item.id\">\n        {{ item.name }} - ${{ item.price }} x {{ item.quantity }}\n        \u003Cbutton @click=\"removeItem(item.id)\">刪除\u003C\u002Fbutton>\n      \u003C\u002Fli>\n    \u003C\u002Ful>\n    \u003Cdiv>總費用: ${{ totalCost }}\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { storeToRefs } from \"pinia\";\nimport { useCartStore } from \"..\u002Fstores\u002Fcart\";\n\nconst cartStore = useCartStore();\n\nconst { items, totalCost } = storeToRefs(cartStore);\n\nfunction removeItem(id) {\n  cartStore.removeItem(id);\n}\n\u003C\u002Fscript>\n",[29,21175,21176,21181,21189,21197,21210,21218,21243,21248,21270,21279,21288,21301,21309,21317,21321,21332,21346,21360,21364,21377,21381,21407,21411,21425,21436,21440],{"__ignoreMap":27},[32,21177,21178],{"class":34,"line":35},[32,21179,21180],{"class":608},"\u003C!-- src\u002Fcomponents\u002FCart.vue -->\n",[32,21182,21183,21185,21187],{"class":34,"line":45},[32,21184,4046],{"class":41},[32,21186,9623],{"class":4049},[32,21188,4062],{"class":41},[32,21190,21191,21193,21195],{"class":34,"line":51},[32,21192,4067],{"class":41},[32,21194,4050],{"class":4049},[32,21196,4062],{"class":41},[32,21198,21199,21201,21203,21206,21208],{"class":34,"line":90},[32,21200,9638],{"class":41},[32,21202,15],{"class":4049},[32,21204,21205],{"class":41},">你的購物車\u003C\u002F",[32,21207,15],{"class":4049},[32,21209,4062],{"class":41},[32,21211,21212,21214,21216],{"class":34,"line":99},[32,21213,9638],{"class":41},[32,21215,4538],{"class":4049},[32,21217,4062],{"class":41},[32,21219,21220,21223,21225,21228,21230,21233,21236,21238,21241],{"class":34,"line":106},[32,21221,21222],{"class":41},"      \u003C",[32,21224,4541],{"class":4049},[32,21226,21227],{"class":4053}," v-for",[32,21229,172],{"class":41},[32,21231,21232],{"class":175},"\"item in items\"",[32,21234,21235],{"class":4053}," :key",[32,21237,172],{"class":41},[32,21239,21240],{"class":175},"\"item.id\"",[32,21242,4062],{"class":41},[32,21244,21245],{"class":34,"line":114},[32,21246,21247],{"class":41},"        {{ item.name }} - ${{ item.price }} x {{ item.quantity }}\n",[32,21249,21250,21253,21255,21258,21260,21263,21266,21268],{"class":34,"line":120},[32,21251,21252],{"class":41},"        \u003C",[32,21254,11493],{"class":4049},[32,21256,21257],{"class":4053}," @click",[32,21259,172],{"class":41},[32,21261,21262],{"class":175},"\"removeItem(item.id)\"",[32,21264,21265],{"class":41},">刪除\u003C\u002F",[32,21267,11493],{"class":4049},[32,21269,4062],{"class":41},[32,21271,21272,21275,21277],{"class":34,"line":127},[32,21273,21274],{"class":41},"      \u003C\u002F",[32,21276,4541],{"class":4049},[32,21278,4062],{"class":41},[32,21280,21281,21284,21286],{"class":34,"line":132},[32,21282,21283],{"class":41},"    \u003C\u002F",[32,21285,4538],{"class":4049},[32,21287,4062],{"class":41},[32,21289,21290,21292,21294,21297,21299],{"class":34,"line":141},[32,21291,9638],{"class":41},[32,21293,4050],{"class":4049},[32,21295,21296],{"class":41},">總費用: ${{ totalCost }}\u003C\u002F",[32,21298,4050],{"class":4049},[32,21300,4062],{"class":41},[32,21302,21303,21305,21307],{"class":34,"line":147},[32,21304,9691],{"class":41},[32,21306,4050],{"class":4049},[32,21308,4062],{"class":41},[32,21310,21311,21313,21315],{"class":34,"line":275},[32,21312,4105],{"class":41},[32,21314,9623],{"class":4049},[32,21316,4062],{"class":41},[32,21318,21319],{"class":34,"line":282},[32,21320,103],{"emptyLinePlaceholder":102},[32,21322,21323,21325,21327,21330],{"class":34,"line":295},[32,21324,4046],{"class":41},[32,21326,4125],{"class":4049},[32,21328,21329],{"class":4053}," setup",[32,21331,4062],{"class":41},[32,21333,21334,21336,21339,21341,21344],{"class":34,"line":605},[32,21335,8794],{"class":38},[32,21337,21338],{"class":41}," { storeToRefs } ",[32,21340,8850],{"class":38},[32,21342,21343],{"class":175}," \"pinia\"",[32,21345,96],{"class":41},[32,21347,21348,21350,21353,21355,21358],{"class":34,"line":612},[32,21349,8794],{"class":38},[32,21351,21352],{"class":41}," { useCartStore } ",[32,21354,8850],{"class":38},[32,21356,21357],{"class":175}," \"..\u002Fstores\u002Fcart\"",[32,21359,96],{"class":41},[32,21361,21362],{"class":34,"line":617},[32,21363,103],{"emptyLinePlaceholder":102},[32,21365,21366,21368,21371,21373,21375],{"class":34,"line":644},[32,21367,6617],{"class":38},[32,21369,21370],{"class":351}," cartStore",[32,21372,894],{"class":38},[32,21374,20835],{"class":217},[32,21376,687],{"class":41},[32,21378,21379],{"class":34,"line":649},[32,21380,103],{"emptyLinePlaceholder":102},[32,21382,21383,21385,21388,21391,21393,21396,21399,21401,21404],{"class":34,"line":671},[32,21384,6617],{"class":38},[32,21386,21387],{"class":41}," { ",[32,21389,21390],{"class":351},"items",[32,21392,635],{"class":41},[32,21394,21395],{"class":351},"totalCost",[32,21397,21398],{"class":41}," } ",[32,21400,172],{"class":38},[32,21402,21403],{"class":217}," storeToRefs",[32,21405,21406],{"class":41},"(cartStore);\n",[32,21408,21409],{"class":34,"line":690},[32,21410,103],{"emptyLinePlaceholder":102},[32,21412,21413,21415,21418,21420,21423],{"class":34,"line":696},[32,21414,665],{"class":38},[32,21416,21417],{"class":217}," removeItem",[32,21419,477],{"class":41},[32,21421,21422],{"class":903},"id",[32,21424,520],{"class":41},[32,21426,21427,21430,21433],{"class":34,"line":706},[32,21428,21429],{"class":41},"  cartStore.",[32,21431,21432],{"class":217},"removeItem",[32,21434,21435],{"class":41},"(id);\n",[32,21437,21438],{"class":34,"line":721},[32,21439,54],{"class":41},[32,21441,21442,21444,21446],{"class":34,"line":728},[32,21443,4105],{"class":41},[32,21445,4125],{"class":4049},[32,21447,4062],{"class":41},[151,21449,21451],{"id":21450},"為什麼要用-storetorefs","為什麼要用 storeToRefs",[11,21453,21454,21455,5240],{},"這是最常踩的坑。直接解構會",[12249,21456,21457],{},"失去響應性",[22,21459,21461],{"className":20643,"code":21460,"language":20645,"meta":27,"style":27},"\u002F\u002F 壞掉：items 變成一般變數，store 更新時畫面不會動\nconst { items, totalCost } = useCartStore();\n\n\u002F\u002F 正確：storeToRefs 把 state 與 getters 包成 ref\nconst { items, totalCost } = storeToRefs(cartStore);\n",[29,21462,21463,21468,21488,21492,21497],{"__ignoreMap":27},[32,21464,21465],{"class":34,"line":35},[32,21466,21467],{"class":608},"\u002F\u002F 壞掉：items 變成一般變數，store 更新時畫面不會動\n",[32,21469,21470,21472,21474,21476,21478,21480,21482,21484,21486],{"class":34,"line":45},[32,21471,6617],{"class":38},[32,21473,21387],{"class":41},[32,21475,21390],{"class":351},[32,21477,635],{"class":41},[32,21479,21395],{"class":351},[32,21481,21398],{"class":41},[32,21483,172],{"class":38},[32,21485,20835],{"class":217},[32,21487,687],{"class":41},[32,21489,21490],{"class":34,"line":51},[32,21491,103],{"emptyLinePlaceholder":102},[32,21493,21494],{"class":34,"line":90},[32,21495,21496],{"class":608},"\u002F\u002F 正確：storeToRefs 把 state 與 getters 包成 ref\n",[32,21498,21499,21501,21503,21505,21507,21509,21511,21513,21515],{"class":34,"line":99},[32,21500,6617],{"class":38},[32,21502,21387],{"class":41},[32,21504,21390],{"class":351},[32,21506,635],{"class":41},[32,21508,21395],{"class":351},[32,21510,21398],{"class":41},[32,21512,172],{"class":38},[32,21514,21403],{"class":217},[32,21516,21406],{"class":41},[11,21518,21519,21520,21527],{},"但 ",[12249,21521,21522,21523,21526],{},"action 不要用 ",[29,21524,21525],{},"storeToRefs"," 取","，它們是函式、本來就不需要響應性，直接從 store 取即可：",[22,21529,21531],{"className":20643,"code":21530,"language":20645,"meta":27,"style":27},"const { addItem, removeItem } = cartStore;\n",[29,21532,21533],{"__ignoreMap":27},[32,21534,21535,21537,21539,21542,21544,21546,21548,21550],{"class":34,"line":35},[32,21536,6617],{"class":38},[32,21538,21387],{"class":41},[32,21540,21541],{"class":351},"addItem",[32,21543,635],{"class":41},[32,21545,21432],{"class":351},[32,21547,21398],{"class":41},[32,21549,172],{"class":38},[32,21551,21552],{"class":41}," cartStore;\n",[15,21554,21556],{"id":21555},"寫法二setup-風格","寫法二：setup 風格",[11,21558,21559,21560,21563,21564,21567],{},"用 Composition API 的方式寫，跟平常寫元件邏輯一模一樣——",[29,21561,21562],{},"ref"," 就是 state、",[29,21565,21566],{},"computed"," 就是 getter、function 就是 action。",[22,21569,21571],{"className":20759,"code":21570,"language":20761,"meta":27,"style":27},"import { getElectionGroups, getCounties } from '~\u002Fassets\u002Fapi\u002Felection'\n\ninterface Candidate {\n  id: string\n  society: string\n  societyEng: string\n  name: string\n  subName: string\n}\n\nexport const useCandidateAndCountyStore = defineStore('candidatesAndCounty', () => {\n  \u002F\u002F state\n  const candidates = ref\u003CCandidate[]>([])\n  const counties = ref\u003Cstring[]>([])\n\n  \u002F\u002F getters\n  const candidatesGetter = computed(() => candidates.value || [])\n  const countiesGetter = computed(() => counties.value || [])\n\n  \u002F\u002F actions\n  const fetchCandidatesAndCounties = async (): Promise\u003Cvoid> => {\n    const [candidatesData, countiesData] = await Promise.all([\n      getElectionGroups(),\n      getCounties()\n    ])\n    candidates.value = candidatesData as Candidate[]\n    counties.value = countiesData as string[]\n  }\n\n  return {\n    candidates,\n    candidatesGetter,\n    counties,\n    countiesGetter,\n    fetchCandidatesAndCounties\n  }\n})\n",[29,21572,21573,21585,21589,21599,21609,21618,21627,21635,21644,21648,21652,21676,21681,21700,21718,21722,21727,21752,21774,21778,21783,21814,21845,21853,21861,21866,21884,21901,21905,21909,21915,21920,21925,21930,21935,21940,21944],{"__ignoreMap":27},[32,21574,21575,21577,21580,21582],{"class":34,"line":35},[32,21576,8794],{"class":38},[32,21578,21579],{"class":41}," { getElectionGroups, getCounties } ",[32,21581,8850],{"class":38},[32,21583,21584],{"class":175}," '~\u002Fassets\u002Fapi\u002Felection'\n",[32,21586,21587],{"class":34,"line":45},[32,21588,103],{"emptyLinePlaceholder":102},[32,21590,21591,21594,21597],{"class":34,"line":51},[32,21592,21593],{"class":38},"interface",[32,21595,21596],{"class":2066}," Candidate",[32,21598,703],{"class":41},[32,21600,21601,21604,21606],{"class":34,"line":90},[32,21602,21603],{"class":903},"  id",[32,21605,322],{"class":38},[32,21607,21608],{"class":351}," string\n",[32,21610,21611,21614,21616],{"class":34,"line":99},[32,21612,21613],{"class":903},"  society",[32,21615,322],{"class":38},[32,21617,21608],{"class":351},[32,21619,21620,21623,21625],{"class":34,"line":106},[32,21621,21622],{"class":903},"  societyEng",[32,21624,322],{"class":38},[32,21626,21608],{"class":351},[32,21628,21629,21631,21633],{"class":34,"line":114},[32,21630,9859],{"class":903},[32,21632,322],{"class":38},[32,21634,21608],{"class":351},[32,21636,21637,21640,21642],{"class":34,"line":120},[32,21638,21639],{"class":903},"  subName",[32,21641,322],{"class":38},[32,21643,21608],{"class":351},[32,21645,21646],{"class":34,"line":127},[32,21647,54],{"class":41},[32,21649,21650],{"class":34,"line":132},[32,21651,103],{"emptyLinePlaceholder":102},[32,21653,21654,21656,21658,21661,21663,21665,21667,21670,21672,21674],{"class":34,"line":141},[32,21655,5038],{"class":38},[32,21657,20832],{"class":38},[32,21659,21660],{"class":351}," useCandidateAndCountyStore",[32,21662,894],{"class":38},[32,21664,20840],{"class":217},[32,21666,477],{"class":41},[32,21668,21669],{"class":175},"'candidatesAndCounty'",[32,21671,11218],{"class":41},[32,21673,5090],{"class":38},[32,21675,703],{"class":41},[32,21677,21678],{"class":34,"line":147},[32,21679,21680],{"class":608},"  \u002F\u002F state\n",[32,21682,21683,21685,21688,21690,21692,21694,21697],{"class":34,"line":275},[32,21684,4157],{"class":38},[32,21686,21687],{"class":351}," candidates",[32,21689,894],{"class":38},[32,21691,19797],{"class":217},[32,21693,4046],{"class":41},[32,21695,21696],{"class":2066},"Candidate",[32,21698,21699],{"class":41},"[]>([])\n",[32,21701,21702,21704,21707,21709,21711,21713,21716],{"class":34,"line":282},[32,21703,4157],{"class":38},[32,21705,21706],{"class":351}," counties",[32,21708,894],{"class":38},[32,21710,19797],{"class":217},[32,21712,4046],{"class":41},[32,21714,21715],{"class":351},"string",[32,21717,21699],{"class":41},[32,21719,21720],{"class":34,"line":295},[32,21721,103],{"emptyLinePlaceholder":102},[32,21723,21724],{"class":34,"line":605},[32,21725,21726],{"class":608},"  \u002F\u002F getters\n",[32,21728,21729,21731,21734,21736,21739,21742,21744,21747,21749],{"class":34,"line":612},[32,21730,4157],{"class":38},[32,21732,21733],{"class":351}," candidatesGetter",[32,21735,894],{"class":38},[32,21737,21738],{"class":217}," computed",[32,21740,21741],{"class":41},"(() ",[32,21743,5090],{"class":38},[32,21745,21746],{"class":41}," candidates.value ",[32,21748,1036],{"class":38},[32,21750,21751],{"class":41}," [])\n",[32,21753,21754,21756,21759,21761,21763,21765,21767,21770,21772],{"class":34,"line":617},[32,21755,4157],{"class":38},[32,21757,21758],{"class":351}," countiesGetter",[32,21760,894],{"class":38},[32,21762,21738],{"class":217},[32,21764,21741],{"class":41},[32,21766,5090],{"class":38},[32,21768,21769],{"class":41}," counties.value ",[32,21771,1036],{"class":38},[32,21773,21751],{"class":41},[32,21775,21776],{"class":34,"line":644},[32,21777,103],{"emptyLinePlaceholder":102},[32,21779,21780],{"class":34,"line":649},[32,21781,21782],{"class":608},"  \u002F\u002F actions\n",[32,21784,21785,21787,21790,21792,21795,21798,21800,21803,21805,21808,21810,21812],{"class":34,"line":671},[32,21786,4157],{"class":38},[32,21788,21789],{"class":217}," fetchCandidatesAndCounties",[32,21791,894],{"class":38},[32,21793,21794],{"class":38}," async",[32,21796,21797],{"class":41}," ()",[32,21799,322],{"class":38},[32,21801,21802],{"class":2066}," Promise",[32,21804,4046],{"class":41},[32,21806,21807],{"class":351},"void",[32,21809,12401],{"class":41},[32,21811,5090],{"class":38},[32,21813,703],{"class":41},[32,21815,21816,21818,21820,21823,21825,21828,21830,21832,21835,21837,21839,21842],{"class":34,"line":690},[32,21817,9409],{"class":38},[32,21819,8261],{"class":41},[32,21821,21822],{"class":351},"candidatesData",[32,21824,635],{"class":41},[32,21826,21827],{"class":351},"countiesData",[32,21829,10616],{"class":41},[32,21831,172],{"class":38},[32,21833,21834],{"class":38}," await",[32,21836,21802],{"class":351},[32,21838,1278],{"class":41},[32,21840,21841],{"class":217},"all",[32,21843,21844],{"class":41},"([\n",[32,21846,21847,21850],{"class":34,"line":696},[32,21848,21849],{"class":217},"      getElectionGroups",[32,21851,21852],{"class":41},"(),\n",[32,21854,21855,21858],{"class":34,"line":706},[32,21856,21857],{"class":217},"      getCounties",[32,21859,21860],{"class":41},"()\n",[32,21862,21863],{"class":34,"line":721},[32,21864,21865],{"class":41},"    ])\n",[32,21867,21868,21871,21873,21876,21879,21881],{"class":34,"line":728},[32,21869,21870],{"class":41},"    candidates.value ",[32,21872,172],{"class":38},[32,21874,21875],{"class":41}," candidatesData ",[32,21877,21878],{"class":38},"as",[32,21880,21596],{"class":2066},[32,21882,21883],{"class":41},"[]\n",[32,21885,21886,21889,21891,21894,21896,21899],{"class":34,"line":737},[32,21887,21888],{"class":41},"    counties.value ",[32,21890,172],{"class":38},[32,21892,21893],{"class":41}," countiesData ",[32,21895,21878],{"class":38},[32,21897,21898],{"class":351}," string",[32,21900,21883],{"class":41},[32,21902,21903],{"class":34,"line":742},[32,21904,1203],{"class":41},[32,21906,21907],{"class":34,"line":747},[32,21908,103],{"emptyLinePlaceholder":102},[32,21910,21911,21913],{"class":34,"line":752},[32,21912,10974],{"class":38},[32,21914,703],{"class":41},[32,21916,21917],{"class":34,"line":773},[32,21918,21919],{"class":41},"    candidates,\n",[32,21921,21922],{"class":34,"line":789},[32,21923,21924],{"class":41},"    candidatesGetter,\n",[32,21926,21927],{"class":34,"line":795},[32,21928,21929],{"class":41},"    counties,\n",[32,21931,21932],{"class":34,"line":800},[32,21933,21934],{"class":41},"    countiesGetter,\n",[32,21936,21937],{"class":34,"line":816},[32,21938,21939],{"class":41},"    fetchCandidatesAndCounties\n",[32,21941,21942],{"class":34,"line":824},[32,21943,1203],{"class":41},[32,21945,21946],{"class":34,"line":833},[32,21947,20790],{"class":41},[11,21949,21950,21955],{},[12249,21951,21952,21953],{},"要記得 ",[29,21954,4428],{},"——沒有回傳的東西外面拿不到，這是 setup 寫法最常見的錯誤。",[11,21957,21958],{},"在元件裡用起來完全一樣：",[22,21960,21962],{"className":8665,"code":21961,"language":4112,"meta":27,"style":27},"\u003Cscript setup lang=\"ts\">\nimport { storeToRefs } from 'pinia'\nimport { useCandidateAndCountyStore } from '~\u002Fstore\u002FcandidatesAndCounty'\n\nconst store = useCandidateAndCountyStore()\nconst { candidatesGetter, countiesGetter } = storeToRefs(store)\n\n\u002F\u002F 進頁面就抓資料\nawait store.fetchCandidatesAndCounties()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cul>\n    \u003Cli v-for=\"c in candidatesGetter\" :key=\"c.id\">\n      {{ c.name }}（{{ c.society }}）\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n",[29,21963,21964,21981,21991,22003,22007,22020,22043,22047,22052,22065,22073,22077,22085,22093,22115,22120,22128,22136],{"__ignoreMap":27},[32,21965,21966,21968,21970,21972,21974,21976,21979],{"class":34,"line":35},[32,21967,4046],{"class":41},[32,21969,4125],{"class":4049},[32,21971,21329],{"class":4053},[32,21973,8677],{"class":4053},[32,21975,172],{"class":41},[32,21977,21978],{"class":175},"\"ts\"",[32,21980,4062],{"class":41},[32,21982,21983,21985,21987,21989],{"class":34,"line":45},[32,21984,8794],{"class":38},[32,21986,21338],{"class":41},[32,21988,8850],{"class":38},[32,21990,20671],{"class":175},[32,21992,21993,21995,21998,22000],{"class":34,"line":51},[32,21994,8794],{"class":38},[32,21996,21997],{"class":41}," { useCandidateAndCountyStore } ",[32,21999,8850],{"class":38},[32,22001,22002],{"class":175}," '~\u002Fstore\u002FcandidatesAndCounty'\n",[32,22004,22005],{"class":34,"line":90},[32,22006,103],{"emptyLinePlaceholder":102},[32,22008,22009,22011,22014,22016,22018],{"class":34,"line":99},[32,22010,6617],{"class":38},[32,22012,22013],{"class":351}," store",[32,22015,894],{"class":38},[32,22017,21660],{"class":217},[32,22019,21860],{"class":41},[32,22021,22022,22024,22026,22029,22031,22034,22036,22038,22040],{"class":34,"line":106},[32,22023,6617],{"class":38},[32,22025,21387],{"class":41},[32,22027,22028],{"class":351},"candidatesGetter",[32,22030,635],{"class":41},[32,22032,22033],{"class":351},"countiesGetter",[32,22035,21398],{"class":41},[32,22037,172],{"class":38},[32,22039,21403],{"class":217},[32,22041,22042],{"class":41},"(store)\n",[32,22044,22045],{"class":34,"line":114},[32,22046,103],{"emptyLinePlaceholder":102},[32,22048,22049],{"class":34,"line":120},[32,22050,22051],{"class":608},"\u002F\u002F 進頁面就抓資料\n",[32,22053,22054,22057,22060,22063],{"class":34,"line":127},[32,22055,22056],{"class":38},"await",[32,22058,22059],{"class":41}," store.",[32,22061,22062],{"class":217},"fetchCandidatesAndCounties",[32,22064,21860],{"class":41},[32,22066,22067,22069,22071],{"class":34,"line":132},[32,22068,4105],{"class":41},[32,22070,4125],{"class":4049},[32,22072,4062],{"class":41},[32,22074,22075],{"class":34,"line":141},[32,22076,103],{"emptyLinePlaceholder":102},[32,22078,22079,22081,22083],{"class":34,"line":147},[32,22080,4046],{"class":41},[32,22082,9623],{"class":4049},[32,22084,4062],{"class":41},[32,22086,22087,22089,22091],{"class":34,"line":275},[32,22088,4067],{"class":41},[32,22090,4538],{"class":4049},[32,22092,4062],{"class":41},[32,22094,22095,22097,22099,22101,22103,22106,22108,22110,22113],{"class":34,"line":282},[32,22096,9638],{"class":41},[32,22098,4541],{"class":4049},[32,22100,21227],{"class":4053},[32,22102,172],{"class":41},[32,22104,22105],{"class":175},"\"c in candidatesGetter\"",[32,22107,21235],{"class":4053},[32,22109,172],{"class":41},[32,22111,22112],{"class":175},"\"c.id\"",[32,22114,4062],{"class":41},[32,22116,22117],{"class":34,"line":295},[32,22118,22119],{"class":41},"      {{ c.name }}（{{ c.society }}）\n",[32,22121,22122,22124,22126],{"class":34,"line":605},[32,22123,21283],{"class":41},[32,22125,4541],{"class":4049},[32,22127,4062],{"class":41},[32,22129,22130,22132,22134],{"class":34,"line":612},[32,22131,9691],{"class":41},[32,22133,4538],{"class":4049},[32,22135,4062],{"class":41},[32,22137,22138,22140,22142],{"class":34,"line":617},[32,22139,4105],{"class":41},[32,22141,9623],{"class":4049},[32,22143,4062],{"class":41},[11,22145,22146,22147,22149],{},"兩種寫法可以混用，同一個專案裡不同 store 用不同寫法沒問題。setup 風格對 TypeScript 比較友善，型別直接從 ",[29,22148,21562],{}," 推導出來。",[15,22151,22153],{"id":22152},"store-之間互相呼叫","store 之間互相呼叫",[11,22155,22156],{},"Pinia 的 store 就是函式，要用別的 store 直接呼叫它就好，不需要像 Vuex 那樣處理 namespace。",[11,22158,22159,5240],{},[29,22160,22161],{},"stores\u002Fuser.ts",[22,22163,22165],{"className":20759,"code":22164,"language":20761,"meta":27,"style":27},"export const useUserStore = defineStore('user', () => {\n  const token = ref\u003Cstring | null>(null)\n  const isLoggedIn = computed(() => !!token.value)\n\n  const login = async (email: string, password: string) => {\n    const res = await api.login(email, password)\n    token.value = res.token\n  }\n\n  return { token, isLoggedIn, login }\n})\n",[29,22166,22167,22191,22220,22240,22244,22279,22299,22309,22313,22317,22324],{"__ignoreMap":27},[32,22168,22169,22171,22173,22176,22178,22180,22182,22185,22187,22189],{"class":34,"line":35},[32,22170,5038],{"class":38},[32,22172,20832],{"class":38},[32,22174,22175],{"class":351}," useUserStore",[32,22177,894],{"class":38},[32,22179,20840],{"class":217},[32,22181,477],{"class":41},[32,22183,22184],{"class":175},"'user'",[32,22186,11218],{"class":41},[32,22188,5090],{"class":38},[32,22190,703],{"class":41},[32,22192,22193,22195,22198,22200,22202,22204,22206,22209,22212,22215,22218],{"class":34,"line":45},[32,22194,4157],{"class":38},[32,22196,22197],{"class":351}," token",[32,22199,894],{"class":38},[32,22201,19797],{"class":217},[32,22203,4046],{"class":41},[32,22205,21715],{"class":351},[32,22207,22208],{"class":38}," |",[32,22210,22211],{"class":351}," null",[32,22213,22214],{"class":41},">(",[32,22216,22217],{"class":351},"null",[32,22219,515],{"class":41},[32,22221,22222,22224,22227,22229,22231,22233,22235,22237],{"class":34,"line":51},[32,22223,4157],{"class":38},[32,22225,22226],{"class":351}," isLoggedIn",[32,22228,894],{"class":38},[32,22230,21738],{"class":217},[32,22232,21741],{"class":41},[32,22234,5090],{"class":38},[32,22236,1490],{"class":38},[32,22238,22239],{"class":41},"token.value)\n",[32,22241,22242],{"class":34,"line":90},[32,22243,103],{"emptyLinePlaceholder":102},[32,22245,22246,22248,22251,22253,22255,22257,22260,22262,22264,22266,22269,22271,22273,22275,22277],{"class":34,"line":99},[32,22247,4157],{"class":38},[32,22249,22250],{"class":217}," login",[32,22252,894],{"class":38},[32,22254,21794],{"class":38},[32,22256,900],{"class":41},[32,22258,22259],{"class":903},"email",[32,22261,322],{"class":38},[32,22263,21898],{"class":351},[32,22265,635],{"class":41},[32,22267,22268],{"class":903},"password",[32,22270,322],{"class":38},[32,22272,21898],{"class":351},[32,22274,483],{"class":41},[32,22276,5090],{"class":38},[32,22278,703],{"class":41},[32,22280,22281,22283,22286,22288,22290,22293,22296],{"class":34,"line":106},[32,22282,9409],{"class":38},[32,22284,22285],{"class":351}," res",[32,22287,894],{"class":38},[32,22289,21834],{"class":38},[32,22291,22292],{"class":41}," api.",[32,22294,22295],{"class":217},"login",[32,22297,22298],{"class":41},"(email, password)\n",[32,22300,22301,22304,22306],{"class":34,"line":114},[32,22302,22303],{"class":41},"    token.value ",[32,22305,172],{"class":38},[32,22307,22308],{"class":41}," res.token\n",[32,22310,22311],{"class":34,"line":120},[32,22312,1203],{"class":41},[32,22314,22315],{"class":34,"line":127},[32,22316,103],{"emptyLinePlaceholder":102},[32,22318,22319,22321],{"class":34,"line":132},[32,22320,10974],{"class":38},[32,22322,22323],{"class":41}," { token, isLoggedIn, login }\n",[32,22325,22326],{"class":34,"line":141},[32,22327,20790],{"class":41},[11,22329,22330,5240],{},[29,22331,22332],{},"stores\u002Fcart.ts",[22,22334,22336],{"className":20759,"code":22335,"language":20761,"meta":27,"style":27},"import { useUserStore } from '.\u002Fuser'\n\nexport const useCartStore = defineStore('cart', () => {\n  const items = ref\u003CCartItem[]>([])\n\n  const checkout = async () => {\n    \u002F\u002F 在 action 裡呼叫，不要放在 store 的最外層\n    const userStore = useUserStore()\n\n    if (!userStore.isLoggedIn) {\n      throw new Error('請先登入')\n    }\n\n    await api.checkout(items.value, userStore.token)\n    items.value = []\n  }\n\n  return { items, checkout }\n})\n",[29,22337,22338,22350,22354,22376,22394,22398,22414,22419,22432,22436,22447,22464,22468,22472,22484,22494,22498,22502,22509],{"__ignoreMap":27},[32,22339,22340,22342,22345,22347],{"class":34,"line":35},[32,22341,8794],{"class":38},[32,22343,22344],{"class":41}," { useUserStore } ",[32,22346,8850],{"class":38},[32,22348,22349],{"class":175}," '.\u002Fuser'\n",[32,22351,22352],{"class":34,"line":45},[32,22353,103],{"emptyLinePlaceholder":102},[32,22355,22356,22358,22360,22362,22364,22366,22368,22370,22372,22374],{"class":34,"line":51},[32,22357,5038],{"class":38},[32,22359,20832],{"class":38},[32,22361,20835],{"class":351},[32,22363,894],{"class":38},[32,22365,20840],{"class":217},[32,22367,477],{"class":41},[32,22369,20845],{"class":175},[32,22371,11218],{"class":41},[32,22373,5090],{"class":38},[32,22375,703],{"class":41},[32,22377,22378,22380,22383,22385,22387,22389,22392],{"class":34,"line":90},[32,22379,4157],{"class":38},[32,22381,22382],{"class":351}," items",[32,22384,894],{"class":38},[32,22386,19797],{"class":217},[32,22388,4046],{"class":41},[32,22390,22391],{"class":2066},"CartItem",[32,22393,21699],{"class":41},[32,22395,22396],{"class":34,"line":99},[32,22397,103],{"emptyLinePlaceholder":102},[32,22399,22400,22402,22404,22406,22408,22410,22412],{"class":34,"line":106},[32,22401,4157],{"class":38},[32,22403,2923],{"class":217},[32,22405,894],{"class":38},[32,22407,21794],{"class":38},[32,22409,11257],{"class":41},[32,22411,5090],{"class":38},[32,22413,703],{"class":41},[32,22415,22416],{"class":34,"line":114},[32,22417,22418],{"class":608},"    \u002F\u002F 在 action 裡呼叫，不要放在 store 的最外層\n",[32,22420,22421,22423,22426,22428,22430],{"class":34,"line":120},[32,22422,9409],{"class":38},[32,22424,22425],{"class":351}," userStore",[32,22427,894],{"class":38},[32,22429,22175],{"class":217},[32,22431,21860],{"class":41},[32,22433,22434],{"class":34,"line":127},[32,22435,103],{"emptyLinePlaceholder":102},[32,22437,22438,22440,22442,22444],{"class":34,"line":132},[32,22439,5554],{"class":38},[32,22441,900],{"class":41},[32,22443,19154],{"class":38},[32,22445,22446],{"class":41},"userStore.isLoggedIn) {\n",[32,22448,22449,22452,22454,22457,22459,22462],{"class":34,"line":141},[32,22450,22451],{"class":38},"      throw",[32,22453,4165],{"class":38},[32,22455,22456],{"class":217}," Error",[32,22458,477],{"class":41},[32,22460,22461],{"class":175},"'請先登入'",[32,22463,515],{"class":41},[32,22465,22466],{"class":34,"line":147},[32,22467,5591],{"class":41},[32,22469,22470],{"class":34,"line":275},[32,22471,103],{"emptyLinePlaceholder":102},[32,22473,22474,22477,22479,22481],{"class":34,"line":282},[32,22475,22476],{"class":38},"    await",[32,22478,22292],{"class":41},[32,22480,3763],{"class":217},[32,22482,22483],{"class":41},"(items.value, userStore.token)\n",[32,22485,22486,22489,22491],{"class":34,"line":295},[32,22487,22488],{"class":41},"    items.value ",[32,22490,172],{"class":38},[32,22492,22493],{"class":41}," []\n",[32,22495,22496],{"class":34,"line":605},[32,22497,1203],{"class":41},[32,22499,22500],{"class":34,"line":612},[32,22501,103],{"emptyLinePlaceholder":102},[32,22503,22504,22506],{"class":34,"line":617},[32,22505,10974],{"class":38},[32,22507,22508],{"class":41}," { items, checkout }\n",[32,22510,22511],{"class":34,"line":644},[32,22512,20790],{"class":41},[11,22514,22515,22522,22523,22526],{},[12249,22516,22517,22518,22521],{},"關鍵是 ",[29,22519,22520],{},"useUserStore()"," 要寫在 action 裡面，不要寫在 store 的最外層。"," 寫在外層時，那行程式會在模組載入當下就執行，而那時候 Pinia 實例可能還沒建立好（尤其在 SSR 環境），會拿到 ",[29,22524,22525],{},"getActivePinia was called with no active Pinia"," 這個錯誤。",[11,22528,22529],{},"要注意兩個 store 互相引用會形成循環相依。就 JavaScript 模組來說這是可行的，但如果 A 跟 B 頻繁互相呼叫，通常代表它們該合併成一個 store，或該把共用的邏輯抽成一般的 composable。",[15,22531,22532],{"id":22532},"什麼時候該用狀態管理",[11,22534,22535],{},"不是所有共用資料都需要 store。判斷標準大致是：",[4538,22537,22538,22544,22550],{},[4541,22539,22540,22543],{},[12249,22541,22542],{},"父子元件之間"," → props 與 emit 就夠了",[4541,22545,22546,22549],{},[12249,22547,22548],{},"跨多層、多個分支的元件"," → 用 store",[4541,22551,22552,22555,22556,11621,22559,22562],{},[12249,22553,22554],{},"只是伺服器資料的快取","（列表、詳情） → Nuxt 的 ",[29,22557,22558],{},"useFetch",[29,22560,22561],{},"useAsyncData"," 通常就夠，不必進 store",[11,22564,22565],{},"過早引入狀態管理，只會讓資料流變得更難追。",[15,22567,2004],{"id":2003},[11,22569,22570],{},"本文保留 Vuex 與 Pinia 的比較筆記。不同 Vue、Nuxt 與 Pinia 版本的支援範圍可能不同，新專案請以各套件目前文件確認。",[15,22572,22573],{"id":22573},"相關連結",[4538,22575,22576,22583,22590],{},[4541,22577,22578],{},[412,22579,22582],{"href":22580,"rel":22581},"https:\u002F\u002Fpinia.vuejs.org\u002F",[416],"Pinia 官方文件",[4541,22584,22585],{},[412,22586,22589],{"href":22587,"rel":22588},"https:\u002F\u002Fstackblitz.com\u002Fgithub\u002Fpiniajs\u002Fexample-vue-3-vite?file=src%2Fstores%2Fcart.ts",[416],"Pinia 官方範例（StackBlitz）",[4541,22591,22592],{},[412,22593,22596],{"href":22594,"rel":22595},"https:\u002F\u002Fwww.vuemastery.com\u002Fblog\u002Fadvantages-of-pinia-vs-vuex\u002F",[416],"Advantages of Pinia vs Vuex",[368,22598,22599],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":22601},[22602,22605,22606,22607,22611,22614,22615,22616,22617,22618],{"id":20387,"depth":45,"text":20388,"children":22603},[22604],{"id":20439,"depth":51,"text":20439},{"id":20468,"depth":45,"text":20469},{"id":20504,"depth":45,"text":20504},{"id":19439,"depth":45,"text":19439,"children":22608},[22609,22610],{"id":20621,"depth":51,"text":20622},{"id":20733,"depth":51,"text":20734},{"id":20796,"depth":45,"text":20797,"children":22612},[22613],{"id":21450,"depth":51,"text":21451},{"id":21555,"depth":45,"text":21556},{"id":22152,"depth":45,"text":22153},{"id":22532,"depth":45,"text":22532},{"id":2003,"depth":45,"text":2004},{"id":22573,"depth":45,"text":22573},"紀錄 Vuex、Pinia 的狀態管理概念、差異與用法。",{},"\u002Fposts\u002Fpinia-vuex-state-management","2024-05-05",[],{"title":20376,"description":22619},"posts\u002F20240505.pinia-vuex-state-management",[20517,4844,20372,22627,15195],"狀態管理","RDWbM3jg6LXqr1hxfbo57b2-7cL5GnLOFp4Mj-4bfR0",{"id":22630,"title":22631,"body":22632,"category":378,"description":25285,"draft":380,"extension":381,"image":382,"meta":25286,"navigation":102,"path":25287,"publishedAt":25288,"relatedExperiments":25289,"seo":25290,"stem":25291,"tags":25292,"updatedAt":14272,"__hash__":25294},"posts\u002Fposts\u002F20250724.nuxt3-setup-notes.md","Nuxt 筆記",{"type":8,"value":22633,"toc":25245},[22634,22638,22641,22644,22647,22660,22666,22669,22694,22697,22703,22706,22712,22715,22728,22730,22737,22740,22757,22765,22803,22806,22809,22812,22816,22838,22842,22848,22950,22964,22977,22980,22983,22989,23155,23158,23204,23223,23232,23235,23241,23244,23253,23299,23311,23314,23317,23329,23344,23416,23419,23430,23476,23479,23482,23488,23674,23677,23680,23686,23831,23849,23853,23859,23998,24007,24010,24013,24019,24028,24034,24047,24050,24053,24059,24062,24067,24177,24184,24188,24380,24388,24391,24396,24494,24500,24540,24560,24563,24571,24577,24597,24614,24617,24620,24638,24642,24676,24680,24686,24720,24727,24729,24750,24779,24783,24799,24803,24831,24836,24940,24946,24950,24953,24969,24973,24976,24991,24994,25000,25003,25016,25019,25023,25035,25039,25056,25062,25112,25115,25198,25200,25203,25205,25242],[15,22635,22637],{"id":22636},"安裝-nuxt-cli","安裝 Nuxt CLI",[11,22639,22640],{},"nuxi 全名是 Nuxt CLI（Nuxt Command Line Interface），是 Nuxt 官方提供的標準工具。它之於 Nuxt，就像 Vue CLI 之於 Vue——用來建立與管理專案。",[151,22642,22643],{"id":22643},"環境準備",[11,22645,22646],{},"為了確保 nuxi 不會拿到快取的舊版本，可以先清一次 npx 快取：",[22,22648,22650],{"className":2057,"code":22649,"language":2059,"meta":27,"style":27},"npx clear-npx-cache\n",[29,22651,22652],{"__ignoreMap":27},[32,22653,22654,22657],{"class":34,"line":35},[32,22655,22656],{"class":2066},"npx",[32,22658,22659],{"class":175}," clear-npx-cache\n",[11,22661,22662,22663,3775],{},"Node.js 需要 ",[12249,22664,22665],{},"v16.10.0 以上",[151,22667,22668],{"id":22668},"建立專案",[22,22670,22672],{"className":2057,"code":22671,"language":2059,"meta":27,"style":27},"npx nuxi@latest init \u003Cproject-name>\n",[29,22673,22674],{"__ignoreMap":27},[32,22675,22676,22678,22681,22683,22686,22689,22692],{"class":34,"line":35},[32,22677,22656],{"class":2066},[32,22679,22680],{"class":175}," nuxi@latest",[32,22682,8581],{"class":175},[32,22684,22685],{"class":38}," \u003C",[32,22687,22688],{"class":175},"project-nam",[32,22690,22691],{"class":41},"e",[32,22693,4062],{"class":38},[11,22695,22696],{},"執行後會問幾個問題，一路照預設走就好：",[22,22698,22701],{"className":22699,"code":22700,"language":426,"meta":27},[424],"✔ Which package manager would you like to use?\n  › npm \u002F pnpm \u002F yarn \u002F bun\n\n✔ Initialize git repository?\n  › Yes \u002F No\n",[29,22702,22700],{"__ignoreMap":27},[11,22704,22705],{},"裝完的專案長這樣（只有最基本的幾個檔案，其他資料夾要自己開）：",[22,22707,22710],{"className":22708,"code":22709,"language":426,"meta":27},[424],"nuxt-app\u002F\n├── .nuxt\u002F\n├── node_modules\u002F\n├── public\u002F\n├── server\u002F\n├── app.vue\n├── nuxt.config.ts\n├── package.json\n├── tsconfig.json\n└── README.md\n",[29,22711,22709],{"__ignoreMap":27},[11,22713,22714],{},"啟動：",[22,22716,22718],{"className":2057,"code":22717,"language":2059,"meta":27,"style":27},"npm run dev\n",[29,22719,22720],{"__ignoreMap":27},[32,22721,22722,22724,22726],{"class":34,"line":35},[32,22723,4625],{"class":2066},[32,22725,4743],{"class":175},[32,22727,10438],{"class":175},[15,22729,20552],{"id":20761},[11,22731,22732,22733,22736],{},"Nuxt 3 內建支援 TypeScript，設定放在專案根目錄的 ",[29,22734,22735],{},"tsconfig.json","。我習慣在開發時就開型別檢查，出錯當下就看到，不要等到 build。",[11,22738,22739],{},"安裝 Vue 的型別檢查工具：",[22,22741,22743],{"className":2057,"code":22742,"language":2059,"meta":27,"style":27},"npm install -D vue-tsc\n",[29,22744,22745],{"__ignoreMap":27},[32,22746,22747,22749,22751,22754],{"class":34,"line":35},[32,22748,4625],{"class":2066},[32,22750,4650],{"class":175},[32,22752,22753],{"class":351}," -D",[32,22755,22756],{"class":175}," vue-tsc\n",[11,22758,5134,22759,22761,22762,5240],{},[29,22760,20756],{}," 打開 ",[29,22763,22764],{},"typeCheck",[22,22766,22770],{"className":22767,"code":22768,"language":22769,"meta":27,"style":27},"language-ts shiki shiki-themes github-light github-dark-default","export default defineNuxtConfig({\n  typescript: {\n    typeCheck: true\n  }\n})\n","ts",[29,22771,22772,22782,22787,22795,22799],{"__ignoreMap":27},[32,22773,22774,22776,22778,22780],{"class":34,"line":35},[32,22775,5038],{"class":38},[32,22777,5041],{"class":38},[32,22779,20772],{"class":217},[32,22781,1143],{"class":5049},[32,22783,22784],{"class":34,"line":45},[32,22785,22786],{"class":41},"  typescript: {\n",[32,22788,22789,22792],{"class":34,"line":51},[32,22790,22791],{"class":41},"    typeCheck: ",[32,22793,22794],{"class":351},"true\n",[32,22796,22797],{"class":34,"line":90},[32,22798,1203],{"class":41},[32,22800,22801],{"class":34,"line":99},[32,22802,20790],{"class":5049},[15,22804,4853],{"id":22805},"eslint",[11,22807,22808],{},"ESLint 是 JavaScript 的 linter，用來檢查程式碼風格（縮排、單雙引號⋯⋯）並找出語法問題。在團隊裡它的價值更明顯：大家寫出來的東西會長得一樣，code review 就不用花時間在排版上吵架。",[11,22810,22811],{},"它可以直接套用大公司的規則配置（Google、Airbnb），也可以自己客製。這裡選 Nuxt 官方提供的那組。",[151,22813,22815],{"id":22814},"_1-安裝套件","1. 安裝套件",[22,22817,22819],{"className":2057,"code":22818,"language":2059,"meta":27,"style":27},"npm install -D eslint @nuxtjs\u002Feslint-config-typescript eslint-plugin-vue\n",[29,22820,22821],{"__ignoreMap":27},[32,22822,22823,22825,22827,22829,22832,22835],{"class":34,"line":35},[32,22824,4625],{"class":2066},[32,22826,4650],{"class":175},[32,22828,22753],{"class":351},[32,22830,22831],{"class":175}," eslint",[32,22833,22834],{"class":175}," @nuxtjs\u002Feslint-config-typescript",[32,22836,22837],{"class":175}," eslint-plugin-vue\n",[151,22839,22841],{"id":22840},"_2-建立設定檔","2. 建立設定檔",[11,22843,22844,22845,5240],{},"專案根目錄新增 ",[29,22846,22847],{},".eslintrc.js",[22,22849,22851],{"className":24,"code":22850,"language":26,"meta":27,"style":27},"module.exports = {\n  env: {\n    browser: true,\n    es2023: true\n  },\n  extends: ['@nuxtjs\u002Feslint-config-typescript'],\n  parserOptions: {\n    ecmaVersion: 2023,\n    sourceType: 'module'\n  },\n  rules: {\n    'no-undef': 'off'\n  }\n}\n",[29,22852,22853,22865,22870,22879,22886,22890,22900,22905,22915,22923,22927,22932,22942,22946],{"__ignoreMap":27},[32,22854,22855,22857,22859,22861,22863],{"class":34,"line":35},[32,22856,7130],{"class":351},[32,22858,1278],{"class":41},[32,22860,7135],{"class":351},[32,22862,894],{"class":38},[32,22864,703],{"class":41},[32,22866,22867],{"class":34,"line":45},[32,22868,22869],{"class":41},"  env: {\n",[32,22871,22872,22875,22877],{"class":34,"line":51},[32,22873,22874],{"class":41},"    browser: ",[32,22876,6206],{"class":351},[32,22878,547],{"class":41},[32,22880,22881,22884],{"class":34,"line":90},[32,22882,22883],{"class":41},"    es2023: ",[32,22885,22794],{"class":351},[32,22887,22888],{"class":34,"line":99},[32,22889,5639],{"class":41},[32,22891,22892,22895,22898],{"class":34,"line":106},[32,22893,22894],{"class":41},"  extends: [",[32,22896,22897],{"class":175},"'@nuxtjs\u002Feslint-config-typescript'",[32,22899,8212],{"class":41},[32,22901,22902],{"class":34,"line":114},[32,22903,22904],{"class":41},"  parserOptions: {\n",[32,22906,22907,22910,22913],{"class":34,"line":120},[32,22908,22909],{"class":41},"    ecmaVersion: ",[32,22911,22912],{"class":351},"2023",[32,22914,547],{"class":41},[32,22916,22917,22920],{"class":34,"line":127},[32,22918,22919],{"class":41},"    sourceType: ",[32,22921,22922],{"class":175},"'module'\n",[32,22924,22925],{"class":34,"line":132},[32,22926,5639],{"class":41},[32,22928,22929],{"class":34,"line":141},[32,22930,22931],{"class":41},"  rules: {\n",[32,22933,22934,22937,22939],{"class":34,"line":147},[32,22935,22936],{"class":175},"    'no-undef'",[32,22938,5269],{"class":41},[32,22940,22941],{"class":175},"'off'\n",[32,22943,22944],{"class":34,"line":275},[32,22945,1203],{"class":41},[32,22947,22948],{"class":34,"line":282},[32,22949,54],{"class":41},[11,22951,22952,22955,22956,22959,22960,22963],{},[29,22953,22954],{},"extends"," 是陣列，放要擴展的規則配置。",[29,22957,22958],{},"@nuxtjs\u002Feslint-config-typescript"," 是官方針對 Nuxt + TypeScript 的規則；如果專案沒用 TypeScript，改用 ",[29,22961,22962],{},"@nuxtjs\u002Feslint-config"," 即可。",[11,22965,22966,22969,22970,3750,22973,22976],{},[29,22967,22968],{},"no-undef"," 要關掉，是因為 Nuxt 有大量自動匯入的 API（",[29,22971,22972],{},"useRoute",[29,22974,22975],{},"defineNuxtConfig","⋯⋯），ESLint 看不到它們的宣告，開著會滿江紅。",[15,22978,22979],{"id":22979},"預設目錄結構",[11,22981,22982],{},"Nuxt 3 是「約定優於設定」，資料夾名稱本身就是設定，所以要先知道每個資料夾在幹嘛。",[22,22984,22987],{"className":22985,"code":22986,"language":426,"meta":27},[424],"nuxt-app\u002F\n├── .nuxt\u002F\n├── .output\u002F\n├── assets\u002F\n├── components\u002F\n├── composables\u002F\n├── content\u002F\n├── layouts\u002F\n├── middleware\u002F\n├── node_modules\u002F\n├── pages\u002F\n├── plugins\u002F\n├── public\u002F\n└── server\u002F\n    ├── api\u002F\n    ├── routes\u002F\n    └── middleware\u002F\n├── .gitignore\n├── .nuxtignore\n├── app.config.ts\n├── app.vue\n├── nuxt.config.ts\n├── package.json\n└── tsconfig.json\n",[29,22988,22986],{"__ignoreMap":27},[13433,22990,22991,23001],{},[13436,22992,22993],{},[13439,22994,22995,22998],{},[13442,22996,22997],{},"目錄／檔案",[13442,22999,23000],{},"用途",[13449,23002,23003,23016,23028,23038,23048,23058,23081,23091,23101,23114,23124,23141],{},[13439,23004,23005,23010],{},[13454,23006,23007],{},[29,23008,23009],{},".nuxt\u002F",[13454,23011,23012,23013],{},"開發環境下自動產生的 Vue 網站，",[12249,23014,23015],{},"不要手動改",[13439,23017,23018,23023],{},[13454,23019,23020],{},[29,23021,23022],{},".output\u002F",[13454,23024,23025,23026],{},"build 的產出，每次建置都會重新產生，",[12249,23027,23015],{},[13439,23029,23030,23035],{},[13454,23031,23032],{},[29,23033,23034],{},"assets\u002F",[13454,23036,23037],{},"需要被 Vite 處理的靜態資源（CSS\u002FSASS、字型、圖片）",[13439,23039,23040,23045],{},[13454,23041,23042],{},[29,23043,23044],{},"components\u002F",[13454,23046,23047],{},"Vue 元件，Nuxt 會自動載入，不用 import",[13439,23049,23050,23055],{},[13454,23051,23052],{},[29,23053,23054],{},"composables\u002F",[13454,23056,23057],{},"組合式函數，同樣自動載入",[13439,23059,23060,23065],{},[13454,23061,23062],{},[29,23063,23064],{},"content\u002F",[13454,23066,23067,23068,11621,23071,11621,23074,11621,23077,23080],{},"給 Nuxt Content 用，放 ",[29,23069,23070],{},".md",[29,23072,23073],{},".yml",[29,23075,23076],{},".csv",[29,23078,23079],{},".json","，做檔案式 CMS",[13439,23082,23083,23088],{},[13454,23084,23085],{},[29,23086,23087],{},"layouts\u002F",[13454,23089,23090],{},"版面模板，提供跨頁面重複使用的外框",[13439,23092,23093,23098],{},[13454,23094,23095],{},[29,23096,23097],{},"middleware\u002F",[13454,23099,23100],{},"路由中間件，導航到下一頁之前執行（例如權限驗證）",[13439,23102,23103,23108],{},[13454,23104,23105],{},[29,23106,23107],{},"pages\u002F",[13454,23109,23110,23111],{},"頁面，",[12249,23112,23113],{},"檔案結構直接決定路由",[13439,23115,23116,23121],{},[13454,23117,23118],{},[29,23119,23120],{},"plugins\u002F",[13454,23122,23123],{},"外掛，會自動載入",[13439,23125,23126,23131],{},[13454,23127,23128],{},[29,23129,23130],{},"public\u002F",[13454,23132,23133,23134,3750,23137,23140],{},"直接放在網站根目錄的檔案（",[29,23135,23136],{},"robots.txt",[29,23138,23139],{},"favicon.ico","）",[13439,23142,23143,23148],{},[13454,23144,23145],{},[29,23146,23147],{},"server\u002F",[13454,23149,23150,23151,23154],{},"後端邏輯（API、routes、middleware），",[12249,23152,23153],{},"不自動載入","但支援 HMR",[11,23156,23157],{},"幾個檔案：",[4538,23159,23160,23168,23179,23187,23194],{},[4541,23161,23162,23167],{},[12249,23163,23164],{},[29,23165,23166],{},".nuxtignore","：建置時要忽略的檔案",[4541,23169,23170,23175,23176],{},[12249,23171,23172],{},[29,23173,23174],{},"app.config.ts","：執行期會暴露給客戶端的設定，",[12249,23177,23178],{},"不要放任何機密",[4541,23180,23181,23186],{},[12249,23182,23183],{},[29,23184,23185],{},"app.vue","：Nuxt 3 網站的入口元件",[4541,23188,23189,23193],{},[12249,23190,23191],{},[29,23192,20756],{},"：專案設定檔",[4541,23195,23196,23200,23201,23203],{},[12249,23197,23198],{},[29,23199,22735],{},"：Nuxt 3 會在 ",[29,23202,23009],{}," 底下自動產一份含路徑別名的設定，根目錄這份用來擴展或覆蓋它",[11,23205,23206,7090,23208,23210,23211,16883,23216,23218,23219,23222],{},[29,23207,23034],{},[29,23209,23130],{}," 最容易搞混：",[12249,23212,23213,23215],{},[29,23214,23034],{}," 裡的東西要在 JS\u002FCSS 裡 import 才會被處理",[29,23217,23130],{}," 則是原封不動搬到根目錄，用絕對路徑 ",[29,23220,23221],{},"\u002Fxxx.png"," 引用。",[11,23224,23225,23226,7218,23228,23231],{},"目錄名稱也可以改，在 ",[29,23227,20756],{},[29,23229,23230],{},"dir"," 參數調整，但不是每個都能改，能改的只有官方列出的那幾個。",[15,23233,23234],{"id":23234},"檔案系統路由",[11,23236,23237,23238,23240],{},"Nuxt 的核心特性是「檔案系統路由器（file system router）」——",[29,23239,23107],{}," 底下每一個 Vue 檔案都會產生一個對應的 URL。底層還是 vue-router，只是路由表由檔名自動推出來，不用自己維護。",[151,23242,23243],{"id":23243},"建立第一個頁面",[11,23245,12767,23246,23249,23250,23252],{},[29,23247,23248],{},"pages\u002Findex.vue","，然後把 ",[29,23251,23185],{}," 改成：",[22,23254,23256],{"className":8665,"code":23255,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003CNuxtPage \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,23257,23258,23266,23274,23283,23291],{"__ignoreMap":27},[32,23259,23260,23262,23264],{"class":34,"line":35},[32,23261,4046],{"class":41},[32,23263,9623],{"class":4049},[32,23265,4062],{"class":41},[32,23267,23268,23270,23272],{"class":34,"line":45},[32,23269,4067],{"class":41},[32,23271,4050],{"class":4049},[32,23273,4062],{"class":41},[32,23275,23276,23278,23281],{"class":34,"line":51},[32,23277,9638],{"class":41},[32,23279,23280],{"class":4049},"NuxtPage",[32,23282,15104],{"class":41},[32,23284,23285,23287,23289],{"class":34,"line":90},[32,23286,9691],{"class":41},[32,23288,4050],{"class":4049},[32,23290,4062],{"class":41},[32,23292,23293,23295,23297],{"class":34,"line":99},[32,23294,4105],{"class":41},[32,23296,9623],{"class":4049},[32,23298,4062],{"class":41},[11,23300,23301,23303,23304,23310],{},[29,23302,15180],{}," 就是路由頁面被塞進來的位置。",[12249,23305,23306,23307,23309],{},"一旦建立了 ",[29,23308,23107],{}," 目錄，就一定要有這個元件","，否則什麼都不會顯示。",[151,23312,23313],{"id":23313},"查看自動產生的路由",[11,23315,23316],{},"想看 Nuxt 實際產出的路由表長什麼樣，可以 build 之後翻產物：",[22,23318,23319],{"className":2057,"code":4973,"language":2059,"meta":27,"style":27},[29,23320,23321],{"__ignoreMap":27},[32,23322,23323,23325,23327],{"class":34,"line":35},[32,23324,4625],{"class":2066},[32,23326,4743],{"class":175},[32,23328,4755],{"class":175},[11,23330,23331,23332,23335,23336,23339,23340,23343],{},"打開 ",[29,23333,23334],{},".output\u002Fserver\u002Fchunks\u002Fapp\u002Fserver.mjs","，搜尋 ",[29,23337,23338],{},"const _routes =","，或直接搜尋你剛建立的檔名（例如 ",[29,23341,23342],{},"about","），就會看到類似這樣的結構：",[22,23345,23347],{"className":24,"code":23346,"language":26,"meta":27,"style":27},"const _routes = [\n  {\n    name: \"about\",\n    path: \"\u002Fabout\",\n    component: () => import('.\u002F_nuxt\u002Fabout-xxxxxxxx.mjs')\n  },\n  ...\n]\n",[29,23348,23349,23360,23364,23374,23384,23402,23406,23411],{"__ignoreMap":27},[32,23350,23351,23353,23356,23358],{"class":34,"line":35},[32,23352,6617],{"class":38},[32,23354,23355],{"class":351}," _routes",[32,23357,894],{"class":38},[32,23359,15218],{"class":41},[32,23361,23362],{"class":34,"line":45},[32,23363,6526],{"class":41},[32,23365,23366,23369,23372],{"class":34,"line":51},[32,23367,23368],{"class":41},"    name: ",[32,23370,23371],{"class":175},"\"about\"",[32,23373,547],{"class":41},[32,23375,23376,23379,23382],{"class":34,"line":90},[32,23377,23378],{"class":41},"    path: ",[32,23380,23381],{"class":175},"\"\u002Fabout\"",[32,23383,547],{"class":41},[32,23385,23386,23389,23391,23393,23395,23397,23400],{"class":34,"line":99},[32,23387,23388],{"class":217},"    component",[32,23390,5087],{"class":41},[32,23392,5090],{"class":38},[32,23394,5093],{"class":38},[32,23396,477],{"class":41},[32,23398,23399],{"class":175},"'.\u002F_nuxt\u002Fabout-xxxxxxxx.mjs'",[32,23401,515],{"class":41},[32,23403,23404],{"class":34,"line":106},[32,23405,5639],{"class":41},[32,23407,23408],{"class":34,"line":114},[32,23409,23410],{"class":38},"  ...\n",[32,23412,23413],{"class":34,"line":120},[32,23414,23415],{"class":41},"]\n",[151,23417,23418],{"id":23418},"路由連結",[11,23420,23421,23422,23425,23426,23429],{},"用 ",[29,23423,23424],{},"\u003CNuxtLink>"," 而不是 ",[29,23427,23428],{},"\u003Ca>","，才會走前端導航不重新載入整頁：",[22,23431,23433],{"className":8665,"code":23432,"language":4112,"meta":27,"style":27},"\u003CNuxtLink to=\"\u002Fabout\">前往 About\u003C\u002FNuxtLink>\n\u003CNuxtLink to=\"\u002Fcontact\">前往 Contact\u003C\u002FNuxtLink>\n",[29,23434,23435,23456],{"__ignoreMap":27},[32,23436,23437,23439,23442,23445,23447,23449,23452,23454],{"class":34,"line":35},[32,23438,4046],{"class":41},[32,23440,23441],{"class":4049},"NuxtLink",[32,23443,23444],{"class":4053}," to",[32,23446,172],{"class":41},[32,23448,23381],{"class":175},[32,23450,23451],{"class":41},">前往 About\u003C\u002F",[32,23453,23441],{"class":4049},[32,23455,4062],{"class":41},[32,23457,23458,23460,23462,23464,23466,23469,23472,23474],{"class":34,"line":45},[32,23459,4046],{"class":41},[32,23461,23441],{"class":4049},[32,23463,23444],{"class":4053},[32,23465,172],{"class":41},[32,23467,23468],{"class":175},"\"\u002Fcontact\"",[32,23470,23471],{"class":41},">前往 Contact\u003C\u002F",[32,23473,23441],{"class":4049},[32,23475,4062],{"class":41},[151,23477,23478],{"id":23478},"動態路由",[11,23480,23481],{},"檔名用中括號包起來就是動態參數：",[22,23483,23486],{"className":23484,"code":23485,"language":426,"meta":27},[424],".\u002Fpages\u002F\n└── users\u002F\n    └── [id].vue\n",[29,23487,23485],{"__ignoreMap":27},[22,23489,23491],{"className":8665,"code":23490,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv class=\"bg-white py-24\">\n    \u003Cdiv class=\"flex flex-col items-center\">\n      \u003Ch1 class=\"text-3xl text-gray-600\">這裡是 Users 動態路由頁面\u003C\u002Fh1>\n      \u003Cp class=\"my-8 text-3xl text-gray-600\">\n        匹配到的 Id:\n        \u003Cspan class=\"text-5xl font-semibold text-blue-600\">{{ id }}\u003C\u002Fspan>\n      \u003C\u002Fp>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst route = useRoute()\nconst { id } = route.params\n\u003C\u002Fscript>\n",[29,23492,23493,23501,23516,23531,23551,23566,23571,23591,23599,23607,23615,23623,23627,23637,23651,23666],{"__ignoreMap":27},[32,23494,23495,23497,23499],{"class":34,"line":35},[32,23496,4046],{"class":41},[32,23498,9623],{"class":4049},[32,23500,4062],{"class":41},[32,23502,23503,23505,23507,23509,23511,23514],{"class":34,"line":45},[32,23504,4067],{"class":41},[32,23506,4050],{"class":4049},[32,23508,9897],{"class":4053},[32,23510,172],{"class":41},[32,23512,23513],{"class":175},"\"bg-white py-24\"",[32,23515,4062],{"class":41},[32,23517,23518,23520,23522,23524,23526,23529],{"class":34,"line":51},[32,23519,9638],{"class":41},[32,23521,4050],{"class":4049},[32,23523,9897],{"class":4053},[32,23525,172],{"class":41},[32,23527,23528],{"class":175},"\"flex flex-col items-center\"",[32,23530,4062],{"class":41},[32,23532,23533,23535,23537,23539,23541,23544,23547,23549],{"class":34,"line":90},[32,23534,21222],{"class":41},[32,23536,12467],{"class":4049},[32,23538,9897],{"class":4053},[32,23540,172],{"class":41},[32,23542,23543],{"class":175},"\"text-3xl text-gray-600\"",[32,23545,23546],{"class":41},">這裡是 Users 動態路由頁面\u003C\u002F",[32,23548,12467],{"class":4049},[32,23550,4062],{"class":41},[32,23552,23553,23555,23557,23559,23561,23564],{"class":34,"line":99},[32,23554,21222],{"class":41},[32,23556,11],{"class":4049},[32,23558,9897],{"class":4053},[32,23560,172],{"class":41},[32,23562,23563],{"class":175},"\"my-8 text-3xl text-gray-600\"",[32,23565,4062],{"class":41},[32,23567,23568],{"class":34,"line":106},[32,23569,23570],{"class":41},"        匹配到的 Id:\n",[32,23572,23573,23575,23577,23579,23581,23584,23587,23589],{"class":34,"line":114},[32,23574,21252],{"class":41},[32,23576,32],{"class":4049},[32,23578,9897],{"class":4053},[32,23580,172],{"class":41},[32,23582,23583],{"class":175},"\"text-5xl font-semibold text-blue-600\"",[32,23585,23586],{"class":41},">{{ id }}\u003C\u002F",[32,23588,32],{"class":4049},[32,23590,4062],{"class":41},[32,23592,23593,23595,23597],{"class":34,"line":120},[32,23594,21274],{"class":41},[32,23596,11],{"class":4049},[32,23598,4062],{"class":41},[32,23600,23601,23603,23605],{"class":34,"line":127},[32,23602,21283],{"class":41},[32,23604,4050],{"class":4049},[32,23606,4062],{"class":41},[32,23608,23609,23611,23613],{"class":34,"line":132},[32,23610,9691],{"class":41},[32,23612,4050],{"class":4049},[32,23614,4062],{"class":41},[32,23616,23617,23619,23621],{"class":34,"line":141},[32,23618,4105],{"class":41},[32,23620,9623],{"class":4049},[32,23622,4062],{"class":41},[32,23624,23625],{"class":34,"line":147},[32,23626,103],{"emptyLinePlaceholder":102},[32,23628,23629,23631,23633,23635],{"class":34,"line":275},[32,23630,4046],{"class":41},[32,23632,4125],{"class":4049},[32,23634,21329],{"class":4053},[32,23636,4062],{"class":41},[32,23638,23639,23641,23644,23646,23649],{"class":34,"line":282},[32,23640,6617],{"class":38},[32,23642,23643],{"class":351}," route",[32,23645,894],{"class":38},[32,23647,23648],{"class":217}," useRoute",[32,23650,21860],{"class":41},[32,23652,23653,23655,23657,23659,23661,23663],{"class":34,"line":295},[32,23654,6617],{"class":38},[32,23656,21387],{"class":41},[32,23658,21422],{"class":351},[32,23660,21398],{"class":41},[32,23662,172],{"class":38},[32,23664,23665],{"class":41}," route.params\n",[32,23667,23668,23670,23672],{"class":34,"line":605},[32,23669,4105],{"class":41},[32,23671,4125],{"class":4049},[32,23673,4062],{"class":41},[151,23675,23676],{"id":23676},"匹配所有層級",[11,23678,23679],{},"三個點加參數名，可以吃掉後面所有層級：",[22,23681,23684],{"className":23682,"code":23683,"language":426,"meta":27},[424],".\u002Fpages\u002F\n└── catch-all\u002F\n    └── [...slug].vue\n",[29,23685,23683],{"__ignoreMap":27},[22,23687,23689],{"className":8665,"code":23688,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv class=\"bg-white py-24\">\n    \u003Cdiv class=\"flex flex-col items-center\">\n      \u003Ch1 class=\"text-4xl text-gray-800\">這是 catch-all\u002F... 下的頁面\u003C\u002Fh1>\n      \u003Cp class=\"mt-8 text-3xl text-gray-600\">匹配到的 Params:\u003C\u002Fp>\n      \u003Cp class=\"my-4 text-5xl font-semibold text-violet-500\">{{ $route.params.slug }}\u003C\u002Fp>\n      \u003Cspan class=\"text-xl text-gray-400\">每個陣列元素對應一個層級\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,23690,23691,23699,23713,23727,23747,23767,23787,23807,23815,23823],{"__ignoreMap":27},[32,23692,23693,23695,23697],{"class":34,"line":35},[32,23694,4046],{"class":41},[32,23696,9623],{"class":4049},[32,23698,4062],{"class":41},[32,23700,23701,23703,23705,23707,23709,23711],{"class":34,"line":45},[32,23702,4067],{"class":41},[32,23704,4050],{"class":4049},[32,23706,9897],{"class":4053},[32,23708,172],{"class":41},[32,23710,23513],{"class":175},[32,23712,4062],{"class":41},[32,23714,23715,23717,23719,23721,23723,23725],{"class":34,"line":51},[32,23716,9638],{"class":41},[32,23718,4050],{"class":4049},[32,23720,9897],{"class":4053},[32,23722,172],{"class":41},[32,23724,23528],{"class":175},[32,23726,4062],{"class":41},[32,23728,23729,23731,23733,23735,23737,23740,23743,23745],{"class":34,"line":90},[32,23730,21222],{"class":41},[32,23732,12467],{"class":4049},[32,23734,9897],{"class":4053},[32,23736,172],{"class":41},[32,23738,23739],{"class":175},"\"text-4xl text-gray-800\"",[32,23741,23742],{"class":41},">這是 catch-all\u002F... 下的頁面\u003C\u002F",[32,23744,12467],{"class":4049},[32,23746,4062],{"class":41},[32,23748,23749,23751,23753,23755,23757,23760,23763,23765],{"class":34,"line":99},[32,23750,21222],{"class":41},[32,23752,11],{"class":4049},[32,23754,9897],{"class":4053},[32,23756,172],{"class":41},[32,23758,23759],{"class":175},"\"mt-8 text-3xl text-gray-600\"",[32,23761,23762],{"class":41},">匹配到的 Params:\u003C\u002F",[32,23764,11],{"class":4049},[32,23766,4062],{"class":41},[32,23768,23769,23771,23773,23775,23777,23780,23783,23785],{"class":34,"line":106},[32,23770,21222],{"class":41},[32,23772,11],{"class":4049},[32,23774,9897],{"class":4053},[32,23776,172],{"class":41},[32,23778,23779],{"class":175},"\"my-4 text-5xl font-semibold text-violet-500\"",[32,23781,23782],{"class":41},">{{ $route.params.slug }}\u003C\u002F",[32,23784,11],{"class":4049},[32,23786,4062],{"class":41},[32,23788,23789,23791,23793,23795,23797,23800,23803,23805],{"class":34,"line":114},[32,23790,21222],{"class":41},[32,23792,32],{"class":4049},[32,23794,9897],{"class":4053},[32,23796,172],{"class":41},[32,23798,23799],{"class":175},"\"text-xl text-gray-400\"",[32,23801,23802],{"class":41},">每個陣列元素對應一個層級\u003C\u002F",[32,23804,32],{"class":4049},[32,23806,4062],{"class":41},[32,23808,23809,23811,23813],{"class":34,"line":120},[32,23810,21283],{"class":41},[32,23812,4050],{"class":4049},[32,23814,4062],{"class":41},[32,23816,23817,23819,23821],{"class":34,"line":127},[32,23818,9691],{"class":41},[32,23820,4050],{"class":4049},[32,23822,4062],{"class":41},[32,23824,23825,23827,23829],{"class":34,"line":132},[32,23826,4105],{"class":41},[32,23828,9623],{"class":4049},[32,23830,4062],{"class":41},[11,23832,23833,23834,7090,23837,23840,23841,23844,23845,23848],{},"輸入 ",[29,23835,23836],{},"\u002Fcatch-all\u002Fhello",[29,23838,23839],{},"\u002Fcatch-all\u002Fhello\u002Fworld"," 都會進到這頁，差別在 ",[29,23842,23843],{},"slug"," 是一個",[12249,23846,23847],{},"陣列","，每個元素對應一個層級。",[151,23850,23852],{"id":23851},"_404-頁面","404 頁面",[11,23854,23855,23856,23858],{},"把 catch-all 放在 ",[29,23857,23107],{}," 根目錄，所有沒被匹配到的路由都會交給它：",[22,23860,23862],{"className":8665,"code":23861,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv class=\"bg-white py-24\">\n    \u003Cdiv class=\"flex flex-col items-center\">\n      \u003Ch1 class=\"text-8xl font-semibold text-red-500\">404\u003C\u002Fh1>\n      \u003Cp class=\"my-8 text-3xl text-gray-800\">Not Found\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nsetResponseStatus(404)\n\u003C\u002Fscript>\n",[29,23863,23864,23872,23886,23900,23920,23940,23948,23956,23964,23968,23978,23990],{"__ignoreMap":27},[32,23865,23866,23868,23870],{"class":34,"line":35},[32,23867,4046],{"class":41},[32,23869,9623],{"class":4049},[32,23871,4062],{"class":41},[32,23873,23874,23876,23878,23880,23882,23884],{"class":34,"line":45},[32,23875,4067],{"class":41},[32,23877,4050],{"class":4049},[32,23879,9897],{"class":4053},[32,23881,172],{"class":41},[32,23883,23513],{"class":175},[32,23885,4062],{"class":41},[32,23887,23888,23890,23892,23894,23896,23898],{"class":34,"line":51},[32,23889,9638],{"class":41},[32,23891,4050],{"class":4049},[32,23893,9897],{"class":4053},[32,23895,172],{"class":41},[32,23897,23528],{"class":175},[32,23899,4062],{"class":41},[32,23901,23902,23904,23906,23908,23910,23913,23916,23918],{"class":34,"line":90},[32,23903,21222],{"class":41},[32,23905,12467],{"class":4049},[32,23907,9897],{"class":4053},[32,23909,172],{"class":41},[32,23911,23912],{"class":175},"\"text-8xl font-semibold text-red-500\"",[32,23914,23915],{"class":41},">404\u003C\u002F",[32,23917,12467],{"class":4049},[32,23919,4062],{"class":41},[32,23921,23922,23924,23926,23928,23930,23933,23936,23938],{"class":34,"line":99},[32,23923,21222],{"class":41},[32,23925,11],{"class":4049},[32,23927,9897],{"class":4053},[32,23929,172],{"class":41},[32,23931,23932],{"class":175},"\"my-8 text-3xl text-gray-800\"",[32,23934,23935],{"class":41},">Not Found\u003C\u002F",[32,23937,11],{"class":4049},[32,23939,4062],{"class":41},[32,23941,23942,23944,23946],{"class":34,"line":106},[32,23943,21283],{"class":41},[32,23945,4050],{"class":4049},[32,23947,4062],{"class":41},[32,23949,23950,23952,23954],{"class":34,"line":114},[32,23951,9691],{"class":41},[32,23953,4050],{"class":4049},[32,23955,4062],{"class":41},[32,23957,23958,23960,23962],{"class":34,"line":120},[32,23959,4105],{"class":41},[32,23961,9623],{"class":4049},[32,23963,4062],{"class":41},[32,23965,23966],{"class":34,"line":127},[32,23967,103],{"emptyLinePlaceholder":102},[32,23969,23970,23972,23974,23976],{"class":34,"line":132},[32,23971,4046],{"class":41},[32,23973,4125],{"class":4049},[32,23975,21329],{"class":4053},[32,23977,4062],{"class":41},[32,23979,23980,23983,23985,23988],{"class":34,"line":141},[32,23981,23982],{"class":217},"setResponseStatus",[32,23984,477],{"class":41},[32,23986,23987],{"class":351},"404",[32,23989,515],{"class":41},[32,23991,23992,23994,23996],{"class":34,"line":147},[32,23993,4105],{"class":41},[32,23995,4125],{"class":4049},[32,23997,4062],{"class":41},[11,23999,24000,24006],{},[12249,24001,24002,24005],{},[29,24003,24004],{},"setResponseStatus(404)"," 不能省","。少了它畫面上雖然寫著 404，HTTP 狀態碼卻是 200，搜尋引擎會把這些不存在的頁面通通收錄進去。",[151,24008,24009],{"id":24009},"多層目錄與巢狀路由",[11,24011,24012],{},"目錄結構直接對應路徑層級：",[22,24014,24017],{"className":24015,"code":24016,"language":426,"meta":27},[424],".\u002Fpages\u002F\n└── posts\u002F\n    ├── [postId]\u002F\n    │   ├── comments\u002F\n    │   │   └── [commentId].vue\n    │   └── index.vue\n    ├── index.vue\n    └── top-[number].vue\n",[29,24018,24016],{"__ignoreMap":27},[11,24020,24021,24022,5240],{},"巢狀路由則是",[12249,24023,24024,24025,24027],{},"同名的資料夾與 ",[29,24026,5141],{}," 檔並存",[22,24029,24032],{"className":24030,"code":24031,"language":426,"meta":27},[424],".\u002Fpages\u002F\n├── docs\u002F\n│   ├── doc-1.vue\n│   └── doc-2.vue\n└── docs.vue\n",[29,24033,24031],{"__ignoreMap":27},[11,24035,24036,24039,24040,24042,24043,24046],{},[29,24037,24038],{},"docs.vue"," 是外層容器（裡面要放 ",[29,24041,15180],{},"），",[29,24044,24045],{},"docs\u002F"," 底下的檔案會被渲染進去。",[11,24048,24049],{},"靠目錄結構與中括號就能涵蓋大部分情境，實務上很少需要手動定義路由規則。",[15,24051,13062],{"id":24052},"layout",[11,24054,24055,24056,24058],{},"版面模板放在 ",[29,24057,23087],{},"，同樣會自動載入。",[151,24060,24061],{"id":24061},"預設模板",[11,24063,12767,24064,5240],{},[29,24065,24066],{},"layouts\u002Fdefault.vue",[22,24068,24070],{"className":8665,"code":24069,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv class=\"bg-sky-100 py-2\">\n    \u003Cp class=\"px-6 py-4 text-2xl text-gray-700\">這是預設的布局，全部頁面都會使用到\u003C\u002Fp>\n    \u003Cslot name=\"header\" \u002F>\n    \u003Cslot \u002F>\n    \u003Cslot name=\"footer\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,24071,24072,24080,24095,24115,24134,24144,24161,24169],{"__ignoreMap":27},[32,24073,24074,24076,24078],{"class":34,"line":35},[32,24075,4046],{"class":41},[32,24077,9623],{"class":4049},[32,24079,4062],{"class":41},[32,24081,24082,24084,24086,24088,24090,24093],{"class":34,"line":45},[32,24083,4067],{"class":41},[32,24085,4050],{"class":4049},[32,24087,9897],{"class":4053},[32,24089,172],{"class":41},[32,24091,24092],{"class":175},"\"bg-sky-100 py-2\"",[32,24094,4062],{"class":41},[32,24096,24097,24099,24101,24103,24105,24108,24111,24113],{"class":34,"line":51},[32,24098,9638],{"class":41},[32,24100,11],{"class":4049},[32,24102,9897],{"class":4053},[32,24104,172],{"class":41},[32,24106,24107],{"class":175},"\"px-6 py-4 text-2xl text-gray-700\"",[32,24109,24110],{"class":41},">這是預設的布局，全部頁面都會使用到\u003C\u002F",[32,24112,11],{"class":4049},[32,24114,4062],{"class":41},[32,24116,24117,24119,24122,24124,24126,24129,24132],{"class":34,"line":90},[32,24118,9638],{"class":41},[32,24120,24121],{"class":4049},"slot",[32,24123,5668],{"class":4053},[32,24125,172],{"class":41},[32,24127,24128],{"class":175},"\"header\"",[32,24130,8160],{"class":24131},"sAjPK",[32,24133,4062],{"class":41},[32,24135,24136,24138,24140,24142],{"class":34,"line":99},[32,24137,9638],{"class":41},[32,24139,24121],{"class":4049},[32,24141,8160],{"class":24131},[32,24143,4062],{"class":41},[32,24145,24146,24148,24150,24152,24154,24157,24159],{"class":34,"line":106},[32,24147,9638],{"class":41},[32,24149,24121],{"class":4049},[32,24151,5668],{"class":4053},[32,24153,172],{"class":41},[32,24155,24156],{"class":175},"\"footer\"",[32,24158,8160],{"class":24131},[32,24160,4062],{"class":41},[32,24162,24163,24165,24167],{"class":34,"line":114},[32,24164,9691],{"class":41},[32,24166,4050],{"class":4049},[32,24168,4062],{"class":41},[32,24170,24171,24173,24175],{"class":34,"line":120},[32,24172,4105],{"class":41},[32,24174,9623],{"class":4049},[32,24176,4062],{"class":41},[11,24178,24179,24180,24183],{},"模板裡一定要有一個未命名的 ",[29,24181,24182],{},"\u003Cslot \u002F>","，那是採用這個模板的頁面內容會出現的位置。",[151,24185,24187],{"id":24186},"在-appvue-掛上-nuxtlayout","在 app.vue 掛上 NuxtLayout",[22,24189,24191],{"className":8665,"code":24190,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cp class=\"pb-4 text-2xl text-slate-600\">這裡是最外層 app.vue\u003C\u002Fp>\n    \u003CNuxtLayout name=\"default\">\n      \u003Ctemplate #header>\n        \u003Cp class=\"px-6 pt-4 text-xl text-green-500\">這段會放置在 header 插槽\u003C\u002Fp>\n      \u003C\u002Ftemplate>\n      \u003Ctemplate #default>\n        \u003CNuxtPage \u002F>\n      \u003C\u002Ftemplate>\n      \u003Ctemplate #footer>\n        \u003Cp class=\"px-6 pt-4 text-xl text-blue-500\">這段會放置在 footer 插槽\u003C\u002Fp>\n      \u003C\u002Ftemplate>\n    \u003C\u002FNuxtLayout>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,24192,24193,24201,24209,24229,24245,24259,24279,24287,24300,24308,24316,24328,24348,24356,24364,24372],{"__ignoreMap":27},[32,24194,24195,24197,24199],{"class":34,"line":35},[32,24196,4046],{"class":41},[32,24198,9623],{"class":4049},[32,24200,4062],{"class":41},[32,24202,24203,24205,24207],{"class":34,"line":45},[32,24204,4067],{"class":41},[32,24206,4050],{"class":4049},[32,24208,4062],{"class":41},[32,24210,24211,24213,24215,24217,24219,24222,24225,24227],{"class":34,"line":51},[32,24212,9638],{"class":41},[32,24214,11],{"class":4049},[32,24216,9897],{"class":4053},[32,24218,172],{"class":41},[32,24220,24221],{"class":175},"\"pb-4 text-2xl text-slate-600\"",[32,24223,24224],{"class":41},">這裡是最外層 app.vue\u003C\u002F",[32,24226,11],{"class":4049},[32,24228,4062],{"class":41},[32,24230,24231,24233,24236,24238,24240,24243],{"class":34,"line":90},[32,24232,9638],{"class":41},[32,24234,24235],{"class":4049},"NuxtLayout",[32,24237,5668],{"class":4053},[32,24239,172],{"class":41},[32,24241,24242],{"class":175},"\"default\"",[32,24244,4062],{"class":41},[32,24246,24247,24249,24251,24254,24257],{"class":34,"line":99},[32,24248,21222],{"class":41},[32,24250,9623],{"class":4049},[32,24252,24253],{"class":41}," #",[32,24255,24256],{"class":4053},"header",[32,24258,4062],{"class":41},[32,24260,24261,24263,24265,24267,24269,24272,24275,24277],{"class":34,"line":106},[32,24262,21252],{"class":41},[32,24264,11],{"class":4049},[32,24266,9897],{"class":4053},[32,24268,172],{"class":41},[32,24270,24271],{"class":175},"\"px-6 pt-4 text-xl text-green-500\"",[32,24273,24274],{"class":41},">這段會放置在 header 插槽\u003C\u002F",[32,24276,11],{"class":4049},[32,24278,4062],{"class":41},[32,24280,24281,24283,24285],{"class":34,"line":114},[32,24282,21274],{"class":41},[32,24284,9623],{"class":4049},[32,24286,4062],{"class":41},[32,24288,24289,24291,24293,24295,24298],{"class":34,"line":120},[32,24290,21222],{"class":41},[32,24292,9623],{"class":4049},[32,24294,24253],{"class":41},[32,24296,24297],{"class":4053},"default",[32,24299,4062],{"class":41},[32,24301,24302,24304,24306],{"class":34,"line":127},[32,24303,21252],{"class":41},[32,24305,23280],{"class":4049},[32,24307,15104],{"class":41},[32,24309,24310,24312,24314],{"class":34,"line":132},[32,24311,21274],{"class":41},[32,24313,9623],{"class":4049},[32,24315,4062],{"class":41},[32,24317,24318,24320,24322,24324,24326],{"class":34,"line":141},[32,24319,21222],{"class":41},[32,24321,9623],{"class":4049},[32,24323,24253],{"class":41},[32,24325,14213],{"class":4053},[32,24327,4062],{"class":41},[32,24329,24330,24332,24334,24336,24338,24341,24344,24346],{"class":34,"line":147},[32,24331,21252],{"class":41},[32,24333,11],{"class":4049},[32,24335,9897],{"class":4053},[32,24337,172],{"class":41},[32,24339,24340],{"class":175},"\"px-6 pt-4 text-xl text-blue-500\"",[32,24342,24343],{"class":41},">這段會放置在 footer 插槽\u003C\u002F",[32,24345,11],{"class":4049},[32,24347,4062],{"class":41},[32,24349,24350,24352,24354],{"class":34,"line":275},[32,24351,21274],{"class":41},[32,24353,9623],{"class":4049},[32,24355,4062],{"class":41},[32,24357,24358,24360,24362],{"class":34,"line":282},[32,24359,21283],{"class":41},[32,24361,24235],{"class":4049},[32,24363,4062],{"class":41},[32,24365,24366,24368,24370],{"class":34,"line":295},[32,24367,9691],{"class":41},[32,24369,4050],{"class":4049},[32,24371,4062],{"class":41},[32,24373,24374,24376,24378],{"class":34,"line":605},[32,24375,4105],{"class":41},[32,24377,9623],{"class":4049},[32,24379,4062],{"class":41},[11,24381,24382,24384,24385,24387],{},[29,24383,15924],{}," 預設就是 ",[29,24386,24297],{},"，這裡明寫出來只是避免誤會。",[151,24389,24390],{"id":24390},"指定其他模板",[11,24392,12767,24393,5240],{},[29,24394,24395],{},"layouts\u002Fcustom.vue",[22,24397,24399],{"className":8665,"code":24398,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv class=\"bg-rose-100 py-2\">\n    \u003Cp class=\"px-6 py-4 text-2xl text-gray-700\">\n      使用 \u003Cspan class=\"font-bold text-rose-500\">Custom\u003C\u002Fspan> 布局\n    \u003C\u002Fp>\n    \u003Cslot \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,24400,24401,24409,24424,24438,24460,24468,24478,24486],{"__ignoreMap":27},[32,24402,24403,24405,24407],{"class":34,"line":35},[32,24404,4046],{"class":41},[32,24406,9623],{"class":4049},[32,24408,4062],{"class":41},[32,24410,24411,24413,24415,24417,24419,24422],{"class":34,"line":45},[32,24412,4067],{"class":41},[32,24414,4050],{"class":4049},[32,24416,9897],{"class":4053},[32,24418,172],{"class":41},[32,24420,24421],{"class":175},"\"bg-rose-100 py-2\"",[32,24423,4062],{"class":41},[32,24425,24426,24428,24430,24432,24434,24436],{"class":34,"line":51},[32,24427,9638],{"class":41},[32,24429,11],{"class":4049},[32,24431,9897],{"class":4053},[32,24433,172],{"class":41},[32,24435,24107],{"class":175},[32,24437,4062],{"class":41},[32,24439,24440,24443,24445,24447,24449,24452,24455,24457],{"class":34,"line":90},[32,24441,24442],{"class":41},"      使用 \u003C",[32,24444,32],{"class":4049},[32,24446,9897],{"class":4053},[32,24448,172],{"class":41},[32,24450,24451],{"class":175},"\"font-bold text-rose-500\"",[32,24453,24454],{"class":41},">Custom\u003C\u002F",[32,24456,32],{"class":4049},[32,24458,24459],{"class":41},"> 布局\n",[32,24461,24462,24464,24466],{"class":34,"line":99},[32,24463,21283],{"class":41},[32,24465,11],{"class":4049},[32,24467,4062],{"class":41},[32,24469,24470,24472,24474,24476],{"class":34,"line":106},[32,24471,9638],{"class":41},[32,24473,24121],{"class":4049},[32,24475,8160],{"class":24131},[32,24477,4062],{"class":41},[32,24479,24480,24482,24484],{"class":34,"line":114},[32,24481,9691],{"class":41},[32,24483,4050],{"class":4049},[32,24485,4062],{"class":41},[32,24487,24488,24490,24492],{"class":34,"line":120},[32,24489,4105],{"class":41},[32,24491,9623],{"class":4049},[32,24493,4062],{"class":41},[11,24495,24496,24497,5240],{},"在要套用的頁面用 ",[29,24498,24499],{},"definePageMeta",[22,24501,24503],{"className":8665,"code":24502,"language":4112,"meta":27,"style":27},"\u003Cscript setup>\ndefinePageMeta({\n  layout: 'custom'\n})\n\u003C\u002Fscript>\n",[29,24504,24505,24515,24521,24528,24532],{"__ignoreMap":27},[32,24506,24507,24509,24511,24513],{"class":34,"line":35},[32,24508,4046],{"class":41},[32,24510,4125],{"class":4049},[32,24512,21329],{"class":4053},[32,24514,4062],{"class":41},[32,24516,24517,24519],{"class":34,"line":45},[32,24518,24499],{"class":217},[32,24520,1143],{"class":41},[32,24522,24523,24525],{"class":34,"line":51},[32,24524,15149],{"class":41},[32,24526,24527],{"class":175},"'custom'\n",[32,24529,24530],{"class":34,"line":90},[32,24531,20790],{"class":41},[32,24533,24534,24536,24538],{"class":34,"line":99},[32,24535,4105],{"class":41},[32,24537,4125],{"class":4049},[32,24539,4062],{"class":41},[11,24541,24542,24545,24546,24549,24550,24552,24553,24556,24557,3775],{},[12249,24543,24544],{},"模板名稱一律是 kebab-case","。檔名寫 ",[29,24547,24548],{},"customLayout.vue"," 的話，要傳給 ",[29,24551,24052],{}," 的值是 ",[29,24554,24555],{},"custom-layout","，不是 ",[29,24558,24559],{},"customLayout",[15,24561,24562],{"id":24562},"元件",[11,24564,24565,24567,24568,5240],{},[29,24566,23044],{}," 底下的元件會被自動載入，不需要 import。命名規則是",[12249,24569,24570],{},"用路徑推出元件名稱",[22,24572,24575],{"className":24573,"code":24574,"language":426,"meta":27},[424],".\u002Fcomponents\u002F\n├── AppHeader.vue          → \u003CAppHeader \u002F>\n└── base\u002F\n    └── Button.vue         → \u003CBaseButton \u002F>\n",[29,24576,24574],{"__ignoreMap":27},[11,24578,24579,24580,24583,24584,23425,24587,24590,24591,24593,24594,3775],{},"子資料夾名稱會變成元件名稱的前綴，所以 ",[29,24581,24582],{},"base\u002FButton.vue"," 是 ",[29,24585,24586],{},"\u003CBaseButton \u002F>",[29,24588,24589],{},"\u003CButton \u002F>","。想關掉這個行為，在 ",[29,24592,20756],{}," 設 ",[29,24595,24596],{},"components: { pathPrefix: false }",[11,24598,24599,24600,10450,24603,24606,24607,24610,24611,24613],{},"檔名加上 ",[29,24601,24602],{},".client",[29,24604,24605],{},".server"," 後綴可以決定它只在哪一端渲染，例如 ",[29,24608,24609],{},"Chart.client.vue"," 只在瀏覽器渲染——用到 ",[29,24612,11296],{}," 的元件很需要這個。",[15,24615,20517],{"id":24616},"pinia",[11,24618,24619],{},"Pinia 是取代 Vuex 的全域狀態管理函式庫，比較輕量，適合中小型專案。",[22,24621,24623],{"className":2057,"code":24622,"language":2059,"meta":27,"style":27},"npm install pinia @pinia\u002Fnuxt --save-dev\n",[29,24624,24625],{"__ignoreMap":27},[32,24626,24627,24629,24631,24633,24636],{"class":34,"line":35},[32,24628,4625],{"class":2066},[32,24630,4650],{"class":175},[32,24632,20748],{"class":175},[32,24634,24635],{"class":175}," @pinia\u002Fnuxt",[32,24637,7066],{"class":351},[11,24639,24640,5240],{},[29,24641,20756],{},[22,24643,24645],{"className":22767,"code":24644,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: [\n    '@pinia\u002Fnuxt'\n  ]\n})\n",[29,24646,24647,24657,24662,24667,24672],{"__ignoreMap":27},[32,24648,24649,24651,24653,24655],{"class":34,"line":35},[32,24650,5038],{"class":38},[32,24652,5041],{"class":38},[32,24654,20772],{"class":217},[32,24656,1143],{"class":5049},[32,24658,24659],{"class":34,"line":45},[32,24660,24661],{"class":41},"  modules: [\n",[32,24663,24664],{"class":34,"line":51},[32,24665,24666],{"class":175},"    '@pinia\u002Fnuxt'\n",[32,24668,24669],{"class":34,"line":90},[32,24670,24671],{"class":41},"  ]\n",[32,24673,24674],{"class":34,"line":99},[32,24675,20790],{"class":5049},[151,24677,24679],{"id":24678},"踩坑pinia-或相依套件裝不起來","踩坑：Pinia 或相依套件裝不起來",[11,24681,24682,24683,24685],{},"裝的時候如果一直卡在相依衝突，在 ",[29,24684,4945],{}," 加上：",[22,24687,24689],{"className":5243,"code":24688,"language":5245,"meta":27,"style":27},"{\n  \"overrides\": {\n    \"vue\": \"latest\"\n  }\n}\n",[29,24690,24691,24695,24702,24712,24716],{"__ignoreMap":27},[32,24692,24693],{"class":34,"line":35},[32,24694,5252],{"class":41},[32,24696,24697,24700],{"class":34,"line":45},[32,24698,24699],{"class":5257},"  \"overrides\"",[32,24701,5261],{"class":41},[32,24703,24704,24707,24709],{"class":34,"line":51},[32,24705,24706],{"class":5257},"    \"vue\"",[32,24708,5269],{"class":41},[32,24710,24711],{"class":175},"\"latest\"\n",[32,24713,24714],{"class":34,"line":90},[32,24715,1203],{"class":41},[32,24717,24718],{"class":34,"line":99},[32,24719,54],{"class":41},[11,24721,24722,24723,24726],{},"原因是 Pinia 與 Nuxt 各自宣告的 vue 版本範圍對不上，npm 解不出一組共同的答案。",[29,24724,24725],{},"overrides"," 直接指定用哪一版，繞過解析。",[15,24728,4847],{"id":15027},[22,24730,24732],{"className":2057,"code":24731,"language":2059,"meta":27,"style":27},"npm install node-sass sass-loader sass -D\n",[29,24733,24734],{"__ignoreMap":27},[32,24735,24736,24738,24740,24742,24744,24747],{"class":34,"line":35},[32,24737,4625],{"class":2066},[32,24739,4650],{"class":175},[32,24741,8632],{"class":175},[32,24743,8635],{"class":175},[32,24745,24746],{"class":175}," sass",[32,24748,24749],{"class":351}," -D\n",[22,24751,24753],{"className":22767,"code":24752,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  css: ['~\u002Fassets\u002Fscss\u002Fapp.scss']\n})\n",[29,24754,24755,24765,24775],{"__ignoreMap":27},[32,24756,24757,24759,24761,24763],{"class":34,"line":35},[32,24758,5038],{"class":38},[32,24760,5041],{"class":38},[32,24762,20772],{"class":217},[32,24764,1143],{"class":5049},[32,24766,24767,24770,24773],{"class":34,"line":45},[32,24768,24769],{"class":41},"  css: [",[32,24771,24772],{"class":175},"'~\u002Fassets\u002Fscss\u002Fapp.scss'",[32,24774,23415],{"class":41},[32,24776,24777],{"class":34,"line":51},[32,24778,20790],{"class":5049},[15,24780,24782],{"id":24781},"tailwind-css","Tailwind CSS",[22,24784,24786],{"className":2057,"code":24785,"language":2059,"meta":27,"style":27},"npm install -D @nuxtjs\u002Ftailwindcss\n",[29,24787,24788],{"__ignoreMap":27},[32,24789,24790,24792,24794,24796],{"class":34,"line":35},[32,24791,4625],{"class":2066},[32,24793,4650],{"class":175},[32,24795,22753],{"class":351},[32,24797,24798],{"class":175}," @nuxtjs\u002Ftailwindcss\n",[11,24800,24801,5240],{},[29,24802,20756],{},[22,24804,24806],{"className":22767,"code":24805,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: ['@nuxtjs\u002Ftailwindcss']\n})\n",[29,24807,24808,24818,24827],{"__ignoreMap":27},[32,24809,24810,24812,24814,24816],{"class":34,"line":35},[32,24811,5038],{"class":38},[32,24813,5041],{"class":38},[32,24815,20772],{"class":217},[32,24817,1143],{"class":5049},[32,24819,24820,24822,24825],{"class":34,"line":45},[32,24821,17916],{"class":41},[32,24823,24824],{"class":175},"'@nuxtjs\u002Ftailwindcss'",[32,24826,23415],{"class":41},[32,24828,24829],{"class":34,"line":51},[32,24830,20790],{"class":5049},[11,24832,24833,5240],{},[29,24834,24835],{},"tailwind.config.js",[22,24837,24839],{"className":24,"code":24838,"language":26,"meta":27,"style":27},"\u002F** @type {import('tailwindcss').Config} *\u002F\nmodule.exports = {\n  content: [\n    '.\u002Fcomponents\u002F**\u002F*.{vue,js,ts}',\n    '.\u002Flayouts\u002F**\u002F*.vue',\n    '.\u002Fpages\u002F**\u002F*.vue',\n    '.\u002Fcomposables\u002F**\u002F*.{js,ts}',\n    '.\u002Fplugins\u002F**\u002F*.{js,ts}',\n    '.\u002Fapp.{js,ts,vue}'\n  ],\n  theme: {\n    extend: {}\n  },\n  plugins: []\n}\n",[29,24840,24841,24855,24867,24872,24879,24886,24893,24900,24907,24912,24917,24922,24927,24931,24936],{"__ignoreMap":27},[32,24842,24843,24846,24849,24852],{"class":34,"line":35},[32,24844,24845],{"class":608},"\u002F** ",[32,24847,24848],{"class":38},"@type",[32,24850,24851],{"class":2066}," {import('tailwindcss').Config}",[32,24853,24854],{"class":608}," *\u002F\n",[32,24856,24857,24859,24861,24863,24865],{"class":34,"line":45},[32,24858,7130],{"class":351},[32,24860,1278],{"class":41},[32,24862,7135],{"class":351},[32,24864,894],{"class":38},[32,24866,703],{"class":41},[32,24868,24869],{"class":34,"line":51},[32,24870,24871],{"class":41},"  content: [\n",[32,24873,24874,24877],{"class":34,"line":90},[32,24875,24876],{"class":175},"    '.\u002Fcomponents\u002F**\u002F*.{vue,js,ts}'",[32,24878,547],{"class":41},[32,24880,24881,24884],{"class":34,"line":99},[32,24882,24883],{"class":175},"    '.\u002Flayouts\u002F**\u002F*.vue'",[32,24885,547],{"class":41},[32,24887,24888,24891],{"class":34,"line":106},[32,24889,24890],{"class":175},"    '.\u002Fpages\u002F**\u002F*.vue'",[32,24892,547],{"class":41},[32,24894,24895,24898],{"class":34,"line":114},[32,24896,24897],{"class":175},"    '.\u002Fcomposables\u002F**\u002F*.{js,ts}'",[32,24899,547],{"class":41},[32,24901,24902,24905],{"class":34,"line":120},[32,24903,24904],{"class":175},"    '.\u002Fplugins\u002F**\u002F*.{js,ts}'",[32,24906,547],{"class":41},[32,24908,24909],{"class":34,"line":127},[32,24910,24911],{"class":175},"    '.\u002Fapp.{js,ts,vue}'\n",[32,24913,24914],{"class":34,"line":132},[32,24915,24916],{"class":41},"  ],\n",[32,24918,24919],{"class":34,"line":141},[32,24920,24921],{"class":41},"  theme: {\n",[32,24923,24924],{"class":34,"line":147},[32,24925,24926],{"class":41},"    extend: {}\n",[32,24928,24929],{"class":34,"line":275},[32,24930,5639],{"class":41},[32,24932,24933],{"class":34,"line":282},[32,24934,24935],{"class":41},"  plugins: []\n",[32,24937,24938],{"class":34,"line":295},[32,24939,54],{"class":41},[11,24941,24942,24945],{},[29,24943,24944],{},"content"," 這個陣列很關鍵——Tailwind 只會產出這些檔案裡真的出現過的 class。漏掉某個資料夾，那裡的樣式在正式環境就會整組消失（開發環境常常看不出來）。",[151,24947,24949],{"id":24948},"搭配-prettier-自動排序","搭配 Prettier 自動排序",[11,24951,24952],{},"class 一多就很難一眼確認有沒有重複，官方的 Prettier 外掛可以自動照推薦順序排列：",[22,24954,24956],{"className":2057,"code":24955,"language":2059,"meta":27,"style":27},"npm install -D prettier-plugin-tailwindcss\n",[29,24957,24958],{"__ignoreMap":27},[32,24959,24960,24962,24964,24966],{"class":34,"line":35},[32,24961,4625],{"class":2066},[32,24963,4650],{"class":175},[32,24965,22753],{"class":351},[32,24967,24968],{"class":175}," prettier-plugin-tailwindcss\n",[15,24970,24972],{"id":24971},"附錄nuxt-2-的-create-nuxt-app","附錄：Nuxt 2 的 create-nuxt-app",[11,24974,24975],{},"Nuxt 2 用的是另一支 CLI，會問一長串問題：",[22,24977,24979],{"className":2057,"code":24978,"language":2059,"meta":27,"style":27},"npx create-nuxt-app my-nuxt-project\n",[29,24980,24981],{"__ignoreMap":27},[32,24982,24983,24985,24988],{"class":34,"line":35},[32,24984,22656],{"class":2066},[32,24986,24987],{"class":175}," create-nuxt-app",[32,24989,24990],{"class":175}," my-nuxt-project\n",[11,24992,24993],{},"逐題的選項大致如下：",[22,24995,24998],{"className":24996,"code":24997,"language":426,"meta":27},[424],"? Project name: my-nuxt-project\n? Programming language: (Use arrow keys)\n❯ JavaScript\n  TypeScript\n\n? Package manager:\n❯ Yarn\n  Npm\n\n? UI framework:\n❯ None\n  Ant Design Vue\n  BalmUI\n  Bootstrap Vue\n  Buefy\n  Chakra UI\n  Element\n  Framevuerk\n  Oruga\n  Tachyons\n  Tailwind CSS\n  Windi CSS\n  Vant\n  View UI\n  Vuetify.js\n\n? Template engine:\n❯ HTML\n  Pug\n\n? Nuxt.js modules: (Press \u003Cspace> to select)\n❯ ◯ Axios - Promise based HTTP client\n  ◯ Progressive Web App (PWA)\n  ◯ Content - Git-based headless CMS\n\n? Linting tools: (Press \u003Cspace> to select)\n❯ ◯ ESLint\n  ◯ Prettier\n  ◯ Lint staged files\n  ◯ StyleLint\n  ◯ Commitlint\n\n? Testing framework:\n❯ None\n  Jest\n  AVA\n  WebdriverIO\n  Nightwatch\n\n? Rendering mode:\n❯ Universal (SSR \u002F SSG)\n  Single Page App\n\n? Deployment target:\n❯ Server (Node.js hosting)\n  Static (Static\u002FJamstack hosting)\n\n? Development tools: (Press \u003Cspace> to select)\n❯ ◯ jsconfig.json\n  ◯ Semantic Pull Requests\n  ◯ Dependabot\n",[29,24999,24997],{"__ignoreMap":27},[11,25001,25002],{},"ESLint 與 Prettier 兩個都會出現在 linting 那題，它們的分工是：",[4538,25004,25005,25010],{},[4541,25006,25007,25009],{},[12249,25008,4853],{},"：靜態分析工具，找出程式碼裡的問題，也管風格",[4541,25011,25012,25015],{},[12249,25013,25014],{},"Prettier","：純格式化工具，只管排版，不管品質",[11,25017,25018],{},"通常兩個一起用——ESLint 負責分析，Prettier 負責排版。",[151,25020,25022],{"id":25021},"nuxt-2-裝-pinia","Nuxt 2 裝 Pinia",[22,25024,25025],{"className":2057,"code":20625,"language":2059,"meta":27,"style":27},[29,25026,25027],{"__ignoreMap":27},[32,25028,25029,25031,25033],{"class":34,"line":35},[32,25030,4625],{"class":2066},[32,25032,4650],{"class":175},[32,25034,20636],{"class":175},[151,25036,25038],{"id":25037},"nuxt-2-裝-sass","Nuxt 2 裝 Sass",[22,25040,25042],{"className":2057,"code":25041,"language":2059,"meta":27,"style":27},"npm install node-sass sass-loader --save-dev\n",[29,25043,25044],{"__ignoreMap":27},[32,25045,25046,25048,25050,25052,25054],{"class":34,"line":35},[32,25047,4625],{"class":2066},[32,25049,4650],{"class":175},[32,25051,8632],{"class":175},[32,25053,8635],{"class":175},[32,25055,7066],{"class":351},[11,25057,5134,25058,7218,25060,24685],{},[29,25059,17897],{},[29,25061,7225],{},[22,25063,25065],{"className":24,"code":25064,"language":26,"meta":27,"style":27},"build: {\n  loaders: {\n    scss: { implementation: require('sass') }\n  }\n}\n",[29,25066,25067,25073,25080,25104,25108],{"__ignoreMap":27},[32,25068,25069,25071],{"class":34,"line":35},[32,25070,7225],{"class":2066},[32,25072,5261],{"class":41},[32,25074,25075,25078],{"class":34,"line":45},[32,25076,25077],{"class":2066},"  loaders",[32,25079,5261],{"class":41},[32,25081,25082,25085,25088,25091,25093,25096,25098,25101],{"class":34,"line":51},[32,25083,25084],{"class":2066},"    scss",[32,25086,25087],{"class":41},": { ",[32,25089,25090],{"class":2066},"implementation",[32,25092,5269],{"class":41},[32,25094,25095],{"class":217},"require",[32,25097,477],{"class":41},[32,25099,25100],{"class":175},"'sass'",[32,25102,25103],{"class":41},") }\n",[32,25105,25106],{"class":34,"line":90},[32,25107,1203],{"class":41},[32,25109,25110],{"class":34,"line":99},[32,25111,54],{"class":41},[11,25113,25114],{},"TypeScript 版本：",[22,25116,25118],{"className":22767,"code":25117,"language":22769,"meta":27,"style":27},"import { Configuration } from '@nuxt\u002Ftypes'\n\nconst config: Configuration = {\n  build: {\n    loaders: {\n      scss: { implementation: require('sass') }\n    }\n  }\n}\n\nexport default config\n",[29,25119,25120,25132,25136,25151,25155,25160,25173,25177,25181,25185,25189],{"__ignoreMap":27},[32,25121,25122,25124,25127,25129],{"class":34,"line":35},[32,25123,8794],{"class":38},[32,25125,25126],{"class":41}," { Configuration } ",[32,25128,8850],{"class":38},[32,25130,25131],{"class":175}," '@nuxt\u002Ftypes'\n",[32,25133,25134],{"class":34,"line":45},[32,25135,103],{"emptyLinePlaceholder":102},[32,25137,25138,25140,25142,25144,25147,25149],{"class":34,"line":51},[32,25139,6617],{"class":38},[32,25141,3425],{"class":351},[32,25143,322],{"class":38},[32,25145,25146],{"class":2066}," Configuration",[32,25148,894],{"class":38},[32,25150,703],{"class":41},[32,25152,25153],{"class":34,"line":90},[32,25154,19885],{"class":41},[32,25156,25157],{"class":34,"line":99},[32,25158,25159],{"class":41},"    loaders: {\n",[32,25161,25162,25165,25167,25169,25171],{"class":34,"line":106},[32,25163,25164],{"class":41},"      scss: { implementation: ",[32,25166,25095],{"class":217},[32,25168,477],{"class":41},[32,25170,25100],{"class":175},[32,25172,25103],{"class":41},[32,25174,25175],{"class":34,"line":114},[32,25176,5591],{"class":41},[32,25178,25179],{"class":34,"line":120},[32,25180,1203],{"class":41},[32,25182,25183],{"class":34,"line":127},[32,25184,54],{"class":41},[32,25186,25187],{"class":34,"line":132},[32,25188,103],{"emptyLinePlaceholder":102},[32,25190,25191,25193,25195],{"class":34,"line":141},[32,25192,5038],{"class":38},[32,25194,5041],{"class":38},[32,25196,25197],{"class":41}," config\n",[15,25199,2004],{"id":2003},[11,25201,25202],{},"本文是 Nuxt 3 與當時依賴版本的筆記。Nuxt、ESLint、Sass、Tailwind 與 Pinia 的設定方式已可能不同；新專案請採目前版本的官方初始化流程，不直接複製舊設定。",[15,25204,4536],{"id":4536},[4538,25206,25207,25214,25221,25228,25235],{},[4541,25208,25209],{},[412,25210,25213],{"href":25211,"rel":25212},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fgetting-started\u002Finstallation",[416],"Nuxt 3 官方文件",[4541,25215,25216],{},[412,25217,25220],{"href":25218,"rel":25219},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10295432",[416],"iThome：Nuxt 3 教學",[4541,25222,25223],{},[412,25224,25227],{"href":25225,"rel":25226},"https:\u002F\u002Fwww.penguin-cho.com\u002Fposts\u002Fnuxt3-pinia",[416],"Nuxt 3 + Pinia",[4541,25229,25230],{},[412,25231,25234],{"href":25232,"rel":25233},"https:\u002F\u002Fpinia.vuejs.org\u002Fssr\u002Fnuxt.html",[416],"Pinia 官方文件（Nuxt SSR）",[4541,25236,25237],{},[412,25238,25241],{"href":25239,"rel":25240},"https:\u002F\u002Fhackmd.io\u002F@Yan06\u002FSJgkRrhej",[416],"Nuxt 3 配置入門",[368,25243,25244],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}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 .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sAjPK, html code.shiki .sAjPK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FFA198;--shiki-dark-font-style:italic}html pre.shiki code .swgif, html code.shiki .swgif{--shiki-default:#005CC5;--shiki-dark:#7EE787}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}",{"title":27,"searchDepth":51,"depth":51,"links":25246},[25247,25251,25252,25256,25257,25266,25271,25272,25275,25276,25279,25283,25284],{"id":22636,"depth":45,"text":22637,"children":25248},[25249,25250],{"id":22643,"depth":51,"text":22643},{"id":22668,"depth":51,"text":22668},{"id":20761,"depth":45,"text":20552},{"id":22805,"depth":45,"text":4853,"children":25253},[25254,25255],{"id":22814,"depth":51,"text":22815},{"id":22840,"depth":51,"text":22841},{"id":22979,"depth":45,"text":22979},{"id":23234,"depth":45,"text":23234,"children":25258},[25259,25260,25261,25262,25263,25264,25265],{"id":23243,"depth":51,"text":23243},{"id":23313,"depth":51,"text":23313},{"id":23418,"depth":51,"text":23418},{"id":23478,"depth":51,"text":23478},{"id":23676,"depth":51,"text":23676},{"id":23851,"depth":51,"text":23852},{"id":24009,"depth":51,"text":24009},{"id":24052,"depth":45,"text":13062,"children":25267},[25268,25269,25270],{"id":24061,"depth":51,"text":24061},{"id":24186,"depth":51,"text":24187},{"id":24390,"depth":51,"text":24390},{"id":24562,"depth":45,"text":24562},{"id":24616,"depth":45,"text":20517,"children":25273},[25274],{"id":24678,"depth":51,"text":24679},{"id":15027,"depth":45,"text":4847},{"id":24781,"depth":45,"text":24782,"children":25277},[25278],{"id":24948,"depth":51,"text":24949},{"id":24971,"depth":45,"text":24972,"children":25280},[25281,25282],{"id":25021,"depth":51,"text":25022},{"id":25037,"depth":51,"text":25038},{"id":2003,"depth":45,"text":2004},{"id":4536,"depth":45,"text":4536},"紀錄 Nuxt 3 的安裝、目錄、路由、Layout 與相關套件設定。",{},"\u002Fposts\u002Fnuxt3-setup-notes","2025-07-24",[],{"title":22631,"description":25285},"posts\u002F20250724.nuxt3-setup-notes",[25293,20372,20517,24782,4853,20552],"Nuxt3","tb0qwFvd7FhIfiIEo2aKM64gP_RL2ynB0lpBNlRqPrc",{"id":25296,"title":25297,"body":25298,"category":378,"description":25828,"draft":380,"extension":381,"image":382,"meta":25829,"navigation":102,"path":25830,"publishedAt":25831,"relatedExperiments":25832,"seo":25833,"stem":25834,"tags":25835,"updatedAt":25831,"__hash__":25836},"posts\u002Fposts\u002F20260506.vite-vue3-tailwind4-shadcn-vue.md","Vite + Vue 3 + Tailwind CSS 4 + shadcn-vue 安裝心得與常見踩坑",{"type":8,"value":25299,"toc":25809},[25300,25303,25326,25330,25334,25345,25348,25352,25363,25367,25370,25373,25384,25387,25391,25394,25405,25408,25410,25434,25438,25445,25448,25457,25460,25476,25479,25545,25553,25556,25579,25582,25593,25611,25614,25627,25633,25641,25644,25650,25653,25656,25664,25670,25674,25677,25680,25685,25688,25692,25695,25699,25702,25705,25707,25710,25714,25716,25722,25725,25728,25747,25750,25766,25769,25806],[15,25301,25302],{"id":25302},"專案環境",[4538,25304,25305,25308,25311,25313,25315,25317,25320,25323],{},[4541,25306,25307],{},"Vite 7",[4541,25309,25310],{},"Vue 3",[4541,25312,20552],{},[4541,25314,20517],{},[4541,25316,4841],{},[4541,25318,25319],{},"unplugin-vue-router",[4541,25321,25322],{},"Tailwind CSS 4",[4541,25324,25325],{},"shadcn-vue",[15,25327,25329],{"id":25328},"_1-vite-與-vike-的差異","1. Vite 與 Vike 的差異",[151,25331,25333],{"id":25332},"vite","Vite",[4538,25335,25336,25339,25342],{},[4541,25337,25338],{},"前端建置工具（Build Tool）",[4541,25340,25341],{},"提供快速開發伺服器（HMR）",[4541,25343,25344],{},"不內建 Router、SSR",[11,25346,25347],{},"適合： - SPA - 後台系統 - Vue \u002F React 專案",[151,25349,25351],{"id":25350},"vike","Vike",[4538,25353,25354,25357,25360],{},[4541,25355,25356],{},"建立在 Vite 之上的 Web Framework",[4541,25358,25359],{},"提供 SSR、Routing、SEO 等能力",[4541,25361,25362],{},"類似 Next.js（React）或 Nuxt（Vue）",[15,25364,25366],{"id":25365},"_2-vue-專案一定要安裝-vue-router-嗎","2. Vue 專案一定要安裝 vue-router 嗎？",[11,25368,25369],{},"如果只有一個畫面，可以不用。",[11,25371,25372],{},"只要有：",[4538,25374,25375,25378,25381],{},[4541,25376,25377],{},"\u002Flogin",[4541,25379,25380],{},"\u002Fdashboard",[4541,25382,25383],{},"\u002Fhouse\u002F:id",[11,25385,25386],{},"就需要 vue-router。",[151,25388,25390],{"id":25389},"unplugin-vue-router-不是-router","unplugin-vue-router 不是 Router",[11,25392,25393],{},"它只是：",[4538,25395,25396,25399,25402],{},[4541,25397,25398],{},"自動產生 routes",[4541,25400,25401],{},"提供型別安全",[4541,25403,25404],{},"使用檔案式路由",[11,25406,25407],{},"底層仍然是 vue-router。",[11,25409,6399],{},[22,25411,25413],{"className":2057,"code":25412,"language":2059,"meta":27,"style":27},"npm install vue-router\nnpm install -D unplugin-vue-router\n",[29,25414,25415,25423],{"__ignoreMap":27},[32,25416,25417,25419,25421],{"class":34,"line":35},[32,25418,4625],{"class":2066},[32,25420,4650],{"class":175},[32,25422,9164],{"class":175},[32,25424,25425,25427,25429,25431],{"class":34,"line":45},[32,25426,4625],{"class":2066},[32,25428,4650],{"class":175},[32,25430,22753],{"class":351},[32,25432,25433],{"class":175}," unplugin-vue-router\n",[15,25435,25437],{"id":25436},"_3-tailwind-css-4-的重大變更","3. Tailwind CSS 4 的重大變更",[11,25439,25440,25441,25444],{},"Tailwind CSS 4 已經不能再把 ",[29,25442,25443],{},"tailwindcss"," 當作 PostCSS Plugin 使用。",[11,25446,25447],{},"以前：",[22,25449,25451],{"className":24,"code":25450,"language":26,"meta":27,"style":27},"tailwindcss\n",[29,25452,25453],{"__ignoreMap":27},[32,25454,25455],{"class":34,"line":35},[32,25456,25450],{"class":41},[11,25458,25459],{},"現在需要：",[22,25461,25463],{"className":2057,"code":25462,"language":2059,"meta":27,"style":27},"npm install -D @tailwindcss\u002Fpostcss\n",[29,25464,25465],{"__ignoreMap":27},[32,25466,25467,25469,25471,25473],{"class":34,"line":35},[32,25468,4625],{"class":2066},[32,25470,4650],{"class":175},[32,25472,22753],{"class":351},[32,25474,25475],{"class":175}," @tailwindcss\u002Fpostcss\n",[11,25477,25478],{},"PostCSS：",[22,25480,25482],{"className":24,"code":25481,"language":26,"meta":27,"style":27},"import tailwindcss from \"@tailwindcss\u002Fpostcss\"\nimport autoprefixer from \"autoprefixer\"\n\nexport default {\n  plugins: {\n    tailwindcss,\n    autoprefixer,\n  },\n}\n",[29,25483,25484,25496,25508,25512,25520,25525,25530,25535,25541],{"__ignoreMap":27},[32,25485,25486,25488,25491,25493],{"class":34,"line":35},[32,25487,8794],{"class":38},[32,25489,25490],{"class":41}," tailwindcss ",[32,25492,8850],{"class":38},[32,25494,25495],{"class":175}," \"@tailwindcss\u002Fpostcss\"\n",[32,25497,25498,25500,25503,25505],{"class":34,"line":45},[32,25499,8794],{"class":38},[32,25501,25502],{"class":41}," autoprefixer ",[32,25504,8850],{"class":38},[32,25506,25507],{"class":175}," \"autoprefixer\"\n",[32,25509,25510],{"class":34,"line":51},[32,25511,103],{"emptyLinePlaceholder":102},[32,25513,25514,25516,25518],{"class":34,"line":90},[32,25515,5038],{"class":38},[32,25517,5041],{"class":38},[32,25519,703],{"class":5049},[32,25521,25522],{"class":34,"line":99},[32,25523,25524],{"class":41},"  plugins: {\n",[32,25526,25527],{"class":34,"line":106},[32,25528,25529],{"class":41},"    tailwindcss,\n",[32,25531,25532],{"class":34,"line":114},[32,25533,25534],{"class":41},"    autoprefixer,\n",[32,25536,25537,25539],{"class":34,"line":120},[32,25538,9758],{"class":41},[32,25540,547],{"class":5049},[32,25542,25543],{"class":34,"line":127},[32,25544,54],{"class":5049},[15,25546,25548,25549,25552],{"id":25547},"_4-packagejson-使用-type-module-要注意","4. package.json 使用 ",[29,25550,25551],{},"\"type\": \"module\""," 要注意",[11,25554,25555],{},"如果 package.json：",[22,25557,25559],{"className":5243,"code":25558,"language":5245,"meta":27,"style":27},"{\n  \"type\": \"module\"\n}\n",[29,25560,25561,25565,25575],{"__ignoreMap":27},[32,25562,25563],{"class":34,"line":35},[32,25564,5252],{"class":41},[32,25566,25567,25570,25572],{"class":34,"line":45},[32,25568,25569],{"class":5257},"  \"type\"",[32,25571,5269],{"class":41},[32,25573,25574],{"class":175},"\"module\"\n",[32,25576,25577],{"class":34,"line":51},[32,25578,54],{"class":41},[11,25580,25581],{},"代表：",[4538,25583,25584,25590],{},[4541,25585,25586,25589],{},[29,25587,25588],{},".js"," 會被視為 ESM",[4541,25591,25592],{},"不可使用：",[22,25594,25596],{"className":24,"code":25595,"language":26,"meta":27,"style":27},"module.exports = {}\n",[29,25597,25598],{"__ignoreMap":27},[32,25599,25600,25602,25604,25606,25608],{"class":34,"line":35},[32,25601,7130],{"class":351},[32,25603,1278],{"class":41},[32,25605,7135],{"class":351},[32,25607,894],{"class":38},[32,25609,25610],{"class":41}," {}\n",[11,25612,25613],{},"必須改成：",[22,25615,25617],{"className":24,"code":25616,"language":26,"meta":27,"style":27},"export default {}\n",[29,25618,25619],{"__ignoreMap":27},[32,25620,25621,25623,25625],{"class":34,"line":35},[32,25622,5038],{"class":38},[32,25624,5041],{"class":38},[32,25626,25610],{"class":5049},[11,25628,25629,25630,3775],{},"或者把設定檔改成 ",[29,25631,25632],{},".cjs",[15,25634,25636,25637,25640],{"id":25635},"_5-為什麼-npx-tailwindcss-init-p-失敗","5. 為什麼 ",[29,25638,25639],{},"npx tailwindcss init -p"," 失敗？",[11,25642,25643],{},"錯誤：",[22,25645,25648],{"className":25646,"code":25647,"language":426,"meta":27},[424],"npm error could not determine executable to run\n",[29,25649,25647],{"__ignoreMap":27},[11,25651,25652],{},"在 Tailwind CSS 4 已經不一定需要依賴這個指令。",[11,25654,25655],{},"可以直接：",[4538,25657,25658,25661],{},[4541,25659,25660],{},"手動建立 Tailwind Config",[4541,25662,25663],{},"或直接使用官方新的設定方式",[11,25665,25666,25667,3775],{},"因此不用執著於 ",[29,25668,25669],{},"init -p",[15,25671,25673],{"id":25672},"_6-shadcn-vue-是否可以使用","6. shadcn-vue 是否可以使用？",[11,25675,25676],{},"可以。",[11,25678,25679],{},"React 使用：",[4538,25681,25682],{},[4541,25683,25684],{},"shadcn\u002Fui",[11,25686,25687],{},"Vue 使用：",[4538,25689,25690],{},[4541,25691,25325],{},[11,25693,25694],{},"不能直接把 React 的 shadcn\u002Fui 放進 Vue 專案。",[15,25696,25698],{"id":25697},"_7-element-plus-shadcn-vue","7. Element Plus → shadcn-vue",[11,25700,25701],{},"常見對照：",[11,25703,25704],{},"Element Plus   shadcn-vue",[10525,25706],{},[11,25708,25709],{},"el-card        Card\nel-button      Button\nel-input       Input\nel-select      Select\nel-dialog      Dialog\nel-slider      Slider\nel-table       Table",[15,25711,25713],{"id":25712},"_8-git-push-出現-invalid-username-or-token","8. Git Push 出現 Invalid username or token",[11,25715,2427],{},[22,25717,25720],{"className":25718,"code":25719,"language":426,"meta":27},[424],"Password authentication is not supported\n",[29,25721,25719],{"__ignoreMap":27},[11,25723,25724],{},"代表目前還在使用 HTTPS。",[11,25726,25727],{},"建議改用 SSH：",[22,25729,25731],{"className":2057,"code":25730,"language":2059,"meta":27,"style":27},"git remote set-url origin git@github.com:USER\u002FREPO.git\n",[29,25732,25733],{"__ignoreMap":27},[32,25734,25735,25737,25739,25742,25744],{"class":34,"line":35},[32,25736,2126],{"class":2066},[32,25738,12725],{"class":175},[32,25740,25741],{"class":175}," set-url",[32,25743,12730],{"class":175},[32,25745,25746],{"class":175}," git@github.com:USER\u002FREPO.git\n",[11,25748,25749],{},"測試：",[22,25751,25753],{"className":2057,"code":25752,"language":2059,"meta":27,"style":27},"ssh -T git@github.com\n",[29,25754,25755],{"__ignoreMap":27},[32,25756,25757,25760,25763],{"class":34,"line":35},[32,25758,25759],{"class":2066},"ssh",[32,25761,25762],{"class":351}," -T",[32,25764,25765],{"class":175}," git@github.com\n",[15,25767,25768],{"id":25768},"本次重點整理",[4538,25770,25771,25774,25777,25780,25783,25789,25800,25803],{},[4541,25772,25773],{},"Vite 是 Build Tool，不是 Framework。",[4541,25775,25776],{},"Vike 提供 SSR 與 Routing。",[4541,25778,25779],{},"Vue 多頁面專案需要 vue-router。",[4541,25781,25782],{},"unplugin-vue-router 只是自動產生 routes。",[4541,25784,25785,25786,3775],{},"Tailwind CSS 4 已改用 ",[29,25787,25788],{},"@tailwindcss\u002Fpostcss",[4541,25790,25791,25793,25794,25797,25798,3775],{},[29,25792,25551],{}," 專案要使用 ESM (",[29,25795,25796],{},"export default",") 或 ",[29,25799,25632],{},[4541,25801,25802],{},"Vue 專案請使用 shadcn-vue，不是 React 的 shadcn\u002Fui。",[4541,25804,25805],{},"GitHub 建議使用 SSH 推送，不要使用密碼。",[368,25807,25808],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}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 .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .swgif, html code.shiki .swgif{--shiki-default:#005CC5;--shiki-dark:#7EE787}",{"title":27,"searchDepth":51,"depth":51,"links":25810},[25811,25812,25816,25819,25820,25822,25824,25825,25826,25827],{"id":25302,"depth":45,"text":25302},{"id":25328,"depth":45,"text":25329,"children":25813},[25814,25815],{"id":25332,"depth":51,"text":25333},{"id":25350,"depth":51,"text":25351},{"id":25365,"depth":45,"text":25366,"children":25817},[25818],{"id":25389,"depth":51,"text":25390},{"id":25436,"depth":45,"text":25437},{"id":25547,"depth":45,"text":25821},"4. package.json 使用 \"type\": \"module\" 要注意",{"id":25635,"depth":45,"text":25823},"5. 為什麼 npx tailwindcss init -p 失敗？",{"id":25672,"depth":45,"text":25673},{"id":25697,"depth":45,"text":25698},{"id":25712,"depth":45,"text":25713},{"id":25768,"depth":45,"text":25768},"記錄用 Vite、Vue 3、Tailwind CSS 4、shadcn-vue 建專案時踩到的坑，包含 vue-router 安裝、Tailwind 4 的 PostCSS 變更、ESM 設定與 Git SSH 推送問題。",{},"\u002Fposts\u002Fvite-vue3-tailwind4-shadcn-vue","2026-05-06",[],{"title":25297,"description":25828},"posts\u002F20260506.vite-vue3-tailwind4-shadcn-vue",[25333,20372,25322,25325],"ipF_6dy1h87-9ZQ-SEwWcghcwFuGrYJpFiS4LncEL0M",{"id":25838,"title":25839,"body":25840,"category":25931,"description":25932,"draft":380,"extension":381,"image":382,"meta":25933,"navigation":102,"path":25934,"publishedAt":392,"relatedExperiments":25935,"seo":25937,"stem":25938,"tags":25939,"updatedAt":6716,"__hash__":25942},"posts\u002Fposts\u002F20260805.hello.md","自由實驗室開張",{"type":8,"value":25841,"toc":25928},[25842,25845,25848,25851,25854,25857,25925],[11,25843,25844],{},"很開心，終於有一個屬於自己的部落格了！\n其實從好幾年前開始，我就一直想做自己的部落格，只是每次做到一半，都覺得好像少了點什麼。\n光是名字就想了很久，也因此拖了很長一段時間。",[11,25846,25847],{},"這次原本也沒有想得這麼複雜，只是想做一個放小工具的站台。\n結果做到一半才發現，站名不但太泛用，還剛好跟其他同類型的網站撞名。\n看到的時候只覺得……\n真的超級無敵尷尬。\n最後乾脆決定整個打掉重來。",[11,25849,25850],{},"重新整理的過程中，我也開始覺得，如果只拿來放小工具好像有點可惜。\n既然本來就有自己的部落格，也有很多平常寫下來的東西，那不如全部放在一起。\n文章、小工具、小遊戲、互動實驗，甚至一些突然想到、單純只是想做看看的東西，都可以丟進來。\n不用特別限制它一定要是什麼。\n「自由實驗室」也就這樣慢慢成形了。\n所以往後這個網站上，應該會出現很多奇奇怪怪的東西。\n技術文章可能旁邊突然出現一個小遊戲，過幾天又多了一個不知道拿來幹嘛的小工具。\n想做什麼就做什麼。\n大概就是這個地方存在的原因。",[15,25852,25853],{"id":25853},"技術選擇",[11,25855,25856],{},"這次也順便把整個網站重新整理了一次，目前主要使用這些技術：",[13433,25858,25859,25871],{},[13436,25860,25861],{},[13439,25862,25863,25865,25868],{},[13442,25864,13544],{},[13442,25866,25867],{},"選擇",[13442,25869,25870],{},"原因",[13449,25872,25873,25884,25895,25904,25914],{},[13439,25874,25875,25878,25881],{},[13454,25876,25877],{},"框架",[13454,25879,25880],{},"Nuxt 4",[13454,25882,25883],{},"想繼續熟悉 Nuxt，也很適合拿來做內容型網站",[13439,25885,25886,25889,25892],{},[13454,25887,25888],{},"樣式",[13454,25890,25891],{},"Tailwind CSS v4",[13454,25893,25894],{},"寫樣式方便，網站要慢慢調整也比較自由",[13439,25896,25897,25899,25901],{},[13454,25898,24562],{},[13454,25900,25325],{},[13454,25902,25903],{},"元件直接放在專案裡，需要修改時可以自己調整",[13439,25905,25906,25908,25911],{},[13454,25907,19299],{},[13454,25909,25910],{},"Zod",[13454,25912,25913],{},"可以統一處理資料與 Content frontmatter 的格式驗證",[13439,25915,25916,25919,25922],{},[13454,25917,25918],{},"部署",[13454,25920,25921],{},"Cloudflare Workers",[13454,25923,25924],{},"部署方便，也可以直接搭配自己的網域",[11,25926,25927],{},"目前網站還在慢慢整理中。\n以前寫過的文章也會陸續搬回來，有些甚至已經是很多年前留下來的內容了。\n就先一點一點整理吧。\n至少這次，終於真的把它做出來了。",{"title":27,"searchDepth":51,"depth":51,"links":25929},[25930],{"id":25853,"depth":45,"text":25853},"project","原本只是想做一個小工具站，做到一半卻因為撞名決定整個重來，最後變成現在的自由實驗室。",{},"\u002Fposts\u002Fhello",[25936],"bmi-calculator",{"title":25839,"description":25932},"posts\u002F20260805.hello",[15195,25940,25941],"Cloudflare","重構","GDqPOiGjUiqmnYHJ-q9L4C3qENyU0WuYEWnCz6LuxhA",{"id":25944,"title":25945,"body":25946,"category":378,"description":27230,"draft":380,"extension":381,"image":382,"meta":27231,"navigation":102,"path":27232,"publishedAt":27233,"relatedExperiments":27234,"seo":27235,"stem":27236,"tags":27237,"updatedAt":27233,"__hash__":27240},"posts\u002Fposts\u002F20260818.nuxt4-project-setup.md","Nuxt 4 現在怎麼開專案：app\u002F 目錄、@nuxt\u002Feslint 與 Tailwind 4",{"type":8,"value":25947,"toc":27214},[25948,25967,25974,25977,25986,26008,26014,26052,26057,26061,26085,26091,26109,26112,26138,26142,26148,26194,26200,26204,26207,26234,26241,26243,26254,26265,26270,26304,26322,26344,26348,26356,26375,26403,26415,26468,26478,26482,26488,26507,26571,26576,26625,26628,26671,26680,26684,26695,26735,26738,26749,26752,26756,26770,26896,26903,26912,26916,26919,26955,26970,26995,26998,27114,27117,27120,27167,27173,27175,27211],[11,25949,25950,25951,25954,25955,3750,25958,3750,25960,25963,25964,25966],{},"之前寫過 ",[412,25952,25953],{"href":25287},"Nuxt 3 專案建立筆記","，那篇裡的 ",[29,25956,25957],{},"npx nuxi@latest init",[29,25959,22847],{},[29,25961,25962],{},"@nuxtjs\u002Ftailwindcss"," + ",[29,25965,24835],{}," 現在照著做都會撞牆。",[11,25968,25969,25970,25973],{},"Nuxt 4 的改動不算多，但",[12249,25971,25972],{},"每一項都在你開專案的第一個小時就會遇到","，所以值得單獨記一次。這篇的設定都是這個站自己在跑的。",[15,25975,25976],{"id":25976},"建專案",[11,25978,25979,25982,25983,25985],{},[29,25980,25981],{},"nuxi"," 這個獨立指令已經併回 ",[29,25984,15101],{}," 本身，現在的入口是：",[22,25987,25989],{"className":2057,"code":25988,"language":2059,"meta":27,"style":27},"npm create nuxt@latest \u003Cproject-name>\n",[29,25990,25991],{"__ignoreMap":27},[32,25992,25993,25995,25997,26000,26002,26004,26006],{"class":34,"line":35},[32,25994,4625],{"class":2066},[32,25996,4799],{"class":175},[32,25998,25999],{"class":175}," nuxt@latest",[32,26001,22685],{"class":38},[32,26003,22688],{"class":175},[32,26005,22691],{"class":41},[32,26007,4062],{"class":38},[11,26009,26010,26011,26013],{},"裝完之後，日常指令都掛在 ",[29,26012,15101],{}," 底下：",[22,26015,26017],{"className":2057,"code":26016,"language":2059,"meta":27,"style":27},"nuxt dev\nnuxt build\nnuxt preview\nnuxt typecheck\nnuxt prepare\n",[29,26018,26019,26025,26031,26038,26045],{"__ignoreMap":27},[32,26020,26021,26023],{"class":34,"line":35},[32,26022,15101],{"class":2066},[32,26024,10438],{"class":175},[32,26026,26027,26029],{"class":34,"line":45},[32,26028,15101],{"class":2066},[32,26030,4755],{"class":175},[32,26032,26033,26035],{"class":34,"line":51},[32,26034,15101],{"class":2066},[32,26036,26037],{"class":175}," preview\n",[32,26039,26040,26042],{"class":34,"line":90},[32,26041,15101],{"class":2066},[32,26043,26044],{"class":175}," typecheck\n",[32,26046,26047,26049],{"class":34,"line":99},[32,26048,15101],{"class":2066},[32,26050,26051],{"class":175}," prepare\n",[11,26053,26054,26056],{},[29,26055,25957],{}," 還能動，但它只是轉呼叫上面那個，文件已經不提了。",[15,26058,26060],{"id":26059},"最大的改動srcdir-變成-app","最大的改動：srcDir 變成 app\u002F",[11,26062,26063,26064,3750,26066,3750,26068,3750,26070,26072,26073,3750,26076,26078,26079,5240],{},"Nuxt 3 的 ",[29,26065,23107],{},[29,26067,23044],{},[29,26069,23054],{},[29,26071,23087],{}," 都在根目錄，跟 ",[29,26074,26075],{},"node_modules\u002F",[29,26077,23022],{},"、設定檔混在一起。Nuxt 4 把",[12249,26080,26081,26082],{},"前端的部分整組搬進 ",[29,26083,26084],{},"app\u002F",[22,26086,26089],{"className":26087,"code":26088,"language":426,"meta":27},[424],"my-app\u002F\n├── app\u002F                  ← 前端全部在這裡\n│   ├── assets\u002F\n│   ├── components\u002F\n│   ├── composables\u002F\n│   ├── layouts\u002F\n│   ├── middleware\u002F\n│   ├── pages\u002F\n│   ├── plugins\u002F\n│   ├── app.vue\n│   └── app.config.ts\n├── server\u002F               ← 留在根目錄\n│   ├── api\u002F\n│   ├── routes\u002F\n│   └── middleware\u002F\n├── content\u002F              ← 留在根目錄\n├── public\u002F               ← 留在根目錄\n├── nuxt.config.ts\n└── package.json\n",[29,26090,26088],{"__ignoreMap":27},[11,26092,26093,26105,26106,26108],{},[12249,26094,26095,26096,3750,26098,3750,26100,7090,26102],{},"留在根目錄的是 ",[29,26097,23147],{},[29,26099,23064],{},[29,26101,23130],{},[29,26103,26104],{},"modules\u002F","。判準很單純：",[29,26107,26084],{}," 底下的東西會被打包進前端 bundle，其他的不會。",[11,26110,26111],{},"實務上的影響：",[4538,26113,26114,26129,26135],{},[4541,26115,26116,26119,26120,26122,26123,24583,26126],{},[29,26117,26118],{},"~\u002F"," 別名現在指向 ",[29,26121,26084],{},"，所以 ",[29,26124,26125],{},"~\u002Fcomponents\u002FFoo.vue",[29,26127,26128],{},"app\u002Fcomponents\u002FFoo.vue",[4541,26130,26131,26132,26134],{},"從 ",[29,26133,26084],{}," 底下要引用根目錄的設定檔，得用相對路徑往上跳一層",[4541,26136,26137],{},"檔案監看的範圍縮小了，dev server 啟動與 HMR 都比較快",[151,26139,26141],{"id":26140},"從-nuxt-3-升上來","從 Nuxt 3 升上來",[11,26143,26144,26145,26147],{},"不想一次搬完的話，",[29,26146,20756],{}," 可以留在舊行為：",[22,26149,26151],{"className":22767,"code":26150,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  srcDir: '.',\n  dir: {\n    app: 'app'\n  }\n})\n",[29,26152,26153,26163,26173,26178,26186,26190],{"__ignoreMap":27},[32,26154,26155,26157,26159,26161],{"class":34,"line":35},[32,26156,5038],{"class":38},[32,26158,5041],{"class":38},[32,26160,20772],{"class":217},[32,26162,1143],{"class":5049},[32,26164,26165,26168,26171],{"class":34,"line":45},[32,26166,26167],{"class":41},"  srcDir: ",[32,26169,26170],{"class":175},"'.'",[32,26172,547],{"class":5049},[32,26174,26175],{"class":34,"line":51},[32,26176,26177],{"class":41},"  dir: {\n",[32,26179,26180,26183],{"class":34,"line":90},[32,26181,26182],{"class":41},"    app: ",[32,26184,26185],{"class":175},"'app'\n",[32,26187,26188],{"class":34,"line":99},[32,26189,1203],{"class":41},[32,26191,26192],{"class":34,"line":106},[32,26193,20790],{"class":5049},[11,26195,26196,26197,26199],{},"但這只是緩衝。新專案直接用 ",[29,26198,26084],{},"，不要為了省一次搬檔案而長期背著一份跟文件不一致的結構。",[15,26201,26203],{"id":26202},"compatibilitydate","compatibilityDate",[11,26205,26206],{},"Nuxt 4 的設定檔多了一個一定要填的欄位：",[22,26208,26210],{"className":22767,"code":26209,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  compatibilityDate: '2025-07-15'\n})\n",[29,26211,26212,26222,26230],{"__ignoreMap":27},[32,26213,26214,26216,26218,26220],{"class":34,"line":35},[32,26215,5038],{"class":38},[32,26217,5041],{"class":38},[32,26219,20772],{"class":217},[32,26221,1143],{"class":5049},[32,26223,26224,26227],{"class":34,"line":45},[32,26225,26226],{"class":41},"  compatibilityDate: ",[32,26228,26229],{"class":175},"'2025-07-15'\n",[32,26231,26232],{"class":34,"line":51},[32,26233,20790],{"class":5049},[11,26235,26236,26237,26240],{},"它鎖住 Nitro 與各家部署平台的行為版本。",[12249,26238,26239],{},"沒填的話升級 Nuxt 時可能會靜靜地換掉某些預設值","——填一個日期，之後升版行為就不會自己漂移，等你有空再往前推。",[15,26242,20552],{"id":20761},[11,26244,26245,26246,26249,26250,26253],{},"型別檢查不用再自己裝 ",[29,26247,26248],{},"vue-tsc"," 加 ",[29,26251,26252],{},"typeCheck: true"," 了，直接有指令：",[22,26255,26257],{"className":2057,"code":26256,"language":2059,"meta":27,"style":27},"nuxt typecheck\n",[29,26258,26259],{"__ignoreMap":27},[32,26260,26261,26263],{"class":34,"line":35},[32,26262,15101],{"class":2066},[32,26264,26044],{"class":175},[11,26266,26267,26269],{},[29,26268,20756],{}," 只留 strict 就好：",[22,26271,26273],{"className":22767,"code":26272,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  typescript: {\n    strict: true\n  }\n})\n",[29,26274,26275,26285,26289,26296,26300],{"__ignoreMap":27},[32,26276,26277,26279,26281,26283],{"class":34,"line":35},[32,26278,5038],{"class":38},[32,26280,5041],{"class":38},[32,26282,20772],{"class":217},[32,26284,1143],{"class":5049},[32,26286,26287],{"class":34,"line":45},[32,26288,22786],{"class":41},[32,26290,26291,26294],{"class":34,"line":51},[32,26292,26293],{"class":41},"    strict: ",[32,26295,22794],{"class":351},[32,26297,26298],{"class":34,"line":90},[32,26299,1203],{"class":41},[32,26301,26302],{"class":34,"line":99},[32,26303,20790],{"class":5049},[11,26305,26306,26307,3750,26309,3750,26311,26314,26315,26317,26318,26321],{},"Nuxt 4 會為 ",[29,26308,26084],{},[29,26310,23147],{},[29,26312,26313],{},"shared\u002F"," 各產生一份獨立的 tsconfig，所以在 ",[29,26316,23147],{}," 底下寫 ",[29,26319,26320],{},"document.querySelector"," 會直接被型別擋下來——Nuxt 3 是不會的。",[2184,26323,26324],{},[11,26325,26326,26335,26336,26339,26340,26343],{},[12249,26327,26328,26331,26332],{},[29,26329,26330],{},"nuxt typecheck"," 內部會跑 ",[29,26333,26334],{},"nuxt prepare","。如果專案用了 ",[29,26337,26338],{},"@nuxt\u002Fcontent","，它會重建本機的 content 資料庫，",[12249,26341,26342],{},"dev server 開著的時候跑會把 dev 那邊的文章清空","。停掉 dev 再跑。",[15,26345,26347],{"id":26346},"eslint改用-nuxteslint","ESLint：改用 @nuxt\u002Feslint",[11,26349,26350,26352,26353,26355],{},[29,26351,22847],{}," 這種 legacy config 已經不再是 ESLint 的預設，",[29,26354,22958],{}," 也停在原地了。現在的做法是官方的模組：",[22,26357,26359],{"className":2057,"code":26358,"language":2059,"meta":27,"style":27},"npm install -D @nuxt\u002Feslint eslint\n",[29,26360,26361],{"__ignoreMap":27},[32,26362,26363,26365,26367,26369,26372],{"class":34,"line":35},[32,26364,4625],{"class":2066},[32,26366,4650],{"class":175},[32,26368,22753],{"class":351},[32,26370,26371],{"class":175}," @nuxt\u002Feslint",[32,26373,26374],{"class":175}," eslint\n",[22,26376,26378],{"className":22767,"code":26377,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: ['@nuxt\u002Feslint']\n})\n",[29,26379,26380,26390,26399],{"__ignoreMap":27},[32,26381,26382,26384,26386,26388],{"class":34,"line":35},[32,26383,5038],{"class":38},[32,26385,5041],{"class":38},[32,26387,20772],{"class":217},[32,26389,1143],{"class":5049},[32,26391,26392,26394,26397],{"class":34,"line":45},[32,26393,17916],{"class":41},[32,26395,26396],{"class":175},"'@nuxt\u002Feslint'",[32,26398,23415],{"class":41},[32,26400,26401],{"class":34,"line":51},[32,26402,20790],{"class":5049},[11,26404,26405,26406,26408,26409,5240],{},"跑一次 ",[29,26407,26334],{},"，它會",[12249,26410,26411,26412],{},"自動產生一份 ",[29,26413,26414],{},"eslint.config.mjs",[22,26416,26418],{"className":24,"code":26417,"language":26,"meta":27,"style":27},"import withNuxt from '.\u002F.nuxt\u002Feslint.config.mjs'\n\nexport default withNuxt({\n  rules: {\n    'vue\u002Fmulti-word-component-names': 'off'\n  }\n})\n",[29,26419,26420,26432,26436,26447,26451,26460,26464],{"__ignoreMap":27},[32,26421,26422,26424,26427,26429],{"class":34,"line":35},[32,26423,8794],{"class":38},[32,26425,26426],{"class":41}," withNuxt ",[32,26428,8850],{"class":38},[32,26430,26431],{"class":175}," '.\u002F.nuxt\u002Feslint.config.mjs'\n",[32,26433,26434],{"class":34,"line":45},[32,26435,103],{"emptyLinePlaceholder":102},[32,26437,26438,26440,26442,26445],{"class":34,"line":51},[32,26439,5038],{"class":38},[32,26441,5041],{"class":38},[32,26443,26444],{"class":217}," withNuxt",[32,26446,1143],{"class":5049},[32,26448,26449],{"class":34,"line":90},[32,26450,22931],{"class":41},[32,26452,26453,26456,26458],{"class":34,"line":99},[32,26454,26455],{"class":175},"    'vue\u002Fmulti-word-component-names'",[32,26457,5269],{"class":41},[32,26459,22941],{"class":175},[32,26461,26462],{"class":34,"line":106},[32,26463,1203],{"class":41},[32,26465,26466],{"class":34,"line":114},[32,26467,20790],{"class":5049},[11,26469,26470,26471,26474,26475,26477],{},"它比手寫設定好的地方在於：規則是",[12249,26472,26473],{},"依你實際安裝的模組產生的","，Nuxt 自動匯入的那些 API 也已經登記好，不用再像以前那樣為了消掉滿江紅的 ",[29,26476,22968],{}," 而整條關掉。",[15,26479,26481],{"id":26480},"tailwind-4不再有-tailwindconfigjs","Tailwind 4：不再有 tailwind.config.js",[11,26483,26484,26485,26487],{},"這是變動最大的一塊。",[29,26486,25962],{}," 那條路已經不需要了，Tailwind 4 自己提供 Vite plugin：",[22,26489,26491],{"className":2057,"code":26490,"language":2059,"meta":27,"style":27},"npm install -D tailwindcss @tailwindcss\u002Fvite\n",[29,26492,26493],{"__ignoreMap":27},[32,26494,26495,26497,26499,26501,26504],{"class":34,"line":35},[32,26496,4625],{"class":2066},[32,26498,4650],{"class":175},[32,26500,22753],{"class":351},[32,26502,26503],{"class":175}," tailwindcss",[32,26505,26506],{"class":175}," @tailwindcss\u002Fvite\n",[22,26508,26510],{"className":22767,"code":26509,"language":22769,"meta":27,"style":27},"import tailwindcss from '@tailwindcss\u002Fvite'\n\nexport default defineNuxtConfig({\n  css: ['~\u002Fassets\u002Fcss\u002Fmain.css'],\n  vite: {\n    plugins: [tailwindcss()]\n  }\n})\n",[29,26511,26512,26523,26527,26537,26548,26553,26563,26567],{"__ignoreMap":27},[32,26513,26514,26516,26518,26520],{"class":34,"line":35},[32,26515,8794],{"class":38},[32,26517,25490],{"class":41},[32,26519,8850],{"class":38},[32,26521,26522],{"class":175}," '@tailwindcss\u002Fvite'\n",[32,26524,26525],{"class":34,"line":45},[32,26526,103],{"emptyLinePlaceholder":102},[32,26528,26529,26531,26533,26535],{"class":34,"line":51},[32,26530,5038],{"class":38},[32,26532,5041],{"class":38},[32,26534,20772],{"class":217},[32,26536,1143],{"class":5049},[32,26538,26539,26541,26544,26546],{"class":34,"line":90},[32,26540,24769],{"class":41},[32,26542,26543],{"class":175},"'~\u002Fassets\u002Fcss\u002Fmain.css'",[32,26545,17922],{"class":41},[32,26547,547],{"class":5049},[32,26549,26550],{"class":34,"line":99},[32,26551,26552],{"class":41},"  vite: {\n",[32,26554,26555,26558,26560],{"class":34,"line":106},[32,26556,26557],{"class":41},"    plugins: [",[32,26559,25443],{"class":217},[32,26561,26562],{"class":41},"()]\n",[32,26564,26565],{"class":34,"line":114},[32,26566,1203],{"class":41},[32,26568,26569],{"class":34,"line":120},[32,26570,20790],{"class":5049},[11,26572,26573,5240],{},[29,26574,26575],{},"app\u002Fassets\u002Fcss\u002Fmain.css",[22,26577,26579],{"className":5412,"code":26578,"language":1140,"meta":27,"style":27},"@import \"tailwindcss\";\n\n@theme {\n  --color-brand: #000000;\n  --font-sans: \"Noto Sans TC\", sans-serif;\n}\n",[29,26580,26581,26590,26594,26601,26611,26621],{"__ignoreMap":27},[32,26582,26583,26585,26588],{"class":34,"line":35},[32,26584,8744],{"class":38},[32,26586,26587],{"class":175}," \"tailwindcss\"",[32,26589,96],{"class":41},[32,26591,26592],{"class":34,"line":45},[32,26593,103],{"emptyLinePlaceholder":102},[32,26595,26596,26599],{"class":34,"line":51},[32,26597,26598],{"class":38},"@theme",[32,26600,703],{"class":41},[32,26602,26603,26606,26609],{"class":34,"line":90},[32,26604,26605],{"class":41},"  --color-brand: ",[32,26607,26608],{"class":24131},"#000000",[32,26610,96],{"class":41},[32,26612,26613,26616,26619],{"class":34,"line":99},[32,26614,26615],{"class":41},"  --font-sans: \"Noto Sans TC\", ",[32,26617,26618],{"class":4049},"sans-serif",[32,26620,96],{"class":41},[32,26622,26623],{"class":34,"line":106},[32,26624,54],{"class":41},[11,26626,26627],{},"三個要注意的：",[6426,26629,26630,26644,26653],{},[4541,26631,26632,26637,26638,26640,26641,26643],{},[12249,26633,26634,26635],{},"沒有 ",[29,26636,24835],{},"。主題設定改用 CSS 的 ",[29,26639,26598],{}," 區塊寫，跑 ",[29,26642,25639],{}," 會直接失敗。",[4541,26645,26646,26652],{},[12249,26647,26648,26649,26651],{},"不用再維護 ",[29,26650,24944],{}," 陣列","。Tailwind 4 自動掃描，以前那種「漏掉一個資料夾、正式站樣式整組消失」的坑沒有了。",[4541,26654,26655,26664,26665,26668,26669,3775],{},[12249,26656,26657,26660,26661],{},[29,26658,26659],{},"@apply"," 在 scoped style 裡要先 ",[29,26662,26663],{},"@reference","。單檔元件的 ",[29,26666,26667],{},"\u003Cstyle scoped>"," 是獨立編譯的，看不到主檔案的 ",[29,26670,8744],{},[11,26672,26673,26674,26676,26677,3775],{},"Tailwind 4 本身的其他變更（PostCSS 設定、",[29,26675,26598],{}," 的用法）另外寫在 ",[412,26678,26679],{"href":25830},"Vite + Vue 3 + Tailwind CSS 4 + shadcn-vue 安裝心得",[15,26681,26683],{"id":26682},"狀態管理先問要不要-pinia","狀態管理：先問要不要 Pinia",[11,26685,26686,26687,26690,26691,26694],{},"Nuxt 3 那篇裡裝 Pinia 是預設動作。實際上 Nuxt 內建的 ",[29,26688,26689],{},"useState"," 已經能處理大部分情況——它是 ",[12249,26692,26693],{},"SSR 友善的共用 ref","，伺服器端算出來的值會被序列化帶到瀏覽器：",[22,26696,26698],{"className":22767,"code":26697,"language":22769,"meta":27,"style":27},"export const useCounter = () => useState\u003Cnumber>('counter', () => 0)\n",[29,26699,26700],{"__ignoreMap":27},[32,26701,26702,26704,26706,26709,26711,26713,26715,26718,26720,26722,26724,26727,26729,26731,26733],{"class":34,"line":35},[32,26703,5038],{"class":38},[32,26705,20832],{"class":38},[32,26707,26708],{"class":217}," useCounter",[32,26710,894],{"class":38},[32,26712,11257],{"class":41},[32,26714,5090],{"class":38},[32,26716,26717],{"class":217}," useState",[32,26719,4046],{"class":41},[32,26721,18187],{"class":351},[32,26723,22214],{"class":41},[32,26725,26726],{"class":175},"'counter'",[32,26728,11218],{"class":41},[32,26730,5090],{"class":38},[32,26732,1523],{"class":351},[32,26734,515],{"class":41},[11,26736,26737],{},"在任何元件裡呼叫同一個 key 就拿到同一份狀態。什麼時候才真的需要 Pinia：",[4538,26739,26740,26743,26746],{},[4541,26741,26742],{},"需要 store 的 actions／getters 組織一大包邏輯",[4541,26744,26745],{},"需要 devtools 的時間旅行除錯",[4541,26747,26748],{},"已經有一套 Pinia store 要從別的專案搬過來",[11,26750,26751],{},"不然多一層抽象只是多一層要維護的東西。",[15,26753,26755],{"id":26754},"資料取得預渲染一定要-await","資料取得：預渲染一定要 await",[11,26757,26758,26759,7090,26761,26763,26764,5240],{},"這是最容易吃虧的一個。",[29,26760,22561],{},[29,26762,22558],{}," 回傳的是 ref，",[12249,26765,26766,26767,26769],{},"在 setup 階段沒有 ",[29,26768,22056],{},"，預渲染就會在資料回來之前先把 HTML 吐出去",[22,26771,26773],{"className":8665,"code":26772,"language":4112,"meta":27,"style":27},"\u003Cscript setup lang=\"ts\">\n\u002F\u002F ✗ 預渲染出來的 HTML 裡 posts 是空的\nconst { data: posts } = useAsyncData('posts', () => queryCollection('posts').all())\n\n\u002F\u002F ✓\nconst { data: posts } = await useAsyncData('posts', () => queryCollection('posts').all())\n\u003C\u002Fscript>\n",[29,26774,26775,26791,26796,26839,26843,26848,26888],{"__ignoreMap":27},[32,26776,26777,26779,26781,26783,26785,26787,26789],{"class":34,"line":35},[32,26778,4046],{"class":41},[32,26780,4125],{"class":4049},[32,26782,21329],{"class":4053},[32,26784,8677],{"class":4053},[32,26786,172],{"class":41},[32,26788,21978],{"class":175},[32,26790,4062],{"class":41},[32,26792,26793],{"class":34,"line":45},[32,26794,26795],{"class":608},"\u002F\u002F ✗ 預渲染出來的 HTML 裡 posts 是空的\n",[32,26797,26798,26800,26802,26805,26807,26810,26812,26814,26817,26819,26822,26824,26826,26829,26831,26833,26835,26837],{"class":34,"line":51},[32,26799,6617],{"class":38},[32,26801,21387],{"class":41},[32,26803,26804],{"class":903},"data",[32,26806,5269],{"class":41},[32,26808,26809],{"class":351},"posts",[32,26811,21398],{"class":41},[32,26813,172],{"class":38},[32,26815,26816],{"class":217}," useAsyncData",[32,26818,477],{"class":41},[32,26820,26821],{"class":175},"'posts'",[32,26823,11218],{"class":41},[32,26825,5090],{"class":38},[32,26827,26828],{"class":217}," queryCollection",[32,26830,477],{"class":41},[32,26832,26821],{"class":175},[32,26834,533],{"class":41},[32,26836,21841],{"class":217},[32,26838,20717],{"class":41},[32,26840,26841],{"class":34,"line":90},[32,26842,103],{"emptyLinePlaceholder":102},[32,26844,26845],{"class":34,"line":99},[32,26846,26847],{"class":608},"\u002F\u002F ✓\n",[32,26849,26850,26852,26854,26856,26858,26860,26862,26864,26866,26868,26870,26872,26874,26876,26878,26880,26882,26884,26886],{"class":34,"line":106},[32,26851,6617],{"class":38},[32,26853,21387],{"class":41},[32,26855,26804],{"class":903},[32,26857,5269],{"class":41},[32,26859,26809],{"class":351},[32,26861,21398],{"class":41},[32,26863,172],{"class":38},[32,26865,21834],{"class":38},[32,26867,26816],{"class":217},[32,26869,477],{"class":41},[32,26871,26821],{"class":175},[32,26873,11218],{"class":41},[32,26875,5090],{"class":38},[32,26877,26828],{"class":217},[32,26879,477],{"class":41},[32,26881,26821],{"class":175},[32,26883,533],{"class":41},[32,26885,21841],{"class":217},[32,26887,20717],{"class":41},[32,26889,26890,26892,26894],{"class":34,"line":114},[32,26891,4105],{"class":41},[32,26893,4125],{"class":4049},[32,26895,4062],{"class":41},[11,26897,26898,26899,26902],{},"畫面上看不出差別——瀏覽器端 hydrate 完照樣有資料。",[12249,26900,26901],{},"壞掉的是原始 HTML","，爬蟲跟社群分享卡片讀到的就是空的。這種問題不會有錯誤訊息，只能自己記得。",[11,26904,26905,26906,7218,26908,26911],{},"同一份資料在多個元件用時，",[29,26907,22561],{},[12249,26909,26910],{},"key 要一致","，Nuxt 才會共用同一次請求而不是各打各的。",[15,26913,26915],{"id":26914},"部署nitro-preset","部署：Nitro preset",[11,26917,26918],{},"後端由 Nitro 負責，換部署目標基本上就是換一行：",[22,26920,26922],{"className":22767,"code":26921,"language":22769,"meta":27,"style":27},"export default defineNuxtConfig({\n  nitro: {\n    preset: 'cloudflare_module'\n  }\n})\n",[29,26923,26924,26934,26939,26947,26951],{"__ignoreMap":27},[32,26925,26926,26928,26930,26932],{"class":34,"line":35},[32,26927,5038],{"class":38},[32,26929,5041],{"class":38},[32,26931,20772],{"class":217},[32,26933,1143],{"class":5049},[32,26935,26936],{"class":34,"line":45},[32,26937,26938],{"class":41},"  nitro: {\n",[32,26940,26941,26944],{"class":34,"line":51},[32,26942,26943],{"class":41},"    preset: ",[32,26945,26946],{"class":175},"'cloudflare_module'\n",[32,26948,26949],{"class":34,"line":90},[32,26950,1203],{"class":41},[32,26952,26953],{"class":34,"line":99},[32,26954,20790],{"class":5049},[11,26956,26957,26958,3750,26961,3750,26964,3750,26967,3775],{},"常見的還有 ",[29,26959,26960],{},"node-server",[29,26962,26963],{},"vercel",[29,26965,26966],{},"netlify",[29,26968,26969],{},"static",[11,26971,26972,26975,26976,26978,26979,26982,26983,26986,26987,26994],{},[12249,26973,26974],{},"要注意 preset 之間的執行環境差異不會被型別擋下來。"," 這個站踩過一個：workerd 在請求階段解不了動態 ",[29,26977,5027],{},"，配上 ",[29,26980,26981],{},"defineAsyncComponent"," 會安靜地渲染出空白而不是報錯——",[29,26984,26985],{},"npm run dev"," 走 vite-node、預渲染是建置時在 Node 跑的，兩者都碰不到那個限制。",[12249,26988,26989,26990,26993],{},"請求時才 SSR 的頁面一定要用 ",[29,26991,26992],{},"nuxt preview"," 在真正的 runtime 驗過","，靜態伺服器看不到 worker 的行為。",[15,26996,26997],{"id":26997},"對照表",[13433,26999,27000,27010],{},[13436,27001,27002],{},[13439,27003,27004,27006,27008],{},[13442,27005,13544],{},[13442,27007,20590],{},[13442,27009,25880],{},[13449,27011,27012,27025,27037,27053,27070,27088,27100],{},[13439,27013,27014,27016,27020],{},[13454,27015,25976],{},[13454,27017,27018],{},[29,27019,25957],{},[13454,27021,27022],{},[29,27023,27024],{},"npm create nuxt@latest",[13439,27026,27027,27030,27033],{},[13454,27028,27029],{},"前端原始碼位置",[13454,27031,27032],{},"根目錄",[13454,27034,27035],{},[29,27036,26084],{},[13439,27038,27039,27042,27049],{},[13454,27040,27041],{},"型別檢查",[13454,27043,27044,27045,25963,27047],{},"自己裝 ",[29,27046,26248],{},[29,27048,26252],{},[13454,27050,27051],{},[29,27052,26330],{},[13439,27054,27055,27057,27063],{},[13454,27056,4853],{},[13454,27058,27059,25963,27061],{},[29,27060,22847],{},[29,27062,22958],{},[13454,27064,27065,25963,27068],{},[29,27066,27067],{},"@nuxt\u002Feslint",[29,27069,26414],{},[13439,27071,27072,27075,27081],{},[13454,27073,27074],{},"Tailwind",[13454,27076,27077,25963,27079],{},[29,27078,25962],{},[29,27080,24835],{},[13454,27082,27083,25963,27086],{},[29,27084,27085],{},"@tailwindcss\u002Fvite",[29,27087,26598],{},[13439,27089,27090,27093,27096],{},[13454,27091,27092],{},"相容性鎖定",[13454,27094,27095],{},"無",[13454,27097,27098],{},[29,27099,26203],{},[13439,27101,27102,27105,27108],{},[13454,27103,27104],{},"全域狀態",[13454,27106,27107],{},"大多直接上 Pinia",[13454,27109,27110,27111,27113],{},"先看 ",[29,27112,26689],{}," 夠不夠",[15,27115,27116],{"id":27116},"沒有變的部分",[11,27118,27119],{},"Nuxt 3 那篇裡有一半以上仍然完全適用，不用重學：",[4538,27121,27122,27132,27137,27146,27151,27159],{},[4541,27123,27124,27125,3750,27128,27131],{},"檔案系統路由（",[29,27126,27127],{},"[id].vue",[29,27129,27130],{},"[...slug].vue","、巢狀路由）",[4541,27133,27134,27135],{},"404 頁面與 ",[29,27136,24004],{},[4541,27138,27139,3750,27141,3750,27143],{},[29,27140,15180],{},[29,27142,23424],{},[29,27144,27145],{},"\u003CNuxtLayout>",[4541,27147,27148,27149],{},"Layout 與具名插槽、",[29,27150,24499],{},[4541,27152,27153,27154,27156,27157,23140],{},"元件自動載入與路徑前綴命名（",[29,27155,24582],{}," → ",[29,27158,24586],{},[4541,27160,27161,27163,27164,27166],{},[29,27162,24602],{}," \u002F ",[29,27165,24605],{}," 後綴",[11,27168,27169,27170,27172],{},"差別只在檔案現在放 ",[29,27171,26084],{}," 底下。",[15,27174,4536],{"id":4536},[4538,27176,27177,27184,27191,27197,27204],{},[4541,27178,27179],{},[412,27180,27183],{"href":27181,"rel":27182},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fgetting-started\u002Fupgrade",[416],"Nuxt 4 升級指南",[4541,27185,27186],{},[412,27187,27190],{"href":27188,"rel":27189},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fguide\u002Fdirectory-structure\u002Fapp",[416],"Nuxt 目錄結構",[4541,27192,27193],{},[412,27194,27067],{"href":27195,"rel":27196},"https:\u002F\u002Feslint.nuxt.com\u002F",[416],[4541,27198,27199],{},[412,27200,27203],{"href":27201,"rel":27202},"https:\u002F\u002Ftailwindcss.com\u002Fdocs\u002Finstallation\u002Fusing-vite",[416],"Tailwind CSS 4：Vite plugin",[4541,27205,27206],{},[412,27207,27210],{"href":27208,"rel":27209},"https:\u002F\u002Fnitro.build\u002Fdeploy",[416],"Nitro 部署 preset",[368,27212,27213],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}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 .sVjZL, html code.shiki .sVjZL{--shiki-default:#6F42C1;--shiki-dark:#D2A8FF}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .sAjPK, html code.shiki .sAjPK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FFA198;--shiki-dark-font-style:italic}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}",{"title":27,"searchDepth":51,"depth":51,"links":27215},[27216,27217,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229],{"id":25976,"depth":45,"text":25976},{"id":26059,"depth":45,"text":26060,"children":27218},[27219],{"id":26140,"depth":51,"text":26141},{"id":26202,"depth":45,"text":26203},{"id":20761,"depth":45,"text":20552},{"id":26346,"depth":45,"text":26347},{"id":26480,"depth":45,"text":26481},{"id":26682,"depth":45,"text":26683},{"id":26754,"depth":45,"text":26755},{"id":26914,"depth":45,"text":26915},{"id":26997,"depth":45,"text":26997},{"id":27116,"depth":45,"text":27116},{"id":4536,"depth":45,"text":4536},"對照 Nuxt 3 的建立流程，整理 Nuxt 4 實際變了什麼——srcDir 搬進 app\u002F、nuxi 併入 nuxt CLI、ESLint 改用 @nuxt\u002Feslint 的 flat config、Tailwind 4 改掛 Vite plugin 不再需要 tailwind.config.js，以及預渲染時 useAsyncData 沒 await 會安靜出錯的陷阱。",{},"\u002Fposts\u002Fnuxt4-project-setup","2026-08-18",[],{"title":25945,"description":27230},"posts\u002F20260818.nuxt4-project-setup",[27238,20372,25322,4853,20552,27239],"Nuxt4","Nitro","ODepHVQEFuCgJscw6ddZRJ5orBW31R4ETthbWRXh3GE",1787672666361]