[{"data":1,"prerenderedAt":30711},["ShallowReactive",2],{"search-dialog-posts":3,"post-\u002Fposts\u002Fes6-spread-rest":30628,"post-surround-\u002Fposts\u002Fes6-spread-rest":30708},[4,394,2044,4024,4574,5398,6030,6241,6718,7035,8412,10519,10733,10850,10972,11072,11708,11743,11791,12457,12687,12785,12955,13031,13147,13565,13762,13810,13873,14478,14705,14758,14907,15148,15422,15857,16133,16456,16542,16783,16888,17037,17747,17945,18189,18332,19889,20290,20523,20799,20889,20926,21105,21166,21366,21447,22148,22463,22703,22824,22957,23337,23544,23773,26022,28683,29225,29331],{"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":10724,"draft":380,"extension":381,"image":382,"meta":10725,"navigation":102,"path":10726,"publishedAt":10727,"relatedExperiments":10728,"seo":10729,"stem":10730,"tags":10731,"updatedAt":392,"__hash__":10732},"posts\u002Fposts\u002F20190315.legacy-url-parsing.md","使用 location.href 取得網址片段",{"type":8,"value":10523,"toc":10721},[10524,10527,10537,10692,10699,10701,10715,10718],[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如果網址結構改變，就可能取得錯誤的內容。",[15,10700,2004],{"id":2003},[11,10702,10703,10704,10707,10708,7090,10711,10714],{},"現在如果只是要取得網址路徑，可以使用 ",[29,10705,10706],{},"location.pathname","；如果需要解析完整網址或查詢參數，則可以使用瀏覽器內建的 ",[29,10709,10710],{},"URL",[29,10712,10713],{},"URLSearchParams"," API。",[11,10716,10717],{},"較新的寫法整理在《用 URL API 解析網址》。",[368,10719,10720],{},"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":10722},[10723],{"id":2003,"depth":45,"text":2004},"2019 年使用 location.href 搭配 split() 取得網址片段的程式碼筆記，並補充較新的寫法。",{},"\u002Fposts\u002Flegacy-url-parsing","2019-03-15",[],{"title":10521,"description":10724},"posts\u002F20190315.legacy-url-parsing",[390,10710],"pACHY-b52jxDdllyOMtzZW_RuGCe86zyjtzJfypGpIU",{"id":10734,"title":10735,"body":10736,"category":378,"description":10838,"draft":380,"extension":381,"image":382,"meta":10839,"navigation":102,"path":10840,"publishedAt":10841,"relatedExperiments":10842,"seo":10843,"stem":10844,"tags":10845,"updatedAt":10848,"__hash__":10849},"posts\u002Fposts\u002F20200203.es6-var-let-const.md","JavaScript ES6：var、let 與 const",{"type":8,"value":10737,"toc":10832},[10738,10749,10753,10758,10765,10769,10777,10783,10791,10797,10801,10806,10812,10815,10821,10824],[11,10739,10740,10741,3750,10743,7090,10746,10748],{},"這邊記錄 ",[29,10742,166],{},[29,10744,10745],{},"let",[29,10747,6617],{}," 變數之間差異。",[15,10750,10752],{"id":10751},"var-宣告","var 宣告",[11,10754,4675,10755,10757],{},[29,10756,166],{}," 宣告變數時，會先在記憶體裡面存取空間。",[11,10759,10760],{},[10761,10762],"img",{"alt":10763,"src":10764},"開發者工具使用 var 宣告 test 變數，宣告結果顯示 undefined","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F01.webp",[15,10766,10768],{"id":10767},"var-與-let-的作用域","var 與 let 的作用域",[11,10770,10771,10773,10774,10776],{},[29,10772,166],{}," 在 function 裡宣告，作用域是 function scope；",[29,10775,10745],{}," 的作用域是 block。",[11,10778,10779],{},[10761,10780],{"alt":10781,"src":10782},"var 與 let 在 if 區塊中的作用域比較，var 會影響外層變數，let 不會","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F02.webp",[11,10784,10785,10786,7090,10788,10790],{},"下面比較 ",[29,10787,166],{},[29,10789,10745],{}," 在迴圈裡的差異。",[11,10792,10793],{},[10761,10794],{"alt":10795,"src":10796},"for 迴圈分別使用 var 與 let，var 成為全域變數並輸出 10，let 依序輸出 0 到 9","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F03.webp",[15,10798,10800],{"id":10799},"const-常數","const 常數",[11,10802,10803,10805],{},[29,10804,6617],{}," 宣告的變數不能被更換。",[11,10807,10808],{},[10761,10809],{"alt":10810,"src":10811},"重新指定 const 變數時出現 Assignment to constant variable 錯誤","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F04.webp",[11,10813,10814],{},"物件本身是傳參考而不是傳值，因此物件內的屬性仍然可以修改。",[11,10816,10817],{},[10761,10818],{"alt":10819,"src":10820},"const 宣告物件後修改 a2 屬性，物件內容由 456 變成 222","\u002Fimages\u002Fposts\u002Fes6-var-let-const\u002F05.webp",[15,10822,10823],{"id":10823},"結論",[11,10825,10826,10827,10829,10830,3775],{},"作用域預設使用 ",[29,10828,6617],{},"，需要重新賦值時才使用 ",[29,10831,10745],{},{"title":27,"searchDepth":51,"depth":51,"links":10833},[10834,10835,10836,10837],{"id":10751,"depth":45,"text":10752},{"id":10767,"depth":45,"text":10768},{"id":10799,"depth":45,"text":10800},{"id":10823,"depth":45,"text":10823},"2020 年整理的 var、let 與 const 變數宣告及作用域筆記。",{},"\u002Fposts\u002Fes6-var-let-const","2020-02-03",[],{"title":10735,"description":10838},"posts\u002F20200203.es6-var-let-const",[390,10846,10847],"ES6","變數宣告","2026-08-06","3yvA0FjmicBouy6o7wc7PCuHBY_Eba7xxCZizBvAL8g",{"id":10851,"title":10852,"body":10853,"category":378,"description":10962,"draft":380,"extension":381,"image":382,"meta":10963,"navigation":102,"path":10964,"publishedAt":10965,"relatedExperiments":10966,"seo":10967,"stem":10968,"tags":10969,"updatedAt":10848,"__hash__":10971},"posts\u002Fposts\u002F20200204.es6-spread-rest.md","JavaScript ES6：展開與其餘參數",{"type":8,"value":10854,"toc":10955},[10855,10858,10861,10875,10881,10884,10893,10899,10902,10908,10911,10914,10920,10929,10935,10938,10941,10947,10949],[11,10856,10857],{},"這邊記錄展開與其餘參數。",[15,10859,10860],{"id":10860},"合併陣列",[11,10862,10863,10864,7090,10867,10870,10871,10874],{},"範例：將 ",[29,10865,10866],{},"groupA",[29,10868,10869],{},"groupB"," 合併。",[29,10872,10873],{},"console.log(...groupA)"," 會把值一個一個取出來。",[11,10876,10877],{},[10761,10878],{"alt":10879,"src":10880},"使用 concat 與展開運算子合併 groupA、groupB，兩者都得到六個元素的陣列","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F01.webp",[15,10882,10883],{"id":10883},"淺複製",[11,10885,10886,10887,10889,10890,10892],{},"範例：直接將 ",[29,10888,10866],{}," 指定給 ",[29,10891,10869],{},"，兩個變數會共用同一個陣列參考。",[11,10894,10895],{},[10761,10896],{"alt":10897,"src":10898},"將 groupA 直接指定給 groupB，再 push 新值時 groupA 也一起改變","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F02.webp",[11,10900,10901],{},"若不要互相影響，可以用展開語法建立新陣列。",[11,10903,10904],{},[10761,10905],{"alt":10906,"src":10907},"比較直接指定陣列與使用展開語法建立新陣列，後者不會影響 groupA","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F03.webp",[15,10909,10910],{"id":10910},"類陣列轉成陣列",[11,10912,10913],{},"類陣列不是真正的陣列，使用展開語法後可以轉成陣列。",[11,10915,10916],{},[10761,10917],{"alt":10918,"src":10919},"將 querySelectorAll 取得的 NodeList 展開成真正陣列，轉換後可使用完整陣列方法","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F04.webp",[11,10921,10922,10925,10926,3775],{},[29,10923,10924],{},"arguments"," 也不是陣列，可以用展開語法轉換後再使用 ",[29,10927,10928],{},"reduce()",[11,10930,10931],{},[10761,10932],{"alt":10933,"src":10934},"arguments 直接使用 reduce 會出錯，展開成陣列後可正常加總","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F05.webp",[15,10936,10937],{"id":10937},"其餘參數",[11,10939,10940],{},"其餘參數可以接收不固定數量的參數。",[11,10942,10943],{},[10761,10944],{"alt":10945,"src":10946},"函式使用其餘參數收集不固定數量的 money 參數，也可在前面保留固定參數","\u002Fimages\u002Fposts\u002Fes6-spread-rest\u002F06.webp",[15,10948,2004],{"id":2003},[11,10950,10951,10952,3775],{},"展開只會建立淺層副本；需要複製巢狀資料時可改用瀏覽器內建的 ",[29,10953,10954],{},"structuredClone()",{"title":27,"searchDepth":51,"depth":51,"links":10956},[10957,10958,10959,10960,10961],{"id":10860,"depth":45,"text":10860},{"id":10883,"depth":45,"text":10883},{"id":10910,"depth":45,"text":10910},{"id":10937,"depth":45,"text":10937},{"id":2003,"depth":45,"text":2004},"2020 年整理的展開運算子、淺複製、類陣列轉換與其餘參數筆記。",{},"\u002Fposts\u002Fes6-spread-rest","2020-02-04",[],{"title":10852,"description":10962},"posts\u002F20200204.es6-spread-rest",[390,10846,10970],"展開運算子","20MmZ1lReE9LGAOB7ChhQFqbZRPdpHsUYZj9ImNyjJU",{"id":10973,"title":10974,"body":10975,"category":378,"description":11062,"draft":380,"extension":381,"image":382,"meta":11063,"navigation":102,"path":11064,"publishedAt":11065,"relatedExperiments":11066,"seo":11067,"stem":11068,"tags":11069,"updatedAt":10848,"__hash__":11071},"posts\u002Fposts\u002F20200205.es6-destructuring.md","JavaScript ES6：解構賦值",{"type":8,"value":10976,"toc":11055},[10977,10980,10983,10986,10992,10995,10998,11004,11007,11013,11016,11019,11025,11028,11034,11037,11040,11046,11049],[11,10978,10979],{},"解構賦值是將右邊的值賦予給左邊的變數，有點像鏡射的概念。\n如果左右兩邊數量不同，右邊多餘的值不會進行賦值。",[15,10981,10982],{"id":10982},"陣列解構",[11,10984,10985],{},"範例：將陣列裡的值賦予變數。逗號之間沒有變數時，會跳過該位置。",[11,10987,10988],{},[10761,10989],{"alt":10990,"src":10991},"陣列解構依序取得值、只取前兩個值，以及用空位跳過中間元素","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F01.webp",[15,10993,10994],{"id":10994},"交換變數",[11,10996,10997],{},"解構賦值可以直接交換變數，不需要第三個暫存變數。",[11,10999,11000],{},[10761,11001],{"alt":11002,"src":11003},"使用陣列解構交換 aa 與 bb，輸出結果由 aa bb 變成 bb aa","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F02.webp",[15,11005,11006],{"id":11006},"拆解字串",[11,11008,11009],{},[10761,11010],{"alt":11011,"src":11012},"將 hello 字串解構成五個字元並逐一輸出","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F03.webp",[15,11014,11015],{"id":11015},"物件解構",[11,11017,11018],{},"可以取出物件其中一個值，也可以指定新的變數名稱。",[11,11020,11021],{},[10761,11022],{"alt":11023,"src":11024},"從物件取出 aa 屬性，並示範將 aa 改名成 gg","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F04.webp",[11,11026,11027],{},"物件與陣列也能一起解構。",[11,11029,11030],{},[10761,11031],{"alt":11032,"src":11033},"同時解構物件的 ll 屬性與 tt 陣列第二個元素，輸出 test 與 bb","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F05.webp",[15,11035,11036],{"id":11036},"預設值",[11,11038,11039],{},"陣列解構可以設定預設值。",[11,11041,11042],{},[10761,11043],{"alt":11044,"src":11045},"陣列只有 cc 一個值時，testa 取得 cc，testb 使用預設值 bb","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F06.webp",[11,11047,11048],{},"物件解構改名時也能設定預設值。",[11,11050,11051],{},[10761,11052],{"alt":11053,"src":11054},"從空物件解構 testc 並改名為 ming，最後使用預設值 aa","\u002Fimages\u002Fposts\u002Fes6-destructuring\u002F07.webp",{"title":27,"searchDepth":51,"depth":51,"links":11056},[11057,11058,11059,11060,11061],{"id":10982,"depth":45,"text":10982},{"id":10994,"depth":45,"text":10994},{"id":11006,"depth":45,"text":11006},{"id":11015,"depth":45,"text":11015},{"id":11036,"depth":45,"text":11036},"2020 年整理的陣列、字串與物件解構賦值筆記。",{},"\u002Fposts\u002Fes6-destructuring","2020-02-05",[],{"title":10974,"description":11062},"posts\u002F20200205.es6-destructuring",[390,10846,11070],"解構賦值","3eZqGwKLbvymn70nkehs7tumY0sH9ooYT1dyONm1nDA",{"id":11073,"title":11074,"body":11075,"category":378,"description":11698,"draft":380,"extension":381,"image":382,"meta":11699,"navigation":102,"path":11700,"publishedAt":11701,"relatedExperiments":11702,"seo":11703,"stem":11704,"tags":11705,"updatedAt":10848,"__hash__":11707},"posts\u002Fposts\u002F20200206.es6-arrow-functions.md","JavaScript ES6：箭頭函式",{"type":8,"value":11076,"toc":11688},[11077,11080,11088,11195,11198,11251,11254,11337,11340,11373,11376,11382,11419,11423,11429,11432,11439,11506,11509,11512,11616,11620,11623,11656,11674,11676,11685],[15,11078,11079],{"id":11079},"語法簡寫",[4538,11081,11082,11085],{},[4541,11083,11084],{},"參數只有一個時可以省略小括號。",[4541,11086,11087],{},"內容只有一行並回傳時，可以簡寫成一行。",[22,11089,11091],{"className":24,"code":11090,"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,11092,11093,11111,11126,11130,11134,11152,11164,11168,11172],{"__ignoreMap":27},[32,11094,11095,11097,11100,11102,11104,11106,11109],{"class":34,"line":35},[32,11096,166],{"class":38},[32,11098,11099],{"class":217}," double",[32,11101,894],{"class":38},[32,11103,897],{"class":38},[32,11105,900],{"class":41},[32,11107,11108],{"class":903},"x",[32,11110,520],{"class":41},[32,11112,11113,11116,11119,11121,11124],{"class":34,"line":45},[32,11114,11115],{"class":38},"  return",[32,11117,11118],{"class":41}," x ",[32,11120,6078],{"class":38},[32,11122,11123],{"class":351}," 2",[32,11125,96],{"class":41},[32,11127,11128],{"class":34,"line":51},[32,11129,7189],{"class":41},[32,11131,11132],{"class":34,"line":90},[32,11133,103],{"emptyLinePlaceholder":102},[32,11135,11136,11138,11140,11142,11144,11146,11148,11150],{"class":34,"line":99},[32,11137,6617],{"class":38},[32,11139,11099],{"class":217},[32,11141,894],{"class":38},[32,11143,900],{"class":41},[32,11145,11108],{"class":903},[32,11147,483],{"class":41},[32,11149,5090],{"class":38},[32,11151,703],{"class":41},[32,11153,11154,11156,11158,11160,11162],{"class":34,"line":106},[32,11155,11115],{"class":38},[32,11157,11118],{"class":41},[32,11159,6078],{"class":38},[32,11161,11123],{"class":351},[32,11163,96],{"class":41},[32,11165,11166],{"class":34,"line":114},[32,11167,7189],{"class":41},[32,11169,11170],{"class":34,"line":120},[32,11171,103],{"emptyLinePlaceholder":102},[32,11173,11174,11176,11179,11181,11184,11187,11189,11191,11193],{"class":34,"line":127},[32,11175,6617],{"class":38},[32,11177,11178],{"class":217}," shortDouble",[32,11180,894],{"class":38},[32,11182,11183],{"class":903}," x",[32,11185,11186],{"class":38}," =>",[32,11188,11118],{"class":41},[32,11190,6078],{"class":38},[32,11192,11123],{"class":351},[32,11194,96],{"class":41},[11,11196,11197],{},"只有一個參數時可以省略小括號；有兩個參數時要保留：",[22,11199,11201],{"className":24,"code":11200,"language":26,"meta":27,"style":27},"const double = x => x * 2;\nconst add = (x, y) => x + y;\n",[29,11202,11203,11223],{"__ignoreMap":27},[32,11204,11205,11207,11209,11211,11213,11215,11217,11219,11221],{"class":34,"line":35},[32,11206,6617],{"class":38},[32,11208,11099],{"class":217},[32,11210,894],{"class":38},[32,11212,11183],{"class":903},[32,11214,11186],{"class":38},[32,11216,11118],{"class":41},[32,11218,6078],{"class":38},[32,11220,11123],{"class":351},[32,11222,96],{"class":41},[32,11224,11225,11227,11229,11231,11233,11235,11237,11240,11242,11244,11246,11248],{"class":34,"line":45},[32,11226,6617],{"class":38},[32,11228,2493],{"class":217},[32,11230,894],{"class":38},[32,11232,900],{"class":41},[32,11234,11108],{"class":903},[32,11236,635],{"class":41},[32,11238,11239],{"class":903},"y",[32,11241,483],{"class":41},[32,11243,5090],{"class":38},[32,11245,11118],{"class":41},[32,11247,224],{"class":38},[32,11249,11250],{"class":41}," y;\n",[11,11252,11253],{},"陣列方法的 ES5 與 ES6 寫法：",[22,11255,11257],{"className":24,"code":11256,"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,11258,11259,11264,11287,11299,11303,11307,11312],{"__ignoreMap":27},[32,11260,11261],{"class":34,"line":35},[32,11262,11263],{"class":608},"\u002F\u002F ES5\n",[32,11265,11266,11269,11272,11274,11276,11278,11281,11283,11285],{"class":34,"line":45},[32,11267,11268],{"class":41},"arr.",[32,11270,11271],{"class":217},"map",[32,11273,477],{"class":41},[32,11275,665],{"class":38},[32,11277,900],{"class":41},[32,11279,11280],{"class":903},"elm",[32,11282,635],{"class":41},[32,11284,8301],{"class":903},[32,11286,520],{"class":41},[32,11288,11289,11291,11294,11296],{"class":34,"line":51},[32,11290,11115],{"class":38},[32,11292,11293],{"class":41}," elm ",[32,11295,224],{"class":38},[32,11297,11298],{"class":41}," idx;\n",[32,11300,11301],{"class":34,"line":90},[32,11302,792],{"class":41},[32,11304,11305],{"class":34,"line":99},[32,11306,103],{"emptyLinePlaceholder":102},[32,11308,11309],{"class":34,"line":106},[32,11310,11311],{"class":608},"\u002F\u002F ES6\n",[32,11313,11314,11316,11318,11320,11322,11324,11326,11328,11330,11332,11334],{"class":34,"line":114},[32,11315,11268],{"class":41},[32,11317,11271],{"class":217},[32,11319,8293],{"class":41},[32,11321,11280],{"class":903},[32,11323,635],{"class":41},[32,11325,8301],{"class":903},[32,11327,483],{"class":41},[32,11329,5090],{"class":38},[32,11331,11293],{"class":41},[32,11333,224],{"class":38},[32,11335,11336],{"class":41}," idx);\n",[11,11338,11339],{},"事件監聽：",[22,11341,11343],{"className":24,"code":11342,"language":26,"meta":27,"style":27},"btn.addEventListener('click', () => console.log(10));\n",[29,11344,11345],{"__ignoreMap":27},[32,11346,11347,11350,11352,11354,11357,11360,11362,11364,11366,11368,11371],{"class":34,"line":35},[32,11348,11349],{"class":41},"btn.",[32,11351,5517],{"class":217},[32,11353,477],{"class":41},[32,11355,11356],{"class":175},"'click'",[32,11358,11359],{"class":41},", () ",[32,11361,5090],{"class":38},[32,11363,8308],{"class":41},[32,11365,5197],{"class":217},[32,11367,477],{"class":41},[32,11369,11370],{"class":351},"10",[32,11372,8328],{"class":41},[15,11374,11375],{"id":11375},"自動綁定",[11,11377,11378,11379,11381],{},"箭頭函式內部的 ",[29,11380,1083],{}," 與外部相同。",[22,11383,11385],{"className":24,"code":11384,"language":26,"meta":27,"style":27},"const a = () => {\n  console.log(this);\n};\n",[29,11386,11387,11403,11415],{"__ignoreMap":27},[32,11388,11389,11391,11394,11396,11399,11401],{"class":34,"line":35},[32,11390,6617],{"class":38},[32,11392,11393],{"class":217}," a",[32,11395,894],{"class":38},[32,11397,11398],{"class":41}," () ",[32,11400,5090],{"class":38},[32,11402,703],{"class":41},[32,11404,11405,11407,11409,11411,11413],{"class":34,"line":45},[32,11406,5194],{"class":41},[32,11408,5197],{"class":217},[32,11410,477],{"class":41},[32,11412,1083],{"class":351},[32,11414,230],{"class":41},[32,11416,11417],{"class":34,"line":51},[32,11418,7189],{"class":41},[15,11420,11422],{"id":11421},"一般函式的-this","一般函式的 this",[11,11424,11425,11426,11428],{},"一般函式的 ",[29,11427,1083],{}," 由函式呼叫方式決定。",[151,11430,11431],{"id":11431},"直接執行",[11,11433,11434,11435,11438],{},"直接執行時指向 ",[29,11436,11437],{},"window","（global）：",[22,11440,11442],{"className":24,"code":11441,"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,11443,11444,11457,11461,11474,11487,11491,11495],{"__ignoreMap":27},[32,11445,11446,11448,11450,11452,11455],{"class":34,"line":35},[32,11447,166],{"class":38},[32,11449,169],{"class":41},[32,11451,172],{"class":38},[32,11453,11454],{"class":175}," 'hello'",[32,11456,96],{"class":41},[32,11458,11459],{"class":34,"line":45},[32,11460,103],{"emptyLinePlaceholder":102},[32,11462,11463,11465,11468,11470,11472],{"class":34,"line":51},[32,11464,166],{"class":38},[32,11466,11467],{"class":217}," sayMyName",[32,11469,894],{"class":38},[32,11471,897],{"class":38},[32,11473,668],{"class":41},[32,11475,11476,11478,11480,11482,11484],{"class":34,"line":90},[32,11477,5194],{"class":41},[32,11479,5197],{"class":217},[32,11481,477],{"class":41},[32,11483,1083],{"class":351},[32,11485,11486],{"class":41},".name);\n",[32,11488,11489],{"class":34,"line":99},[32,11490,7189],{"class":41},[32,11492,11493],{"class":34,"line":106},[32,11494,103],{"emptyLinePlaceholder":102},[32,11496,11497,11500,11503],{"class":34,"line":114},[32,11498,11499],{"class":217},"sayMyName",[32,11501,11502],{"class":41},"(); ",[32,11504,11505],{"class":608},"\u002F\u002F global.hello\n",[151,11507,11508],{"id":11508},"作為物件的成員函式",[11,11510,11511],{},"作為物件的成員函式執行時，指向該物件：",[22,11513,11515],{"className":24,"code":11514,"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,11516,11517,11529,11533,11545,11557,11561,11565,11576,11586,11590,11594,11604],{"__ignoreMap":27},[32,11518,11519,11521,11523,11525,11527],{"class":34,"line":35},[32,11520,166],{"class":38},[32,11522,169],{"class":41},[32,11524,172],{"class":38},[32,11526,11454],{"class":175},[32,11528,96],{"class":41},[32,11530,11531],{"class":34,"line":45},[32,11532,103],{"emptyLinePlaceholder":102},[32,11534,11535,11537,11539,11541,11543],{"class":34,"line":51},[32,11536,166],{"class":38},[32,11538,11467],{"class":217},[32,11540,894],{"class":38},[32,11542,897],{"class":38},[32,11544,668],{"class":41},[32,11546,11547,11549,11551,11553,11555],{"class":34,"line":90},[32,11548,5194],{"class":41},[32,11550,5197],{"class":217},[32,11552,477],{"class":41},[32,11554,1083],{"class":351},[32,11556,11486],{"class":41},[32,11558,11559],{"class":34,"line":99},[32,11560,7189],{"class":41},[32,11562,11563],{"class":34,"line":106},[32,11564,103],{"emptyLinePlaceholder":102},[32,11566,11567,11569,11572,11574],{"class":34,"line":114},[32,11568,166],{"class":38},[32,11570,11571],{"class":41}," teacher ",[32,11573,172],{"class":38},[32,11575,703],{"class":41},[32,11577,11578,11581,11584],{"class":34,"line":120},[32,11579,11580],{"class":41},"  name: ",[32,11582,11583],{"class":175},"'white'",[32,11585,547],{"class":41},[32,11587,11588],{"class":34,"line":127},[32,11589,7189],{"class":41},[32,11591,11592],{"class":34,"line":132},[32,11593,103],{"emptyLinePlaceholder":102},[32,11595,11596,11599,11601],{"class":34,"line":141},[32,11597,11598],{"class":41},"teacher.sayMyName ",[32,11600,172],{"class":38},[32,11602,11603],{"class":41}," sayMyName;\n",[32,11605,11606,11609,11611,11613],{"class":34,"line":147},[32,11607,11608],{"class":41},"teacher.",[32,11610,11499],{"class":217},[32,11612,11502],{"class":41},[32,11614,11615],{"class":608},"\u002F\u002F white\n",[151,11617,11619],{"id":11618},"作為-dom-的監聽函式","作為 DOM 的監聽函式",[11,11621,11622],{},"作為 DOM 的監聽函式執行時，指向該 DOM：",[22,11624,11626],{"className":4038,"code":11625,"language":4034,"meta":27,"style":27},"\u003Cbutton id=\"btn\" name=\"God damn right\">Response\u003C\u002Fbutton>\n",[29,11627,11628],{"__ignoreMap":27},[32,11629,11630,11632,11635,11637,11639,11642,11644,11646,11649,11652,11654],{"class":34,"line":35},[32,11631,4046],{"class":41},[32,11633,11634],{"class":4049},"button",[32,11636,4054],{"class":4053},[32,11638,172],{"class":41},[32,11640,11641],{"class":175},"\"btn\"",[32,11643,5668],{"class":4053},[32,11645,172],{"class":41},[32,11647,11648],{"class":175},"\"God damn right\"",[32,11650,11651],{"class":41},">Response\u003C\u002F",[32,11653,11634],{"class":4049},[32,11655,4062],{"class":41},[22,11657,11659],{"className":24,"code":11658,"language":26,"meta":27,"style":27},"btn.addEventListener('click', sayMyName);\n",[29,11660,11661],{"__ignoreMap":27},[32,11662,11663,11665,11667,11669,11671],{"class":34,"line":35},[32,11664,11349],{"class":41},[32,11666,5517],{"class":217},[32,11668,477],{"class":41},[32,11670,11356],{"class":175},[32,11672,11673],{"class":41},", sayMyName);\n",[15,11675,2004],{"id":2003},[11,11677,11678,11679,11681,11682,11684],{},"箭頭函式的語法與 ",[29,11680,1083],{}," 規則沒有改變。需要依呼叫者取得 ",[29,11683,1083],{}," 的物件方法或 DOM 監聽器，仍要留意是否適合使用一般函式。",[368,11686,11687],{},"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":11689},[11690,11691,11692,11697],{"id":11079,"depth":45,"text":11079},{"id":11375,"depth":45,"text":11375},{"id":11421,"depth":45,"text":11422,"children":11693},[11694,11695,11696],{"id":11431,"depth":51,"text":11431},{"id":11508,"depth":51,"text":11508},{"id":11618,"depth":51,"text":11619},{"id":2003,"depth":45,"text":2004},"2020 年整理的箭頭函式簡寫方式與 this 綁定筆記。",{},"\u002Fposts\u002Fes6-arrow-functions","2020-02-06",[],{"title":11074,"description":11698},"posts\u002F20200206.es6-arrow-functions",[390,10846,11706,1083],"箭頭函式","ET-V7Wwr3RvHTnz33yXdaif4tVHMmUow5CFJvL-td8Y",{"id":11709,"title":11710,"body":11711,"category":378,"description":11733,"draft":380,"extension":381,"image":382,"meta":11734,"navigation":102,"path":11735,"publishedAt":11736,"relatedExperiments":11737,"seo":11738,"stem":11739,"tags":11740,"updatedAt":6716,"__hash__":11742},"posts\u002Fposts\u002F20200228.google-fonts-embed.md","Google Fonts 引用筆記",{"type":8,"value":11712,"toc":11730},[11713,11716,11725,11727],[11,11714,11715],{},"這邊記錄網頁需要字型時，可以從哪邊引用：",[4538,11717,11718],{},[4541,11719,11720],{},[412,11721,11724],{"href":11722,"rel":11723},"https:\u002F\u002Ffonts.google.com\u002F",[416],"Google Fonts",[15,11726,2004],{"id":2003},[11,11728,11729],{},"Google Fonts 現在仍可使用，但若在意載入效能與訪客請求會連到第三方網域，可以改成自架字型。相關做法整理在《現在引用網頁字型的做法》。",{"title":27,"searchDepth":51,"depth":51,"links":11731},[11732],{"id":2003,"depth":45,"text":2004},"2020 年記錄網頁需要字型時，可以從 Google Fonts 取得引用方式。",{},"\u002Fposts\u002Fgoogle-fonts-embed","2020-02-28",[],{"title":11710,"description":11733},"posts\u002F20200228.google-fonts-embed",[1757,11724,11741],"字型","vo42ZtA9vW9kyb7P771zblsxG2jjuM6gtyGqjWX-8Rw",{"id":11744,"title":11745,"body":11746,"category":378,"description":11782,"draft":380,"extension":381,"image":382,"meta":11783,"navigation":102,"path":11784,"publishedAt":11785,"relatedExperiments":11786,"seo":11787,"stem":11788,"tags":11789,"updatedAt":10848,"__hash__":11790},"posts\u002Fposts\u002F20200310.box-sizing-border-box.md","CSS box-sizing 筆記",{"type":8,"value":11747,"toc":11779},[11748,11753,11766,11772,11774],[11,11749,10740,11750,3775],{},[29,11751,11752],{},"box-sizing",[11,11754,11755,11758,11759,11762,11763,11765],{},[29,11756,11757],{},"box-sizing: border-box"," 可以把 padding 與 border 計入設定的 ",[29,11760,11761],{},"width","／",[29,11764,6762],{},"，避免元素的實際尺寸向外增加。",[11,11767,11768],{},[10761,11769],{"alt":11770,"src":11771},"兩個相同寬高、邊框與內距的方塊，未設定 box-sizing 的方塊較大，設定 border-box 的方塊維持 50px","\u002Fimages\u002Fposts\u002Fbox-sizing-border-box\u002F01.webp",[15,11773,2004],{"id":2003},[11,11775,11776,11778],{},[29,11777,11757],{}," 現在仍普遍使用，通常會連同偽元素一起設為全域規則。",{"title":27,"searchDepth":51,"depth":51,"links":11780},[11781],{"id":2003,"depth":45,"text":2004},"2020 年記錄 box-sizing 如何讓 padding 與 border 計入元素設定的寬高。",{},"\u002Fposts\u002Fbox-sizing-border-box","2020-03-10",[],{"title":11745,"description":11782},"posts\u002F20200310.box-sizing-border-box",[1757],"Hsa5G1waJHX12ORw72prX8uMREyZxjDlCeZ-YBv8OMM",{"id":11792,"title":11793,"body":11794,"category":378,"description":12448,"draft":380,"extension":381,"image":382,"meta":12449,"navigation":102,"path":12450,"publishedAt":11785,"relatedExperiments":12451,"seo":12452,"stem":12453,"tags":12454,"updatedAt":10848,"__hash__":12456},"posts\u002Fposts\u002F20200310.scss-icon-sprite-map.md","用 SCSS 的 Map 與 @each 統一管理背景圖示",{"type":8,"value":11795,"toc":12440},[11796,11803,11807,11940,11948,11952,12137,12157,12160,12174,12376,12384,12387,12394,12400,12402,12419,12421,12437],[11,11797,11798,11799,11802],{},"網站圖示如果是一批各自獨立的 PNG 檔案（而不是圖示字型或 SVG），每個圖示又要處理 hover／normal 兩種狀態，手動幫每一個圖示各寫一段 CSS 很容易漏東漏西。\n這篇整理當時用 SCSS 的 map 加 ",[29,11800,11801],{},"@each"," 迴圈批次產生的做法。",[15,11804,11806],{"id":11805},"用-map-存圖示路徑","用 map 存圖示路徑",[22,11808,11810],{"className":8735,"code":11809,"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,11811,11812,11849,11853,11861,11873,11885,11897,11909,11921,11933],{"__ignoreMap":27},[32,11813,11814,11817,11819,11822,11824,11827,11829,11832,11834,11837,11839,11842,11844,11847],{"class":34,"line":35},[32,11815,11816],{"class":903},"$icon-name",[32,11818,5269],{"class":5049},[32,11820,11821],{"class":175},"'bookmark'",[32,11823,635],{"class":5049},[32,11825,11826],{"class":175},"'avatar'",[32,11828,635],{"class":5049},[32,11830,11831],{"class":175},"'chat'",[32,11833,635],{"class":5049},[32,11835,11836],{"class":175},"'page'",[32,11838,635],{"class":5049},[32,11840,11841],{"class":175},"'stars'",[32,11843,635],{"class":5049},[32,11845,11846],{"class":175},"'focus'",[32,11848,96],{"class":41},[32,11850,11851],{"class":34,"line":45},[32,11852,103],{"emptyLinePlaceholder":102},[32,11854,11855,11858],{"class":34,"line":51},[32,11856,11857],{"class":903},"$iconImageGroup",[32,11859,11860],{"class":5049},": (\n",[32,11862,11863,11866,11868,11871],{"class":34,"line":90},[32,11864,11865],{"class":175},"  'bookmark-hover'",[32,11867,5269],{"class":5049},[32,11869,11870],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-hover.png'",[32,11872,547],{"class":5049},[32,11874,11875,11878,11880,11883],{"class":34,"line":99},[32,11876,11877],{"class":175},"  'bookmark-normal'",[32,11879,5269],{"class":5049},[32,11881,11882],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-bookmark-normal.png'",[32,11884,547],{"class":5049},[32,11886,11887,11890,11892,11895],{"class":34,"line":106},[32,11888,11889],{"class":175},"  'stars-hover'",[32,11891,5269],{"class":5049},[32,11893,11894],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-hover.png'",[32,11896,547],{"class":5049},[32,11898,11899,11902,11904,11907],{"class":34,"line":114},[32,11900,11901],{"class":175},"  'stars-normal'",[32,11903,5269],{"class":5049},[32,11905,11906],{"class":175},"'..\u002F..\u002Fassets\u002F_img\u002F_icon\u002Ficon-stars-normal.png'",[32,11908,547],{"class":5049},[32,11910,11911,11914,11916,11919],{"class":34,"line":120},[32,11912,11913],{"class":175},"  'focus-hover'",[32,11915,5269],{"class":5049},[32,11917,11918],{"class":175},"'\u002F_img\u002F_icon\u002Ficon_focus_hover.png'",[32,11920,547],{"class":5049},[32,11922,11923,11926,11928,11931],{"class":34,"line":127},[32,11924,11925],{"class":175},"  'focus-normal'",[32,11927,5269],{"class":5049},[32,11929,11930],{"class":175},"'\u002F_img\u002F_icon\u002Ficon_focus_normal.png'",[32,11932,547],{"class":5049},[32,11934,11935,11938],{"class":34,"line":132},[32,11936,11937],{"class":5049},")",[32,11939,96],{"class":41},[11,11941,11942,11944,11945,11947],{},[29,11943,11816],{}," 是一份圖示名稱清單，",[29,11946,11857],{}," 是一個 map（SCSS 的鍵值對結構），把每個圖示 hover／normal 兩種狀態各自對應到一個圖檔路徑。",[15,11949,11951],{"id":11950},"用-each-批次產生-class","用 @each 批次產生 class",[22,11953,11955],{"className":8735,"code":11954,"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,11956,11957,11971,11984,11999,12013,12030,12061,12073,12088,12103,12117,12129,12133],{"__ignoreMap":27},[32,11958,11959,11961,11964,11966,11969],{"class":34,"line":35},[32,11960,11801],{"class":38},[32,11962,11963],{"class":903}," $name",[32,11965,5527],{"class":38},[32,11967,11968],{"class":903}," $icon-name",[32,11970,703],{"class":41},[32,11972,11973,11976,11979,11982],{"class":34,"line":45},[32,11974,11975],{"class":4049},"  &",[32,11977,11978],{"class":4053},".icon-",[32,11980,11981],{"class":903},"#{$name}",[32,11983,703],{"class":41},[32,11985,11986,11989,11991,11994,11997],{"class":34,"line":51},[32,11987,11988],{"class":351},"    width",[32,11990,5269],{"class":41},[32,11992,11993],{"class":351},"26",[32,11995,11996],{"class":38},"px",[32,11998,96],{"class":41},[32,12000,12001,12004,12006,12009,12011],{"class":34,"line":90},[32,12002,12003],{"class":351},"    height",[32,12005,5269],{"class":41},[32,12007,12008],{"class":351},"24",[32,12010,11996],{"class":38},[32,12012,96],{"class":41},[32,12014,12015,12018,12020,12023,12025,12028],{"class":34,"line":99},[32,12016,12017],{"class":351},"    padding",[32,12019,5269],{"class":41},[32,12021,12022],{"class":351},"0",[32,12024,11996],{"class":38},[32,12026,12027],{"class":38}," !important",[32,12029,96],{"class":41},[32,12031,12032,12035,12037,12040,12042,12045,12047,12049,12051,12054,12056,12059],{"class":34,"line":106},[32,12033,12034],{"class":351},"    background",[32,12036,5269],{"class":41},[32,12038,12039],{"class":351},"url",[32,12041,477],{"class":41},[32,12043,12044],{"class":351},"map-get",[32,12046,477],{"class":41},[32,12048,11857],{"class":903},[32,12050,635],{"class":41},[32,12052,12053],{"class":903},"$name",[32,12055,1799],{"class":38},[32,12057,12058],{"class":175}," '-normal'",[32,12060,8328],{"class":41},[32,12062,12063,12066,12068,12071],{"class":34,"line":114},[32,12064,12065],{"class":351},"    background-repeat",[32,12067,5269],{"class":41},[32,12069,12070],{"class":351},"no-repeat",[32,12072,96],{"class":41},[32,12074,12075,12078,12080,12083,12086],{"class":34,"line":120},[32,12076,12077],{"class":351},"    background-position",[32,12079,5269],{"class":41},[32,12081,12082],{"class":351},"center",[32,12084,12085],{"class":351}," center",[32,12087,96],{"class":41},[32,12089,12090,12093,12095,12098,12101],{"class":34,"line":127},[32,12091,12092],{"class":351},"    transition",[32,12094,5269],{"class":41},[32,12096,12097],{"class":351},"0.3",[32,12099,12100],{"class":38},"s",[32,12102,96],{"class":41},[32,12104,12105,12108,12110,12113,12115],{"class":34,"line":132},[32,12106,12107],{"class":351},"    margin-right",[32,12109,5269],{"class":41},[32,12111,12112],{"class":351},"2",[32,12114,11996],{"class":38},[32,12116,96],{"class":41},[32,12118,12119,12122,12124,12127],{"class":34,"line":141},[32,12120,12121],{"class":351},"    display",[32,12123,5269],{"class":41},[32,12125,12126],{"class":351},"inline-block",[32,12128,96],{"class":41},[32,12130,12131],{"class":34,"line":147},[32,12132,1203],{"class":41},[32,12134,12135],{"class":34,"line":275},[32,12136,54],{"class":41},[11,12138,12139,12142,12143,12145,12146,3750,12149,12152,12153,12156],{},[29,12140,12141],{},"@each $name in $icon-name"," 會把清單裡的每個名稱輪流帶入迴圈，",[29,12144,11981],{}," 是字串插值，讓 class 名稱依名稱動態產生（",[29,12147,12148],{},".icon-bookmark",[29,12150,12151],{},".icon-avatar","……），",[29,12154,12155],{},"map-get()"," 則依名稱去 map 裡查對應的圖檔路徑。\n六個圖示的樣式規則就這樣一次產生完，之後要加第七個圖示，只需要在兩份清單裡各加一筆。",[15,12158,12159],{"id":12159},"依名稱做例外處理",[11,12161,12162,12163,11762,12166,12169,12170,12173],{},"不是每個圖示都遵循同一套規則，某些圖示需要額外的狀態 class（例如 ",[29,12164,12165],{},"bookmark",[29,12167,12168],{},"unbookmark"," 兩種狀態各自的樣式），可以用 ",[29,12171,12172],{},"@if"," 針對特定名稱加規則：",[22,12175,12177],{"className":8735,"code":12176,"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,12178,12179,12191,12201,12206,12210,12226,12236,12248,12272,12286,12300,12304,12313,12325,12337,12360,12364,12368,12372],{"__ignoreMap":27},[32,12180,12181,12183,12185,12187,12189],{"class":34,"line":35},[32,12182,11801],{"class":38},[32,12184,11963],{"class":903},[32,12186,5527],{"class":38},[32,12188,11968],{"class":903},[32,12190,703],{"class":41},[32,12192,12193,12195,12197,12199],{"class":34,"line":45},[32,12194,11975],{"class":4049},[32,12196,11978],{"class":4053},[32,12198,11981],{"class":903},[32,12200,703],{"class":41},[32,12202,12203],{"class":34,"line":51},[32,12204,12205],{"class":608},"    \u002F\u002F 通用規則...\n",[32,12207,12208],{"class":34,"line":90},[32,12209,103],{"emptyLinePlaceholder":102},[32,12211,12212,12215,12217,12219,12222,12224],{"class":34,"line":99},[32,12213,12214],{"class":38},"    @if",[32,12216,900],{"class":41},[32,12218,12053],{"class":903},[32,12220,12221],{"class":41}," == ",[32,12223,11821],{"class":175},[32,12225,520],{"class":41},[32,12227,12228,12231,12234],{"class":34,"line":106},[32,12229,12230],{"class":4049},"      &",[32,12232,12233],{"class":4053},".bookmark",[32,12235,703],{"class":41},[32,12237,12238,12241,12243,12246],{"class":34,"line":114},[32,12239,12240],{"class":4049},"        cursor",[32,12242,5269],{"class":41},[32,12244,12245],{"class":351},"pointer",[32,12247,96],{"class":41},[32,12249,12250,12253,12255,12257,12259,12261,12263,12265,12267,12270],{"class":34,"line":120},[32,12251,12252],{"class":351},"        background",[32,12254,5269],{"class":41},[32,12256,12039],{"class":351},[32,12258,477],{"class":41},[32,12260,12044],{"class":351},[32,12262,477],{"class":41},[32,12264,11857],{"class":903},[32,12266,635],{"class":41},[32,12268,12269],{"class":175},"'bookmark-hover'",[32,12271,8328],{"class":41},[32,12273,12274,12277,12279,12282,12284],{"class":34,"line":127},[32,12275,12276],{"class":351},"        width",[32,12278,5269],{"class":41},[32,12280,12281],{"class":351},"22",[32,12283,11996],{"class":38},[32,12285,96],{"class":41},[32,12287,12288,12291,12293,12296,12298],{"class":34,"line":132},[32,12289,12290],{"class":351},"        height",[32,12292,5269],{"class":41},[32,12294,12295],{"class":351},"32",[32,12297,11996],{"class":38},[32,12299,96],{"class":41},[32,12301,12302],{"class":34,"line":141},[32,12303,1193],{"class":41},[32,12305,12306,12308,12311],{"class":34,"line":147},[32,12307,12230],{"class":4049},[32,12309,12310],{"class":4053},".unbookmark",[32,12312,703],{"class":41},[32,12314,12315,12317,12319,12321,12323],{"class":34,"line":275},[32,12316,12276],{"class":351},[32,12318,5269],{"class":41},[32,12320,12281],{"class":351},[32,12322,11996],{"class":38},[32,12324,96],{"class":41},[32,12326,12327,12329,12331,12333,12335],{"class":34,"line":282},[32,12328,12290],{"class":351},[32,12330,5269],{"class":41},[32,12332,12295],{"class":351},[32,12334,11996],{"class":38},[32,12336,96],{"class":41},[32,12338,12339,12341,12343,12345,12347,12349,12351,12353,12355,12358],{"class":34,"line":295},[32,12340,12252],{"class":351},[32,12342,5269],{"class":41},[32,12344,12039],{"class":351},[32,12346,477],{"class":41},[32,12348,12044],{"class":351},[32,12350,477],{"class":41},[32,12352,11857],{"class":903},[32,12354,635],{"class":41},[32,12356,12357],{"class":175},"'bookmark-normal'",[32,12359,8328],{"class":41},[32,12361,12362],{"class":34,"line":605},[32,12363,1193],{"class":41},[32,12365,12366],{"class":34,"line":612},[32,12367,5591],{"class":41},[32,12369,12370],{"class":34,"line":617},[32,12371,1203],{"class":41},[32,12373,12374],{"class":34,"line":644},[32,12375,54],{"class":41},[11,12377,12378,12380,12381,12383],{},[29,12379,12172],{}," 在迴圈內部依當下的 ",[29,12382,12053],{}," 值判斷，只有名稱符合條件時才會加上額外的巢狀規則，其餘圖示不受影響。",[15,12385,12386],{"id":12386},"這個做法的代價",[11,12388,12389,12393],{},[12390,12391,12392],"strong",{},"每個圖示、每種狀態都是一個獨立的圖檔請求","。hover 狀態要切換圖片，代表瀏覽器要先把 hover 版本的圖也下載下來（或是遇到滑鼠移上去才臨時載入，反而有延遲閃爍的問題），圖示數量一多，請求數跟著往上疊。",[11,12395,12396,12399],{},[12390,12397,12398],{},"顏色調整要重新出圖","。網站要換色系、或同一個圖示要在不同背景色上呈現不同顏色，PNG 圖示沒辦法用 CSS 調色，只能請設計重新出一版圖檔。",[15,12401,2004],{"id":2003},[11,12403,12404,12407,12408,12410,12411,12414,12415,12418],{},[12390,12405,12406],{},"這套「用資料結構驅動批次產生樣式」的思路本身沒有過時","，SCSS 的 map／",[29,12409,11801],{}," 現在同樣好用。真正被取代的是",[12390,12412,12413],{},"用一堆獨立 PNG 檔案管理圖示","這件事——現在多半用 SVG 圖示元件，一份圖示可以用 ",[29,12416,12417],{},"currentColor"," 直接吃 CSS 的文字顏色，不需要為了換色重新出圖，也不用為了 hover 狀態多準備一張圖。整理在《SVG 圖示元件：取代背景圖示與圖示字型》。",[15,12420,4536],{"id":4536},[4538,12422,12423,12430],{},[4541,12424,12425],{},[412,12426,12429],{"href":12427,"rel":12428},"https:\u002F\u002Fsass-lang.com\u002Fdocumentation\u002Fvalues\u002Fmaps\u002F",[416],"Sass 官方文件：Maps",[4541,12431,12432],{},[412,12433,12436],{"href":12434,"rel":12435},"https:\u002F\u002Fsass-lang.com\u002Fdocumentation\u002Fat-rules\u002Fcontrol\u002Feach\u002F",[416],"Sass 官方文件：@each",[368,12438,12439],{},"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":12441},[12442,12443,12444,12445,12446,12447],{"id":11805,"depth":45,"text":11806},{"id":11950,"depth":45,"text":11951},{"id":12159,"depth":45,"text":12159},{"id":12386,"depth":45,"text":12386},{"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":11793,"description":12448},"posts\u002F20200310.scss-icon-sprite-map",[12455,1757,4847],"SCSS","qNGNDDRHUx-7vcZ7tskko8SwRuReYeSbdJwM-WwT7Vk",{"id":12458,"title":12459,"body":12460,"category":378,"description":12678,"draft":380,"extension":381,"image":382,"meta":12679,"navigation":102,"path":12680,"publishedAt":12681,"relatedExperiments":12682,"seo":12683,"stem":12684,"tags":12685,"updatedAt":10848,"__hash__":12686},"posts\u002Fposts\u002F20200311.html5-meta-basics.md","HTML5 基本 meta 資訊筆記",{"type":8,"value":12461,"toc":12675},[12462,12657,12659,12672],[22,12463,12465],{"className":4038,"code":12464,"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,12466,12467,12480,12495,12504,12520,12546,12572,12586,12594,12602,12616,12629,12641,12649],{"__ignoreMap":27},[32,12468,12469,12472,12475,12478],{"class":34,"line":35},[32,12470,12471],{"class":41},"\u003C!",[32,12473,12474],{"class":4049},"DOCTYPE",[32,12476,12477],{"class":4053}," html",[32,12479,4062],{"class":41},[32,12481,12482,12484,12486,12488,12490,12493],{"class":34,"line":45},[32,12483,4046],{"class":41},[32,12485,4034],{"class":4049},[32,12487,8677],{"class":4053},[32,12489,172],{"class":41},[32,12491,12492],{"class":175},"\"en\"",[32,12494,4062],{"class":41},[32,12496,12497,12499,12502],{"class":34,"line":51},[32,12498,4046],{"class":41},[32,12500,12501],{"class":4049},"head",[32,12503,4062],{"class":41},[32,12505,12506,12508,12510,12513,12515,12518],{"class":34,"line":90},[32,12507,4067],{"class":41},[32,12509,5665],{"class":4049},[32,12511,12512],{"class":4053}," charset",[32,12514,172],{"class":41},[32,12516,12517],{"class":175},"\"UTF-8\"",[32,12519,4062],{"class":41},[32,12521,12522,12524,12526,12528,12530,12533,12535,12537,12540,12543],{"class":34,"line":99},[32,12523,4067],{"class":41},[32,12525,5665],{"class":4049},[32,12527,5668],{"class":4053},[32,12529,172],{"class":41},[32,12531,12532],{"class":175},"\"viewport\"",[32,12534,5676],{"class":4053},[32,12536,172],{"class":41},[32,12538,12539],{"class":175},"\"width=device-width,initial-scale=1.0\"",[32,12541,12542],{"class":41},"> ",[32,12544,12545],{"class":608},"\u003C!-- 行動裝置必須加 -->\n",[32,12547,12548,12550,12552,12555,12557,12560,12562,12564,12567,12569],{"class":34,"line":106},[32,12549,4067],{"class":41},[32,12551,5665],{"class":4049},[32,12553,12554],{"class":4053}," http-equiv",[32,12556,172],{"class":41},[32,12558,12559],{"class":175},"\"X-UA-Compatible\"",[32,12561,5676],{"class":4053},[32,12563,172],{"class":41},[32,12565,12566],{"class":175},"\"ie=edge\"",[32,12568,12542],{"class":41},[32,12570,12571],{"class":608},"\u003C!-- 將瀏覽器更新到 IE Edge -->\n",[32,12573,12574,12576,12579,12582,12584],{"class":34,"line":114},[32,12575,4067],{"class":41},[32,12577,12578],{"class":4049},"title",[32,12580,12581],{"class":41},">Yahoo 新聞\u003C\u002F",[32,12583,12578],{"class":4049},[32,12585,4062],{"class":41},[32,12587,12588,12590,12592],{"class":34,"line":120},[32,12589,4105],{"class":41},[32,12591,12501],{"class":4049},[32,12593,4062],{"class":41},[32,12595,12596,12598,12600],{"class":34,"line":127},[32,12597,4046],{"class":41},[32,12599,5495],{"class":4049},[32,12601,4062],{"class":41},[32,12603,12604,12606,12609,12612,12614],{"class":34,"line":132},[32,12605,4067],{"class":41},[32,12607,12608],{"class":4049},"h1",[32,12610,12611],{"class":41},">標題\u003C\u002F",[32,12613,12608],{"class":4049},[32,12615,4062],{"class":41},[32,12617,12618,12620,12622,12625,12627],{"class":34,"line":141},[32,12619,4067],{"class":41},[32,12621,11],{"class":4049},[32,12623,12624],{"class":41},">段落段落\u003C\u002F",[32,12626,11],{"class":4049},[32,12628,4062],{"class":41},[32,12630,12631,12633,12635,12637,12639],{"class":34,"line":147},[32,12632,4067],{"class":41},[32,12634,11],{"class":4049},[32,12636,12624],{"class":41},[32,12638,11],{"class":4049},[32,12640,4062],{"class":41},[32,12642,12643,12645,12647],{"class":34,"line":275},[32,12644,4105],{"class":41},[32,12646,5495],{"class":4049},[32,12648,4062],{"class":41},[32,12650,12651,12653,12655],{"class":34,"line":282},[32,12652,4105],{"class":41},[32,12654,4034],{"class":4049},[32,12656,4062],{"class":41},[15,12658,2004],{"id":2003},[11,12660,12661,7090,12664,12667,12668,12671],{},[29,12662,12663],{},"charset",[29,12665,12666],{},"viewport"," 現在仍是基本設定；",[29,12669,12670],{},"X-UA-Compatible"," 是給 Internet Explorer 的舊設定，新專案已不需要。現行頁面資訊可參考《現在的 HTML meta 標籤怎麼寫》。",[368,12673,12674],{},"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":12676},[12677],{"id":2003,"depth":45,"text":2004},"2020 年留下的 HTML5 頁面骨架與基本 meta 標籤。",{},"\u002Fposts\u002Fhtml5-meta-basics","2020-03-11",[],{"title":12459,"description":12678},"posts\u002F20200311.html5-meta-basics",[4035,5665],"TcHYP9NY4iyRlNma-aQwG2M9mErLhsU1swF2Gz9k80w",{"id":12688,"title":12689,"body":12690,"category":378,"description":12775,"draft":380,"extension":381,"image":382,"meta":12776,"navigation":102,"path":12777,"publishedAt":12778,"relatedExperiments":12779,"seo":12780,"stem":12781,"tags":12782,"updatedAt":10848,"__hash__":12784},"posts\u002Fposts\u002F20200313.bootstrap-modal-scrollbar-fix.md","Bootstrap Modal 捲軸變動修正",{"type":8,"value":12691,"toc":12772},[12692,12699,12702,12760,12762,12769],[11,12693,12694,12695,12698],{},"使用 Bootstrap 的 Modal 元件時，如果頁面 Header 設為 ",[29,12696,12697],{},"position: fixed","，會發現開啟 Modal 時捲軸與版面發生變動。",[11,12700,12701],{},"當時使用以下 CSS 修正：",[22,12703,12705],{"className":5412,"code":12704,"language":1140,"meta":27,"style":27},"body,\nbody.swal2-shown,\nbody.modal-open {\n  overflow: inherit;\n  padding-right: inherit !important;\n}\n",[29,12706,12707,12713,12722,12731,12743,12756],{"__ignoreMap":27},[32,12708,12709,12711],{"class":34,"line":35},[32,12710,5495],{"class":4049},[32,12712,547],{"class":41},[32,12714,12715,12717,12720],{"class":34,"line":45},[32,12716,5495],{"class":4049},[32,12718,12719],{"class":4053},".swal2-shown",[32,12721,547],{"class":41},[32,12723,12724,12726,12729],{"class":34,"line":51},[32,12725,5495],{"class":4049},[32,12727,12728],{"class":4053},".modal-open",[32,12730,703],{"class":41},[32,12732,12733,12736,12738,12741],{"class":34,"line":90},[32,12734,12735],{"class":351},"  overflow",[32,12737,5269],{"class":41},[32,12739,12740],{"class":351},"inherit",[32,12742,96],{"class":41},[32,12744,12745,12748,12750,12752,12754],{"class":34,"line":99},[32,12746,12747],{"class":351},"  padding-right",[32,12749,5269],{"class":41},[32,12751,12740],{"class":351},[32,12753,12027],{"class":38},[32,12755,96],{"class":41},[32,12757,12758],{"class":34,"line":106},[32,12759,54],{"class":41},[15,12761,2004],{"id":2003},[11,12763,12764,12765,12768],{},"這段覆蓋規則會取消套件原本的捲動鎖定與捲軸寬度補償，只適合當時的版面情境。新專案若不依賴 Bootstrap Modal，也可以考慮瀏覽器原生的 ",[29,12766,12767],{},"dialog"," 元素。",[368,12770,12771],{},"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":12773},[12774],{"id":2003,"depth":45,"text":2004},"2020 年記錄 Bootstrap Modal 與 fixed Header 一起使用時的捲軸修正方式。",{},"\u002Fposts\u002Fbootstrap-modal-scrollbar-fix","2020-03-13",[],{"title":12689,"description":12775},"posts\u002F20200313.bootstrap-modal-scrollbar-fix",[10517,1757,12783],"Modal","EVd-qtpdp1Yhv-cXjxVDZ4ceK7-IiK6TUgid-9-YIgU",{"id":12786,"title":12787,"body":12788,"category":4012,"description":12944,"draft":380,"extension":381,"image":382,"meta":12945,"navigation":102,"path":12946,"publishedAt":12947,"relatedExperiments":12948,"seo":12949,"stem":12950,"tags":12951,"updatedAt":10848,"__hash__":12954},"posts\u002Fposts\u002F20200315.github-first-push.md","專案上傳 GitHub 前的初始化流程",{"type":8,"value":12789,"toc":12938},[12790,12793,12797,12800,12806,12809,12815,12821,12824,12827,12833,12836,12846,12852,12855,12875,12878,12884,12888,12891,12897,12900,12906,12913,12919,12921,12935],[11,12791,12792],{},"這邊記錄專案上傳 GitHub 前會先做的動作。",[15,12794,12796],{"id":12795},"在-github-建立專案","在 GitHub 建立專案",[11,12798,12799],{},"進到 GitHub，點選右上角新增專案。",[11,12801,12802],{},[10761,12803],{"alt":12804,"src":12805},"GitHub 右上角的新增選單，New repository 選項用紅框標示","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F01.png",[11,12807,12808],{},"填寫專案名稱並選擇是否公開。",[11,12810,12811],{},[10761,12812],{"alt":12813,"src":12814},"GitHub 的 Create a new repository 表單，可填寫專案名稱並選擇 Public 或 Private","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F02.png",[11,12816,12817],{},[10761,12818],{"alt":12819,"src":12820},"GitHub 建立空倉庫後顯示的 command line 初始化指令","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F03.png",[15,12822,12823],{"id":12823},"本機初始化",[11,12825,12826],{},"開啟 PowerShell，將路徑切換到要上傳的專案並查看檔案清單。",[11,12828,12829],{},[10761,12830],{"alt":12831,"src":12832},"PowerShell 使用 ls 顯示專案資料夾中的檔案與目錄","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F04.png",[11,12834,12835],{},"初始化 Git：",[22,12837,12838],{"className":2057,"code":2381,"language":2059,"meta":27,"style":27},[29,12839,12840],{"__ignoreMap":27},[32,12841,12842,12844],{"class":34,"line":35},[32,12843,2126],{"class":2066},[32,12845,2390],{"class":175},[11,12847,12848],{},[10761,12849],{"alt":12850,"src":12851},"PowerShell 執行 git init，顯示 Initialized empty Git repository","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F05.png",[11,12853,12854],{},"告訴本機資料夾要連到哪個 GitHub 倉庫：",[22,12856,12858],{"className":2057,"code":12857,"language":2059,"meta":27,"style":27},"git remote add origin https:\u002F\u002Fgithub.com\u002F帳號\u002F專案名稱.git\n",[29,12859,12860],{"__ignoreMap":27},[32,12861,12862,12864,12867,12869,12872],{"class":34,"line":35},[32,12863,2126],{"class":2066},[32,12865,12866],{"class":175}," remote",[32,12868,2493],{"class":175},[32,12870,12871],{"class":175}," origin",[32,12873,12874],{"class":175}," https:\u002F\u002Fgithub.com\u002F帳號\u002F專案名稱.git\n",[11,12876,12877],{},"沒有任何錯誤或其他訊息出現，就代表設定成功。",[11,12879,12880],{},[10761,12881],{"alt":12882,"src":12883},"PowerShell 執行 git remote add origin，成功時沒有其他訊息","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F06.png",[15,12885,12887],{"id":12886},"使用-github-desktop","使用 GitHub Desktop",[11,12889,12890],{},"開啟 GitHub Desktop。",[11,12892,12893],{},[10761,12894],{"alt":12895,"src":12896},"GitHub Desktop 的 File 選單，Add local repository 選項被選取","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F07.png",[11,12898,12899],{},"選擇已建立、準備上傳的專案。",[11,12901,12902],{},[10761,12903],{"alt":12904,"src":12905},"GitHub Desktop 的 Add local repository 視窗，可選擇本機專案路徑","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F08.png",[11,12907,12908,12909,12912],{},"新增 ",[29,12910,12911],{},"CHANGELOG.md","，填寫 commit 訊息後提交並 push。",[11,12914,12915],{},[10761,12916],{"alt":12917,"src":12918},"GitHub Desktop 顯示專案變更，提交訊息欄位填寫初始化 Laravel 專案","\u002Fimages\u002Fposts\u002Fgithub-first-push\u002F09.png",[15,12920,2004],{"id":2003},[11,12922,12923,12924,12927,12928,12930,12931,12934],{},"初始化、設定 remote、commit 與 push 的流程沒有改變；現在 GitHub 新倉庫的預設分支通常是 ",[29,12925,12926],{},"main","，舊截圖則仍顯示 ",[29,12929,3753],{},"。常用指令可參考《",[412,12932,12933],{"href":4015},"Git 常用指令整理","》。",[368,12936,12937],{},"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":12939},[12940,12941,12942,12943],{"id":12795,"depth":45,"text":12796},{"id":12823,"depth":45,"text":12823},{"id":12886,"depth":45,"text":12887},{"id":2003,"depth":45,"text":2004},"2020 年記錄建立 GitHub 倉庫、本機初始化並用 GitHub Desktop 完成第一次提交的流程。",{},"\u002Fposts\u002Fgithub-first-push","2020-03-15",[],{"title":12787,"description":12944},"posts\u002F20200315.github-first-push",[4021,12952,12953],"GitHub","GitHub Desktop","w1rx37B0l7tYN3oI2p6GNhHrDvSJgFmqR0LK532n4fk",{"id":12956,"title":12957,"body":12958,"category":378,"description":13022,"draft":380,"extension":381,"image":382,"meta":13023,"navigation":102,"path":13024,"publishedAt":13025,"relatedExperiments":13026,"seo":13027,"stem":13028,"tags":13029,"updatedAt":10848,"__hash__":13030},"posts\u002Fposts\u002F20200316.css-reset-normalize.md","CSS Reset 與 Normalize.css 筆記",{"type":8,"value":12959,"toc":13016},[12960,12963,12967,12979,12983,12992,12995,13002,13008,13010],[11,12961,12962],{},"開始製作專案時，習慣先將瀏覽器的預設樣式清空，以免撰寫 CSS 時出現不一致。\n清空方式很多，也可以自己手寫，這邊記錄當時常用的兩種選擇。",[15,12964,12966],{"id":12965},"reset-css","Reset CSS",[4538,12968,12969,12972],{},[4541,12970,12971],{},"會將不同瀏覽器的預設樣式清空。",[4541,12973,12974],{},[412,12975,12978],{"href":12976,"rel":12977},"https:\u002F\u002Fmeyerweb.com\u002Feric\u002Ftools\u002Fcss\u002Freset\u002F",[416],"Eric Meyer 的 Reset CSS",[15,12980,12982],{"id":12981},"normalizecss","Normalize.css",[4538,12984,12985],{},[4541,12986,12987,12988],{},"會保留部分預設樣式，並清除瀏覽器之間多餘或不一致的設定。當時較常使用這一套，Bootstrap 也有採用。\n",[412,12989,12982],{"href":12990,"rel":12991},"https:\u002F\u002Fnecolas.github.io\u002Fnormalize.css\u002F",[416],[15,12993,12994],{"id":12994},"使用方式",[11,12996,12997,12998,13001],{},"選擇一套習慣的方案，下載後可以直接把 CSS 檔改成 ",[29,12999,13000],{},"_xxx.scss","，再匯入主要的 SCSS 檔案。",[11,13003,13004],{},[10761,13005],{"alt":13006,"src":13007},"SCSS 入口檔使用 import 引入 normalize、animate、變數與 mixin 等檔案","\u002Fimages\u002Fposts\u002Fcss-reset-normalize\u002F01.webp",[15,13009,2004],{"id":2003},[11,13011,13012,13013,13015],{},"這兩套方案仍可使用；現代瀏覽器也可以搭配更精簡的 reset，整理在《現在的 CSS Reset》。Sass 的 ",[29,13014,8744],{}," 已有新的模組寫法，這篇保留當時的專案結構。",{"title":27,"searchDepth":51,"depth":51,"links":13017},[13018,13019,13020,13021],{"id":12965,"depth":45,"text":12966},{"id":12981,"depth":45,"text":12982},{"id":12994,"depth":45,"text":12994},{"id":2003,"depth":45,"text":2004},"2020 年整理的 CSS Reset、Normalize.css 與 Sass 引入方式。",{},"\u002Fposts\u002Fcss-reset-normalize","2020-03-16",[],{"title":12957,"description":13022},"posts\u002F20200316.css-reset-normalize",[1757,12455,12982],"2tIswfoUUD1KKmVrMk9YL5eph33bYXiugPlZQdwWGdI",{"id":13032,"title":13033,"body":13034,"category":378,"description":13138,"draft":380,"extension":381,"image":382,"meta":13139,"navigation":102,"path":13140,"publishedAt":13141,"relatedExperiments":13142,"seo":13143,"stem":13144,"tags":13145,"updatedAt":10848,"__hash__":13146},"posts\u002Fposts\u002F20200317.sass-scss-syntax-basics.md","關於 Sass／SCSS：兩種語法與專案架構",{"type":8,"value":13035,"toc":13132},[13036,13039,13043,13046,13049,13055,13061,13065,13068,13074,13080,13083,13089,13095,13101,13114,13116,13129],[11,13037,13038],{},"Sass／SCSS 是用來管理 CSS 的工具與程式語言，透過編譯工具轉成瀏覽器看得懂的 CSS。SCSS 是 Sass 3 引入的新語法，兩種寫法有些不同，但執行順序都是由上而下。",[15,13040,13042],{"id":13041},"sass-與-scss-寫法","Sass 與 SCSS 寫法",[11,13044,13045],{},"兩者最大的表面差異，是 Sass 省略了分號與大括號。Sass 寫起來較簡潔，但內容很多時只靠縮排會比較難分辨段落。",[11,13047,13048],{},"下面的 SCSS 與 Sass 寫法沒有功能差異，會編譯成相同的 CSS。",[11,13050,13051],{},[10761,13052],{"alt":13053,"src":13054},"SCSS 使用大括號與分號撰寫巢狀 nav，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F01.webp",[11,13056,13057],{},[10761,13058],{"alt":13059,"src":13060},"Sass 使用縮排撰寫相同的 nav 樣式，右側顯示相同的編譯結果","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F02.webp",[15,13062,13064],{"id":13063},"mixin-寫法","mixin 寫法",[11,13066,13067],{},"Mixin 在 SCSS 與 Sass 中的寫法不同。",[11,13069,13070],{},[10761,13071],{"alt":13072,"src":13073},"SCSS 使用 @mixin 與 @include 定義 transform，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F03.webp",[11,13075,13076],{},[10761,13077],{"alt":13078,"src":13079},"Sass 使用等號與加號定義及呼叫 transform mixin，右側顯示編譯後 CSS","\u002Fimages\u002Fposts\u002Fsass-scss-syntax-basics\u002F04.webp",[15,13081,13082],{"id":13082},"專案架構",[11,13084,13085,13086,13088],{},"當時用 ",[29,13087,8744],{}," 組成的簡單架構：",[22,13090,13093],{"className":13091,"code":13092,"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,13094,13092],{"__ignoreMap":27},[11,13096,13097,13100],{},[29,13098,13099],{},"_all.scss"," 內的寫法：",[22,13102,13104],{"className":8735,"code":13103,"language":8737,"meta":27,"style":27},"@import 'variable';\n",[29,13105,13106],{"__ignoreMap":27},[32,13107,13108,13110,13112],{"class":34,"line":35},[32,13109,8744],{"class":38},[32,13111,10306],{"class":175},[32,13113,96],{"class":41},[15,13115,2004],{"id":2003},[11,13117,13118,13119,7090,13122,13125,13126,13128],{},"SCSS 仍是常見語法，但 Sass 官方已用 ",[29,13120,13121],{},"@use",[29,13123,13124],{},"@forward"," 取代舊式 ",[29,13127,8744],{}," 架構；現行模組方式整理在《Sass 的 @use 與 @forward》。",[368,13130,13131],{},"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":13133},[13134,13135,13136,13137],{"id":13041,"depth":45,"text":13042},{"id":13063,"depth":45,"text":13064},{"id":13082,"depth":45,"text":13082},{"id":2003,"depth":45,"text":2004},"2020 年整理的 Sass、SCSS 語法差異、mixin 與 import 專案結構。",{},"\u002Fposts\u002Fsass-scss-syntax-basics","2020-03-17",[],{"title":13033,"description":13138},"posts\u002F20200317.sass-scss-syntax-basics",[4847,12455],"j87ORCDJiqkqsXGX6jbLhz0Q_PZRE4jOpg2Kq20V0ck",{"id":13148,"title":13149,"body":13150,"category":378,"description":13556,"draft":380,"extension":381,"image":382,"meta":13557,"navigation":102,"path":13558,"publishedAt":13559,"relatedExperiments":13560,"seo":13561,"stem":13562,"tags":13563,"updatedAt":10848,"__hash__":13564},"posts\u002Fposts\u002F20200318.css-methodologies-smacss-oocss-bem.md","CSS 架構方法論：SMACSS、OOCSS、BEM",{"type":8,"value":13151,"toc":13543},[13152,13155,13159,13162,13174,13177,13256,13265,13331,13338,13342,13345,13353,13373,13397,13401,13405,13416,13423,13434,13441,13455,13458,13529,13535,13537,13540],[11,13153,13154],{},"Modular CSS 的目的是讓程式碼易懂、可重用，進而有效率地開發及維護。",[15,13156,13158],{"id":13157},"smacss","SMACSS",[11,13160,13161],{},"SMACSS（Scalable and Modular Architecture for CSS）具有結構規範與命名規則，將 CSS 結構分類，並讓 CSS 與 HTML 分離。",[4538,13163,13164,13167],{},[4541,13165,13166],{},"作者：Jonathan Snook",[4541,13168,13169,13170],{},"網站：",[412,13171,13158],{"href":13172,"rel":13173},"http:\u002F\u002Fsmacss.com\u002F",[416],[11,13175,13176],{},"分類方式：",[4538,13178,13179,13199,13216,13233,13250],{},[4541,13180,13181,13184,13185],{},[12390,13182,13183],{},"Base","：基底\n",[4538,13186,13187,13190,13193],{},[4541,13188,13189],{},"CSS Reset",[4541,13191,13192],{},"CSS Normalize",[4541,13194,13195,13196],{},"不應該使用 ",[29,13197,13198],{},"!important",[4541,13200,13201,13204,13205],{},[12390,13202,13203],{},"Layout","：圖層\n",[4538,13206,13207,13210,13213],{},[4541,13208,13209],{},"Header",[4541,13211,13212],{},"Sidebar",[4541,13214,13215],{},"Content",[4541,13217,13218,13221,13222],{},[12390,13219,13220],{},"Module","：模組\n",[4538,13223,13224,13227,13230],{},[4541,13225,13226],{},"Tabs",[4541,13228,13229],{},"Button",[4541,13231,13232],{},"List",[4541,13234,13235,13238,13239],{},[12390,13236,13237],{},"State","：狀態\n",[4538,13240,13241,13244,13247],{},[4541,13242,13243],{},"Disabled State",[4541,13245,13246],{},"Default State",[4541,13248,13249],{},"Active State",[4541,13251,13252,13255],{},[12390,13253,13254],{},"Theme","：頁面上可單獨存在並可重複使用的元件",[11,13257,13258,13259,3750,13262,3775],{},"定義 Module 時，應避免使用 ID 或標籤名稱作為選擇器。子模組以原模組名稱加連字號作為名稱，例如 ",[29,13260,13261],{},".mod-header",[29,13263,13264],{},".mod-body",[22,13266,13268],{"className":4038,"code":13267,"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,13269,13270,13285,13304,13323],{"__ignoreMap":27},[32,13271,13272,13274,13276,13278,13280,13283],{"class":34,"line":35},[32,13273,4046],{"class":41},[32,13275,4050],{"class":4049},[32,13277,9897],{"class":4053},[32,13279,172],{"class":41},[32,13281,13282],{"class":175},"\"fld\"",[32,13284,4062],{"class":41},[32,13286,13287,13289,13291,13293,13295,13298,13300,13302],{"class":34,"line":45},[32,13288,4067],{"class":41},[32,13290,11],{"class":4049},[32,13292,9897],{"class":4053},[32,13294,172],{"class":41},[32,13296,13297],{"class":175},"\"fld-name\"",[32,13299,4136],{"class":41},[32,13301,11],{"class":4049},[32,13303,4062],{"class":41},[32,13305,13306,13308,13310,13312,13314,13317,13319,13321],{"class":34,"line":51},[32,13307,4067],{"class":41},[32,13309,11],{"class":4049},[32,13311,9897],{"class":4053},[32,13313,172],{"class":41},[32,13315,13316],{"class":175},"\"fld-item\"",[32,13318,4136],{"class":41},[32,13320,11],{"class":4049},[32,13322,4062],{"class":41},[32,13324,13325,13327,13329],{"class":34,"line":90},[32,13326,4105],{"class":41},[32,13328,4050],{"class":4049},[32,13330,4062],{"class":41},[11,13332,10400,13333],{},[412,13334,13337],{"href":13335,"rel":13336},"https:\u002F\u002Fwww.slideshare.net\u002Fkurotanshi\u002Fcss-oocss-smacss-bem",[416],"CSS：OOCSS、SMACSS、BEM",[15,13339,13341],{"id":13340},"oocss","OOCSS",[11,13343,13344],{},"OOCSS（Object Oriented CSS）最典型的框架例子是 Bootstrap。",[4538,13346,13347,13350],{},[4541,13348,13349],{},"結構與外觀分離：與樣式有關的部分要獨立出來。",[4541,13351,13352],{},"容器與內容分離，例如格線系統 Grid System。",[22,13354,13356],{"className":5412,"code":13355,"language":1140,"meta":27,"style":27},".container .grid_1\n.container .grid_2\n",[29,13357,13358,13366],{"__ignoreMap":27},[32,13359,13360,13363],{"class":34,"line":35},[32,13361,13362],{"class":4053},".container",[32,13364,13365],{"class":4053}," .grid_1\n",[32,13367,13368,13370],{"class":34,"line":45},[32,13369,13362],{"class":4053},[32,13371,13372],{"class":4053}," .grid_2\n",[22,13374,13376],{"className":4038,"code":13375,"language":4034,"meta":27,"style":27},"\u003Cbutton class=\"btn btn-small btn-primary\">\u003C\u002Fbutton>\n",[29,13377,13378],{"__ignoreMap":27},[32,13379,13380,13382,13384,13386,13388,13391,13393,13395],{"class":34,"line":35},[32,13381,4046],{"class":41},[32,13383,11634],{"class":4049},[32,13385,9897],{"class":4053},[32,13387,172],{"class":41},[32,13389,13390],{"class":175},"\"btn btn-small btn-primary\"",[32,13392,4136],{"class":41},[32,13394,11634],{"class":4049},[32,13396,4062],{"class":41},[15,13398,13400],{"id":13399},"bem","BEM",[151,13402,13404],{"id":13403},"block區塊","Block（區塊）",[4538,13406,13407,13410,13413],{},[4541,13408,13409],{},"在頁面上獨立存在並可重複使用的元件。",[4541,13411,13412],{},"如同 SMACSS 的 Module、Layout。",[4541,13414,13415],{},"每個 Block 都是獨立存在。",[151,13417,13419,13420],{"id":13418},"element元素__","Element（元素）",[29,13421,13422],{},"__",[4538,13424,13425,13428,13431],{},[4541,13426,13427],{},"Block 的一部分，也就是子元件。",[4541,13429,13430],{},"無法獨立於 Block 之外。",[4541,13432,13433],{},"有些 Block 可能沒有 Element。",[151,13435,13437,13438],{"id":13436},"modifier修飾符","Modifier（修飾符）",[29,13439,13440],{},"--",[4538,13442,13443,13446,13449,13452],{},[4541,13444,13445],{},"用來修改樣式。",[4541,13447,13448],{},"定義 Block 或 Element 的狀態或屬性。",[4541,13450,13451],{},"類似 SMACSS 的 State。",[4541,13453,13454],{},"同一個 Block 或 Element 可以同時存在多組 Modifier。",[15,13456,13457],{"id":13457},"命名筆記",[4538,13459,13460,13463,13487,13502,13511,13517,13520,13523,13526],{},[4541,13461,13462],{},"階層不要超過五層。",[4541,13464,13465,13466,3750,13469,3750,13472,3750,13475,3750,13478,3750,13481,3750,13484,3775],{},"前綴詞：",[29,13467,13468],{},".l-layout",[29,13470,13471],{},".e-element",[29,13473,13474],{},".p-page",[29,13476,13477],{},".h-helper",[29,13479,13480],{},".col-",[29,13482,13483],{},".fas",[29,13485,13486],{},".fa-icon",[4541,13488,13489,13490,3750,13493,3750,13496,3750,13499,3775],{},"Element：",[29,13491,13492],{},".button__icon",[29,13494,13495],{},".text-field__label",[29,13497,13498],{},".heading__title",[29,13500,13501],{},".menu__item",[4541,13503,13504,13505,3750,13508,3775],{},"Modifier：",[29,13506,13507],{},".button_active",[29,13509,13510],{},".text-field_editable",[4541,13512,13513,13514,3775],{},"當時 CSS 通常使用小駝峰寫法，例如 ",[29,13515,13516],{},".bookList",[4541,13518,13519],{},"依照開發規範選擇命名方式，重點是保持一致。",[4541,13521,13522],{},"可以使用 BEM 設計模式與命名規範。",[4541,13524,13525],{},"拋棄語意命名方式，改以工具性質命名（SMACSS）。",[4541,13527,13528],{},"多參考其他框架，了解不同命名方式。",[11,13530,13531,13532,3775],{},"良好的 CSS 架構：",[12390,13533,13534],{},"可預測 → 可複用 → 可維護 → 可延展",[15,13536,2004],{"id":2003},[11,13538,13539],{},"這些方法論仍可用在全域 CSS；元件 scoped style、CSS Modules 與 utility-first CSS 則提供了不同的作用域與命名方式，整理在《Scoped Style 與 Utility-First CSS》。",[368,13541,13542],{},"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":13544},[13545,13546,13547,13554,13555],{"id":13157,"depth":45,"text":13158},{"id":13340,"depth":45,"text":13341},{"id":13399,"depth":45,"text":13400,"children":13548},[13549,13550,13552],{"id":13403,"depth":51,"text":13404},{"id":13418,"depth":51,"text":13551},"Element（元素）__",{"id":13436,"depth":51,"text":13553},"Modifier（修飾符）--",{"id":13457,"depth":45,"text":13457},{"id":2003,"depth":45,"text":2004},"2020 年整理的 SMACSS、OOCSS、BEM 分類與命名筆記。",{},"\u002Fposts\u002Fcss-methodologies-smacss-oocss-bem","2020-03-18",[],{"title":13149,"description":13556},"posts\u002F20200318.css-methodologies-smacss-oocss-bem",[1757,13400,13158,13341],"x5xxmylpKKc2860imGPWbwo0ArnzP-siL-1cFC3Rhqk",{"id":13566,"title":13567,"body":13568,"category":378,"description":13752,"draft":380,"extension":381,"image":382,"meta":13753,"navigation":102,"path":13754,"publishedAt":13755,"relatedExperiments":13756,"seo":13757,"stem":13758,"tags":13759,"updatedAt":10848,"__hash__":13761},"posts\u002Fposts\u002F20200319.css-scss-team-standard.md","2020 年 CSS／Sass 規範與檢核表",{"type":8,"value":13569,"toc":13747},[13570,13573,13674,13677,13739,13741],[15,13571,13572],{"id":13572},"規範",[13574,13575,13576,13589],"table",{},[13577,13578,13579],"thead",{},[13580,13581,13582,13586],"tr",{},[13583,13584,13585],"th",{},"項次",[13583,13587,13588],{},"規範敘述",[13590,13591,13592,13600,13607,13615,13623,13630,13642,13649,13660,13667],"tbody",{},[13580,13593,13594,13597],{},[13595,13596,6544],"td",{},[13595,13598,13599],{},"類別階層以不超過四層為原則",[13580,13601,13602,13604],{},[13595,13603,12112],{},[13595,13605,13606],{},"不使用 ID，一律使用 class；ID 通常只用於唯一值與錨點定位",[13580,13608,13609,13612],{},[13595,13610,13611],{},"3",[13595,13613,13614],{},"使用 OOCSS 建立類別工具庫",[13580,13616,13617,13620],{},[13595,13618,13619],{},"4",[13595,13621,13622],{},"排版結構以 BEM 開發",[13580,13624,13625,13627],{},[13595,13626,10613],{},[13595,13628,13629],{},"導入 Bootstrap 4 的 Grid System",[13580,13631,13632,13635],{},[13595,13633,13634],{},"6",[13595,13636,13637,13638,13641],{},"使用 Sass ",[29,13639,13640],{},"for"," 管理擴充元件",[13580,13643,13644,13646],{},[13595,13645,1269],{},[13595,13647,13648],{},"一律採用小駝峰式命名",[13580,13650,13651,13653],{},[13595,13652,1031],{},[13595,13654,13655,13656,13659],{},"第三方插件在 Sass 的 ",[29,13657,13658],{},"vendor"," 分類中引入",[13580,13661,13662,13664],{},[13595,13663,1043],{},[13595,13665,13666],{},"使用 REM 或 vmin 單位",[13580,13668,13669,13671],{},[13595,13670,11370],{},[13595,13672,13673],{},"使用 flexbox 進行元件布局",[15,13675,13676],{"id":13676},"檢核表",[13574,13678,13679,13689],{},[13577,13680,13681],{},[13580,13682,13683,13686],{},[13583,13684,13685],{},"項目",[13583,13687,13688],{},"敘述",[13590,13690,13691,13699,13707,13715,13723,13731],{},[13580,13692,13693,13696],{},[13595,13694,13695],{},"網頁相容性",[13595,13697,13698],{},"檢查各大瀏覽器版本，例如 Chrome、Firefox、Edge",[13580,13700,13701,13704],{},[13595,13702,13703],{},"螢幕解析度",[13595,13705,13706],{},"可自行設定 1920、1440、1280、1024、768、414、370、320 等尺寸；使用 Bootstrap 時改用 BS4 的 breakpoints",[13580,13708,13709,13712],{},[13595,13710,13711],{},"可讀性",[13595,13713,13714],{},"class 的連字號、底線與駝峰寫法要有一致規則，並統一縮排與註解",[13580,13716,13717,13720],{},[13595,13718,13719],{},"可擴充性",[13595,13721,13722],{},"具備元件化設計觀念（BEM 或自訂規則），不輕易影響主體架構與 JS hooks",[13580,13724,13725,13728],{},[13595,13726,13727],{},"可重用性",[13595,13729,13730],{},"自訂 class 可在多處使用（OOCSS），不重複套用多餘 CSS",[13580,13732,13733,13736],{},[13595,13734,13735],{},"可維護性",[13595,13737,13738],{},"Sass import 結構清晰易懂，整體風格一致",[15,13740,2004],{"id":2003},[11,13742,13743,13744,13746],{},"這份規範保留的是當時的團隊約定，其中 Bootstrap 4 Grid、Sass ",[29,13745,8744],{}," 與命名方式不必直接套用到新專案。現代元件樣式與 utility-first 的取捨可參考《Scoped Style 與 Utility-First CSS》。",{"title":27,"searchDepth":51,"depth":51,"links":13748},[13749,13750,13751],{"id":13572,"depth":45,"text":13572},{"id":13676,"depth":45,"text":13676},{"id":2003,"depth":45,"text":2004},"2020 年留下的 CSS／Sass 團隊規範、相容性與維護性檢核表。",{},"\u002Fposts\u002Fcss-scss-team-standard","2020-03-19",[],{"title":13567,"description":13752},"posts\u002F20200319.css-scss-team-standard",[1757,4847,13760],"團隊規範","68E2Iy1aYISP0Sw0Ue3P9da2cVL8hpuctfU36c2zjsc",{"id":13763,"title":13764,"body":13765,"category":378,"description":13799,"draft":380,"extension":381,"image":382,"meta":13800,"navigation":102,"path":13801,"publishedAt":13802,"relatedExperiments":13803,"seo":13804,"stem":13805,"tags":13806,"updatedAt":10848,"__hash__":13809},"posts\u002Fposts\u002F20200320.ios-momentum-scrolling.md","iOS 捲動順暢設定：-webkit-overflow-scrolling",{"type":8,"value":13766,"toc":13796},[13767,13770,13785,13787,13793],[11,13768,13769],{},"若要在 iOS 讓區塊的捲軸滾動順暢，可以使用以下語法：",[22,13771,13773],{"className":5412,"code":13772,"language":1140,"meta":27,"style":27},"overflow: auto;\n-webkit-overflow-scrolling: touch;\n",[29,13774,13775,13780],{"__ignoreMap":27},[32,13776,13777],{"class":34,"line":35},[32,13778,13779],{"class":41},"overflow: auto;\n",[32,13781,13782],{"class":34,"line":45},[32,13783,13784],{"class":41},"-webkit-overflow-scrolling: touch;\n",[15,13786,2004],{"id":2003},[11,13788,13789,13790,3775],{},"這是早期 iOS Safari 的非標準設定。新版 Safari 已預設提供慣性捲動，新專案通常不需要再加入 ",[29,13791,13792],{},"-webkit-overflow-scrolling: touch",[368,13794,13795],{},"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":13797},[13798],{"id":2003,"depth":45,"text":2004},"2020 年記錄 iOS 可捲動區塊啟用慣性捲動的 CSS。",{},"\u002Fposts\u002Fios-momentum-scrolling","2020-03-20",[],{"title":13764,"description":13799},"posts\u002F20200320.ios-momentum-scrolling",[1757,13807,13808],"iOS","Safari","dHIBq5EBemZqS3COAUSR8IkMlYhqdXZWNmbLJCzZeSc",{"id":13811,"title":13812,"body":13813,"category":378,"description":13863,"draft":380,"extension":381,"image":382,"meta":13864,"navigation":102,"path":13865,"publishedAt":13866,"relatedExperiments":13867,"seo":13868,"stem":13869,"tags":13870,"updatedAt":13871,"__hash__":13872},"posts\u002Fposts\u002F20200322.img-inline-gap.md","圖片放進 div 裡為什麼底下會多一段空白",{"type":8,"value":13814,"toc":13860},[13815,13822,13849,13851,13857],[11,13816,13817,13818,13821],{},"圖片放進 ",[29,13819,13820],{},"\u003Cdiv>"," 後，如果底下多出一小段空白，可以加上以下樣式：",[22,13823,13825],{"className":5412,"code":13824,"language":1140,"meta":27,"style":27},"img {\n  display: block;\n}\n",[29,13826,13827,13833,13845],{"__ignoreMap":27},[32,13828,13829,13831],{"class":34,"line":35},[32,13830,10761],{"class":4049},[32,13832,703],{"class":41},[32,13834,13835,13838,13840,13843],{"class":34,"line":45},[32,13836,13837],{"class":351},"  display",[32,13839,5269],{"class":41},[32,13841,13842],{"class":351},"block",[32,13844,96],{"class":41},[32,13846,13847],{"class":34,"line":51},[32,13848,54],{"class":41},[15,13850,2004],{"id":2003},[11,13852,13853,13856],{},[29,13854,13855],{},"\u003Cimg>"," 預設是行內元素，會參與文字的基線對齊，因此底部可能留下空間。將它改為區塊元素後，就不再使用這套對齊方式。",[368,13858,13859],{},"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 .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":13861},[13862],{"id":2003,"depth":45,"text":2004},"記錄圖片放進 div 後，底部多出一小段空白時的 CSS 修正方式。",{},"\u002Fposts\u002Fimg-inline-gap","2020-03-22",[],{"title":13812,"description":13863},"posts\u002F20200322.img-inline-gap",[1757,4035],"2026-08-07","pMzeaTWjACmp-X_hOUD-aUsAUZiFecHFXhmnwYImXPU",{"id":13874,"title":13875,"body":13876,"category":378,"description":14467,"draft":380,"extension":381,"image":382,"meta":14468,"navigation":102,"path":14469,"publishedAt":14470,"relatedExperiments":14471,"seo":14472,"stem":14473,"tags":14474,"updatedAt":14476,"__hash__":14477},"posts\u002Fposts\u002F20200323.scss-color-map.md","用 SCSS 的 Map 建立一份共用色票",{"type":8,"value":13877,"toc":14462},[13878,13881,13885,13894,14097,14100,14103,14106,14255,14258,14405,14408,14454,14456,14459],[11,13879,13880],{},"撰寫 SCSS 時，顏色怎麼命名是一種考驗。這邊分享當時常用的兩種整理方式。",[15,13882,13884],{"id":13883},"擴充-bootstrap-的顏色工具類別","擴充 Bootstrap 的顏色工具類別",[11,13886,13887,13888,13893],{},"因為自己常用 Bootstrap，所以會沿用它的顏色工具類別規範。可以先定義顏色；如果要以顏色名稱命名，我習慣把色碼貼到 ",[412,13889,13892],{"href":13890,"rel":13891},"http:\u002F\u002Fchir.ag\u002Fprojects\u002Fname-that-color\u002F",[416],"Name That Color"," 查詢名稱。",[22,13895,13897],{"className":8735,"code":13896,"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,13898,13899,13906,13918,13930,13941,13953,13965,13977,13983,13987,14004,14013,14023,14027,14031,14040,14053,14057,14061,14070,14089,14093],{"__ignoreMap":27},[32,13900,13901,13904],{"class":34,"line":35},[32,13902,13903],{"class":903},"$colorGroup",[32,13905,11860],{"class":5049},[32,13907,13908,13911,13913,13916],{"class":34,"line":45},[32,13909,13910],{"class":175},"  \"supernova\"",[32,13912,5269],{"class":5049},[32,13914,13915],{"class":351},"#fecc00",[32,13917,547],{"class":5049},[32,13919,13920,13923,13925,13928],{"class":34,"line":51},[32,13921,13922],{"class":175},"  \"fiord\"",[32,13924,5269],{"class":5049},[32,13926,13927],{"class":351},"#4c596c",[32,13929,547],{"class":5049},[32,13931,13932,13935,13937,13939],{"class":34,"line":90},[32,13933,13934],{"class":175},"  \"black\"",[32,13936,5269],{"class":5049},[32,13938,8694],{"class":351},[32,13940,547],{"class":5049},[32,13942,13943,13946,13948,13951],{"class":34,"line":99},[32,13944,13945],{"class":175},"  \"alto\"",[32,13947,5269],{"class":5049},[32,13949,13950],{"class":351},"#dbdbdb",[32,13952,547],{"class":5049},[32,13954,13955,13958,13960,13963],{"class":34,"line":106},[32,13956,13957],{"class":175},"  \"dustyGray\"",[32,13959,5269],{"class":5049},[32,13961,13962],{"class":351},"#999",[32,13964,547],{"class":5049},[32,13966,13967,13970,13972,13975],{"class":34,"line":114},[32,13968,13969],{"class":175},"  \"gray\"",[32,13971,5269],{"class":5049},[32,13973,13974],{"class":351},"#7f7f7f",[32,13976,547],{"class":5049},[32,13978,13979,13981],{"class":34,"line":120},[32,13980,11937],{"class":5049},[32,13982,96],{"class":41},[32,13984,13985],{"class":34,"line":127},[32,13986,103],{"emptyLinePlaceholder":102},[32,13988,13989,13991,13993,13995,13997,13999,14002],{"class":34,"line":132},[32,13990,11801],{"class":38},[32,13992,11963],{"class":903},[32,13994,635],{"class":41},[32,13996,8689],{"class":903},[32,13998,5527],{"class":38},[32,14000,14001],{"class":903}," $colorGroup",[32,14003,703],{"class":41},[32,14005,14006,14009,14011],{"class":34,"line":141},[32,14007,14008],{"class":4053},"  .bg-",[32,14010,11981],{"class":903},[32,14012,703],{"class":41},[32,14014,14015,14017,14019,14021],{"class":34,"line":147},[32,14016,12034],{"class":351},[32,14018,5269],{"class":41},[32,14020,8689],{"class":903},[32,14022,96],{"class":41},[32,14024,14025],{"class":34,"line":275},[32,14026,1203],{"class":41},[32,14028,14029],{"class":34,"line":282},[32,14030,103],{"emptyLinePlaceholder":102},[32,14032,14033,14036,14038],{"class":34,"line":295},[32,14034,14035],{"class":4053},"  .text-",[32,14037,11981],{"class":903},[32,14039,703],{"class":41},[32,14041,14042,14045,14047,14049,14051],{"class":34,"line":605},[32,14043,14044],{"class":351},"    color",[32,14046,5269],{"class":41},[32,14048,8689],{"class":903},[32,14050,12027],{"class":38},[32,14052,96],{"class":41},[32,14054,14055],{"class":34,"line":612},[32,14056,1203],{"class":41},[32,14058,14059],{"class":34,"line":617},[32,14060,103],{"emptyLinePlaceholder":102},[32,14062,14063,14066,14068],{"class":34,"line":644},[32,14064,14065],{"class":4053},"  .border-",[32,14067,11981],{"class":903},[32,14069,703],{"class":41},[32,14071,14072,14075,14077,14079,14081,14084,14087],{"class":34,"line":649},[32,14073,14074],{"class":351},"    border",[32,14076,5269],{"class":41},[32,14078,6544],{"class":351},[32,14080,11996],{"class":38},[32,14082,14083],{"class":351}," solid",[32,14085,14086],{"class":903}," $color",[32,14088,96],{"class":41},[32,14090,14091],{"class":34,"line":671},[32,14092,1203],{"class":41},[32,14094,14095],{"class":34,"line":690},[32,14096,54],{"class":41},[11,14098,14099],{},"SCSS 編譯完成後，就可以直接使用產生出來的 class。",[15,14101,14102],{"id":14102},"依區塊整理顏色",[11,14104,14105],{},"區塊需要的顏色可以直接使用色碼，或引用已經命名的顏色。例如 footer 可以另外整理一份 map：",[22,14107,14109],{"className":8735,"code":14108,"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,14110,14111,14118,14138,14158,14178,14198,14217,14237,14249],{"__ignoreMap":27},[32,14112,14113,14116],{"class":34,"line":35},[32,14114,14115],{"class":903},"$footerGroup",[32,14117,11860],{"class":5049},[32,14119,14120,14123,14125,14127,14129,14131,14133,14136],{"class":34,"line":45},[32,14121,14122],{"class":175},"  \"menu-title-color\"",[32,14124,5269],{"class":5049},[32,14126,12044],{"class":351},[32,14128,477],{"class":5049},[32,14130,13903],{"class":903},[32,14132,635],{"class":5049},[32,14134,14135],{"class":175},"\"nobel\"",[32,14137,5101],{"class":5049},[32,14139,14140,14143,14145,14147,14149,14151,14153,14156],{"class":34,"line":51},[32,14141,14142],{"class":175},"  \"menu-normal-color\"",[32,14144,5269],{"class":5049},[32,14146,12044],{"class":351},[32,14148,477],{"class":5049},[32,14150,13903],{"class":903},[32,14152,635],{"class":5049},[32,14154,14155],{"class":175},"\"doveGray\"",[32,14157,5101],{"class":5049},[32,14159,14160,14163,14165,14167,14169,14171,14173,14176],{"class":34,"line":90},[32,14161,14162],{"class":175},"  \"menu-hover-color\"",[32,14164,5269],{"class":5049},[32,14166,12044],{"class":351},[32,14168,477],{"class":5049},[32,14170,13903],{"class":903},[32,14172,635],{"class":5049},[32,14174,14175],{"class":175},"\"treePoppy\"",[32,14177,5101],{"class":5049},[32,14179,14180,14183,14185,14187,14189,14191,14193,14196],{"class":34,"line":99},[32,14181,14182],{"class":175},"  \"bottom-bg-color\"",[32,14184,5269],{"class":5049},[32,14186,12044],{"class":351},[32,14188,477],{"class":5049},[32,14190,13903],{"class":903},[32,14192,635],{"class":5049},[32,14194,14195],{"class":175},"\"shark\"",[32,14197,5101],{"class":5049},[32,14199,14200,14203,14205,14207,14209,14211,14213,14215],{"class":34,"line":106},[32,14201,14202],{"class":175},"  \"privacy-text-color\"",[32,14204,5269],{"class":5049},[32,14206,12044],{"class":351},[32,14208,477],{"class":5049},[32,14210,13903],{"class":903},[32,14212,635],{"class":5049},[32,14214,14155],{"class":175},[32,14216,5101],{"class":5049},[32,14218,14219,14222,14224,14226,14228,14230,14232,14235],{"class":34,"line":114},[32,14220,14221],{"class":175},"  \"border-color\"",[32,14223,5269],{"class":5049},[32,14225,12044],{"class":351},[32,14227,477],{"class":5049},[32,14229,13903],{"class":903},[32,14231,635],{"class":5049},[32,14233,14234],{"class":175},"\"alto\"",[32,14236,5101],{"class":5049},[32,14238,14239,14242,14244,14247],{"class":34,"line":120},[32,14240,14241],{"class":175},"  \"footer-bg\"",[32,14243,5269],{"class":5049},[32,14245,14246],{"class":351},"white",[32,14248,547],{"class":5049},[32,14250,14251,14253],{"class":34,"line":127},[32,14252,11937],{"class":5049},[32,14254,96],{"class":41},[11,14256,14257],{},"社群圖示也可以直接用色碼命名：",[22,14259,14261],{"className":8735,"code":14260,"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,14262,14263,14270,14282,14294,14306,14375,14387,14399],{"__ignoreMap":27},[32,14264,14265,14268],{"class":34,"line":35},[32,14266,14267],{"class":903},"$socialGroup",[32,14269,11860],{"class":5049},[32,14271,14272,14275,14277,14280],{"class":34,"line":45},[32,14273,14274],{"class":175},"  \"users\"",[32,14276,5269],{"class":5049},[32,14278,14279],{"class":351},"#2ab1f3",[32,14281,547],{"class":5049},[32,14283,14284,14287,14289,14292],{"class":34,"line":51},[32,14285,14286],{"class":175},"  \"fb\"",[32,14288,5269],{"class":5049},[32,14290,14291],{"class":351},"#3b5998",[32,14293,547],{"class":5049},[32,14295,14296,14299,14301,14304],{"class":34,"line":90},[32,14297,14298],{"class":175},"  \"twitter\"",[32,14300,5269],{"class":5049},[32,14302,14303],{"class":351},"#1da1f2",[32,14305,547],{"class":5049},[32,14307,14308,14311,14313,14316,14318,14321,14324,14326,14329,14331,14334,14336,14339,14342,14344,14346,14349,14351,14353,14355,14358,14361,14363,14365,14368,14371,14373],{"class":34,"line":99},[32,14309,14310],{"class":175},"  \"ig\"",[32,14312,5269],{"class":5049},[32,14314,14315],{"class":351},"linear-gradient",[32,14317,477],{"class":5049},[32,14319,14320],{"class":351},"45",[32,14322,14323],{"class":38},"deg",[32,14325,635],{"class":5049},[32,14327,14328],{"class":351},"#f09433",[32,14330,1523],{"class":351},[32,14332,14333],{"class":38},"%",[32,14335,635],{"class":5049},[32,14337,14338],{"class":351},"#e6683c",[32,14340,14341],{"class":351}," 25",[32,14343,14333],{"class":38},[32,14345,635],{"class":5049},[32,14347,14348],{"class":351},"#dc2743",[32,14350,6868],{"class":351},[32,14352,14333],{"class":38},[32,14354,635],{"class":5049},[32,14356,14357],{"class":351},"#cc2366",[32,14359,14360],{"class":351}," 75",[32,14362,14333],{"class":38},[32,14364,635],{"class":5049},[32,14366,14367],{"class":351},"#bc1888",[32,14369,14370],{"class":351}," 100",[32,14372,14333],{"class":38},[32,14374,5101],{"class":5049},[32,14376,14377,14380,14382,14385],{"class":34,"line":106},[32,14378,14379],{"class":175},"  \"telegram\"",[32,14381,5269],{"class":5049},[32,14383,14384],{"class":351},"#0088cc",[32,14386,547],{"class":5049},[32,14388,14389,14392,14394,14397],{"class":34,"line":114},[32,14390,14391],{"class":175},"  \"youtube\"",[32,14393,5269],{"class":5049},[32,14395,14396],{"class":351},"#cd201f",[32,14398,547],{"class":5049},[32,14400,14401,14403],{"class":34,"line":120},[32,14402,11937],{"class":5049},[32,14404,96],{"class":41},[11,14406,14407],{},"調用方式：",[22,14409,14411],{"className":8735,"code":14410,"language":8737,"meta":27,"style":27},"footer {\n  .footer-area {\n    background: map-get($footerGroup, \"footer-bg\");\n  }\n}\n",[29,14412,14413,14420,14427,14446,14450],{"__ignoreMap":27},[32,14414,14415,14418],{"class":34,"line":35},[32,14416,14417],{"class":4049},"footer",[32,14419,703],{"class":41},[32,14421,14422,14425],{"class":34,"line":45},[32,14423,14424],{"class":4053},"  .footer-area",[32,14426,703],{"class":41},[32,14428,14429,14431,14433,14435,14437,14439,14441,14444],{"class":34,"line":51},[32,14430,12034],{"class":351},[32,14432,5269],{"class":41},[32,14434,12044],{"class":351},[32,14436,477],{"class":41},[32,14438,14115],{"class":903},[32,14440,635],{"class":41},[32,14442,14443],{"class":175},"\"footer-bg\"",[32,14445,230],{"class":41},[32,14447,14448],{"class":34,"line":90},[32,14449,1203],{"class":41},[32,14451,14452],{"class":34,"line":99},[32,14453,54],{"class":41},[15,14455,2004],{"id":2003},[11,14457,14458],{},"集中管理顏色的想法仍然適用。需要在瀏覽器執行期間切換主題時，現在通常會改用 CSS 自訂屬性；SCSS map 仍適合編譯期的批次產生工作。",[368,14460,14461],{},"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":14463},[14464,14465,14466],{"id":13883,"depth":45,"text":13884},{"id":14102,"depth":45,"text":14102},{"id":2003,"depth":45,"text":2004},"記錄用顏色名稱整理 SCSS 色票，再以 @each 產生背景、文字與邊框工具類別的做法。",{},"\u002Fposts\u002Fscss-color-map","2020-03-23",[],{"title":13875,"description":14467},"posts\u002F20200323.scss-color-map",[12455,1757,14475],"色彩系統","2026-08-25","YJSmUPoEz2pBgp0FJo38-UtMcfLdNODoBcDCCgdFucg",{"id":14479,"title":14480,"body":14481,"category":4012,"description":14694,"draft":380,"extension":381,"image":382,"meta":14695,"navigation":102,"path":14696,"publishedAt":14697,"relatedExperiments":14698,"seo":14699,"stem":14700,"tags":14701,"updatedAt":13871,"__hash__":14704},"posts\u002Fposts\u002F20200324.vscode-intro-extensions.md","Visual Studio Code 入門：下載安裝與擴充套件市集",{"type":8,"value":14482,"toc":14688},[14483,14486,14490,14498,14504,14507,14510,14516,14519,14580,14582,14680,14683,14685],[11,14484,14485],{},"自從寫前端後接觸到 VS Code，就對它愛不釋手。介面很乾淨，使用起來也很直覺，因此分享一下這套軟體，以及當時常用的套件與快捷鍵。",[15,14487,14489],{"id":14488},"關於-visual-studio-code","關於 Visual Studio Code",[11,14491,14492,14493,6257],{},"Visual Studio Code（VS Code）是由微軟開發的開源程式編輯器，同時支援 Windows、Linux 與 macOS，也內建 Git 版本控制功能。可以前往",[412,14494,14497],{"href":14495,"rel":14496},"https:\u002F\u002Fcode.visualstudio.com\u002F",[416],"官方網站",[11,14499,14500],{},[10761,14501],{"alt":14502,"src":14503},"VS Code 官方網站的下載畫面","\u002Fimages\u002Fposts\u002Fvscode-intro-extensions\u002F01.png",[15,14505,14506],{"id":14506},"擴充套件",[11,14508,14509],{},"點開左側的擴充套件區塊，就能搜尋套件、查看評價並直接安裝：",[11,14511,14512],{},[10761,14513],{"alt":14514,"src":14515},"VS Code 擴充套件市集","\u002Fimages\u002Fposts\u002Fvscode-intro-extensions\u002F02.png",[11,14517,14518],{},"當時常用的套件如下：",[13574,14520,14521,14530],{},[13577,14522,14523],{},[13580,14524,14525,14527],{},[13583,14526,4709],{},[13583,14528,14529],{},"用途",[13590,14531,14532,14540,14548,14556,14564,14572],{},[13580,14533,14534,14537],{},[13595,14535,14536],{},"Monokai Dark Soda",[13595,14538,14539],{},"更換介面主題",[13580,14541,14542,14545],{},[13595,14543,14544],{},"Copy filename",[13595,14546,14547],{},"複製檔名",[13580,14549,14550,14553],{},[13595,14551,14552],{},"Live Server",[13595,14554,14555],{},"模擬伺服器",[13580,14557,14558,14561],{},[13595,14559,14560],{},"Colorize",[13595,14562,14563],{},"顯示色碼對應的顏色",[13580,14565,14566,14569],{},[13595,14567,14568],{},"AutoFileName",[13595,14570,14571],{},"尋找路徑名稱",[13580,14573,14574,14577],{},[13595,14575,14576],{},"vscode-icons",[13595,14578,14579],{},"顯示資料夾與檔案圖示",[15,14581,6671],{"id":6671},[13574,14583,14584,14592],{},[13577,14585,14586],{},[13580,14587,14588,14590],{},[13583,14589,6671],{},[13583,14591,14529],{},[13590,14593,14594,14604,14614,14627,14637,14650,14660,14670],{},[13580,14595,14596,14601],{},[13595,14597,14598],{},[29,14599,14600],{},"Shift + Alt + F",[13595,14602,14603],{},"自動整理程式碼格式",[13580,14605,14606,14611],{},[13595,14607,14608],{},[29,14609,14610],{},"Ctrl + W",[13595,14612,14613],{},"關閉視窗或編輯頁面",[13580,14615,14616,14624],{},[13595,14617,14618,11762,14621],{},[29,14619,14620],{},"Alt + ↑",[29,14622,14623],{},"Alt + ↓",[13595,14625,14626],{},"移動程式碼",[13580,14628,14629,14634],{},[13595,14630,14631],{},[29,14632,14633],{},"Alt + 滑鼠點擊",[13595,14635,14636],{},"同時編輯多個位置",[13580,14638,14639,14647],{},[13595,14640,14641,11762,14644],{},[29,14642,14643],{},"Ctrl + +",[29,14645,14646],{},"Ctrl + -",[13595,14648,14649],{},"放大／縮小字體",[13580,14651,14652,14657],{},[13595,14653,14654],{},[29,14655,14656],{},"Ctrl + B",[13595,14658,14659],{},"顯示或隱藏側邊欄",[13580,14661,14662,14667],{},[13595,14663,14664],{},[29,14665,14666],{},"Ctrl + Shift + E",[13595,14668,14669],{},"切換到檔案總管",[13580,14671,14672,14677],{},[13595,14673,14674],{},[29,14675,14676],{},"Ctrl + Shift + X",[13595,14678,14679],{},"開啟擴充套件面板",[11,14681,14682],{},"往後如果遇到好用的套件，再繼續補充。",[15,14684,2004],{"id":2003},[11,14686,14687],{},"這是 2020 年的使用清單，套件選擇與快捷鍵仍應以目前版本及個人需求為準；其中 Live Server 的用途，在框架專案裡多半已由開發伺服器取代。",{"title":27,"searchDepth":51,"depth":51,"links":14689},[14690,14691,14692,14693],{"id":14488,"depth":45,"text":14489},{"id":14506,"depth":45,"text":14506},{"id":6671,"depth":45,"text":6671},{"id":2003,"depth":45,"text":2004},"記錄 VS Code 的下載方式、擴充套件市集，以及 2020 年使用的套件與快捷鍵。",{},"\u002Fposts\u002Fvscode-intro-extensions","2020-03-24",[],{"title":14480,"description":14694},"posts\u002F20200324.vscode-intro-extensions",[14702,14703],"VS Code","編輯器","uMYlO-qnqjv1lVa85b-1lfX11-1oFhUIdj1xAcnctAQ",{"id":14706,"title":14707,"body":14708,"category":4012,"description":14746,"draft":380,"extension":381,"image":382,"meta":14747,"navigation":102,"path":14748,"publishedAt":14749,"relatedExperiments":14750,"seo":14751,"stem":14752,"tags":14753,"updatedAt":14756,"__hash__":14757},"posts\u002Fposts\u002F20200325.v8-engine-basics.md","關於 V8：Chrome 與 Node.js 背後的 JavaScript 引擎",{"type":8,"value":14709,"toc":14743},[14710,14713,14716,14719,14735,14737,14740],[11,14711,14712],{},"最近學習 Vue 的過程中接觸到 Node.js，也剛好認識了 V8，在這邊稍微記錄一下。",[11,14714,14715],{},"V8 是由 Google 團隊開發、採 BSD 授權條款的開源 JavaScript 引擎，因此所有人都可以用 V8 設計自己的產品。使用 V8 的瀏覽器包括 Chrome；也因為這樣，才能在瀏覽器的 Console 輸入指令，讓引擎解讀並執行。",[11,14717,14718],{},"Node.js 則是以 JavaScript 為基礎的執行環境，內部使用 V8 作為 JavaScript 引擎。除了執行 JavaScript 之外，Node.js 也處理 HTTP、DNS、TCP 等網路功能。",[11,14720,14721,14722,14727,14728,14730,14731,14734],{},"可以進入 ",[412,14723,14726],{"href":14724,"rel":14725},"https:\u002F\u002Fgithub.com\u002Fnodejs\u002Fnode",[416],"Node.js 的 GitHub 倉庫","，從 ",[29,14729,7487],{}," 資料夾查看核心程式碼，再到 ",[29,14732,14733],{},"deps"," 資料夾看到 Node.js 使用的 V8。",[15,14736,2004],{"id":2003},[11,14738,14739],{},"這篇原本只是認識 V8 與 Node.js 時留下的兩篇短筆記，現在合併成一篇。Chrome 與 Node.js 使用 V8 的核心關係沒有改變。",[11,14741,14742],{},"原文把 Node.js 稱為「後端框架」並不精確；它是 JavaScript 執行環境。V8 負責執行 JavaScript，HTTP、DNS、TCP 等能力則由 Node.js 的其他組件提供。當時把 V8 說成「以 C++ 編譯 JavaScript」也過於簡化；V8 是以 C++ 實作的 JavaScript 引擎，會在執行期間將 JavaScript 編譯成機器碼。",{"title":27,"searchDepth":51,"depth":51,"links":14744},[14745],{"id":2003,"depth":45,"text":2004},"記錄學習 Vue 與 Node.js 時認識的 V8 JavaScript 引擎。",{},"\u002Fposts\u002Fv8-engine-basics","2020-03-25",[],{"title":14707,"description":14746},"posts\u002F20200325.v8-engine-basics",[390,14754,14755],"V8","Node.js","2026-08-26","MtUBGak0BWbTPuTT7h8HoMvixmU2A2xA8aD2Fe5b_FI",{"id":14759,"title":14760,"body":14761,"category":378,"description":14897,"draft":380,"extension":381,"image":382,"meta":14898,"navigation":102,"path":14899,"publishedAt":14900,"relatedExperiments":14901,"seo":14902,"stem":14903,"tags":14904,"updatedAt":13871,"__hash__":14906},"posts\u002Fposts\u002F20200327.input-search-cancel-button.md","調整 input type=search 的清除按鈕樣式",{"type":8,"value":14762,"toc":14894},[14763,14777,14884,14886,14891],[11,14764,14765,14766,7218,14769,14772,14773,14776],{},"當 ",[29,14767,14768],{},"\u003Cinput>",[29,14770,14771],{},"type"," 是 ",[29,14774,14775],{},"search"," 時，使用者輸入內容後，右側會顯示清除按鈕。要調整它的樣式，可以使用：",[22,14778,14780],{"className":5412,"code":14779,"language":1140,"meta":27,"style":27},"input::-webkit-search-cancel-button {\n  position: relative;\n  right: 20px;\n  -webkit-appearance: none;\n  width: 20px;\n  height: 20px;\n  border-radius: 10px;\n  background: red;\n}\n",[29,14781,14782,14791,14803,14817,14829,14842,14855,14868,14880],{"__ignoreMap":27},[32,14783,14784,14786,14789],{"class":34,"line":35},[32,14785,4070],{"class":4049},[32,14787,14788],{"class":4053},"::-webkit-search-cancel-button",[32,14790,703],{"class":41},[32,14792,14793,14796,14798,14801],{"class":34,"line":45},[32,14794,14795],{"class":351},"  position",[32,14797,5269],{"class":41},[32,14799,14800],{"class":351},"relative",[32,14802,96],{"class":41},[32,14804,14805,14808,14810,14813,14815],{"class":34,"line":51},[32,14806,14807],{"class":351},"  right",[32,14809,5269],{"class":41},[32,14811,14812],{"class":351},"20",[32,14814,11996],{"class":38},[32,14816,96],{"class":41},[32,14818,14819,14822,14824,14827],{"class":34,"line":90},[32,14820,14821],{"class":351},"  -webkit-appearance",[32,14823,5269],{"class":41},[32,14825,14826],{"class":351},"none",[32,14828,96],{"class":41},[32,14830,14831,14834,14836,14838,14840],{"class":34,"line":99},[32,14832,14833],{"class":351},"  width",[32,14835,5269],{"class":41},[32,14837,14812],{"class":351},[32,14839,11996],{"class":38},[32,14841,96],{"class":41},[32,14843,14844,14847,14849,14851,14853],{"class":34,"line":106},[32,14845,14846],{"class":351},"  height",[32,14848,5269],{"class":41},[32,14850,14812],{"class":351},[32,14852,11996],{"class":38},[32,14854,96],{"class":41},[32,14856,14857,14860,14862,14864,14866],{"class":34,"line":114},[32,14858,14859],{"class":351},"  border-radius",[32,14861,5269],{"class":41},[32,14863,11370],{"class":351},[32,14865,11996],{"class":38},[32,14867,96],{"class":41},[32,14869,14870,14873,14875,14878],{"class":34,"line":120},[32,14871,14872],{"class":351},"  background",[32,14874,5269],{"class":41},[32,14876,14877],{"class":351},"red",[32,14879,96],{"class":41},[32,14881,14882],{"class":34,"line":127},[32,14883,54],{"class":41},[15,14885,2004],{"id":2003},[11,14887,14888,14890],{},[29,14889,14788],{}," 是非標準、瀏覽器引擎限定的偽元素。若需要跨瀏覽器一致的外觀，較穩定的方式是自行建立清除按鈕。",[368,14892,14893],{},"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 .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 .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":14895},[14896],{"id":2003,"depth":45,"text":2004},"記錄用 ::-webkit-search-cancel-button 調整搜尋欄位清除按鈕樣式的方式。",{},"\u002Fposts\u002Finput-search-cancel-button","2020-03-27",[],{"title":14760,"description":14897},"posts\u002F20200327.input-search-cancel-button",[1757,14905],"表單","WSyi00Ifs1M92AQ0krX-PsgQZZEvCFmlD6jao57Sjho",{"id":14908,"title":14909,"body":14910,"category":4012,"description":15140,"draft":380,"extension":381,"image":382,"meta":15141,"navigation":102,"path":15142,"publishedAt":14900,"relatedExperiments":15143,"seo":15144,"stem":15145,"tags":15146,"updatedAt":13871,"__hash__":15147},"posts\u002Fposts\u002F20200327.npm-basics-2020.md","npm 基本指令整理",{"type":8,"value":14911,"toc":15135},[14912,14915,14918,14921,15044,15047,15119,15121],[11,14913,14914],{},"剛學習 Node.js，還有很多不熟悉的地方，希望可以慢慢深入。在這邊記錄 npm 的一些常用基本指令。",[11,14916,14917],{},"npm（Node Package Manager）是 Node.js 預設的套件管理器，也是一套命令列工具。它會從 registry 下載、安裝套件，並處理相依套件。",[15,14919,14920],{"id":14920},"基本指令",[13574,14922,14923,14932],{},[13577,14924,14925],{},[13580,14926,14927,14930],{},[13583,14928,14929],{},"指令",[13583,14931,14529],{},[13590,14933,14934,14944,14954,14964,14974,14984,14994,15004,15014,15024,15034],{},[13580,14935,14936,14941],{},[13595,14937,14938],{},[29,14939,14940],{},"npm -v",[13595,14942,14943],{},"檢查 npm 是否正確安裝",[13580,14945,14946,14951],{},[13595,14947,14948],{},[29,14949,14950],{},"npm init",[13595,14952,14953],{},"初始化專案",[13580,14955,14956,14961],{},[13595,14957,14958],{},[29,14959,14960],{},"npm init -y",[13595,14962,14963],{},"省略提問，快速初始化",[13580,14965,14966,14971],{},[13595,14967,14968],{},[29,14969,14970],{},"npm install \u003Cpackage-name> -g",[13595,14972,14973],{},"全域安裝套件",[13580,14975,14976,14981],{},[13595,14977,14978],{},[29,14979,14980],{},"npm install \u003Cpackage-name>",[13595,14982,14983],{},"在目前專案安裝套件",[13580,14985,14986,14991],{},[13595,14987,14988],{},[29,14989,14990],{},"npm uninstall \u003Cpackage-name> -g",[13595,14992,14993],{},"移除全域套件",[13580,14995,14996,15001],{},[13595,14997,14998],{},[29,14999,15000],{},"npm uninstall \u003Cpackage-name>",[13595,15002,15003],{},"移除專案套件",[13580,15005,15006,15011],{},[13595,15007,15008],{},[29,15009,15010],{},"npm update -g",[13595,15012,15013],{},"更新全域套件",[13580,15015,15016,15021],{},[13595,15017,15018],{},[29,15019,15020],{},"npm ls -g",[13595,15022,15023],{},"列出全域套件",[13580,15025,15026,15031],{},[13595,15027,15028],{},[29,15029,15030],{},"npm install \u003Cpackage-name> --save",[13595,15032,15033],{},"安裝並加入相依套件列表",[13580,15035,15036,15041],{},[13595,15037,15038],{},[29,15039,15040],{},"npm help",[13595,15042,15043],{},"查看 npm 指令說明",[15,15045,15046],{"id":15046},"常用縮寫",[13574,15048,15049,15059],{},[13577,15050,15051],{},[13580,15052,15053,15056],{},[13583,15054,15055],{},"縮寫",[13583,15057,15058],{},"完整寫法",[13590,15060,15061,15073,15085,15097,15108],{},[13580,15062,15063,15068],{},[13595,15064,15065],{},[29,15066,15067],{},"npm i",[13595,15069,15070],{},[29,15071,15072],{},"npm install",[13580,15074,15075,15080],{},[13595,15076,15077],{},[29,15078,15079],{},"npm i -S",[13595,15081,15082],{},[29,15083,15084],{},"npm install --save",[13580,15086,15087,15092],{},[13595,15088,15089],{},[29,15090,15091],{},"npm i -D",[13595,15093,15094],{},[29,15095,15096],{},"npm install --save-dev",[13580,15098,15099,15103],{},[13595,15100,15101],{},[29,15102,14940],{},[13595,15104,15105],{},[29,15106,15107],{},"npm --version",[13580,15109,15110,15114],{},[13595,15111,15112],{},[29,15113,14960],{},[13595,15115,15116],{},[29,15117,15118],{},"npm init --yes",[15,15120,2004],{"id":2003},[11,15122,15123,15124,15127,15128,15131,15132,3775],{},"這是 2020 年的指令筆記。現在一般相依套件安裝後會預設寫入 ",[29,15125,15126],{},"dependencies","，不必再加 ",[29,15129,15130],{},"--save","；開發用相依套件仍可使用 ",[29,15133,15134],{},"-D",{"title":27,"searchDepth":51,"depth":51,"links":15136},[15137,15138,15139],{"id":14920,"depth":45,"text":14920},{"id":15046,"depth":45,"text":15046},{"id":2003,"depth":45,"text":2004},"剛接觸 Node.js 時整理的 npm 初始化、安裝、移除、更新與常用縮寫指令。",{},"\u002Fposts\u002Fnpm-basics-2020",[],{"title":14909,"description":15140},"posts\u002F20200327.npm-basics-2020",[4625,14755],"GTg-jyJgLs4-6BF4fXlRgRE2xaK3Ob2ZPM22zoe_cMo",{"id":15149,"title":15150,"body":15151,"category":378,"description":15412,"draft":380,"extension":381,"image":382,"meta":15413,"navigation":102,"path":15414,"publishedAt":15415,"relatedExperiments":15416,"seo":15417,"stem":15418,"tags":15419,"updatedAt":13871,"__hash__":15421},"posts\u002Fposts\u002F20200328.webkit-scrollbar-styling.md","::-webkit-scrollbar 捲軸樣式調整整理",{"type":8,"value":15152,"toc":15407},[15153,15160,15163,15247,15250,15318,15388,15390,15404],[11,15154,15155,15156,15159],{},"最近在調整 scrollbar 時，發現自己對捲軸還有許多不了解的地方。當時也遇到頁面嵌入 Android WebView 後，單純使用 ",[29,15157,15158],{},"overflow: scroll","，捲軸反而消失的情況，因此爬文整理了一份記錄。",[15,15161,15162],{"id":15162},"捲軸偽元素",[13574,15164,15165,15175],{},[13577,15166,15167],{},[13580,15168,15169,15172],{},[13583,15170,15171],{},"偽元素",[13583,15173,15174],{},"對應部位",[13590,15176,15177,15187,15197,15207,15217,15227,15237],{},[13580,15178,15179,15184],{},[13595,15180,15181],{},[29,15182,15183],{},"::-webkit-scrollbar",[13595,15185,15186],{},"整條捲軸",[13580,15188,15189,15194],{},[13595,15190,15191],{},[29,15192,15193],{},"::-webkit-scrollbar-thumb",[13595,15195,15196],{},"可以上下或左右移動的滑塊",[13580,15198,15199,15204],{},[13595,15200,15201],{},[29,15202,15203],{},"::-webkit-scrollbar-track",[13595,15205,15206],{},"裝著滑塊的軌道",[13580,15208,15209,15214],{},[13595,15210,15211],{},[29,15212,15213],{},"::-webkit-scrollbar-button",[13595,15215,15216],{},"軌道兩端的按鈕",[13580,15218,15219,15224],{},[13595,15220,15221],{},[29,15222,15223],{},"::-webkit-scrollbar-track-piece",[13595,15225,15226],{},"內層軌道",[13580,15228,15229,15234],{},[13595,15230,15231],{},[29,15232,15233],{},"::-webkit-scrollbar-corner",[13595,15235,15236],{},"兩條捲軸的交會處",[13580,15238,15239,15244],{},[13595,15240,15241],{},[29,15242,15243],{},"::-webkit-resizer",[13595,15245,15246],{},"交會處用來調整元素大小的控制元件",[15,15248,15249],{"id":15249},"偽類別",[4538,15251,15252,15258,15264,15270,15276,15282,15288,15294,15300,15306,15312],{},[4541,15253,15254,15257],{},[29,15255,15256],{},":horizontal","：水平方向的捲軸",[4541,15259,15260,15263],{},[29,15261,15262],{},":vertical","：垂直方向的捲軸",[4541,15265,15266,15269],{},[29,15267,15268],{},":decrement","：遞減方向的按鈕或軌道區塊",[4541,15271,15272,15275],{},[29,15273,15274],{},":increment","：遞增方向的按鈕或軌道區塊",[4541,15277,15278,15281],{},[29,15279,15280],{},":start","：位於滑塊前方的物件",[4541,15283,15284,15287],{},[29,15285,15286],{},":end","：位於滑塊後方的物件",[4541,15289,15290,15293],{},[29,15291,15292],{},":double-button","：軌道末端有一對按鈕",[4541,15295,15296,15299],{},[29,15297,15298],{},":single-button","：軌道末端只有一個按鈕",[4541,15301,15302,15305],{},[29,15303,15304],{},":no-button","：軌道末端沒有按鈕",[4541,15307,15308,15311],{},[29,15309,15310],{},":corner-present","：捲軸角落存在",[4541,15313,15314,15317],{},[29,15315,15316],{},":window-inactive","：包含捲軸的視窗未取得焦點",[22,15319,15321],{"className":5412,"code":15320,"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,15322,15323,15330,15335,15339,15343,15354,15359,15363,15367,15379,15384],{"__ignoreMap":27},[32,15324,15325,15327],{"class":34,"line":35},[32,15326,15223],{"class":4053},[32,15328,15329],{"class":41},":start {\n",[32,15331,15332],{"class":34,"line":45},[32,15333,15334],{"class":608},"  \u002F* 捲軸上半邊或左半邊 *\u002F\n",[32,15336,15337],{"class":34,"line":51},[32,15338,54],{"class":41},[32,15340,15341],{"class":34,"line":90},[32,15342,103],{"emptyLinePlaceholder":102},[32,15344,15345,15347,15349,15352],{"class":34,"line":99},[32,15346,15193],{"class":4053},[32,15348,322],{"class":41},[32,15350,15351],{"class":4049},"window-inactive",[32,15353,703],{"class":41},[32,15355,15356],{"class":34,"line":106},[32,15357,15358],{"class":608},"  \u002F* 焦點不在目前視窗時的滑塊 *\u002F\n",[32,15360,15361],{"class":34,"line":114},[32,15362,54],{"class":41},[32,15364,15365],{"class":34,"line":120},[32,15366,103],{"emptyLinePlaceholder":102},[32,15368,15369,15371,15374,15377],{"class":34,"line":127},[32,15370,15213],{"class":4053},[32,15372,15373],{"class":41},":horizontal:decrement",[32,15375,15376],{"class":4053},":hover",[32,15378,703],{"class":41},[32,15380,15381],{"class":34,"line":132},[32,15382,15383],{"class":608},"  \u002F* 滑鼠移到水平捲軸遞減按鈕時 *\u002F\n",[32,15385,15386],{"class":34,"line":141},[32,15387,54],{"class":41},[15,15389,2004],{"id":2003},[11,15391,15392,15393,15396,15397,7090,15400,15403],{},"這組 ",[29,15394,15395],{},"::-webkit-scrollbar-*"," 寫法並非完整的跨瀏覽器標準。現在也有 ",[29,15398,15399],{},"scrollbar-width",[29,15401,15402],{},"scrollbar-color"," 等標準屬性可用，但能調整的細節較少；實作前仍要確認目標瀏覽器。",[368,15405,15406],{},"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":15408},[15409,15410,15411],{"id":15162,"depth":45,"text":15162},{"id":15249,"depth":45,"text":15249},{"id":2003,"depth":45,"text":2004},"記錄 WebKit 捲軸偽元素、偽類別，以及 Android WebView 中捲軸消失的問題。",{},"\u002Fposts\u002Fwebkit-scrollbar-styling","2020-03-28",[],{"title":15150,"description":15412},"posts\u002F20200328.webkit-scrollbar-styling",[1757,15420],"捲軸","rY8aFzX_AK-FuhMjB-CDCo38cHdvdwXdAPPLzSKZc5w",{"id":15423,"title":15424,"body":15425,"category":378,"description":15847,"draft":380,"extension":381,"image":382,"meta":15848,"navigation":102,"path":15849,"publishedAt":15850,"relatedExperiments":15851,"seo":15852,"stem":15853,"tags":15854,"updatedAt":13871,"__hash__":15856},"posts\u002Fposts\u002F20200329.jquery-scroll-animation.md","jQuery 版本的捲動進場動畫：手動比對 offset 與 scrollTop",{"type":8,"value":15426,"toc":15841},[15427,15430,15434,15525,15528,15673,15676,15829,15831,15838],[11,15428,15429],{},"紀錄常使用的 jquery trigger resize 動畫",[15,15431,15433],{"id":15432},"頁面-resize-與-scroll","頁面 resize 與 scroll",[22,15435,15437],{"className":24,"code":15436,"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,15438,15439,15446,15459,15465,15484,15489,15494,15507,15512],{"__ignoreMap":27},[32,15440,15441,15443],{"class":34,"line":35},[32,15442,755],{"class":217},[32,15444,15445],{"class":41},"(window)\n",[32,15447,15448,15451,15453,15455,15457],{"class":34,"line":45},[32,15449,15450],{"class":41},"  .",[32,15452,6728],{"class":217},[32,15454,477],{"class":41},[32,15456,665],{"class":38},[32,15458,668],{"class":41},[32,15460,15461,15463],{"class":34,"line":51},[32,15462,674],{"class":217},[32,15464,15445],{"class":41},[32,15466,15467,15470,15473,15475,15478,15480,15482],{"class":34,"line":90},[32,15468,15469],{"class":41},"      .",[32,15471,15472],{"class":217},"on",[32,15474,477],{"class":41},[32,15476,15477],{"class":175},"\"scroll\"",[32,15479,635],{"class":41},[32,15481,665],{"class":38},[32,15483,668],{"class":41},[32,15485,15486],{"class":34,"line":99},[32,15487,15488],{"class":608},"        \u002F\u002F do something...\n",[32,15490,15491],{"class":34,"line":106},[32,15492,15493],{"class":41},"      })\n",[32,15495,15496,15498,15501,15503,15505],{"class":34,"line":114},[32,15497,15469],{"class":41},[32,15499,15500],{"class":217},"trigger",[32,15502,477],{"class":41},[32,15504,15477],{"class":175},[32,15506,230],{"class":41},[32,15508,15509],{"class":34,"line":120},[32,15510,15511],{"class":41},"  })\n",[32,15513,15514,15516,15518,15520,15523],{"class":34,"line":127},[32,15515,15450],{"class":41},[32,15517,15500],{"class":217},[32,15519,477],{"class":41},[32,15521,15522],{"class":175},"\"resize\"",[32,15524,230],{"class":41},[15,15526,15527],{"id":15527},"捲軸判斷並加入一次性動畫",[22,15529,15531],{"className":24,"code":15530,"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,15532,15533,15550,15578,15596,15600,15612,15629,15644,15652,15665,15669],{"__ignoreMap":27},[32,15534,15535,15537,15540,15542,15544,15546,15548],{"class":34,"line":35},[32,15536,166],{"class":38},[32,15538,15539],{"class":41}," item ",[32,15541,172],{"class":38},[32,15543,6756],{"class":217},[32,15545,477],{"class":41},[32,15547,1083],{"class":351},[32,15549,230],{"class":41},[32,15551,15552,15554,15557,15559,15561,15563,15566,15568,15570,15572,15574,15576],{"class":34,"line":45},[32,15553,166],{"class":38},[32,15555,15556],{"class":41}," windowTop ",[32,15558,172],{"class":38},[32,15560,6756],{"class":217},[32,15562,6759],{"class":41},[32,15564,15565],{"class":217},"scrollTop",[32,15567,6075],{"class":41},[32,15569,224],{"class":38},[32,15571,6756],{"class":217},[32,15573,6759],{"class":41},[32,15575,6762],{"class":217},[32,15577,687],{"class":41},[32,15579,15580,15582,15585,15587,15590,15593],{"class":34,"line":51},[32,15581,166],{"class":38},[32,15583,15584],{"class":41}," pageTop ",[32,15586,172],{"class":38},[32,15588,15589],{"class":41}," item.",[32,15591,15592],{"class":217},"offset",[32,15594,15595],{"class":41},"().top;\n",[32,15597,15598],{"class":34,"line":90},[32,15599,103],{"emptyLinePlaceholder":102},[32,15601,15602,15604,15607,15609],{"class":34,"line":99},[32,15603,17],{"class":38},[32,15605,15606],{"class":41}," (windowTop ",[32,15608,348],{"class":38},[32,15610,15611],{"class":41}," pageTop) {\n",[32,15613,15614,15616,15619,15622,15624,15627],{"class":34,"line":106},[32,15615,1021],{"class":38},[32,15617,15618],{"class":41}," (item.",[32,15620,15621],{"class":217},"hasClass",[32,15623,477],{"class":41},[32,15625,15626],{"class":175},"\"no-gutters\"",[32,15628,1046],{"class":41},[32,15630,15631,15634,15637,15639,15642],{"class":34,"line":114},[32,15632,15633],{"class":41},"    item.",[32,15635,15636],{"class":217},"addClass",[32,15638,477],{"class":41},[32,15640,15641],{"class":175},"\"animate__animated animate__bounceInRight\"",[32,15643,230],{"class":41},[32,15645,15646,15648,15650],{"class":34,"line":120},[32,15647,5911],{"class":41},[32,15649,565],{"class":38},[32,15651,703],{"class":41},[32,15653,15654,15656,15658,15660,15663],{"class":34,"line":127},[32,15655,15633],{"class":41},[32,15657,15636],{"class":217},[32,15659,477],{"class":41},[32,15661,15662],{"class":175},"\"animate__animated animate__bounceInLeft\"",[32,15664,230],{"class":41},[32,15666,15667],{"class":34,"line":132},[32,15668,1203],{"class":41},[32,15670,15671],{"class":34,"line":141},[32,15672,54],{"class":41},[15,15674,15675],{"id":15675},"進入與離開時切換狀態",[22,15677,15679],{"className":24,"code":15678,"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,15680,15681,15696,15740,15767,15771,15781,15803,15825],{"__ignoreMap":27},[32,15682,15683,15685,15688,15690,15692,15694],{"class":34,"line":35},[32,15684,755],{"class":217},[32,15686,15687],{"class":41},"(selector).",[32,15689,1060],{"class":217},[32,15691,477],{"class":41},[32,15693,665],{"class":38},[32,15695,668],{"class":41},[32,15697,15698,15700,15703,15705,15707,15709,15711,15713,15715,15718,15720,15722,15724,15726,15728,15731,15733,15735,15738],{"class":34,"line":45},[32,15699,888],{"class":38},[32,15701,15702],{"class":41}," bottomOfObject ",[32,15704,172],{"class":38},[32,15706,6756],{"class":217},[32,15708,477],{"class":41},[32,15710,1083],{"class":351},[32,15712,533],{"class":41},[32,15714,15592],{"class":217},[32,15716,15717],{"class":41},"().top ",[32,15719,224],{"class":38},[32,15721,6756],{"class":217},[32,15723,477],{"class":41},[32,15725,1083],{"class":351},[32,15727,533],{"class":41},[32,15729,15730],{"class":217},"outerHeight",[32,15732,6075],{"class":41},[32,15734,1275],{"class":38},[32,15736,15737],{"class":351}," 8",[32,15739,96],{"class":41},[32,15741,15742,15744,15747,15749,15751,15753,15755,15757,15759,15761,15763,15765],{"class":34,"line":51},[32,15743,888],{"class":38},[32,15745,15746],{"class":41}," bottomOfWindow ",[32,15748,172],{"class":38},[32,15750,6756],{"class":217},[32,15752,6759],{"class":41},[32,15754,15565],{"class":217},[32,15756,6075],{"class":41},[32,15758,224],{"class":38},[32,15760,6756],{"class":217},[32,15762,6759],{"class":41},[32,15764,6762],{"class":217},[32,15766,687],{"class":41},[32,15768,15769],{"class":34,"line":90},[32,15770,103],{"emptyLinePlaceholder":102},[32,15772,15773,15776,15778],{"class":34,"line":99},[32,15774,15775],{"class":41},"  bottomOfWindow ",[32,15777,1615],{"class":38},[32,15779,15780],{"class":41}," bottomOfObject\n",[32,15782,15783,15786,15788,15790,15792,15794,15796,15798,15801],{"class":34,"line":106},[32,15784,15785],{"class":38},"    ?",[32,15787,6756],{"class":217},[32,15789,477],{"class":41},[32,15791,1083],{"class":351},[32,15793,533],{"class":41},[32,15795,15636],{"class":217},[32,15797,477],{"class":41},[32,15799,15800],{"class":175},"\"active\"",[32,15802,515],{"class":41},[32,15804,15805,15808,15810,15812,15814,15816,15819,15821,15823],{"class":34,"line":114},[32,15806,15807],{"class":38},"    :",[32,15809,6756],{"class":217},[32,15811,477],{"class":41},[32,15813,1083],{"class":351},[32,15815,533],{"class":41},[32,15817,15818],{"class":217},"removeClass",[32,15820,477],{"class":41},[32,15822,15800],{"class":175},[32,15824,230],{"class":41},[32,15826,15827],{"class":34,"line":120},[32,15828,792],{"class":41},[15,15830,2004],{"id":2003},[11,15832,15833,15834,15837],{},"這是當時以 jQuery 手動計算位置的寫法。現在遇到「元素進入可視範圍」的需求，通常會優先使用 ",[29,15835,15836],{},"IntersectionObserver","，不必在每次捲動時重算所有元素的位置。",[368,15839,15840],{},"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":15842},[15843,15844,15845,15846],{"id":15432,"depth":45,"text":15433},{"id":15527,"depth":45,"text":15527},{"id":15675,"depth":45,"text":15675},{"id":2003,"depth":45,"text":2004},"記錄用 jQuery 監聽 resize 與 scroll，再依元素位置加入動畫 class 的寫法。",{},"\u002Fposts\u002Fjquery-scroll-animation","2020-03-29",[],{"title":15424,"description":15847},"posts\u002F20200329.jquery-scroll-animation",[2040,390,15855],"捲動動畫","1v9R2wCFEd0OwPrTsSVnbhVMoTbTVkfKJVin84TOnjs",{"id":15858,"title":15859,"body":15860,"category":378,"description":16124,"draft":380,"extension":381,"image":382,"meta":16125,"navigation":102,"path":16126,"publishedAt":16127,"relatedExperiments":16128,"seo":16129,"stem":16130,"tags":16131,"updatedAt":13871,"__hash__":16132},"posts\u002Fposts\u002F20200331.animate-css-basics.md","用 Animate.css 快速套用進場動畫",{"type":8,"value":15861,"toc":16119},[15862,15870,15873,15876,15892,15895,15909,15912,15949,15951,15958,15991,15994,16058,16061,16063,16070,16102,16109,16116],[11,15863,15864,15869],{},[412,15865,15868],{"href":15866,"rel":15867},"https:\u002F\u002Fanimate.style\u002F",[416],"Animate.css"," 是一套現成的 CSS 動畫函式庫，可以直接透過 class 套用淡入、彈跳、滑入等動畫效果。",[15,15871,15872],{"id":15872},"安裝",[11,15874,15875],{},"當時可以透過 npm 安裝：",[22,15877,15879],{"className":2057,"code":15878,"language":2059,"meta":27,"style":27},"npm install animate.css --save\n",[29,15880,15881],{"__ignoreMap":27},[32,15882,15883,15885,15887,15890],{"class":34,"line":35},[32,15884,4625],{"class":2066},[32,15886,4650],{"class":175},[32,15888,15889],{"class":175}," animate.css",[32,15891,8638],{"class":351},[11,15893,15894],{},"並在專案中引入：",[22,15896,15898],{"className":24,"code":15897,"language":26,"meta":27,"style":27},"import 'animate.css';\n",[29,15899,15900],{"__ignoreMap":27},[32,15901,15902,15904,15907],{"class":34,"line":35},[32,15903,8794],{"class":38},[32,15905,15906],{"class":175}," 'animate.css'",[32,15908,96],{"class":41},[11,15910,15911],{},"如果只是一般 HTML 頁面，也可以直接使用 CDN：",[22,15913,15915],{"className":4038,"code":15914,"language":4034,"meta":27,"style":27},"\u003Clink\n  rel=\"stylesheet\"\n  href=\"https:\u002F\u002Fcdnjs.cloudflare.com\u002Fajax\u002Flibs\u002Fanimate.css\u002F3.7.2\u002Fanimate.min.css\"\n\u002F>\n",[29,15916,15917,15924,15934,15944],{"__ignoreMap":27},[32,15918,15919,15921],{"class":34,"line":35},[32,15920,4046],{"class":41},[32,15922,15923],{"class":4049},"link\n",[32,15925,15926,15929,15931],{"class":34,"line":45},[32,15927,15928],{"class":4053},"  rel",[32,15930,172],{"class":41},[32,15932,15933],{"class":175},"\"stylesheet\"\n",[32,15935,15936,15939,15941],{"class":34,"line":51},[32,15937,15938],{"class":4053},"  href",[32,15940,172],{"class":41},[32,15942,15943],{"class":175},"\"https:\u002F\u002Fcdnjs.cloudflare.com\u002Fajax\u002Flibs\u002Fanimate.css\u002F3.7.2\u002Fanimate.min.css\"\n",[32,15945,15946],{"class":34,"line":90},[32,15947,15948],{"class":41},"\u002F>\n",[15,15950,12994],{"id":12994},[11,15952,15953,15954,15957],{},"v3 版本只要加入 ",[29,15955,15956],{},"animated"," 與想使用的動畫名稱即可：",[22,15959,15961],{"className":4038,"code":15960,"language":4034,"meta":27,"style":27},"\u003Cdiv class=\"animated fadeIn\">\n  Hello Animate.css\n\u003C\u002Fdiv>\n",[29,15962,15963,15978,15983],{"__ignoreMap":27},[32,15964,15965,15967,15969,15971,15973,15976],{"class":34,"line":35},[32,15966,4046],{"class":41},[32,15968,4050],{"class":4049},[32,15970,9897],{"class":4053},[32,15972,172],{"class":41},[32,15974,15975],{"class":175},"\"animated fadeIn\"",[32,15977,4062],{"class":41},[32,15979,15980],{"class":34,"line":45},[32,15981,15982],{"class":41},"  Hello Animate.css\n",[32,15984,15985,15987,15989],{"class":34,"line":51},[32,15986,4105],{"class":41},[32,15988,4050],{"class":4049},[32,15990,4062],{"class":41},[11,15992,15993],{},"例如常見的動畫：",[22,15995,15997],{"className":4038,"code":15996,"language":4034,"meta":27,"style":27},"\u003Cdiv class=\"animated bounce\">Bounce\u003C\u002Fdiv>\n\u003Cdiv class=\"animated fadeIn\">Fade In\u003C\u002Fdiv>\n\u003Cdiv class=\"animated slideInUp\">Slide In Up\u003C\u002Fdiv>\n",[29,15998,15999,16019,16038],{"__ignoreMap":27},[32,16000,16001,16003,16005,16007,16009,16012,16015,16017],{"class":34,"line":35},[32,16002,4046],{"class":41},[32,16004,4050],{"class":4049},[32,16006,9897],{"class":4053},[32,16008,172],{"class":41},[32,16010,16011],{"class":175},"\"animated bounce\"",[32,16013,16014],{"class":41},">Bounce\u003C\u002F",[32,16016,4050],{"class":4049},[32,16018,4062],{"class":41},[32,16020,16021,16023,16025,16027,16029,16031,16034,16036],{"class":34,"line":45},[32,16022,4046],{"class":41},[32,16024,4050],{"class":4049},[32,16026,9897],{"class":4053},[32,16028,172],{"class":41},[32,16030,15975],{"class":175},[32,16032,16033],{"class":41},">Fade In\u003C\u002F",[32,16035,4050],{"class":4049},[32,16037,4062],{"class":41},[32,16039,16040,16042,16044,16046,16048,16051,16054,16056],{"class":34,"line":51},[32,16041,4046],{"class":41},[32,16043,4050],{"class":4049},[32,16045,9897],{"class":4053},[32,16047,172],{"class":41},[32,16049,16050],{"class":175},"\"animated slideInUp\"",[32,16052,16053],{"class":41},">Slide In Up\u003C\u002F",[32,16055,4050],{"class":4049},[32,16057,4062],{"class":41},[11,16059,16060],{},"動畫名稱可以直接到 Animate.css 官方網站查看效果後選擇。",[15,16062,2004],{"id":2003},[11,16064,16065,16066,16069],{},"Animate.css 後來升級到 v4，class 名稱加入了 ",[29,16067,16068],{},"animate__"," 前綴，例如：",[22,16071,16073],{"className":4038,"code":16072,"language":4034,"meta":27,"style":27},"\u003Cdiv class=\"animate__animated animate__fadeIn\">\n  Hello Animate.css\n\u003C\u002Fdiv>\n",[29,16074,16075,16090,16094],{"__ignoreMap":27},[32,16076,16077,16079,16081,16083,16085,16088],{"class":34,"line":35},[32,16078,4046],{"class":41},[32,16080,4050],{"class":4049},[32,16082,9897],{"class":4053},[32,16084,172],{"class":41},[32,16086,16087],{"class":175},"\"animate__animated animate__fadeIn\"",[32,16089,4062],{"class":41},[32,16091,16092],{"class":34,"line":45},[32,16093,15982],{"class":41},[32,16095,16096,16098,16100],{"class":34,"line":51},[32,16097,4105],{"class":41},[32,16099,4050],{"class":4049},[32,16101,4062],{"class":41},[11,16103,16104,16105,16108],{},"因此如果看到舊文章使用 ",[29,16106,16107],{},"animated fadeIn","，通常是 Animate.css v3 時期的寫法。",[11,16110,16111,16112,16115],{},"現在 Animate.css 仍可使用；是否採用套件、其他動畫工具，或自行撰寫 ",[29,16113,16114],{},"@keyframes","，可以依專案需求決定。",[368,16117,16118],{},"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 .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":16120},[16121,16122,16123],{"id":15872,"depth":45,"text":15872},{"id":12994,"depth":45,"text":12994},{"id":2003,"depth":45,"text":2004},"記錄 2020 年使用 Animate.css 快速加入 CSS 動畫的基本方式。",{},"\u002Fposts\u002Fanimate-css-basics","2020-03-31",[],{"title":15859,"description":16124},"posts\u002F20200331.animate-css-basics",[1757,6715],"VtvW8zW3jAx707_R1nnBucwr4BUp0UQE8EhTKonCQ9s",{"id":16134,"title":16135,"body":16136,"category":378,"description":16446,"draft":380,"extension":381,"image":382,"meta":16447,"navigation":102,"path":16448,"publishedAt":16449,"relatedExperiments":16450,"seo":16451,"stem":16452,"tags":16453,"updatedAt":13871,"__hash__":16455},"posts\u002Fposts\u002F20200405.vue-nested-v-for.md","Vue 2 巢狀 v-for 寫法",{"type":8,"value":16137,"toc":16443},[16138,16141,16287,16414,16422,16424,16440],[11,16139,16140],{},"最近在寫 Vue 時遇到雙重迴圈的問題，這邊記錄一下，以免又忘記。",[22,16142,16144],{"className":24,"code":16143,"language":26,"meta":27,"style":27},"data() {\n  return {\n    parentList: [\n      {\n        childList: [\n          { index: 1, childName: \"第一個節點\" },\n          { index: 2, childName: \"第一個節點\" },\n          { index: 3, childName: \"第一個節點\" },\n        ],\n      },\n      {\n        childList: [\n          { index: 6, childName: \"第二個節點\" },\n          { index: 7, childName: \"第二個節點\" },\n          { index: 8, childName: \"第二個節點\" },\n        ],\n      },\n    ],\n  };\n}\n",[29,16145,16146,16153,16159,16164,16168,16173,16189,16201,16213,16218,16222,16226,16230,16243,16255,16267,16271,16275,16279,16283],{"__ignoreMap":27},[32,16147,16148,16151],{"class":34,"line":35},[32,16149,16150],{"class":217},"data",[32,16152,4221],{"class":41},[32,16154,16155,16157],{"class":34,"line":45},[32,16156,11115],{"class":38},[32,16158,703],{"class":41},[32,16160,16161],{"class":34,"line":51},[32,16162,16163],{"class":41},"    parentList: [\n",[32,16165,16166],{"class":34,"line":90},[32,16167,8152],{"class":41},[32,16169,16170],{"class":34,"line":99},[32,16171,16172],{"class":41},"        childList: [\n",[32,16174,16175,16178,16180,16183,16186],{"class":34,"line":106},[32,16176,16177],{"class":41},"          { index: ",[32,16179,6544],{"class":351},[32,16181,16182],{"class":41},", childName: ",[32,16184,16185],{"class":175},"\"第一個節點\"",[32,16187,16188],{"class":41}," },\n",[32,16190,16191,16193,16195,16197,16199],{"class":34,"line":114},[32,16192,16177],{"class":41},[32,16194,12112],{"class":351},[32,16196,16182],{"class":41},[32,16198,16185],{"class":175},[32,16200,16188],{"class":41},[32,16202,16203,16205,16207,16209,16211],{"class":34,"line":120},[32,16204,16177],{"class":41},[32,16206,13611],{"class":351},[32,16208,16182],{"class":41},[32,16210,16185],{"class":175},[32,16212,16188],{"class":41},[32,16214,16215],{"class":34,"line":127},[32,16216,16217],{"class":41},"        ],\n",[32,16219,16220],{"class":34,"line":132},[32,16221,4500],{"class":41},[32,16223,16224],{"class":34,"line":141},[32,16225,8152],{"class":41},[32,16227,16228],{"class":34,"line":147},[32,16229,16172],{"class":41},[32,16231,16232,16234,16236,16238,16241],{"class":34,"line":275},[32,16233,16177],{"class":41},[32,16235,13634],{"class":351},[32,16237,16182],{"class":41},[32,16239,16240],{"class":175},"\"第二個節點\"",[32,16242,16188],{"class":41},[32,16244,16245,16247,16249,16251,16253],{"class":34,"line":282},[32,16246,16177],{"class":41},[32,16248,1269],{"class":351},[32,16250,16182],{"class":41},[32,16252,16240],{"class":175},[32,16254,16188],{"class":41},[32,16256,16257,16259,16261,16263,16265],{"class":34,"line":295},[32,16258,16177],{"class":41},[32,16260,1031],{"class":351},[32,16262,16182],{"class":41},[32,16264,16240],{"class":175},[32,16266,16188],{"class":41},[32,16268,16269],{"class":34,"line":605},[32,16270,16217],{"class":41},[32,16272,16273],{"class":34,"line":612},[32,16274,4500],{"class":41},[32,16276,16277],{"class":34,"line":617},[32,16278,8231],{"class":41},[32,16280,16281],{"class":34,"line":644},[32,16282,1007],{"class":41},[32,16284,16285],{"class":34,"line":649},[32,16286,54],{"class":41},[22,16288,16290],{"className":8665,"code":16289,"language":4112,"meta":27,"style":27},"\u003Cdiv v-for=\"(parent, index) in parentList\" :key=\"index\" class=\"boxArea\">\n  \u003Cdiv\n    v-for=\"child in parent.childList\"\n    :key=\"child.index\"\n    class=\"box\"\n  >\n    \u003Ch1>{{ child.childName }}\u003C\u002Fh1>\n    \u003Cdiv class=\"imageUrl\">\u003C\u002Fdiv>\n    \u003Cdiv class=\"url\">\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n",[29,16291,16292,16340,16345,16350,16355,16360,16365,16370,16379,16398,16406],{"__ignoreMap":27},[32,16293,16294,16296,16298,16301,16303,16307,16310,16313,16316,16318,16320,16323,16325,16327,16329,16331,16333,16335,16338],{"class":34,"line":35},[32,16295,4046],{"class":41},[32,16297,4050],{"class":4049},[32,16299,16300],{"class":38}," v-for",[32,16302,172],{"class":41},[32,16304,16306],{"class":16305},"spddc","\"",[32,16308,16309],{"class":41},"(parent, index) ",[32,16311,16312],{"class":38},"in",[32,16314,16315],{"class":41}," parentList",[32,16317,16306],{"class":16305},[32,16319,361],{"class":41},[32,16321,16322],{"class":4053},"key",[32,16324,172],{"class":41},[32,16326,16306],{"class":16305},[32,16328,7208],{"class":41},[32,16330,16306],{"class":16305},[32,16332,9897],{"class":4053},[32,16334,172],{"class":41},[32,16336,16337],{"class":175},"\"boxArea\"",[32,16339,4062],{"class":41},[32,16341,16342],{"class":34,"line":45},[32,16343,16344],{"class":41},"  \u003Cdiv\n",[32,16346,16347],{"class":34,"line":51},[32,16348,16349],{"class":41},"    v-for=\"child in parent.childList\"\n",[32,16351,16352],{"class":34,"line":90},[32,16353,16354],{"class":41},"    :key=\"child.index\"\n",[32,16356,16357],{"class":34,"line":99},[32,16358,16359],{"class":41},"    class=\"box\"\n",[32,16361,16362],{"class":34,"line":106},[32,16363,16364],{"class":41},"  >\n",[32,16366,16367],{"class":34,"line":114},[32,16368,16369],{"class":41},"    \u003Ch1>{{ child.childName }}\u003C\u002Fh1>\n",[32,16371,16372,16375,16377],{"class":34,"line":120},[32,16373,16374],{"class":41},"    \u003Cdiv class=\"imageUrl\">\u003C\u002F",[32,16376,4050],{"class":4049},[32,16378,4062],{"class":41},[32,16380,16381,16383,16385,16387,16389,16392,16394,16396],{"class":34,"line":127},[32,16382,9638],{"class":41},[32,16384,4050],{"class":4049},[32,16386,9897],{"class":4053},[32,16388,172],{"class":41},[32,16390,16391],{"class":175},"\"url\"",[32,16393,4136],{"class":41},[32,16395,4050],{"class":4049},[32,16397,4062],{"class":41},[32,16399,16400,16402,16404],{"class":34,"line":132},[32,16401,9691],{"class":41},[32,16403,4050],{"class":4049},[32,16405,4062],{"class":41},[32,16407,16408,16410,16412],{"class":34,"line":141},[32,16409,4105],{"class":41},[32,16411,4050],{"class":4049},[32,16413,4062],{"class":41},[11,16415,16416,16417],{},"參考資料：",[412,16418,16421],{"href":16419,"rel":16420},"https:\u002F\u002Fwww.itread01.com\u002Farticle\u002F1537926005.html",[416],"Vue 多重迴圈寫法",[15,16423,2004],{"id":2003},[11,16425,16426,16427,3750,16430,7090,16433,16436,16437,16439],{},"原筆記的資料欄位與模板名稱對不上，整理時統一為 ",[29,16428,16429],{},"parentList",[29,16431,16432],{},"childList",[29,16434,16435],{},"childName","，但保留原本的兩層迴圈結構。實際資料若有穩定 ID，外層 ",[29,16438,16322],{}," 也應優先使用 ID，不要使用索引。",[368,16441,16442],{},"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 .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);}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}html pre.shiki code .spddc, html code.shiki .spddc{--shiki-default:#032F62;--shiki-dark:#E6EDF3}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":16444},[16445],{"id":2003,"depth":45,"text":2004},"記錄 Vue 2 使用巢狀 v-for 渲染父子兩層清單的寫法。",{},"\u002Fposts\u002Fvue-nested-v-for","2020-04-05",[],{"title":16135,"description":16446},"posts\u002F20200405.vue-nested-v-for",[4113,16454],"v-for","fomDHASth97maIX3DFBFUNIhKXY-DrJl8lckus35yE4",{"id":16457,"title":16458,"body":16459,"category":378,"description":16532,"draft":380,"extension":381,"image":382,"meta":16533,"navigation":102,"path":16534,"publishedAt":16535,"relatedExperiments":16536,"seo":16537,"stem":16538,"tags":16539,"updatedAt":13871,"__hash__":16541},"posts\u002Fposts\u002F20200407.create-nuxt-app-wizard.md","npx create-nuxt-app 互動式安裝流程紀錄",{"type":8,"value":16460,"toc":16529},[16461,16464,16467,16480,16483,16515,16518,16520,16527],[11,16462,16463],{},"最近在練習 Nuxt，這邊記錄當時的安裝步驟。",[11,16465,16466],{},"先開啟 VS Code，在終端機輸入：",[22,16468,16470],{"className":2057,"code":16469,"language":2059,"meta":27,"style":27},"npx create-nuxt-app\n",[29,16471,16472],{"__ignoreMap":27},[32,16473,16474,16477],{"class":34,"line":35},[32,16475,16476],{"class":2066},"npx",[32,16478,16479],{"class":175}," create-nuxt-app\n",[11,16481,16482],{},"接下來依序選擇：",[6426,16484,16485,16488,16491,16494,16497,16500,16503,16506,16509,16512],{},[4541,16486,16487],{},"專案名稱",[4541,16489,16490],{},"程式語言",[4541,16492,16493],{},"套件管理器",[4541,16495,16496],{},"UI 框架；當時正在練習 Vuetify，所以選擇 Vuetify",[4541,16498,16499],{},"AJAX 函式庫",[4541,16501,16502],{},"Linting 工具；當時選擇 ESLint",[4541,16504,16505],{},"測試框架",[4541,16507,16508],{},"渲染方式；當時選擇 SSR",[4541,16510,16511],{},"Server 目標",[4541,16513,16514],{},"開發工具",[11,16516,16517],{},"選完後就會開始安裝。",[15,16519,2004],{"id":2003},[11,16521,16522,16523,16526],{},"這是 Nuxt 2 與 ",[29,16524,16525],{},"create-nuxt-app"," 時代的安裝流程，互動式問題與現在的 Nuxt 建立指令不同，不應直接照著操作；本文保留作為當時的安裝紀錄。",[368,16528,12937],{},{"title":27,"searchDepth":51,"depth":51,"links":16530},[16531],{"id":2003,"depth":45,"text":2004},"記錄 2020 年以 npx create-nuxt-app 建立 Nuxt 2 專案時的互動式選項。",{},"\u002Fposts\u002Fcreate-nuxt-app-wizard","2020-04-07",[],{"title":16458,"description":16532},"posts\u002F20200407.create-nuxt-app-wizard",[16540,4113],"Nuxt","OjqYmOHPrewvbiGWRE8Mub6PTj8gFrnUI5wCXtVBIXs",{"id":16543,"title":16544,"body":16545,"category":378,"description":16774,"draft":380,"extension":381,"image":382,"meta":16775,"navigation":102,"path":16776,"publishedAt":16777,"relatedExperiments":16778,"seo":16779,"stem":16780,"tags":16781,"updatedAt":13871,"__hash__":16782},"posts\u002Fposts\u002F20200409.scss-radial-gradient-decoration.md","用 radial-gradient 偽元素畫出雪山裝飾",{"type":8,"value":16546,"toc":16771},[16547,16550,16556,16759,16761,16768],[11,16548,16549],{},"今天練習 SCSS，遇到一個滿有趣的裝飾效果，在這邊記錄一下。",[11,16551,16552],{},[10761,16553],{"alt":16554,"src":16555},"山峰上重複排列的圓形裝飾","\u002Fimages\u002Fposts\u002Fscss-radial-gradient-decoration\u002F01.png",[22,16557,16559],{"className":8735,"code":16558,"language":8737,"meta":27,"style":27},".scene .mountain .snow::after {\n  content: \"\";\n  position: absolute;\n  top: 99px;\n  left: -80px;\n  width: 160px;\n  height: 15px;\n  background-image: radial-gradient(\n    circle at 10px 15px,\n    #3fae4a 12px,\n    transparent 13px\n  );\n  background-repeat: repeat;\n  background-size: 20px 20px;\n  transform: rotateX(180deg);\n}\n",[29,16560,16561,16574,16585,16596,16610,16624,16637,16650,16662,16681,16693,16704,16708,16719,16736,16755],{"__ignoreMap":27},[32,16562,16563,16566,16569,16572],{"class":34,"line":35},[32,16564,16565],{"class":4053},".scene",[32,16567,16568],{"class":4053}," .mountain",[32,16570,16571],{"class":4053}," .snow::after",[32,16573,703],{"class":41},[32,16575,16576,16579,16581,16583],{"class":34,"line":45},[32,16577,16578],{"class":4049},"  content",[32,16580,5269],{"class":41},[32,16582,7268],{"class":175},[32,16584,96],{"class":41},[32,16586,16587,16589,16591,16594],{"class":34,"line":51},[32,16588,14795],{"class":351},[32,16590,5269],{"class":41},[32,16592,16593],{"class":351},"absolute",[32,16595,96],{"class":41},[32,16597,16598,16601,16603,16606,16608],{"class":34,"line":90},[32,16599,16600],{"class":351},"  top",[32,16602,5269],{"class":41},[32,16604,16605],{"class":351},"99",[32,16607,11996],{"class":38},[32,16609,96],{"class":41},[32,16611,16612,16615,16617,16620,16622],{"class":34,"line":99},[32,16613,16614],{"class":351},"  left",[32,16616,5269],{"class":41},[32,16618,16619],{"class":351},"-80",[32,16621,11996],{"class":38},[32,16623,96],{"class":41},[32,16625,16626,16628,16630,16633,16635],{"class":34,"line":106},[32,16627,14833],{"class":351},[32,16629,5269],{"class":41},[32,16631,16632],{"class":351},"160",[32,16634,11996],{"class":38},[32,16636,96],{"class":41},[32,16638,16639,16641,16643,16646,16648],{"class":34,"line":114},[32,16640,14846],{"class":351},[32,16642,5269],{"class":41},[32,16644,16645],{"class":351},"15",[32,16647,11996],{"class":38},[32,16649,96],{"class":41},[32,16651,16652,16655,16657,16660],{"class":34,"line":120},[32,16653,16654],{"class":351},"  background-image",[32,16656,5269],{"class":41},[32,16658,16659],{"class":351},"radial-gradient",[32,16661,539],{"class":41},[32,16663,16664,16667,16670,16672,16674,16677,16679],{"class":34,"line":127},[32,16665,16666],{"class":351},"    circle",[32,16668,16669],{"class":903}," at",[32,16671,4472],{"class":351},[32,16673,11996],{"class":38},[32,16675,16676],{"class":351}," 15",[32,16678,11996],{"class":38},[32,16680,547],{"class":41},[32,16682,16683,16686,16689,16691],{"class":34,"line":132},[32,16684,16685],{"class":351},"    #3fae4a",[32,16687,16688],{"class":351}," 12",[32,16690,11996],{"class":38},[32,16692,547],{"class":41},[32,16694,16695,16698,16701],{"class":34,"line":141},[32,16696,16697],{"class":351},"    transparent",[32,16699,16700],{"class":351}," 13",[32,16702,16703],{"class":38},"px\n",[32,16705,16706],{"class":34,"line":147},[32,16707,557],{"class":41},[32,16709,16710,16713,16715,16717],{"class":34,"line":275},[32,16711,16712],{"class":351},"  background-repeat",[32,16714,5269],{"class":41},[32,16716,6644],{"class":351},[32,16718,96],{"class":41},[32,16720,16721,16724,16726,16728,16730,16732,16734],{"class":34,"line":282},[32,16722,16723],{"class":351},"  background-size",[32,16725,5269],{"class":41},[32,16727,14812],{"class":351},[32,16729,11996],{"class":38},[32,16731,4448],{"class":351},[32,16733,11996],{"class":38},[32,16735,96],{"class":41},[32,16737,16738,16741,16743,16746,16748,16751,16753],{"class":34,"line":295},[32,16739,16740],{"class":351},"  transform",[32,16742,5269],{"class":41},[32,16744,16745],{"class":351},"rotateX",[32,16747,477],{"class":41},[32,16749,16750],{"class":351},"180",[32,16752,14323],{"class":38},[32,16754,230],{"class":41},[32,16756,16757],{"class":34,"line":605},[32,16758,54],{"class":41},[15,16760,2004],{"id":2003},[11,16762,16763,16764,16767],{},"原文只有效果與程式碼截圖。整理時把截圖中的 SCSS 轉成可複製的程式碼；用 ",[29,16765,16766],{},"radial-gradient()"," 搭配偽元素製作重複圖案的方式仍然可用。",[368,16769,16770],{},"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 .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}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 .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);}",{"title":27,"searchDepth":51,"depth":51,"links":16772},[16773],{"id":2003,"depth":45,"text":2004},"記錄練習 SCSS 時，用偽元素與 radial-gradient 製作裝飾圖案的寫法。",{},"\u002Fposts\u002Fscss-radial-gradient-decoration","2020-04-09",[],{"title":16544,"description":16774},"posts\u002F20200409.scss-radial-gradient-decoration",[1757,12455],"5PWOBFUE43YlZ596cLsTvf0L6BnDzkFzOHbqaUer460",{"id":16784,"title":16785,"body":16786,"category":378,"description":16879,"draft":380,"extension":381,"image":382,"meta":16880,"navigation":102,"path":16881,"publishedAt":16882,"relatedExperiments":16883,"seo":16884,"stem":16885,"tags":16886,"updatedAt":13871,"__hash__":16887},"posts\u002Fposts\u002F20200410.autoprefixer-browserslist.md","跨瀏覽器 CSS 前綴：Autoprefixer 與 Browserslist",{"type":8,"value":16787,"toc":16873},[16788,16791,16794,16810,16814,16817,16833,16837,16860,16868,16870],[11,16789,16790],{},"這邊記錄處理跨瀏覽器 CSS 時查到的資訊。",[15,16792,16793],{"id":16793},"相容性查詢",[4538,16795,16796,16803],{},[4541,16797,16798],{},[412,16799,16802],{"href":16800,"rel":16801},"https:\u002F\u002Fcaniuse.com\u002F",[416],"Can I use",[4541,16804,16805],{},[412,16806,16809],{"href":16807,"rel":16808},"https:\u002F\u002Fwww.minwt.com\u002Fwebdesign-dev\u002Fcss\u002F13411.html",[416],"梅問題：Can I use 網站介紹",[15,16811,16813],{"id":16812},"autoprefixer","Autoprefixer",[11,16815,16816],{},"安裝並設定後，編譯時會依支援範圍自動補上其他瀏覽器需要的 CSS 前綴。",[4538,16818,16819,16826],{},[4541,16820,16821],{},[412,16822,16825],{"href":16823,"rel":16824},"https:\u002F\u002Fevilmartians.com\u002Fchronicles\u002Fautoprefixer-7-browserslist-2-released",[416],"Autoprefixer 與 Browserslist 發布文章",[4541,16827,16828],{},[412,16829,16832],{"href":16830,"rel":16831},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10201770",[416],"Autoprefixer 介紹",[15,16834,16836],{"id":16835},"browserslist","Browserslist",[4538,16838,16839,16846,16853],{},[4541,16840,16841],{},[412,16842,16845],{"href":16843,"rel":16844},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fbrowserslist",[416],"Browserslist 套件",[4541,16847,16848],{},[412,16849,16852],{"href":16850,"rel":16851},"https:\u002F\u002Fbrowsersl.ist\u002F",[416],"Browserslist 設定查詢",[4541,16854,16855],{},[412,16856,16859],{"href":16857,"rel":16858},"https:\u002F\u002Fjuejin.im\u002Fpost\u002F6844903669524086797",[416],"當時參考的 Browserslist 翻譯文章",[11,16861,16862,16863,3775],{},"如果要手動處理特定瀏覽器，也可以參考 ",[412,16864,16867],{"href":16865,"rel":16866},"https:\u002F\u002Fgithub.com\u002Fsaadeghi\u002Fbrowser-hack-sass-mixins\u002Fblob\u002Fmaster\u002F_hacks.scss",[416],"browser-hack-sass-mixins",[15,16869,2004],{"id":2003},[11,16871,16872],{},"Autoprefixer 與 Browserslist 的分工仍然是「依目標瀏覽器決定要產生哪些相容性處理」。實際設定方式要以目前建置工具與套件版本為準，也不建議把舊瀏覽器 hack 清單直接整份搬進專案。",{"title":27,"searchDepth":51,"depth":51,"links":16874},[16875,16876,16877,16878],{"id":16793,"depth":45,"text":16793},{"id":16812,"depth":45,"text":16813},{"id":16835,"depth":45,"text":16836},{"id":2003,"depth":45,"text":2004},"記錄當時查詢 CSS 相容性、Autoprefixer、Browserslist 與瀏覽器 hack 的資料來源。",{},"\u002Fposts\u002Fautoprefixer-browserslist","2020-04-10",[],{"title":16785,"description":16879},"posts\u002F20200410.autoprefixer-browserslist",[1757,16813,16836],"2Sy92-H1XfdU3UE1xzDo-rLloN7ZL4JRCYzAoqgdxiw",{"id":16889,"title":16890,"body":16891,"category":378,"description":17028,"draft":380,"extension":381,"image":382,"meta":17029,"navigation":102,"path":17030,"publishedAt":16882,"relatedExperiments":17031,"seo":17032,"stem":17033,"tags":17034,"updatedAt":17035,"__hash__":17036},"posts\u002Fposts\u002F20200410.nuxt-layout-usage.md","Nuxt Layout 使用方式（Nuxt 2）",{"type":8,"value":16892,"toc":17025},[16893,16896,16910,16962,16965,17010,17012,17022],[11,16894,16895],{},"這邊記錄 Nuxt 2 Layout 的使用方式。",[11,16897,16898,16899,16902,16903,16905,16906,16909],{},"先在 ",[29,16900,16901],{},"layouts"," 資料夾新增一個 ",[29,16904,5141],{}," 檔案，版面結構可以參照 ",[29,16907,16908],{},"default.vue","，再自行增加需要的節點：",[22,16911,16913],{"className":8665,"code":16912,"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,16914,16915,16920,16928,16936,16946,16954],{"__ignoreMap":27},[32,16916,16917],{"class":34,"line":35},[32,16918,16919],{"class":608},"\u003C!-- layouts\u002Fanimation.vue -->\n",[32,16921,16922,16924,16926],{"class":34,"line":45},[32,16923,4046],{"class":41},[32,16925,9623],{"class":4049},[32,16927,4062],{"class":41},[32,16929,16930,16932,16934],{"class":34,"line":51},[32,16931,4067],{"class":41},[32,16933,4050],{"class":4049},[32,16935,4062],{"class":41},[32,16937,16938,16940,16943],{"class":34,"line":90},[32,16939,9638],{"class":41},[32,16941,16942],{"class":4049},"nuxt",[32,16944,16945],{"class":41}," \u002F>\n",[32,16947,16948,16950,16952],{"class":34,"line":99},[32,16949,9691],{"class":41},[32,16951,4050],{"class":4049},[32,16953,4062],{"class":41},[32,16955,16956,16958,16960],{"class":34,"line":106},[32,16957,4105],{"class":41},[32,16959,9623],{"class":4049},[32,16961,4062],{"class":41},[11,16963,16964],{},"使用時，在 page 設定 layout 的名稱，就可以沿用剛建立的版面：",[22,16966,16968],{"className":8665,"code":16967,"language":4112,"meta":27,"style":27},"\u003Cscript>\nexport default {\n  layout: \"animation\",\n};\n\u003C\u002Fscript>\n",[29,16969,16970,16978,16986,16996,17002],{"__ignoreMap":27},[32,16971,16972,16974,16976],{"class":34,"line":35},[32,16973,4046],{"class":41},[32,16975,4125],{"class":4049},[32,16977,4062],{"class":41},[32,16979,16980,16982,16984],{"class":34,"line":45},[32,16981,5038],{"class":38},[32,16983,5041],{"class":38},[32,16985,703],{"class":5049},[32,16987,16988,16991,16994],{"class":34,"line":51},[32,16989,16990],{"class":41},"  layout: ",[32,16992,16993],{"class":175},"\"animation\"",[32,16995,547],{"class":5049},[32,16997,16998,17000],{"class":34,"line":90},[32,16999,9765],{"class":5049},[32,17001,96],{"class":41},[32,17003,17004,17006,17008],{"class":34,"line":99},[32,17005,4105],{"class":41},[32,17007,4125],{"class":4049},[32,17009,4062],{"class":41},[15,17011,2004],{"id":2003},[11,17013,17014,17015,17018,17019,3775],{},"這是 Nuxt 2 的寫法。Nuxt 3 之後改用 ",[29,17016,17017],{},"definePageMeta({ layout: \"animation\" })"," 指定版面，layout 裡承載頁面內容的元件也改為 ",[29,17020,17021],{},"\u003CNuxtPage \u002F>",[368,17023,17024],{},"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":17026},[17027],{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 layouts 資料夾新增版面，並由頁面指定 layout 名稱的方式。",{},"\u002Fposts\u002Fnuxt-layout-usage",[],{"title":16890,"description":17028},"posts\u002F20200410.nuxt-layout-usage",[16540,4113],"2026-08-08","08SgZ0jXzxhX4KK90LhJJDmf2Ul-4GmM0bfvDUEqh5o",{"id":17038,"title":17039,"body":17040,"category":378,"description":17737,"draft":380,"extension":381,"image":382,"meta":17738,"navigation":102,"path":17739,"publishedAt":17740,"relatedExperiments":17741,"seo":17742,"stem":17743,"tags":17744,"updatedAt":17035,"__hash__":17746},"posts\u002Fposts\u002F20200412.vue2-countdown-timer.md","Vue 2 倒數計時器：套件與手刻兩種做法",{"type":8,"value":17041,"toc":17732},[17042,17045,17049,17052,17068,17076,17079,17687,17690,17717,17719,17729],[11,17043,17044],{},"這邊記錄兩種倒數計時器的做法。",[15,17046,17048],{"id":17047},"使用-vue2-flip-countdown","使用 vue2-flip-countdown",[11,17050,17051],{},"這個套件有翻牌動畫效果：",[22,17053,17055],{"className":2057,"code":17054,"language":2059,"meta":27,"style":27},"npm i vue2-flip-countdown --save\n",[29,17056,17057],{"__ignoreMap":27},[32,17058,17059,17061,17063,17066],{"class":34,"line":35},[32,17060,4625],{"class":2066},[32,17062,8509],{"class":175},[32,17064,17065],{"class":175}," vue2-flip-countdown",[32,17067,8638],{"class":351},[11,17069,17070,17071],{},"套件頁面：",[412,17072,17075],{"href":17073,"rel":17074},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fvue2-flip-countdown",[416],"vue2-flip-countdown",[15,17077,17078],{"id":17078},"手刻倒數計時器",[22,17080,17082],{"className":8665,"code":17081,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cul>\n    \u003Cli>\u003Ch3>{{ days }}\u003C\u002Fh3>\u003Cspan>Days\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ch3>{{ hours }}\u003C\u002Fh3>\u003Cspan>Hours\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ch3>{{ minutes }}\u003C\u002Fh3>\u003Cspan>Minutes\u003C\u002Fspan>\u003C\u002Fli>\n    \u003Cli>\u003Ch3>{{ seconds }}\u003C\u002Fh3>\u003Cspan>Seconds\u003C\u002Fspan>\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: \"TimerCountdown\",\n  props: [\"gettimer\"],\n  data() {\n    return {\n      minutes: 0,\n      seconds: 0,\n      hours: 0,\n      days: 0,\n    };\n  },\n  mounted() {\n    this.timerCount(this.gettimer);\n  },\n  methods: {\n    timerCount(timer) {\n      const countDownDate = new Date(timer).getTime();\n\n      setInterval(() => {\n        const now = new Date().getTime();\n        const distance = countDownDate - now;\n\n        this.days = Math.floor(distance \u002F (1000 * 60 * 60 * 24));\n        this.hours = Math.floor(\n          (distance % (1000 * 60 * 60 * 24)) \u002F (1000 * 60 * 60),\n        );\n        this.minutes = Math.floor(\n          (distance % (1000 * 60 * 60)) \u002F (1000 * 60),\n        );\n        this.seconds = Math.floor((distance % (1000 * 60)) \u002F 1000);\n      }, 1000);\n    },\n  },\n};\n\u003C\u002Fscript>\n",[29,17083,17084,17092,17100,17131,17161,17191,17221,17229,17237,17241,17249,17257,17266,17279,17287,17293,17302,17311,17320,17329,17333,17339,17348,17364,17370,17375,17387,17410,17414,17426,17446,17463,17467,17507,17522,17564,17569,17584,17616,17620,17654,17663,17667,17673,17679],{"__ignoreMap":27},[32,17085,17086,17088,17090],{"class":34,"line":35},[32,17087,4046],{"class":41},[32,17089,9623],{"class":4049},[32,17091,4062],{"class":41},[32,17093,17094,17096,17098],{"class":34,"line":45},[32,17095,4067],{"class":41},[32,17097,4538],{"class":4049},[32,17099,4062],{"class":41},[32,17101,17102,17104,17106,17109,17111,17114,17116,17118,17120,17123,17125,17127,17129],{"class":34,"line":51},[32,17103,9638],{"class":41},[32,17105,4541],{"class":4049},[32,17107,17108],{"class":41},">\u003C",[32,17110,151],{"class":4049},[32,17112,17113],{"class":41},">{{ days }}\u003C\u002F",[32,17115,151],{"class":4049},[32,17117,17108],{"class":41},[32,17119,32],{"class":4049},[32,17121,17122],{"class":41},">Days\u003C\u002F",[32,17124,32],{"class":4049},[32,17126,4136],{"class":41},[32,17128,4541],{"class":4049},[32,17130,4062],{"class":41},[32,17132,17133,17135,17137,17139,17141,17144,17146,17148,17150,17153,17155,17157,17159],{"class":34,"line":90},[32,17134,9638],{"class":41},[32,17136,4541],{"class":4049},[32,17138,17108],{"class":41},[32,17140,151],{"class":4049},[32,17142,17143],{"class":41},">{{ hours }}\u003C\u002F",[32,17145,151],{"class":4049},[32,17147,17108],{"class":41},[32,17149,32],{"class":4049},[32,17151,17152],{"class":41},">Hours\u003C\u002F",[32,17154,32],{"class":4049},[32,17156,4136],{"class":41},[32,17158,4541],{"class":4049},[32,17160,4062],{"class":41},[32,17162,17163,17165,17167,17169,17171,17174,17176,17178,17180,17183,17185,17187,17189],{"class":34,"line":99},[32,17164,9638],{"class":41},[32,17166,4541],{"class":4049},[32,17168,17108],{"class":41},[32,17170,151],{"class":4049},[32,17172,17173],{"class":41},">{{ minutes }}\u003C\u002F",[32,17175,151],{"class":4049},[32,17177,17108],{"class":41},[32,17179,32],{"class":4049},[32,17181,17182],{"class":41},">Minutes\u003C\u002F",[32,17184,32],{"class":4049},[32,17186,4136],{"class":41},[32,17188,4541],{"class":4049},[32,17190,4062],{"class":41},[32,17192,17193,17195,17197,17199,17201,17204,17206,17208,17210,17213,17215,17217,17219],{"class":34,"line":106},[32,17194,9638],{"class":41},[32,17196,4541],{"class":4049},[32,17198,17108],{"class":41},[32,17200,151],{"class":4049},[32,17202,17203],{"class":41},">{{ seconds }}\u003C\u002F",[32,17205,151],{"class":4049},[32,17207,17108],{"class":41},[32,17209,32],{"class":4049},[32,17211,17212],{"class":41},">Seconds\u003C\u002F",[32,17214,32],{"class":4049},[32,17216,4136],{"class":41},[32,17218,4541],{"class":4049},[32,17220,4062],{"class":41},[32,17222,17223,17225,17227],{"class":34,"line":114},[32,17224,9691],{"class":41},[32,17226,4538],{"class":4049},[32,17228,4062],{"class":41},[32,17230,17231,17233,17235],{"class":34,"line":120},[32,17232,4105],{"class":41},[32,17234,9623],{"class":4049},[32,17236,4062],{"class":41},[32,17238,17239],{"class":34,"line":127},[32,17240,103],{"emptyLinePlaceholder":102},[32,17242,17243,17245,17247],{"class":34,"line":132},[32,17244,4046],{"class":41},[32,17246,4125],{"class":4049},[32,17248,4062],{"class":41},[32,17250,17251,17253,17255],{"class":34,"line":141},[32,17252,5038],{"class":38},[32,17254,5041],{"class":38},[32,17256,703],{"class":5049},[32,17258,17259,17261,17264],{"class":34,"line":147},[32,17260,11580],{"class":41},[32,17262,17263],{"class":175},"\"TimerCountdown\"",[32,17265,547],{"class":5049},[32,17267,17268,17271,17274,17277],{"class":34,"line":275},[32,17269,17270],{"class":41},"  props: [",[32,17272,17273],{"class":175},"\"gettimer\"",[32,17275,17276],{"class":41},"]",[32,17278,547],{"class":5049},[32,17280,17281,17283,17285],{"class":34,"line":282},[32,17282,9728],{"class":217},[32,17284,6075],{"class":5049},[32,17286,5252],{"class":41},[32,17288,17289,17291],{"class":34,"line":295},[32,17290,971],{"class":38},[32,17292,703],{"class":41},[32,17294,17295,17298,17300],{"class":34,"line":605},[32,17296,17297],{"class":41},"      minutes: ",[32,17299,12022],{"class":351},[32,17301,547],{"class":41},[32,17303,17304,17307,17309],{"class":34,"line":612},[32,17305,17306],{"class":41},"      seconds: ",[32,17308,12022],{"class":351},[32,17310,547],{"class":41},[32,17312,17313,17316,17318],{"class":34,"line":617},[32,17314,17315],{"class":41},"      hours: ",[32,17317,12022],{"class":351},[32,17319,547],{"class":41},[32,17321,17322,17325,17327],{"class":34,"line":644},[32,17323,17324],{"class":41},"      days: ",[32,17326,12022],{"class":351},[32,17328,547],{"class":41},[32,17330,17331],{"class":34,"line":649},[32,17332,9753],{"class":41},[32,17334,17335,17337],{"class":34,"line":671},[32,17336,9758],{"class":41},[32,17338,547],{"class":5049},[32,17340,17341,17344,17346],{"class":34,"line":690},[32,17342,17343],{"class":217},"  mounted",[32,17345,6075],{"class":5049},[32,17347,5252],{"class":41},[32,17349,17350,17352,17354,17357,17359,17361],{"class":34,"line":696},[32,17351,10114],{"class":351},[32,17353,1278],{"class":41},[32,17355,17356],{"class":217},"timerCount",[32,17358,477],{"class":41},[32,17360,1083],{"class":351},[32,17362,17363],{"class":41},".gettimer);\n",[32,17365,17366,17368],{"class":34,"line":706},[32,17367,9758],{"class":41},[32,17369,547],{"class":5049},[32,17371,17372],{"class":34,"line":721},[32,17373,17374],{"class":41},"  methods: {\n",[32,17376,17377,17380,17382,17385],{"class":34,"line":728},[32,17378,17379],{"class":217},"    timerCount",[32,17381,477],{"class":41},[32,17383,17384],{"class":903},"timer",[32,17386,520],{"class":41},[32,17388,17389,17392,17395,17397,17399,17402,17405,17408],{"class":34,"line":737},[32,17390,17391],{"class":38},"      const",[32,17393,17394],{"class":351}," countDownDate",[32,17396,894],{"class":38},[32,17398,4165],{"class":38},[32,17400,17401],{"class":217}," Date",[32,17403,17404],{"class":41},"(timer).",[32,17406,17407],{"class":217},"getTime",[32,17409,687],{"class":41},[32,17411,17412],{"class":34,"line":742},[32,17413,103],{"emptyLinePlaceholder":102},[32,17415,17416,17419,17422,17424],{"class":34,"line":747},[32,17417,17418],{"class":217},"      setInterval",[32,17420,17421],{"class":41},"(() ",[32,17423,5090],{"class":38},[32,17425,703],{"class":41},[32,17427,17428,17431,17434,17436,17438,17440,17442,17444],{"class":34,"line":752},[32,17429,17430],{"class":38},"        const",[32,17432,17433],{"class":351}," now",[32,17435,894],{"class":38},[32,17437,4165],{"class":38},[32,17439,17401],{"class":217},[32,17441,10089],{"class":41},[32,17443,17407],{"class":217},[32,17445,687],{"class":41},[32,17447,17448,17450,17453,17455,17458,17460],{"class":34,"line":773},[32,17449,17430],{"class":38},[32,17451,17452],{"class":351}," distance",[32,17454,894],{"class":38},[32,17456,17457],{"class":41}," countDownDate ",[32,17459,6628],{"class":38},[32,17461,17462],{"class":41}," now;\n",[32,17464,17465],{"class":34,"line":789},[32,17466,103],{"emptyLinePlaceholder":102},[32,17468,17469,17472,17475,17477,17479,17481,17484,17486,17488,17491,17493,17496,17498,17500,17502,17505],{"class":34,"line":795},[32,17470,17471],{"class":351},"        this",[32,17473,17474],{"class":41},".days ",[32,17476,172],{"class":38},[32,17478,6063],{"class":41},[32,17480,6066],{"class":217},[32,17482,17483],{"class":41},"(distance ",[32,17485,1275],{"class":38},[32,17487,900],{"class":41},[32,17489,17490],{"class":351},"1000",[32,17492,2341],{"class":38},[32,17494,17495],{"class":351}," 60",[32,17497,2341],{"class":38},[32,17499,17495],{"class":351},[32,17501,2341],{"class":38},[32,17503,17504],{"class":351}," 24",[32,17506,8328],{"class":41},[32,17508,17509,17511,17514,17516,17518,17520],{"class":34,"line":800},[32,17510,17471],{"class":351},[32,17512,17513],{"class":41},".hours ",[32,17515,172],{"class":38},[32,17517,6063],{"class":41},[32,17519,6066],{"class":217},[32,17521,539],{"class":41},[32,17523,17524,17527,17529,17531,17533,17535,17537,17539,17541,17543,17545,17548,17550,17552,17554,17556,17558,17560,17562],{"class":34,"line":816},[32,17525,17526],{"class":41},"          (distance ",[32,17528,14333],{"class":38},[32,17530,900],{"class":41},[32,17532,17490],{"class":351},[32,17534,2341],{"class":38},[32,17536,17495],{"class":351},[32,17538,2341],{"class":38},[32,17540,17495],{"class":351},[32,17542,2341],{"class":38},[32,17544,17504],{"class":351},[32,17546,17547],{"class":41},")) ",[32,17549,1275],{"class":38},[32,17551,900],{"class":41},[32,17553,17490],{"class":351},[32,17555,2341],{"class":38},[32,17557,17495],{"class":351},[32,17559,2341],{"class":38},[32,17561,17495],{"class":351},[32,17563,5101],{"class":41},[32,17565,17566],{"class":34,"line":824},[32,17567,17568],{"class":41},"        );\n",[32,17570,17571,17573,17576,17578,17580,17582],{"class":34,"line":833},[32,17572,17471],{"class":351},[32,17574,17575],{"class":41},".minutes ",[32,17577,172],{"class":38},[32,17579,6063],{"class":41},[32,17581,6066],{"class":217},[32,17583,539],{"class":41},[32,17585,17586,17588,17590,17592,17594,17596,17598,17600,17602,17604,17606,17608,17610,17612,17614],{"class":34,"line":842},[32,17587,17526],{"class":41},[32,17589,14333],{"class":38},[32,17591,900],{"class":41},[32,17593,17490],{"class":351},[32,17595,2341],{"class":38},[32,17597,17495],{"class":351},[32,17599,2341],{"class":38},[32,17601,17495],{"class":351},[32,17603,17547],{"class":41},[32,17605,1275],{"class":38},[32,17607,900],{"class":41},[32,17609,17490],{"class":351},[32,17611,2341],{"class":38},[32,17613,17495],{"class":351},[32,17615,5101],{"class":41},[32,17617,17618],{"class":34,"line":850},[32,17619,17568],{"class":41},[32,17621,17622,17624,17627,17629,17631,17633,17636,17638,17640,17642,17644,17646,17648,17650,17652],{"class":34,"line":856},[32,17623,17471],{"class":351},[32,17625,17626],{"class":41},".seconds ",[32,17628,172],{"class":38},[32,17630,6063],{"class":41},[32,17632,6066],{"class":217},[32,17634,17635],{"class":41},"((distance ",[32,17637,14333],{"class":38},[32,17639,900],{"class":41},[32,17641,17490],{"class":351},[32,17643,2341],{"class":38},[32,17645,17495],{"class":351},[32,17647,17547],{"class":41},[32,17649,1275],{"class":38},[32,17651,6081],{"class":351},[32,17653,230],{"class":41},[32,17655,17656,17659,17661],{"class":34,"line":1815},[32,17657,17658],{"class":41},"      }, ",[32,17660,17490],{"class":351},[32,17662,230],{"class":41},[32,17664,17665],{"class":34,"line":1822},[32,17666,4204],{"class":41},[32,17668,17669,17671],{"class":34,"line":1838},[32,17670,9758],{"class":41},[32,17672,547],{"class":5049},[32,17674,17675,17677],{"class":34,"line":1843},[32,17676,9765],{"class":5049},[32,17678,96],{"class":41},[32,17680,17681,17683,17685],{"class":34,"line":1850},[32,17682,4105],{"class":41},[32,17684,4125],{"class":4049},[32,17686,4062],{"class":41},[11,17688,17689],{},"父層引用：",[22,17691,17693],{"className":8665,"code":17692,"language":4112,"meta":27,"style":27},"\u003CCountDown :gettimer=\"timer\" \u002F>\n",[29,17694,17695],{"__ignoreMap":27},[32,17696,17697,17699,17702,17704,17707,17709,17711,17713,17715],{"class":34,"line":35},[32,17698,4046],{"class":41},[32,17700,17701],{"class":4049},"CountDown",[32,17703,361],{"class":41},[32,17705,17706],{"class":4053},"gettimer",[32,17708,172],{"class":41},[32,17710,16306],{"class":16305},[32,17712,17384],{"class":41},[32,17714,16306],{"class":16305},[32,17716,16945],{"class":41},[15,17718,2004],{"id":2003},[11,17720,17721,17722,17725,17726,3775],{},"這是 Vue 2 的舊寫法，而且原範例沒有保存與清除 ",[29,17723,17724],{},"setInterval","，元件銷毀後計時器仍可能繼續執行。若沿用這段概念，應保存計時器 ID，並在元件卸載時呼叫 ",[29,17727,17728],{},"clearInterval()",[368,17730,17731],{},"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 .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}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 .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}",{"title":27,"searchDepth":51,"depth":51,"links":17733},[17734,17735,17736],{"id":17047,"depth":45,"text":17048},{"id":17078,"depth":45,"text":17078},{"id":2003,"depth":45,"text":2004},"記錄 2020 年使用 vue2-flip-countdown，或以 setInterval 手刻倒數計時器的方式。",{},"\u002Fposts\u002Fvue2-countdown-timer","2020-04-12",[],{"title":17039,"description":17737},"posts\u002F20200412.vue2-countdown-timer",[4113,17745],"倒數計時器","s9vewp6G-tPOK9LWPJz6wORbIqfxLjqsFzQHofOE0do",{"id":17748,"title":17749,"body":17750,"category":378,"description":17935,"draft":380,"extension":381,"image":382,"meta":17936,"navigation":102,"path":17937,"publishedAt":17938,"relatedExperiments":17939,"seo":17940,"stem":17941,"tags":17942,"updatedAt":17035,"__hash__":17944},"posts\u002Fposts\u002F20200413.js-sort-filter-arrow.md","JavaScript sort 與 filter 搭配箭頭函式的範例",{"type":8,"value":17751,"toc":17932},[17752,17903,17910,17912,17929],[22,17753,17755],{"className":24,"code":17754,"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,17756,17757,17769,17785,17799,17813,17817,17821,17826,17861,17865,17870],{"__ignoreMap":27},[32,17758,17759,17761,17764,17766],{"class":34,"line":35},[32,17760,166],{"class":38},[32,17762,17763],{"class":41}," shopData ",[32,17765,172],{"class":38},[32,17767,17768],{"class":41}," [\n",[32,17770,17771,17774,17777,17780,17783],{"class":34,"line":45},[32,17772,17773],{"class":41},"  { name: ",[32,17775,17776],{"class":175},"\"美商博帝 120G SSD\"",[32,17778,17779],{"class":41},", price: ",[32,17781,17782],{"class":351},"638",[32,17784,16188],{"class":41},[32,17786,17787,17789,17792,17794,17797],{"class":34,"line":51},[32,17788,17773],{"class":41},[32,17790,17791],{"class":175},"\"SanDisk 120G SSD\"",[32,17793,17779],{"class":41},[32,17795,17796],{"class":351},"599",[32,17798,16188],{"class":41},[32,17800,17801,17803,17806,17808,17811],{"class":34,"line":90},[32,17802,17773],{"class":41},[32,17804,17805],{"class":175},"\"美光 MX500 250G SSD\"",[32,17807,17779],{"class":41},[32,17809,17810],{"class":351},"1499",[32,17812,16188],{"class":41},[32,17814,17815],{"class":34,"line":99},[32,17816,8282],{"class":41},[32,17818,17819],{"class":34,"line":106},[32,17820,103],{"emptyLinePlaceholder":102},[32,17822,17823],{"class":34,"line":114},[32,17824,17825],{"class":608},"\u002F\u002F 使用 sort 依價格排序\n",[32,17827,17828,17830,17832,17834,17837,17840,17842,17844,17846,17849,17851,17853,17856,17858],{"class":34,"line":120},[32,17829,166],{"class":38},[32,17831,340],{"class":41},[32,17833,172],{"class":38},[32,17835,17836],{"class":41}," shopData.",[32,17838,17839],{"class":217},"sort",[32,17841,8293],{"class":41},[32,17843,412],{"class":903},[32,17845,635],{"class":41},[32,17847,17848],{"class":903},"b",[32,17850,483],{"class":41},[32,17852,5090],{"class":38},[32,17854,17855],{"class":41}," a.price ",[32,17857,6628],{"class":38},[32,17859,17860],{"class":41}," b.price);\n",[32,17862,17863],{"class":34,"line":127},[32,17864,103],{"emptyLinePlaceholder":102},[32,17866,17867],{"class":34,"line":132},[32,17868,17869],{"class":608},"\u002F\u002F 過濾出價格低於 600 的商品\n",[32,17871,17872,17874,17877,17879,17881,17884,17886,17889,17891,17893,17896,17898,17901],{"class":34,"line":141},[32,17873,166],{"class":38},[32,17875,17876],{"class":41}," result2 ",[32,17878,172],{"class":38},[32,17880,17836],{"class":41},[32,17882,17883],{"class":217},"filter",[32,17885,8293],{"class":41},[32,17887,17888],{"class":903},"shop",[32,17890,483],{"class":41},[32,17892,5090],{"class":38},[32,17894,17895],{"class":41}," shop.price ",[32,17897,4046],{"class":38},[32,17899,17900],{"class":351}," 600",[32,17902,230],{"class":41},[11,17904,16416,17905],{},[412,17906,17909],{"href":17907,"rel":17908},"http:\u002F\u002Fwww.eion.com.tw\u002FBlogger\u002F?Pid=1170",[416],"JavaScript 陣列 sort 與 filter",[15,17911,2004],{"id":2003},[11,17913,17914,17917,17918,17921,17922,17925,17926,3775],{},[29,17915,17916],{},"sort()"," 會直接改動原陣列，",[29,17919,17920],{},"filter()"," 則會回傳新陣列。若要保留 ",[29,17923,17924],{},"shopData"," 原本的順序，應先複製再排序，或在支援的環境使用 ",[29,17927,17928],{},"toSorted()",[368,17930,17931],{},"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":17933},[17934],{"id":2003,"depth":45,"text":2004},"用商品清單記錄 sort 排序與 filter 篩選的箭頭函式寫法。",{},"\u002Fposts\u002Fjs-sort-filter-arrow","2020-04-13",[],{"title":17749,"description":17935},"posts\u002F20200413.js-sort-filter-arrow",[390,17943],"陣列方法","1_ZDvKKC8-km6hYl_-YRJCMVddz9DBkYzOplOLsg0Gs",{"id":17946,"title":17947,"body":17948,"category":378,"description":18179,"draft":380,"extension":381,"image":382,"meta":18180,"navigation":102,"path":18181,"publishedAt":18182,"relatedExperiments":18183,"seo":18184,"stem":18185,"tags":18186,"updatedAt":17035,"__hash__":18188},"posts\u002Fposts\u002F20200414.js-object-json-string.md","JavaScript 物件與字串互轉：JSON.stringify 與 JSON.parse",{"type":8,"value":17949,"toc":18174},[17950,17953,18082,18085,18119,18122,18154,18156,18171],[11,17951,17952],{},"先建立一個物件：",[22,17954,17956],{"className":24,"code":17955,"language":26,"meta":27,"style":27},"var person = {\n  firstname: \"li\",\n  lastname: \"eric\",\n  address: {\n    country: \"Taiwan\",\n    city: \"Taichung\",\n    locate: \"i dont know\",\n  },\n};\n\nfunction sayhi(people) {\n  console.log(\"hi\" + people.lastname);\n}\n\nsayhi(person);\n",[29,17957,17958,17969,17979,17989,17994,18004,18014,18024,18028,18032,18036,18050,18066,18070,18074],{"__ignoreMap":27},[32,17959,17960,17962,17965,17967],{"class":34,"line":35},[32,17961,166],{"class":38},[32,17963,17964],{"class":41}," person ",[32,17966,172],{"class":38},[32,17968,703],{"class":41},[32,17970,17971,17974,17977],{"class":34,"line":45},[32,17972,17973],{"class":41},"  firstname: ",[32,17975,17976],{"class":175},"\"li\"",[32,17978,547],{"class":41},[32,17980,17981,17984,17987],{"class":34,"line":51},[32,17982,17983],{"class":41},"  lastname: ",[32,17985,17986],{"class":175},"\"eric\"",[32,17988,547],{"class":41},[32,17990,17991],{"class":34,"line":90},[32,17992,17993],{"class":41},"  address: {\n",[32,17995,17996,17999,18002],{"class":34,"line":99},[32,17997,17998],{"class":41},"    country: ",[32,18000,18001],{"class":175},"\"Taiwan\"",[32,18003,547],{"class":41},[32,18005,18006,18009,18012],{"class":34,"line":106},[32,18007,18008],{"class":41},"    city: ",[32,18010,18011],{"class":175},"\"Taichung\"",[32,18013,547],{"class":41},[32,18015,18016,18019,18022],{"class":34,"line":114},[32,18017,18018],{"class":41},"    locate: ",[32,18020,18021],{"class":175},"\"i dont know\"",[32,18023,547],{"class":41},[32,18025,18026],{"class":34,"line":120},[32,18027,5639],{"class":41},[32,18029,18030],{"class":34,"line":127},[32,18031,7189],{"class":41},[32,18033,18034],{"class":34,"line":132},[32,18035,103],{"emptyLinePlaceholder":102},[32,18037,18038,18040,18043,18045,18048],{"class":34,"line":141},[32,18039,665],{"class":38},[32,18041,18042],{"class":217}," sayhi",[32,18044,477],{"class":41},[32,18046,18047],{"class":903},"people",[32,18049,520],{"class":41},[32,18051,18052,18054,18056,18058,18061,18063],{"class":34,"line":147},[32,18053,5194],{"class":41},[32,18055,5197],{"class":217},[32,18057,477],{"class":41},[32,18059,18060],{"class":175},"\"hi\"",[32,18062,1799],{"class":38},[32,18064,18065],{"class":41}," people.lastname);\n",[32,18067,18068],{"class":34,"line":275},[32,18069,54],{"class":41},[32,18071,18072],{"class":34,"line":282},[32,18073,103],{"emptyLinePlaceholder":102},[32,18075,18076,18079],{"class":34,"line":295},[32,18077,18078],{"class":217},"sayhi",[32,18080,18081],{"class":41},"(person);\n",[15,18083,18084],{"id":18084},"物件轉成字串",[22,18086,18088],{"className":24,"code":18087,"language":26,"meta":27,"style":27},"var objToString = JSON.stringify(person);\nconsole.log(objToString);\n",[29,18089,18090,18109],{"__ignoreMap":27},[32,18091,18092,18094,18097,18099,18102,18104,18107],{"class":34,"line":35},[32,18093,166],{"class":38},[32,18095,18096],{"class":41}," objToString ",[32,18098,172],{"class":38},[32,18100,18101],{"class":351}," JSON",[32,18103,1278],{"class":41},[32,18105,18106],{"class":217},"stringify",[32,18108,18081],{"class":41},[32,18110,18111,18114,18116],{"class":34,"line":45},[32,18112,18113],{"class":41},"console.",[32,18115,5197],{"class":217},[32,18117,18118],{"class":41},"(objToString);\n",[15,18120,18121],{"id":18121},"字串轉回物件",[22,18123,18125],{"className":24,"code":18124,"language":26,"meta":27,"style":27},"var stringToObj = JSON.parse(objToString);\nconsole.log(stringToObj);\n",[29,18126,18127,18145],{"__ignoreMap":27},[32,18128,18129,18131,18134,18136,18138,18140,18143],{"class":34,"line":35},[32,18130,166],{"class":38},[32,18132,18133],{"class":41}," stringToObj ",[32,18135,172],{"class":38},[32,18137,18101],{"class":351},[32,18139,1278],{"class":41},[32,18141,18142],{"class":217},"parse",[32,18144,18118],{"class":41},[32,18146,18147,18149,18151],{"class":34,"line":45},[32,18148,18113],{"class":41},[32,18150,5197],{"class":217},[32,18152,18153],{"class":41},"(stringToObj);\n",[15,18155,2004],{"id":2003},[11,18157,18158,18159,18162,18163,18166,18167,18170],{},"這兩個方法適合處理 JSON 能表示的資料。",[29,18160,18161],{},"undefined","、函式、",[29,18164,18165],{},"Map"," 等內容不會照原型態保留下來，",[29,18168,18169],{},"Date"," 也會先轉成字串，因此不能把它當成適用所有 JavaScript 物件的完整複製方法。",[368,18172,18173],{},"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 .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);}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}",{"title":27,"searchDepth":51,"depth":51,"links":18175},[18176,18177,18178],{"id":18084,"depth":45,"text":18084},{"id":18121,"depth":45,"text":18121},{"id":2003,"depth":45,"text":2004},"記錄以 JSON.stringify 將物件轉成字串，再用 JSON.parse 轉回物件的基本寫法。",{},"\u002Fposts\u002Fjs-object-json-string","2020-04-14",[],{"title":17947,"description":18179},"posts\u002F20200414.js-object-json-string",[390,18187],"JSON","uC-aUdazYMq0y0_wevabOO4hclDfms-s2x58ypBj49U",{"id":18190,"title":18191,"body":18192,"category":4012,"description":18323,"draft":380,"extension":381,"image":382,"meta":18324,"navigation":102,"path":18325,"publishedAt":18326,"relatedExperiments":18327,"seo":18328,"stem":18329,"tags":18330,"updatedAt":17035,"__hash__":18331},"posts\u002Fposts\u002F20200419.eslint-rules-basics.md","ESLint 幾個常用規則與行內停用寫法",{"type":8,"value":18193,"toc":18317},[18194,18197,18200,18209,18212,18221,18224,18229,18250,18265,18268,18273,18287,18290,18309,18311,18314],[15,18195,18196],{"id":18196},"停用規則",[11,18198,18199],{},"停用下一行的檢查：",[22,18201,18203],{"className":24,"code":18202,"language":26,"meta":27,"style":27},"\u002F\u002F eslint-disable-next-line\n",[29,18204,18205],{"__ignoreMap":27},[32,18206,18207],{"class":34,"line":35},[32,18208,18202],{"class":608},[11,18210,18211],{},"停用整份檔案的檢查：",[22,18213,18215],{"className":24,"code":18214,"language":26,"meta":27,"style":27},"\u002F* eslint-disable *\u002F\n",[29,18216,18217],{"__ignoreMap":27},[32,18218,18219],{"class":34,"line":35},[32,18220,18214],{"class":608},[15,18222,18223],{"id":18223},"linebreak-style",[11,18225,18226,18228],{},[29,18227,18223],{}," 用來強制統一換行符號：",[4538,18230,18231,18241],{},[4541,18232,18233,18236,18237,18240],{},[29,18234,18235],{},"unix","：LF（",[29,18238,18239],{},"\\n","）",[4541,18242,18243,18246,18247,18240],{},[29,18244,18245],{},"windows","：CRLF（",[29,18248,18249],{},"\\r\\n",[22,18251,18253],{"className":24,"code":18252,"language":26,"meta":27,"style":27},"\u002F* eslint linebreak-style: [\"error\", \"unix\"] *\u002F\n\u002F* eslint linebreak-style: [\"error\", \"windows\"] *\u002F\n",[29,18254,18255,18260],{"__ignoreMap":27},[32,18256,18257],{"class":34,"line":35},[32,18258,18259],{"class":608},"\u002F* eslint linebreak-style: [\"error\", \"unix\"] *\u002F\n",[32,18261,18262],{"class":34,"line":45},[32,18263,18264],{"class":608},"\u002F* eslint linebreak-style: [\"error\", \"windows\"] *\u002F\n",[15,18266,18267],{"id":18267},"no-new",[11,18269,18270,18272],{},[29,18271,18267],{}," 不允許只建立實例、卻不把它存進變數：",[22,18274,18276],{"className":24,"code":18275,"language":26,"meta":27,"style":27},"new Person();\n",[29,18277,18278],{"__ignoreMap":27},[32,18279,18280,18282,18285],{"class":34,"line":35},[32,18281,9196],{"class":38},[32,18283,18284],{"class":217}," Person",[32,18286,687],{"class":41},[11,18288,18289],{},"改為：",[22,18291,18293],{"className":24,"code":18292,"language":26,"meta":27,"style":27},"var person = new Person();\n",[29,18294,18295],{"__ignoreMap":27},[32,18296,18297,18299,18301,18303,18305,18307],{"class":34,"line":35},[32,18298,166],{"class":38},[32,18300,17964],{"class":41},[32,18302,172],{"class":38},[32,18304,4165],{"class":38},[32,18306,18284],{"class":217},[32,18308,687],{"class":41},[15,18310,2004],{"id":2003},[11,18312,18313],{},"行內停用指令與這兩條規則仍可使用。停用 ESLint 時應縮小範圍並寫清原因，避免用整份檔案停用掩蓋其他問題。",[368,18315,18316],{},"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 .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}",{"title":27,"searchDepth":51,"depth":51,"links":18318},[18319,18320,18321,18322],{"id":18196,"depth":45,"text":18196},{"id":18223,"depth":45,"text":18223},{"id":18267,"depth":45,"text":18267},{"id":2003,"depth":45,"text":2004},"記錄停用 ESLint 檢查，以及 linebreak-style、no-new 規則的基本用法。",{},"\u002Fposts\u002Feslint-rules-basics","2020-04-19",[],{"title":18191,"description":18323},"posts\u002F20200419.eslint-rules-basics",[4853],"hh05nMCpye6vl2TUonvj8ZVpgY1mQP61pHA1r8t2yYs",{"id":18333,"title":18334,"body":18335,"category":378,"description":19880,"draft":380,"extension":381,"image":382,"meta":19881,"navigation":102,"path":19882,"publishedAt":18326,"relatedExperiments":19883,"seo":19884,"stem":19885,"tags":19886,"updatedAt":17035,"__hash__":19888},"posts\u002Fposts\u002F20200419.js-prototype-inheritance.md","JavaScript 物件導向：建構函式、prototype 與繼承三步驟",{"type":8,"value":18336,"toc":19862},[18337,18340,18343,18357,18360,18364,18427,18430,18644,18653,18687,18691,18711,18715,18787,18813,18817,18820,18826,18832,18835,18839,18958,18988,18992,19041,19072,19093,19097,19118,19146,19150,19482,19500,19504,19507,19511,19514,19601,19605,19608,19715,19719,19725,19808,19811,19824,19841,19843,19859],[11,18338,18339],{},"物件導向的核心想法很單純：把情境裡的東西包裝成物件。步驟大致是：把情境描述成物件、定義這些物件的屬性跟行為、讓物件之間互動。",[11,18341,18342],{},"用「人」跟「香蕉」這兩個物件當例子：",[4538,18344,18345,18351],{},[4541,18346,18347,18350],{},[12390,18348,18349],{},"人","：屬性是名字、年齡、有的物品；行為是打招呼、走路、接收物品",[4541,18352,18353,18356],{},[12390,18354,18355],{},"香蕉","：屬性是名字、價格、味道；行為是剝皮、攻擊別人（比喻用，實際不會真的攻擊）",[11,18358,18359],{},"這篇整理 ES5 時代用建構函式手刻這套邏輯的完整流程。",[15,18361,18363],{"id":18362},"封裝把屬性跟方法包進一個建構函式","封裝：把屬性跟方法包進一個建構函式",[22,18365,18367],{"className":24,"code":18366,"language":26,"meta":27,"style":27},"var Ticket = function (初始值) {\n  this.屬性 = 初始值;\n  this.方法 = function () {\n    \u002F\u002F 這裡面可以用 this.屬性 跟 this.方法\n  };\n};\n",[29,18368,18369,18387,18399,18414,18419,18423],{"__ignoreMap":27},[32,18370,18371,18373,18376,18378,18380,18382,18385],{"class":34,"line":35},[32,18372,166],{"class":38},[32,18374,18375],{"class":217}," Ticket",[32,18377,894],{"class":38},[32,18379,897],{"class":38},[32,18381,900],{"class":41},[32,18383,18384],{"class":903},"初始值",[32,18386,520],{"class":41},[32,18388,18389,18391,18394,18396],{"class":34,"line":45},[32,18390,8938],{"class":351},[32,18392,18393],{"class":41},".屬性 ",[32,18395,172],{"class":38},[32,18397,18398],{"class":41}," 初始值;\n",[32,18400,18401,18403,18405,18408,18410,18412],{"class":34,"line":51},[32,18402,8938],{"class":351},[32,18404,1278],{"class":41},[32,18406,18407],{"class":217},"方法",[32,18409,894],{"class":38},[32,18411,897],{"class":38},[32,18413,668],{"class":41},[32,18415,18416],{"class":34,"line":90},[32,18417,18418],{"class":608},"    \u002F\u002F 這裡面可以用 this.屬性 跟 this.方法\n",[32,18420,18421],{"class":34,"line":99},[32,18422,1007],{"class":41},[32,18424,18425],{"class":34,"line":106},[32,18426,7189],{"class":41},[11,18428,18429],{},"用一個實際例子——一張票券，有價格、折扣、固定手續費，還有算總價跟印出描述的方法：",[22,18431,18433],{"className":24,"code":18432,"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,18434,18435,18457,18462,18474,18488,18500,18514,18518,18533,18538,18559,18563,18567,18582,18636,18640],{"__ignoreMap":27},[32,18436,18437,18439,18441,18443,18445,18447,18450,18452,18455],{"class":34,"line":35},[32,18438,166],{"class":38},[32,18440,18375],{"class":217},[32,18442,894],{"class":38},[32,18444,897],{"class":38},[32,18446,900],{"class":41},[32,18448,18449],{"class":903},"init_price",[32,18451,635],{"class":41},[32,18453,18454],{"class":903},"init_discount",[32,18456,520],{"class":41},[32,18458,18459],{"class":34,"line":45},[32,18460,18461],{"class":608},"  \u002F\u002F 初始化\n",[32,18463,18464,18466,18469,18471],{"class":34,"line":51},[32,18465,8938],{"class":351},[32,18467,18468],{"class":41},".price ",[32,18470,172],{"class":38},[32,18472,18473],{"class":41}," init_price;\n",[32,18475,18476,18478,18481,18483,18486],{"class":34,"line":90},[32,18477,8938],{"class":351},[32,18479,18480],{"class":41},".type ",[32,18482,172],{"class":38},[32,18484,18485],{"class":175}," 'student'",[32,18487,96],{"class":41},[32,18489,18490,18492,18495,18497],{"class":34,"line":99},[32,18491,8938],{"class":351},[32,18493,18494],{"class":41},".discount ",[32,18496,172],{"class":38},[32,18498,18499],{"class":41}," init_discount;\n",[32,18501,18502,18504,18507,18509,18512],{"class":34,"line":106},[32,18503,8938],{"class":351},[32,18505,18506],{"class":41},".fee ",[32,18508,172],{"class":38},[32,18510,18511],{"class":351}," 30",[32,18513,96],{"class":41},[32,18515,18516],{"class":34,"line":114},[32,18517,103],{"emptyLinePlaceholder":102},[32,18519,18520,18522,18524,18527,18529,18531],{"class":34,"line":120},[32,18521,8938],{"class":351},[32,18523,1278],{"class":41},[32,18525,18526],{"class":217},"get_price",[32,18528,894],{"class":38},[32,18530,897],{"class":38},[32,18532,668],{"class":41},[32,18534,18535],{"class":34,"line":127},[32,18536,18537],{"class":608},"    \u002F\u002F this 參照物件本體的資訊\n",[32,18539,18540,18542,18544,18546,18548,18550,18552,18554,18556],{"class":34,"line":132},[32,18541,971],{"class":38},[32,18543,4234],{"class":351},[32,18545,18468],{"class":41},[32,18547,6078],{"class":38},[32,18549,4234],{"class":351},[32,18551,18494],{"class":41},[32,18553,224],{"class":38},[32,18555,4234],{"class":351},[32,18557,18558],{"class":41},".fee;\n",[32,18560,18561],{"class":34,"line":141},[32,18562,1007],{"class":41},[32,18564,18565],{"class":34,"line":147},[32,18566,103],{"emptyLinePlaceholder":102},[32,18568,18569,18571,18573,18576,18578,18580],{"class":34,"line":275},[32,18570,8938],{"class":351},[32,18572,1278],{"class":41},[32,18574,18575],{"class":217},"get_description",[32,18577,894],{"class":38},[32,18579,897],{"class":38},[32,18581,668],{"class":41},[32,18583,18584,18586,18588,18590,18593,18595,18597,18599,18601,18604,18606,18608,18610,18612,18614,18616,18619,18621,18623,18625,18627,18629,18631,18634],{"class":34,"line":282},[32,18585,8966],{"class":41},[32,18587,5197],{"class":217},[32,18589,477],{"class":41},[32,18591,18592],{"class":175},"'這張票是'",[32,18594,1799],{"class":38},[32,18596,4234],{"class":351},[32,18598,18480],{"class":41},[32,18600,224],{"class":38},[32,18602,18603],{"class":175}," '票，有'",[32,18605,1799],{"class":38},[32,18607,4234],{"class":351},[32,18609,18494],{"class":41},[32,18611,6078],{"class":38},[32,18613,4472],{"class":351},[32,18615,1799],{"class":38},[32,18617,18618],{"class":175}," '折扣，共'",[32,18620,1799],{"class":38},[32,18622,4234],{"class":351},[32,18624,1278],{"class":41},[32,18626,18526],{"class":217},[32,18628,6075],{"class":41},[32,18630,224],{"class":38},[32,18632,18633],{"class":175}," '元'",[32,18635,230],{"class":41},[32,18637,18638],{"class":34,"line":295},[32,18639,1007],{"class":41},[32,18641,18642],{"class":34,"line":605},[32,18643,7189],{"class":41},[11,18645,18646,18649,18650,18652],{},[12390,18647,18648],{},"建立實體物件","時用 ",[29,18651,9196],{},"，傳進去的參數對應建構函式裡的初始值：",[22,18654,18656],{"className":24,"code":18655,"language":26,"meta":27,"style":27},"var myticket = new Ticket(500, 0.5); \u002F\u002F 產生時，傳進物件價格跟折扣\n",[29,18657,18658],{"__ignoreMap":27},[32,18659,18660,18662,18665,18667,18669,18671,18673,18676,18678,18681,18684],{"class":34,"line":35},[32,18661,166],{"class":38},[32,18663,18664],{"class":41}," myticket ",[32,18666,172],{"class":38},[32,18668,4165],{"class":38},[32,18670,18375],{"class":217},[32,18672,477],{"class":41},[32,18674,18675],{"class":351},"500",[32,18677,635],{"class":41},[32,18679,18680],{"class":351},"0.5",[32,18682,18683],{"class":41},"); ",[32,18685,18686],{"class":608},"\u002F\u002F 產生時，傳進物件價格跟折扣\n",[15,18688,18690],{"id":18689},"這樣寫的問題每個實體都各自複製一份方法","這樣寫的問題：每個實體都各自複製一份方法",[11,18692,18693,18694,3750,18696,18698,18699,18702,18703,18706,18707,18710],{},"上面的寫法裡，",[29,18695,18526],{},[29,18697,18575],{}," 這兩個方法是寫在建構函式",[12390,18700,18701],{},"內部","的，代表每次 ",[29,18704,18705],{},"new Ticket(...)","，這兩個方法都會被",[12390,18708,18709],{},"重新建立一次、各自佔一份記憶體","——就算兩張票券的邏輯完全一樣，也是兩份獨立的函式物件。",[15,18712,18714],{"id":18713},"共用函式掛在-prototype-上","共用函式：掛在 prototype 上",[22,18716,18718],{"className":24,"code":18717,"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,18719,18720,18736,18746,18750,18754,18759,18778,18783],{"__ignoreMap":27},[32,18721,18722,18724,18726,18728,18730,18732,18734],{"class":34,"line":35},[32,18723,166],{"class":38},[32,18725,18375],{"class":217},[32,18727,894],{"class":38},[32,18729,897],{"class":38},[32,18731,900],{"class":41},[32,18733,18384],{"class":903},[32,18735,520],{"class":41},[32,18737,18738,18740,18742,18744],{"class":34,"line":45},[32,18739,8938],{"class":351},[32,18741,18393],{"class":41},[32,18743,172],{"class":38},[32,18745,18398],{"class":41},[32,18747,18748],{"class":34,"line":51},[32,18749,7189],{"class":41},[32,18751,18752],{"class":34,"line":90},[32,18753,103],{"emptyLinePlaceholder":102},[32,18755,18756],{"class":34,"line":99},[32,18757,18758],{"class":608},"\u002F\u002F 共用函數\n",[32,18760,18761,18764,18766,18768,18770,18772,18774,18776],{"class":34,"line":106},[32,18762,18763],{"class":351},"Ticket",[32,18765,1278],{"class":41},[32,18767,1585],{"class":351},[32,18769,1278],{"class":41},[32,18771,18407],{"class":217},[32,18773,894],{"class":38},[32,18775,897],{"class":38},[32,18777,668],{"class":41},[32,18779,18780],{"class":34,"line":114},[32,18781,18782],{"class":608},"  \u002F\u002F 其中可使用 this.屬性 跟 this.方法\n",[32,18784,18785],{"class":34,"line":120},[32,18786,7189],{"class":41},[11,18788,18789,18790,18792,18793,18796,18797,18799,18800,18802,18803,18805,18806,18808,18809,18812],{},"放在 ",[29,18791,1585],{}," 裡的東西",[12390,18794,18795],{},"不會被複製進每一個物件","，物件本身只會有一個參考連到 ",[29,18798,1585],{},"；存取屬性或方法時，先在物件自己身上找，找不到才會往上到 ",[29,18801,1585],{}," 找。這代表不管 ",[29,18804,9196],{}," 出幾個實體，",[29,18807,1585],{}," 上的方法永遠只有",[12390,18810,18811],{},"一份","，多個實體共用同一份參考。",[15,18814,18816],{"id":18815},"繼承類別之間的延續","繼承：類別之間的延續",[11,18818,18819],{},"先定義一個比較上層、比較抽象的類別「生物」，再讓「狗」繼承它：",[22,18821,18824],{"className":18822,"code":18823,"language":426,"meta":27},[424],"生物 (Creature)：名字、生命長度、移動、吃東西\n狗 (Dog)：品種、喜歡吃的東西、吠叫、攻擊\n",[29,18825,18823],{"__ignoreMap":27},[11,18827,18828,18829,3775],{},"「狗」除了自己的專屬屬性（品種、吠叫），也應該擁有「生物」共通的那些（名字、吃東西）——這就是繼承要解決的問題：",[12390,18830,18831],{},"避免每個子類別都要重新定義一次共通的部分",[11,18833,18834],{},"繼承的完整步驟分三步：",[151,18836,18838],{"id":18837},"步驟一建立時呼叫母類別的建構子","步驟一：建立時呼叫母類別的建構子",[22,18840,18842],{"className":24,"code":18841,"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,18843,18844,18867,18879,18891,18895,18899,18925,18942,18954],{"__ignoreMap":27},[32,18845,18846,18848,18851,18853,18855,18857,18860,18862,18865],{"class":34,"line":35},[32,18847,166],{"class":38},[32,18849,18850],{"class":217}," Creature",[32,18852,894],{"class":38},[32,18854,897],{"class":38},[32,18856,900],{"class":41},[32,18858,18859],{"class":903},"name",[32,18861,635],{"class":41},[32,18863,18864],{"class":903},"lifespan",[32,18866,520],{"class":41},[32,18868,18869,18871,18874,18876],{"class":34,"line":45},[32,18870,8938],{"class":351},[32,18872,18873],{"class":41},".name ",[32,18875,172],{"class":38},[32,18877,18878],{"class":41}," name;\n",[32,18880,18881,18883,18886,18888],{"class":34,"line":51},[32,18882,8938],{"class":351},[32,18884,18885],{"class":41},".lifespan ",[32,18887,172],{"class":38},[32,18889,18890],{"class":41}," lifespan;\n",[32,18892,18893],{"class":34,"line":90},[32,18894,7189],{"class":41},[32,18896,18897],{"class":34,"line":99},[32,18898,103],{"emptyLinePlaceholder":102},[32,18900,18901,18903,18906,18908,18910,18912,18914,18916,18918,18920,18923],{"class":34,"line":106},[32,18902,166],{"class":38},[32,18904,18905],{"class":217}," Dog",[32,18907,894],{"class":38},[32,18909,897],{"class":38},[32,18911,900],{"class":41},[32,18913,18859],{"class":903},[32,18915,635],{"class":41},[32,18917,18864],{"class":903},[32,18919,635],{"class":41},[32,18921,18922],{"class":903},"breed",[32,18924,520],{"class":41},[32,18926,18927,18930,18932,18934,18936,18939],{"class":34,"line":114},[32,18928,18929],{"class":41},"  Creature.",[32,18931,1596],{"class":217},[32,18933,477],{"class":41},[32,18935,1083],{"class":351},[32,18937,18938],{"class":41},", name, lifespan); ",[32,18940,18941],{"class":608},"\u002F\u002F 呼叫母類別，針對母類別進行初始化\n",[32,18943,18944,18946,18949,18951],{"class":34,"line":120},[32,18945,8938],{"class":351},[32,18947,18948],{"class":41},".breed ",[32,18950,172],{"class":38},[32,18952,18953],{"class":41}," breed;\n",[32,18955,18956],{"class":34,"line":127},[32,18957,7189],{"class":41},[11,18959,18960,18963,18964,18967,18968,18970,18971,18974,18975,18978,18979,18981,18982,18984,18985,18987],{},[29,18961,18962],{},"Creature.call(this, name, lifespan)"," 的意思是「借用 ",[29,18965,18966],{},"Creature"," 這個建構函式，但讓它的 ",[29,18969,1083],{}," 指向現在正在建立的 ",[29,18972,18973],{},"Dog"," 實體」——這一步只處理",[12390,18976,18977],{},"屬性","的繼承，",[29,18980,18966],{}," 建構子裡對 ",[29,18983,1083],{}," 做的初始化，會套用在正在建立的這個 ",[29,18986,18973],{}," 物件上。",[151,18989,18991],{"id":18990},"步驟二讓子類別的-prototype-接上母類別的-prototype","步驟二：讓子類別的 prototype 接上母類別的 prototype",[22,18993,18995],{"className":24,"code":18994,"language":26,"meta":27,"style":27},"Dog.prototype = Object.create(Creature.prototype);\nDog.prototype.constructor = Dog;\n",[29,18996,18997,19023],{"__ignoreMap":27},[32,18998,18999,19001,19003,19005,19007,19010,19013,19015,19017,19019,19021],{"class":34,"line":35},[32,19000,18973],{"class":351},[32,19002,1278],{"class":41},[32,19004,1585],{"class":351},[32,19006,894],{"class":38},[32,19008,19009],{"class":41}," Object.",[32,19011,19012],{"class":217},"create",[32,19014,477],{"class":41},[32,19016,18966],{"class":351},[32,19018,1278],{"class":41},[32,19020,1585],{"class":351},[32,19022,230],{"class":41},[32,19024,19025,19027,19029,19031,19033,19036,19038],{"class":34,"line":45},[32,19026,18973],{"class":351},[32,19028,1278],{"class":41},[32,19030,1585],{"class":351},[32,19032,1278],{"class":41},[32,19034,19035],{"class":351},"constructor",[32,19037,894],{"class":38},[32,19039,19040],{"class":41}," Dog;\n",[11,19042,19043,19046,19047,19050,19051,19054,19055,19058,19059,19061,19062,19064,19065,19068,19069,19071],{},[29,19044,19045],{},"Object.create(Creature.prototype)"," 建立一個",[12390,19048,19049],{},"空的中繼物件","，這個物件的原型鏈往上連到 ",[29,19052,19053],{},"Creature.prototype","，再把它指派給 ",[29,19056,19057],{},"Dog.prototype","。這一步做完之後，",[29,19060,18973],{}," 的實體如果在自己身上跟 ",[29,19063,19057],{}," 都找不到某個方法，會",[12390,19066,19067],{},"再往上一層","去 ",[29,19070,19053],{}," 找。",[11,19073,19074,19077,19078,19081,19082,19084,19085,19088,19089,19092],{},[12390,19075,19076],{},"只做步驟一不夠","：步驟一只繼承了「屬性」（建構子裡 ",[29,19079,19080],{},"this.xxx = xxx"," 那些），母類別掛在 ",[29,19083,1585],{}," 上的",[12390,19086,19087],{},"共用方法","沒有被繼承到，因為步驟一的 ",[29,19090,19091],{},"call()"," 只是借用建構函式執行了一次，不會動到原型鏈的連結，這正是需要步驟二的原因。",[151,19094,19096],{"id":19095},"步驟三把建構函式指回自己","步驟三：把建構函式指回自己",[22,19098,19100],{"className":24,"code":19099,"language":26,"meta":27,"style":27},"Dog.prototype.constructor = Dog;\n",[29,19101,19102],{"__ignoreMap":27},[32,19103,19104,19106,19108,19110,19112,19114,19116],{"class":34,"line":35},[32,19105,18973],{"class":351},[32,19107,1278],{"class":41},[32,19109,1585],{"class":351},[32,19111,1278],{"class":41},[32,19113,19035],{"class":351},[32,19115,894],{"class":38},[32,19117,19040],{"class":41},[11,19119,19120,19121,19124,19125,19127,19128,19130,19131,19133,19134,19136,19137,19140,19141,19143,19144,3775],{},"步驟二用 ",[29,19122,19123],{},"Object.create()"," 整個換掉了 ",[29,19126,19057],{},"，這個新物件的 ",[29,19129,19035],{}," 屬性預設會指向 ",[29,19132,18966],{},"（因為它是從 ",[29,19135,19053],{}," 複製結構過來的），不修正的話，",[29,19138,19139],{},"someDogInstance.constructor"," 會誤指到 ",[29,19142,18966],{},"，這一步負責把它導正回 ",[29,19145,18973],{},[15,19147,19149],{"id":19148},"完整範例人的繼承","完整範例：人的繼承",[22,19151,19153],{"className":24,"code":19152,"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,19154,19155,19160,19181,19191,19203,19207,19211,19231,19248,19252,19256,19261,19287,19304,19319,19323,19327,19355,19375,19379,19398,19403,19421,19425,19429,19459,19471],{"__ignoreMap":27},[32,19156,19157],{"class":34,"line":35},[32,19158,19159],{"class":608},"\u002F\u002F 母類別\n",[32,19161,19162,19164,19166,19168,19170,19172,19174,19176,19179],{"class":34,"line":45},[32,19163,166],{"class":38},[32,19165,18284],{"class":217},[32,19167,894],{"class":38},[32,19169,897],{"class":38},[32,19171,900],{"class":41},[32,19173,18859],{"class":903},[32,19175,635],{"class":41},[32,19177,19178],{"class":903},"age",[32,19180,520],{"class":41},[32,19182,19183,19185,19187,19189],{"class":34,"line":51},[32,19184,8938],{"class":351},[32,19186,18873],{"class":41},[32,19188,172],{"class":38},[32,19190,18878],{"class":41},[32,19192,19193,19195,19198,19200],{"class":34,"line":90},[32,19194,8938],{"class":351},[32,19196,19197],{"class":41},".age ",[32,19199,172],{"class":38},[32,19201,19202],{"class":41}," age;\n",[32,19204,19205],{"class":34,"line":99},[32,19206,7189],{"class":41},[32,19208,19209],{"class":34,"line":106},[32,19210,103],{"emptyLinePlaceholder":102},[32,19212,19213,19216,19218,19220,19222,19225,19227,19229],{"class":34,"line":114},[32,19214,19215],{"class":351},"Person",[32,19217,1278],{"class":41},[32,19219,1585],{"class":351},[32,19221,1278],{"class":41},[32,19223,19224],{"class":217},"sayHello",[32,19226,894],{"class":38},[32,19228,897],{"class":38},[32,19230,668],{"class":41},[32,19232,19233,19235,19237,19239,19242,19244,19246],{"class":34,"line":120},[32,19234,5194],{"class":41},[32,19236,5197],{"class":217},[32,19238,477],{"class":41},[32,19240,19241],{"class":175},"'hello i am '",[32,19243,1799],{"class":38},[32,19245,4234],{"class":351},[32,19247,11486],{"class":41},[32,19249,19250],{"class":34,"line":127},[32,19251,7189],{"class":41},[32,19253,19254],{"class":34,"line":132},[32,19255,103],{"emptyLinePlaceholder":102},[32,19257,19258],{"class":34,"line":141},[32,19259,19260],{"class":608},"\u002F\u002F 子類別：Worker 繼承 Person\n",[32,19262,19263,19265,19268,19270,19272,19274,19276,19278,19280,19282,19285],{"class":34,"line":147},[32,19264,166],{"class":38},[32,19266,19267],{"class":217}," Worker",[32,19269,894],{"class":38},[32,19271,897],{"class":38},[32,19273,900],{"class":41},[32,19275,18859],{"class":903},[32,19277,635],{"class":41},[32,19279,19178],{"class":903},[32,19281,635],{"class":41},[32,19283,19284],{"class":903},"job",[32,19286,520],{"class":41},[32,19288,19289,19292,19294,19296,19298,19301],{"class":34,"line":275},[32,19290,19291],{"class":41},"  Person.",[32,19293,1596],{"class":217},[32,19295,477],{"class":41},[32,19297,1083],{"class":351},[32,19299,19300],{"class":41},", name, age); ",[32,19302,19303],{"class":608},"\u002F\u002F 步驟一：呼叫母類別初始化\n",[32,19305,19306,19308,19311,19313,19316],{"class":34,"line":282},[32,19307,8938],{"class":351},[32,19309,19310],{"class":41},".job ",[32,19312,172],{"class":38},[32,19314,19315],{"class":41}," job; ",[32,19317,19318],{"class":608},"\u002F\u002F 設定自己的額外屬性\n",[32,19320,19321],{"class":34,"line":295},[32,19322,7189],{"class":41},[32,19324,19325],{"class":34,"line":605},[32,19326,103],{"emptyLinePlaceholder":102},[32,19328,19329,19332,19334,19336,19338,19340,19342,19344,19346,19348,19350,19352],{"class":34,"line":612},[32,19330,19331],{"class":351},"Worker",[32,19333,1278],{"class":41},[32,19335,1585],{"class":351},[32,19337,894],{"class":38},[32,19339,19009],{"class":41},[32,19341,19012],{"class":217},[32,19343,477],{"class":41},[32,19345,19215],{"class":351},[32,19347,1278],{"class":41},[32,19349,1585],{"class":351},[32,19351,18683],{"class":41},[32,19353,19354],{"class":608},"\u002F\u002F 步驟二：接上原型鏈\n",[32,19356,19357,19359,19361,19363,19365,19367,19369,19372],{"class":34,"line":617},[32,19358,19331],{"class":351},[32,19360,1278],{"class":41},[32,19362,1585],{"class":351},[32,19364,1278],{"class":41},[32,19366,19035],{"class":351},[32,19368,894],{"class":38},[32,19370,19371],{"class":41}," Worker; ",[32,19373,19374],{"class":608},"\u002F\u002F 步驟三：建構函式指回自己\n",[32,19376,19377],{"class":34,"line":644},[32,19378,103],{"emptyLinePlaceholder":102},[32,19380,19381,19383,19385,19387,19389,19392,19394,19396],{"class":34,"line":649},[32,19382,19331],{"class":351},[32,19384,1278],{"class":41},[32,19386,1585],{"class":351},[32,19388,1278],{"class":41},[32,19390,19391],{"class":217},"tellJob",[32,19393,894],{"class":38},[32,19395,897],{"class":38},[32,19397,668],{"class":41},[32,19399,19400],{"class":34,"line":671},[32,19401,19402],{"class":608},"  \u002F\u002F Worker 自己的共用方法\n",[32,19404,19405,19407,19409,19411,19414,19416,19418],{"class":34,"line":690},[32,19406,5194],{"class":41},[32,19408,5197],{"class":217},[32,19410,477],{"class":41},[32,19412,19413],{"class":175},"'I am a '",[32,19415,1799],{"class":38},[32,19417,4234],{"class":351},[32,19419,19420],{"class":41},".job);\n",[32,19422,19423],{"class":34,"line":696},[32,19424,7189],{"class":41},[32,19426,19427],{"class":34,"line":706},[32,19428,103],{"emptyLinePlaceholder":102},[32,19430,19431,19433,19436,19438,19440,19442,19444,19447,19449,19452,19454,19457],{"class":34,"line":721},[32,19432,166],{"class":38},[32,19434,19435],{"class":41}," henry ",[32,19437,172],{"class":38},[32,19439,4165],{"class":38},[32,19441,19267],{"class":217},[32,19443,477],{"class":41},[32,19445,19446],{"class":175},"'Henry'",[32,19448,635],{"class":41},[32,19450,19451],{"class":351},"30",[32,19453,635],{"class":41},[32,19455,19456],{"class":175},"'Teacher'",[32,19458,230],{"class":41},[32,19460,19461,19464,19466,19468],{"class":34,"line":728},[32,19462,19463],{"class":41},"henry.",[32,19465,19224],{"class":217},[32,19467,11502],{"class":41},[32,19469,19470],{"class":608},"\u002F\u002F hello i am Henry ← 繼承自 Person.prototype\n",[32,19472,19473,19475,19477,19479],{"class":34,"line":737},[32,19474,19463],{"class":41},[32,19476,19391],{"class":217},[32,19478,11502],{"class":41},[32,19480,19481],{"class":608},"\u002F\u002F I am a Teacher   ← Worker 自己的方法\n",[11,19483,19484,19487,19488,19491,19492,19495,19496,19499],{},[29,19485,19486],{},"henry.sayHello()"," 這個方法沒有寫在 ",[29,19489,19490],{},"Worker.prototype"," 上，",[29,19493,19494],{},"henry"," 自己身上也沒有，會一路往上找到 ",[29,19497,19498],{},"Person.prototype"," 才找到——這就是原型鏈繼承實際運作的樣子。",[15,19501,19503],{"id":19502},"順便記的-es6-物件寫法","順便記的 ES6 物件寫法",[11,19505,19506],{},"練習物件導向的過程中，也整理了幾個 ES6 讓物件字面量寫起來更精簡的語法，跟上面的繼承主題不算同一件事，但當時是一起記的。",[151,19508,19510],{"id":19509},"物件縮寫object-shorthand","物件縮寫（Object Shorthand）",[11,19512,19513],{},"屬性值剛好跟一個同名變數對應時，可以省略冒號跟重複的名稱：",[22,19515,19517],{"className":24,"code":19516,"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,19518,19519,19524,19541,19547,19552,19557,19561,19565,19569,19574,19590,19597],{"__ignoreMap":27},[32,19520,19521],{"class":34,"line":35},[32,19522,19523],{"class":608},"\u002F\u002F 完整寫法\n",[32,19525,19526,19528,19531,19533,19535,19537,19539],{"class":34,"line":45},[32,19527,665],{"class":38},[32,19529,19530],{"class":217}," makePoint",[32,19532,477],{"class":41},[32,19534,11108],{"class":903},[32,19536,635],{"class":41},[32,19538,11239],{"class":903},[32,19540,520],{"class":41},[32,19542,19543,19545],{"class":34,"line":51},[32,19544,11115],{"class":38},[32,19546,703],{"class":41},[32,19548,19549],{"class":34,"line":90},[32,19550,19551],{"class":41},"    x: x,\n",[32,19553,19554],{"class":34,"line":99},[32,19555,19556],{"class":41},"    y: y,\n",[32,19558,19559],{"class":34,"line":106},[32,19560,1007],{"class":41},[32,19562,19563],{"class":34,"line":114},[32,19564,54],{"class":41},[32,19566,19567],{"class":34,"line":120},[32,19568,103],{"emptyLinePlaceholder":102},[32,19570,19571],{"class":34,"line":127},[32,19572,19573],{"class":608},"\u002F\u002F 縮寫\n",[32,19575,19576,19578,19580,19582,19584,19586,19588],{"class":34,"line":132},[32,19577,665],{"class":38},[32,19579,19530],{"class":217},[32,19581,477],{"class":41},[32,19583,11108],{"class":903},[32,19585,635],{"class":41},[32,19587,11239],{"class":903},[32,19589,520],{"class":41},[32,19591,19592,19594],{"class":34,"line":141},[32,19593,11115],{"class":38},[32,19595,19596],{"class":41}," { x, y };\n",[32,19598,19599],{"class":34,"line":147},[32,19600,54],{"class":41},[151,19602,19604],{"id":19603},"計算屬性computed-property-names","計算屬性（Computed Property Names）",[11,19606,19607],{},"屬性名稱需要動態決定時，用中括號包住運算式：",[22,19609,19611],{"className":24,"code":19610,"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,19612,19613,19631,19642,19658,19662,19669,19673,19677,19697],{"__ignoreMap":27},[32,19614,19615,19617,19620,19622,19624,19626,19629],{"class":34,"line":35},[32,19616,665],{"class":38},[32,19618,19619],{"class":217}," createObject",[32,19621,477],{"class":41},[32,19623,16322],{"class":903},[32,19625,635],{"class":41},[32,19627,19628],{"class":903},"value",[32,19630,520],{"class":41},[32,19632,19633,19635,19638,19640],{"class":34,"line":45},[32,19634,4157],{"class":38},[32,19636,19637],{"class":351}," obj",[32,19639,894],{"class":38},[32,19641,703],{"class":41},[32,19643,19644,19647,19649,19652,19655],{"class":34,"line":51},[32,19645,19646],{"class":41},"    [key ",[32,19648,224],{"class":38},[32,19650,19651],{"class":175}," '1'",[32,19653,19654],{"class":41},"]: value, ",[32,19656,19657],{"class":608},"\u002F\u002F 動態決定屬性名稱\n",[32,19659,19660],{"class":34,"line":90},[32,19661,1007],{"class":41},[32,19663,19664,19666],{"class":34,"line":99},[32,19665,11115],{"class":38},[32,19667,19668],{"class":41}," obj;\n",[32,19670,19671],{"class":34,"line":106},[32,19672,54],{"class":41},[32,19674,19675],{"class":34,"line":114},[32,19676,103],{"emptyLinePlaceholder":102},[32,19678,19679,19682,19684,19687,19689,19692,19694],{"class":34,"line":120},[32,19680,19681],{"class":217},"createObject",[32,19683,477],{"class":41},[32,19685,19686],{"class":175},"'name'",[32,19688,635],{"class":41},[32,19690,19691],{"class":175},"'John'",[32,19693,18683],{"class":41},[32,19695,19696],{"class":608},"\u002F\u002F { name1: 'John' }\n",[32,19698,19699,19701,19703,19706,19708,19710,19712],{"class":34,"line":127},[32,19700,19681],{"class":217},[32,19702,477],{"class":41},[32,19704,19705],{"class":175},"'legs'",[32,19707,635],{"class":41},[32,19709,13619],{"class":351},[32,19711,18683],{"class":41},[32,19713,19714],{"class":608},"\u002F\u002F { legs1: 4 }\n",[151,19716,19718],{"id":19717},"函式縮寫method-shorthand","函式縮寫（Method Shorthand）",[11,19720,19721,19722,5240],{},"物件裡的方法不用再寫 ",[29,19723,19724],{},"key: function () {}",[22,19726,19728],{"className":24,"code":19727,"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,19729,19730,19734,19745,19754,19766,19770,19774,19779,19789,19797,19804],{"__ignoreMap":27},[32,19731,19732],{"class":34,"line":35},[32,19733,19523],{"class":608},[32,19735,19736,19738,19741,19743],{"class":34,"line":45},[32,19737,6617],{"class":38},[32,19739,19740],{"class":351}," options",[32,19742,894],{"class":38},[32,19744,703],{"class":41},[32,19746,19747,19749,19752],{"class":34,"line":51},[32,19748,11580],{"class":41},[32,19750,19751],{"class":175},"'Options'",[32,19753,547],{"class":41},[32,19755,19756,19759,19761,19763],{"class":34,"line":90},[32,19757,19758],{"class":217},"  created",[32,19760,5269],{"class":41},[32,19762,665],{"class":38},[32,19764,19765],{"class":41}," () {},\n",[32,19767,19768],{"class":34,"line":99},[32,19769,7189],{"class":41},[32,19771,19772],{"class":34,"line":106},[32,19773,103],{"emptyLinePlaceholder":102},[32,19775,19776],{"class":34,"line":114},[32,19777,19778],{"class":608},"\u002F\u002F ES6 縮寫\n",[32,19780,19781,19783,19785,19787],{"class":34,"line":120},[32,19782,6617],{"class":38},[32,19784,19740],{"class":351},[32,19786,894],{"class":38},[32,19788,703],{"class":41},[32,19790,19791,19793,19795],{"class":34,"line":127},[32,19792,11580],{"class":41},[32,19794,19751],{"class":175},[32,19796,547],{"class":41},[32,19798,19799,19801],{"class":34,"line":132},[32,19800,19758],{"class":217},[32,19802,19803],{"class":41},"() {},\n",[32,19805,19806],{"class":34,"line":141},[32,19807,7189],{"class":41},[15,19809,19810],{"id":19810},"現在還適用嗎",[11,19812,19813,19816,19817,19820,19821,19823],{},[12390,19814,19815],{},"原型鏈這套底層機制到現在完全沒變","，",[29,19818,19819],{},"class"," 語法（ES6 就有）背後運作的原理就是這篇整理的 ",[29,19822,1585],{}," 鏈接，不是另一套全新的東西。物件縮寫、計算屬性、函式縮寫這幾個 ES6 寫法現在也還是日常寫法，沒有過時。",[11,19825,19826,19827,19830,19831,19833,19834,19836,19837,19840],{},"真正變的是",[12390,19828,19829],{},"手刻繼承這件事的人","——現在幾乎沒有人會再手寫 ",[29,19832,19123],{}," 加修正 ",[29,19835,19035],{}," 這三步驟，",[29,19838,19839],{},"class extends"," 把這一整套樣板程式碼包裝起來，寫法更接近其他物件導向語言、也更不容易漏掉某一步。整理在《ES6 Class：prototype 繼承的語法糖》。",[15,19842,4536],{"id":4536},[4538,19844,19845,19852],{},[4541,19846,19847],{},[412,19848,19851],{"href":19849,"rel":19850},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FInheritance_and_the_prototype_chain",[416],"MDN：繼承與原型鏈",[4541,19853,19854],{},[412,19855,19858],{"href":19856,"rel":19857},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FObject\u002Fcreate",[416],"MDN：Object.create()",[368,19860,19861],{},"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":19863},[19864,19865,19866,19867,19872,19873,19878,19879],{"id":18362,"depth":45,"text":18363},{"id":18689,"depth":45,"text":18690},{"id":18713,"depth":45,"text":18714},{"id":18815,"depth":45,"text":18816,"children":19868},[19869,19870,19871],{"id":18837,"depth":51,"text":18838},{"id":18990,"depth":51,"text":18991},{"id":19095,"depth":51,"text":19096},{"id":19148,"depth":45,"text":19149},{"id":19502,"depth":45,"text":19503,"children":19874},[19875,19876,19877],{"id":19509,"depth":51,"text":19510},{"id":19603,"depth":51,"text":19604},{"id":19717,"depth":51,"text":19718},{"id":19810,"depth":45,"text":19810},{"id":4536,"depth":45,"text":4536},"整理 ES5 時代用建構函式加 prototype 手刻物件導向的完整流程——封裝屬性與方法、共用函式為什麼要掛在 prototype 上、以及繼承的三個步驟（call 借用母類別建構子、Object.create 接上原型鏈、修正 constructor 指向），並附上物件縮寫與計算屬性這兩個順便學到的 ES6 寫法。",{},"\u002Fposts\u002Fjs-prototype-inheritance",[],{"title":18334,"description":19880},"posts\u002F20200419.js-prototype-inheritance",[390,19887,1585],"物件導向","YlE4DvcjxvlL7lQMA3S2mawqW6Xv-dg5rdl6ECp0ezQ",{"id":19890,"title":19891,"body":19892,"category":4012,"description":20281,"draft":380,"extension":381,"image":382,"meta":20282,"navigation":102,"path":20283,"publishedAt":20284,"relatedExperiments":20285,"seo":20286,"stem":20287,"tags":20288,"updatedAt":14476,"__hash__":20289},"posts\u002Fposts\u002F20200420.vuex-todos-example.md","Vuex 上課筆記：用一個 todos 範例串起 state、mutation、action",{"type":8,"value":19893,"toc":20278},[19894,19897,19919,19922,20080,20134,20147,20270,20272,20275],[11,19895,19896],{},"上課筆記。Vuex 的四個元素：",[4538,19898,19899,19904,19909,19914],{},[4541,19900,19901],{},[29,19902,19903],{},"state",[4541,19905,19906],{},[29,19907,19908],{},"mutation",[4541,19910,19911],{},[29,19912,19913],{},"getter",[4541,19915,19916],{},[29,19917,19918],{},"action",[11,19920,19921],{},"當時以 todos 做的 store 練習：",[22,19923,19925],{"className":24,"code":19924,"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,19926,19927,19945,19950,19955,19961,19966,19981,19991,19995,20001,20006,20017,20043,20059,20064,20068,20074],{"__ignoreMap":27},[32,19928,19929,19931,19933,19935,19938,19940,19943],{"class":34,"line":35},[32,19930,5038],{"class":38},[32,19932,5041],{"class":38},[32,19934,4165],{"class":38},[32,19936,19937],{"class":41}," Vuex",[32,19939,1278],{"class":5049},[32,19941,19942],{"class":217},"Store",[32,19944,1143],{"class":5049},[32,19946,19947],{"class":34,"line":45},[32,19948,19949],{"class":41},"  state: {\n",[32,19951,19952],{"class":34,"line":51},[32,19953,19954],{"class":41},"    todos: [],\n",[32,19956,19957,19959],{"class":34,"line":90},[32,19958,9758],{"class":41},[32,19960,547],{"class":5049},[32,19962,19963],{"class":34,"line":99},[32,19964,19965],{"class":41},"  mutations: {\n",[32,19967,19968,19971,19973,19975,19977,19979],{"class":34,"line":106},[32,19969,19970],{"class":217},"    setTodos",[32,19972,477],{"class":41},[32,19974,19903],{"class":903},[32,19976,635],{"class":41},[32,19978,19628],{"class":903},[32,19980,520],{"class":41},[32,19982,19983,19986,19988],{"class":34,"line":114},[32,19984,19985],{"class":41},"      state.todos ",[32,19987,172],{"class":38},[32,19989,19990],{"class":41}," value;\n",[32,19992,19993],{"class":34,"line":120},[32,19994,4204],{"class":41},[32,19996,19997,19999],{"class":34,"line":127},[32,19998,9758],{"class":41},[32,20000,547],{"class":5049},[32,20002,20003],{"class":34,"line":132},[32,20004,20005],{"class":41},"  actions: {\n",[32,20007,20008,20011,20013,20015],{"class":34,"line":141},[32,20009,20010],{"class":217},"    loadTodos",[32,20012,477],{"class":41},[32,20014,7449],{"class":903},[32,20016,520],{"class":41},[32,20018,20019,20022,20024,20026,20029,20031,20033,20035,20037,20039,20041],{"class":34,"line":147},[32,20020,20021],{"class":41},"      axios.",[32,20023,8944],{"class":217},[32,20025,477],{"class":41},[32,20027,20028],{"class":175},"\"https:\u002F\u002Fjsonplaceholder.typicode.com\u002Ftodos\"",[32,20030,533],{"class":41},[32,20032,8950],{"class":217},[32,20034,8293],{"class":41},[32,20036,10128],{"class":903},[32,20038,483],{"class":41},[32,20040,5090],{"class":38},[32,20042,703],{"class":41},[32,20044,20045,20048,20051,20053,20056],{"class":34,"line":275},[32,20046,20047],{"class":41},"        context.",[32,20049,20050],{"class":217},"commit",[32,20052,477],{"class":41},[32,20054,20055],{"class":175},"\"setTodos\"",[32,20057,20058],{"class":41},", res.data);\n",[32,20060,20061],{"class":34,"line":282},[32,20062,20063],{"class":41},"      });\n",[32,20065,20066],{"class":34,"line":295},[32,20067,4204],{"class":41},[32,20069,20070,20072],{"class":34,"line":605},[32,20071,9758],{"class":41},[32,20073,547],{"class":5049},[32,20075,20076,20078],{"class":34,"line":612},[32,20077,5117],{"class":5049},[32,20079,96],{"class":41},[22,20081,20083],{"className":24,"code":20082,"language":26,"meta":27,"style":27},"store.dispatch(\"loadTodos\");\nstore.commit(\"setTodos\", [1, 2, 3, 4, 5]);\n",[29,20084,20085,20100],{"__ignoreMap":27},[32,20086,20087,20090,20093,20095,20098],{"class":34,"line":35},[32,20088,20089],{"class":41},"store.",[32,20091,20092],{"class":217},"dispatch",[32,20094,477],{"class":41},[32,20096,20097],{"class":175},"\"loadTodos\"",[32,20099,230],{"class":41},[32,20101,20102,20104,20106,20108,20110,20113,20115,20117,20119,20121,20123,20125,20127,20129,20131],{"class":34,"line":45},[32,20103,20089],{"class":41},[32,20105,20050],{"class":217},[32,20107,477],{"class":41},[32,20109,20055],{"class":175},[32,20111,20112],{"class":41},", [",[32,20114,6544],{"class":351},[32,20116,635],{"class":41},[32,20118,12112],{"class":351},[32,20120,635],{"class":41},[32,20122,13611],{"class":351},[32,20124,635],{"class":41},[32,20126,13619],{"class":351},[32,20128,635],{"class":41},[32,20130,10613],{"class":351},[32,20132,20133],{"class":41},"]);\n",[11,20135,20136,20137,3750,20140,7090,20143,20146],{},"元件裡可以用 ",[29,20138,20139],{},"mapState",[29,20141,20142],{},"mapMutations",[29,20144,20145],{},"mapActions"," 取用：",[22,20148,20150],{"className":24,"code":20149,"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,20151,20152,20166,20170,20178,20183,20199,20205,20213,20224,20230,20234,20246,20258,20264],{"__ignoreMap":27},[32,20153,20154,20156,20159,20161,20164],{"class":34,"line":35},[32,20155,8794],{"class":38},[32,20157,20158],{"class":41}," { mapState, mapMutations, mapActions } ",[32,20160,8850],{"class":38},[32,20162,20163],{"class":175}," \"vuex\"",[32,20165,96],{"class":41},[32,20167,20168],{"class":34,"line":45},[32,20169,103],{"emptyLinePlaceholder":102},[32,20171,20172,20174,20176],{"class":34,"line":51},[32,20173,5038],{"class":38},[32,20175,5041],{"class":38},[32,20177,703],{"class":5049},[32,20179,20180],{"class":34,"line":90},[32,20181,20182],{"class":41},"  computed: {\n",[32,20184,20185,20188,20190,20193,20196],{"class":34,"line":99},[32,20186,20187],{"class":38},"    ...",[32,20189,20139],{"class":217},[32,20191,20192],{"class":41},"([",[32,20194,20195],{"class":175},"\"todos\"",[32,20197,20198],{"class":41},"]),\n",[32,20200,20201,20203],{"class":34,"line":106},[32,20202,9758],{"class":41},[32,20204,547],{"class":5049},[32,20206,20207,20209,20211],{"class":34,"line":114},[32,20208,17343],{"class":217},[32,20210,6075],{"class":5049},[32,20212,5252],{"class":41},[32,20214,20215,20217,20219,20222],{"class":34,"line":120},[32,20216,10114],{"class":351},[32,20218,1278],{"class":41},[32,20220,20221],{"class":217},"loadTodos",[32,20223,687],{"class":41},[32,20225,20226,20228],{"class":34,"line":127},[32,20227,9758],{"class":41},[32,20229,547],{"class":5049},[32,20231,20232],{"class":34,"line":132},[32,20233,17374],{"class":41},[32,20235,20236,20238,20240,20242,20244],{"class":34,"line":141},[32,20237,20187],{"class":38},[32,20239,20142],{"class":217},[32,20241,20192],{"class":41},[32,20243,20055],{"class":175},[32,20245,20198],{"class":41},[32,20247,20248,20250,20252,20254,20256],{"class":34,"line":147},[32,20249,20187],{"class":38},[32,20251,20145],{"class":217},[32,20253,20192],{"class":41},[32,20255,20097],{"class":175},[32,20257,20198],{"class":41},[32,20259,20260,20262],{"class":34,"line":275},[32,20261,9758],{"class":41},[32,20263,547],{"class":5049},[32,20265,20266,20268],{"class":34,"line":282},[32,20267,9765],{"class":5049},[32,20269,96],{"class":41},[15,20271,2004],{"id":2003},[11,20273,20274],{},"原文主要是課堂截圖，整理時只把其中的核心範例轉成文字。這是 Vue 2／Vuex 3 時期的寫法；新專案應依目前使用的 Vue 狀態管理方案調整。",[368,20276,20277],{},"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":20279},[20280],{"id":2003,"depth":45,"text":2004},"上課時以 todos 練習 Vuex state、mutation、action 與 getter 的筆記。",{},"\u002Fposts\u002Fvuex-todos-example","2020-04-20",[],{"title":19891,"description":20281},"posts\u002F20200420.vuex-todos-example",[4844,4113],"kHfrC62F2Q3ZZKDhiUgEjW41PKyS-93pMQylWDN0Tno",{"id":20291,"title":20292,"body":20293,"category":378,"description":20511,"draft":380,"extension":381,"image":382,"meta":20512,"navigation":102,"path":20513,"publishedAt":20514,"relatedExperiments":20515,"seo":20516,"stem":20517,"tags":20518,"updatedAt":17035,"__hash__":20522},"posts\u002Fposts\u002F20200421.threejs-basics.md","Three.js 基礎入門：場景、光源、材質、攝影機",{"type":8,"value":20294,"toc":20508},[20295,20298,20301,20304,20318,20321,20474,20480,20496,20498,20505],[11,20296,20297],{},"這邊是當時的 Three.js 學習筆記。",[11,20299,20300],{},"Three.js 可以先理解成舞台，加上「畫面要怎麼被看到」。它可以搭配 SVG、CSS 或 WebGL 等渲染方式。",[11,20302,20303],{},"基本組成包括：",[4538,20305,20306,20309,20312,20315],{},[4541,20307,20308],{},"場景（scene）",[4541,20310,20311],{},"渲染器（renderer）",[4541,20313,20314],{},"攝影機（camera）",[4541,20316,20317],{},"物件、光源與材質",[11,20319,20320],{},"建立攝影機時，要設定大小、長寬比與其他參數，再設定位置以及要朝哪個方向觀看。",[22,20322,20324],{"className":24,"code":20323,"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,20325,20326,20347,20367,20374,20384,20391,20398,20402,20422,20426,20437,20448,20452,20464],{"__ignoreMap":27},[32,20327,20328,20330,20333,20335,20337,20340,20342,20345],{"class":34,"line":35},[32,20329,166],{"class":38},[32,20331,20332],{"class":41}," scene ",[32,20334,172],{"class":38},[32,20336,4165],{"class":38},[32,20338,20339],{"class":351}," THREE",[32,20341,1278],{"class":41},[32,20343,20344],{"class":217},"Scene",[32,20346,687],{"class":41},[32,20348,20349,20351,20354,20356,20358,20360,20362,20365],{"class":34,"line":45},[32,20350,166],{"class":38},[32,20352,20353],{"class":41}," camera ",[32,20355,172],{"class":38},[32,20357,4165],{"class":38},[32,20359,20339],{"class":351},[32,20361,1278],{"class":41},[32,20363,20364],{"class":217},"PerspectiveCamera",[32,20366,539],{"class":41},[32,20368,20369,20372],{"class":34,"line":51},[32,20370,20371],{"class":351},"  75",[32,20373,547],{"class":41},[32,20375,20376,20379,20381],{"class":34,"line":90},[32,20377,20378],{"class":41},"  window.innerWidth ",[32,20380,1275],{"class":38},[32,20382,20383],{"class":41}," window.innerHeight,\n",[32,20385,20386,20389],{"class":34,"line":99},[32,20387,20388],{"class":351},"  0.1",[32,20390,547],{"class":41},[32,20392,20393,20396],{"class":34,"line":106},[32,20394,20395],{"class":351},"  1000",[32,20397,547],{"class":41},[32,20399,20400],{"class":34,"line":114},[32,20401,230],{"class":41},[32,20403,20404,20406,20409,20411,20413,20415,20417,20420],{"class":34,"line":120},[32,20405,166],{"class":38},[32,20407,20408],{"class":41}," renderer ",[32,20410,172],{"class":38},[32,20412,4165],{"class":38},[32,20414,20339],{"class":351},[32,20416,1278],{"class":41},[32,20418,20419],{"class":217},"WebGLRenderer",[32,20421,687],{"class":41},[32,20423,20424],{"class":34,"line":127},[32,20425,103],{"emptyLinePlaceholder":102},[32,20427,20428,20431,20434],{"class":34,"line":132},[32,20429,20430],{"class":41},"renderer.",[32,20432,20433],{"class":217},"setSize",[32,20435,20436],{"class":41},"(window.innerWidth, window.innerHeight);\n",[32,20438,20439,20442,20445],{"class":34,"line":141},[32,20440,20441],{"class":41},"document.body.",[32,20443,20444],{"class":217},"appendChild",[32,20446,20447],{"class":41},"(renderer.domElement);\n",[32,20449,20450],{"class":34,"line":147},[32,20451,103],{"emptyLinePlaceholder":102},[32,20453,20454,20457,20459,20462],{"class":34,"line":275},[32,20455,20456],{"class":41},"camera.position.z ",[32,20458,172],{"class":38},[32,20460,20461],{"class":351}," 5",[32,20463,96],{"class":41},[32,20465,20466,20468,20471],{"class":34,"line":282},[32,20467,20430],{"class":41},[32,20469,20470],{"class":217},"render",[32,20472,20473],{"class":41},"(scene, camera);\n",[11,20475,20476,20479],{},[29,20477,20478],{},"Group"," 是一個空的 3D 群組物件，可以把多個物件放在一起轉動。",[4538,20481,20482,20489],{},[4541,20483,20484],{},[412,20485,20488],{"href":20486,"rel":20487},"https:\u002F\u002Fthreejs.org\u002F",[416],"Three.js 官方網站",[4541,20490,20491],{},[412,20492,20495],{"href":20493,"rel":20494},"https:\u002F\u002Fcodepen.io\u002Frockayumitw\u002Fpen\u002FZEWLWqx?editors=0110",[416],"當時的 CodePen 練習",[15,20497,2004],{"id":2003},[11,20499,20500,20501,20504],{},"範例是 2020 年以全域 ",[29,20502,20503],{},"THREE"," 物件使用的寫法；目前專案通常透過 ESM 匯入套件，API 也應以使用版本的官方文件為準。",[368,20506,20507],{},"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":20509},[20510],{"id":2003,"depth":45,"text":2004},"2020 年學習 Three.js 時，對場景、渲染器、攝影機與物件群組留下的課堂筆記。",{},"\u002Fposts\u002Fthreejs-basics","2020-04-21",[],{"title":20292,"description":20511},"posts\u002F20200421.threejs-basics",[20519,20520,20521],"Three.js","WebGL","3D","f0BW46EtSiYh8JCjKXCTtnk5JIEaSYl3eviHH1dTufk",{"id":20524,"title":20525,"body":20526,"category":4012,"description":20791,"draft":380,"extension":381,"image":382,"meta":20792,"navigation":102,"path":20793,"publishedAt":20514,"relatedExperiments":20794,"seo":20795,"stem":20796,"tags":20797,"updatedAt":17035,"__hash__":20798},"posts\u002Fposts\u002F20200421.vuex-syntax-cheatsheet.md","Vuex API 語法速查：安裝、state、mutations、actions、getters、modules",{"type":8,"value":20527,"toc":20786},[20528,20540,20543,20555,20558,20574,20578,20706,20709,20728,20731,20770,20778,20780,20783],[11,20529,20530,20531,20534,20535,3750,20537,20539],{},"元件可以透過 ",[29,20532,20533],{},"$store"," 取用 Vuex，也可以使用 ",[29,20536,20139],{},[29,20538,20145],{}," 等輔助函式。要使用這些方法，必須先在最上層注入 store。",[11,20541,20542],{},"拿到新的專案後，先安裝相依套件：",[22,20544,20546],{"className":2057,"code":20545,"language":2059,"meta":27,"style":27},"npm install\n",[29,20547,20548],{"__ignoreMap":27},[32,20549,20550,20552],{"class":34,"line":35},[32,20551,4625],{"class":2066},[32,20553,20554],{"class":175}," install\n",[11,20556,20557],{},"如果還沒有安裝 Vuex：",[22,20559,20561],{"className":2057,"code":20560,"language":2059,"meta":27,"style":27},"npm install vuex --save\n",[29,20562,20563],{"__ignoreMap":27},[32,20564,20565,20567,20569,20572],{"class":34,"line":35},[32,20566,4625],{"class":2066},[32,20568,4650],{"class":175},[32,20570,20571],{"class":175}," vuex",[32,20573,8638],{"class":351},[15,20575,20577],{"id":20576},"建立-store","建立 store",[22,20579,20581],{"className":24,"code":20580,"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,20582,20583,20588,20601,20614,20618,20626,20630,20646,20653,20657,20673,20678,20683,20687,20693,20700],{"__ignoreMap":27},[32,20584,20585],{"class":34,"line":35},[32,20586,20587],{"class":608},"\u002F\u002F src\u002Fstore\u002Findex.js\n",[32,20589,20590,20592,20594,20596,20599],{"class":34,"line":45},[32,20591,8794],{"class":38},[32,20593,8847],{"class":41},[32,20595,8850],{"class":38},[32,20597,20598],{"class":175}," \"vue\"",[32,20600,96],{"class":41},[32,20602,20603,20605,20608,20610,20612],{"class":34,"line":51},[32,20604,8794],{"class":38},[32,20606,20607],{"class":41}," Vuex ",[32,20609,8850],{"class":38},[32,20611,20163],{"class":175},[32,20613,96],{"class":41},[32,20615,20616],{"class":34,"line":90},[32,20617,103],{"emptyLinePlaceholder":102},[32,20619,20620,20622,20624],{"class":34,"line":99},[32,20621,8892],{"class":41},[32,20623,8895],{"class":217},[32,20625,10244],{"class":41},[32,20627,20628],{"class":34,"line":106},[32,20629,103],{"emptyLinePlaceholder":102},[32,20631,20632,20634,20636,20638,20640,20642,20644],{"class":34,"line":114},[32,20633,5038],{"class":38},[32,20635,5041],{"class":38},[32,20637,4165],{"class":38},[32,20639,19937],{"class":41},[32,20641,1278],{"class":5049},[32,20643,19942],{"class":217},[32,20645,1143],{"class":5049},[32,20647,20648,20651],{"class":34,"line":120},[32,20649,20650],{"class":41},"  state: {}",[32,20652,547],{"class":5049},[32,20654,20655],{"class":34,"line":127},[32,20656,20005],{"class":41},[32,20658,20659,20662,20664,20666,20668,20671],{"class":34,"line":132},[32,20660,20661],{"class":217},"    updateLoading",[32,20663,477],{"class":41},[32,20665,7449],{"class":903},[32,20667,635],{"class":41},[32,20669,20670],{"class":903},"status",[32,20672,520],{"class":41},[32,20674,20675],{"class":34,"line":141},[32,20676,20677],{"class":608},"      \u002F\u002F context 是 Vuex 傳入的內容\n",[32,20679,20680],{"class":34,"line":147},[32,20681,20682],{"class":608},"      \u002F\u002F status 是外部傳入的 payload\n",[32,20684,20685],{"class":34,"line":275},[32,20686,4204],{"class":41},[32,20688,20689,20691],{"class":34,"line":282},[32,20690,9758],{"class":41},[32,20692,547],{"class":5049},[32,20694,20695,20698],{"class":34,"line":295},[32,20696,20697],{"class":41},"  mutations: {}",[32,20699,547],{"class":5049},[32,20701,20702,20704],{"class":34,"line":605},[32,20703,5117],{"class":5049},[32,20705,96],{"class":41},[11,20707,20708],{},"當時的理解是：",[4538,20710,20711,20716,20722],{},[4541,20712,20713,20715],{},[29,20714,19903],{},"：保存狀態",[4541,20717,20718,20721],{},[29,20719,20720],{},"actions","：放實際操作與 AJAX 等非同步行為，不直接修改 state",[4541,20723,20724,20727],{},[29,20725,20726],{},"mutations","：實際修改 state，名稱通常以大寫常數表示",[15,20729,20730],{"id":20730},"注入根元件",[22,20732,20734],{"className":24,"code":20733,"language":26,"meta":27,"style":27},"import store from \".\u002Fstore\";\n\nnew Vue({\n  store,\n});\n",[29,20735,20736,20749,20753,20761,20766],{"__ignoreMap":27},[32,20737,20738,20740,20742,20744,20747],{"class":34,"line":35},[32,20739,8794],{"class":38},[32,20741,10259],{"class":41},[32,20743,8850],{"class":38},[32,20745,20746],{"class":175}," \".\u002Fstore\"",[32,20748,96],{"class":41},[32,20750,20751],{"class":34,"line":45},[32,20752,103],{"emptyLinePlaceholder":102},[32,20754,20755,20757,20759],{"class":34,"line":51},[32,20756,9196],{"class":38},[32,20758,4168],{"class":217},[32,20760,1143],{"class":41},[32,20762,20763],{"class":34,"line":90},[32,20764,20765],{"class":41},"  store,\n",[32,20767,20768],{"class":34,"line":99},[32,20769,792],{"class":41},[11,20771,20772,20773],{},"資料來源：",[412,20774,20777],{"href":20775,"rel":20776},"https:\u002F\u002Fvuex.vuejs.org\u002Fzh\u002Fapi\u002F",[416],"Vuex API（封存文件）",[15,20779,2004],{"id":2003},[11,20781,20782],{},"這是 Vue 2／Vuex 3 時期的速記，原文沒有完整涵蓋標題列出的每個 API。Vuex 仍可維護既有專案，但新專案的安裝與狀態管理方式應依目前框架版本選擇。",[368,20784,20785],{},"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":20787},[20788,20789,20790],{"id":20576,"depth":45,"text":20577},{"id":20730,"depth":45,"text":20730},{"id":2003,"depth":45,"text":2004},"記錄 Vue 2 專案安裝、注入 Vuex，以及 state、actions、mutations 的基本分工。",{},"\u002Fposts\u002Fvuex-syntax-cheatsheet",[],{"title":20525,"description":20791},"posts\u002F20200421.vuex-syntax-cheatsheet",[4844,4113],"rmv4flyoKADRhaK-6yyTEHxrN6QkPG7Gd3FaCAL2ZE4",{"id":20800,"title":20801,"body":20802,"category":378,"description":20880,"draft":380,"extension":381,"image":382,"meta":20881,"navigation":102,"path":20882,"publishedAt":20883,"relatedExperiments":20884,"seo":20885,"stem":20886,"tags":20887,"updatedAt":14476,"__hash__":20888},"posts\u002Fposts\u002F20200429.nuxt-axios-module.md","Nuxt 安裝 @nuxtjs\u002Faxios 模組",{"type":8,"value":20803,"toc":20877},[20804,20807,20821,20828,20859,20861,20874],[11,20805,20806],{},"這邊記錄 Nuxt 2 安裝 axios 模組。",[22,20808,20810],{"className":2057,"code":20809,"language":2059,"meta":27,"style":27},"npm install @nuxtjs\u002Faxios\n",[29,20811,20812],{"__ignoreMap":27},[32,20813,20814,20816,20818],{"class":34,"line":35},[32,20815,4625],{"class":2066},[32,20817,4650],{"class":175},[32,20819,20820],{"class":175}," @nuxtjs\u002Faxios\n",[11,20822,20823,20824,20827],{},"接著在 ",[29,20825,20826],{},"nuxt.config.js"," 註冊：",[22,20829,20831],{"className":24,"code":20830,"language":26,"meta":27,"style":27},"export default {\n  modules: [\"@nuxtjs\u002Faxios\"],\n};\n",[29,20832,20833,20841,20853],{"__ignoreMap":27},[32,20834,20835,20837,20839],{"class":34,"line":35},[32,20836,5038],{"class":38},[32,20838,5041],{"class":38},[32,20840,703],{"class":5049},[32,20842,20843,20846,20849,20851],{"class":34,"line":45},[32,20844,20845],{"class":41},"  modules: [",[32,20847,20848],{"class":175},"\"@nuxtjs\u002Faxios\"",[32,20850,17276],{"class":41},[32,20852,547],{"class":5049},[32,20854,20855,20857],{"class":34,"line":51},[32,20856,9765],{"class":5049},[32,20858,96],{"class":41},[15,20860,2004],{"id":2003},[11,20862,20863,20864,20867,20868,10450,20871,3775],{},"這是 Nuxt 2 的舊模組。",[29,20865,20866],{},"@nuxtjs\u002Faxios"," 已停止維護，Nuxt 3 之後通常改用內建的 ",[29,20869,20870],{},"useFetch()",[29,20872,20873],{},"$fetch()",[368,20875,20876],{},"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":20878},[20879],{"id":2003,"depth":45,"text":2004},"記錄 2020 年在 Nuxt 2 專案安裝並註冊 @nuxtjs\u002Faxios 的方式。",{},"\u002Fposts\u002Fnuxt-axios-module","2020-04-29",[],{"title":20801,"description":20880},"posts\u002F20200429.nuxt-axios-module",[16540,9540],"fAIXo4zAF_lIyN9CXjmGbK9O2PWGsKGY5it8Z9NNWz0",{"id":20890,"title":20891,"body":20892,"category":4012,"description":20916,"draft":380,"extension":381,"image":382,"meta":20917,"navigation":102,"path":20918,"publishedAt":20919,"relatedExperiments":20920,"seo":20921,"stem":20922,"tags":20923,"updatedAt":17035,"__hash__":20925},"posts\u002Fposts\u002F20200430.mock-api-tools.md","練習串接 API 時，沒有現成後端怎麼辦",{"type":8,"value":20893,"toc":20913},[20894,20897,20905,20908,20910],[11,20895,20896],{},"今天想練習介接 API 時，發現課程上老師提供的路徑失效了，頓時間不知道該怎麼辦。",[11,20898,20899,20900,3775],{},"想到之前曾在論壇詢問，很多人提供了 fake JSON API 網站，結果找到一個好工具：",[412,20901,20904],{"href":20902,"rel":20903},"https:\u002F\u002Fmocki.io\u002Ffake-json-api",[416],"Mocki",[11,20906,20907],{},"自己撰寫 JSON 格式，它就會產出一個假的 API 路徑，這下可以繼續練習了。",[15,20909,2004],{"id":2003},[11,20911,20912],{},"這篇只記錄當時解決練習資料來源的過程。第三方測試服務的網址、功能與使用限制可能變動；正式專案不應依賴免費假 API，也不要把私密資料貼進這類服務。",{"title":27,"searchDepth":51,"depth":51,"links":20914},[20915],{"id":2003,"depth":45,"text":2004},"記錄課程 API 失效後，找到 mocki.io 產生假 API 路徑的過程。",{},"\u002Fposts\u002Fmock-api-tools","2020-04-30",[],{"title":20891,"description":20916},"posts\u002F20200430.mock-api-tools",[5687,20924],"練習","Xrbw3RVlsaT-GDjvu3sq_IWLC_WgFkSLOHtJGP-j-ro",{"id":20927,"title":20928,"body":20929,"category":378,"description":21095,"draft":380,"extension":381,"image":382,"meta":21096,"navigation":102,"path":21097,"publishedAt":21098,"relatedExperiments":21099,"seo":21100,"stem":21101,"tags":21102,"updatedAt":17035,"__hash__":21104},"posts\u002Fposts\u002F20200501.bootstrap-vue-table.md","BootstrapVue 表格元件的欄位設定",{"type":8,"value":20930,"toc":21090},[20931,20934,20937,20946,20992,20995,21000,21072,21079,21081,21087],[11,20932,20933],{},"這邊記錄 BootstrapVue 的 Table 調整方式。",[15,20935,20936],{"id":20936},"fields",[11,20938,20939,20941,20942,20945],{},[29,20940,16322],{}," 要與取得資料中的物件欄位一致；",[29,20943,20944],{},"label"," 可以自行命名，會顯示在 table header。",[22,20947,20949],{"className":24,"code":20948,"language":26,"meta":27,"style":27},"fields: [\n  { key: \"name\", label: \"名稱\" },\n  { key: \"price\", label: \"價格\" },\n];\n",[29,20950,20951,20958,20974,20988],{"__ignoreMap":27},[32,20952,20953,20955],{"class":34,"line":35},[32,20954,20936],{"class":2066},[32,20956,20957],{"class":41},": [\n",[32,20959,20960,20963,20966,20969,20972],{"class":34,"line":45},[32,20961,20962],{"class":41},"  { key: ",[32,20964,20965],{"class":175},"\"name\"",[32,20967,20968],{"class":41},", label: ",[32,20970,20971],{"class":175},"\"名稱\"",[32,20973,16188],{"class":41},[32,20975,20976,20978,20981,20983,20986],{"class":34,"line":51},[32,20977,20962],{"class":41},[32,20979,20980],{"class":175},"\"price\"",[32,20982,20968],{"class":41},[32,20984,20985],{"class":175},"\"價格\"",[32,20987,16188],{"class":41},[32,20989,20990],{"class":34,"line":90},[32,20991,8282],{"class":41},[15,20993,20994],{"id":20994},"巢狀資料",[11,20996,20997,20998,5240],{},"如果取得的資料有好幾層，可以在欄位模板裡使用 ",[29,20999,16454],{},[22,21001,21003],{"className":8665,"code":21002,"language":4112,"meta":27,"style":27},"\u003Cb-table :items=\"items\" :fields=\"fields\">\n  \u003Ctemplate #cell(tags)=\"data\">\n    \u003Cspan v-for=\"tag in data.item.tags\" :key=\"tag\">\n      {{ tag }}\n    \u003C\u002Fspan>\n  \u003C\u002Ftemplate>\n\u003C\u002Fb-table>\n",[29,21004,21005,21039,21044,21049,21054,21059,21064],{"__ignoreMap":27},[32,21006,21007,21009,21012,21014,21017,21019,21021,21023,21025,21027,21029,21031,21033,21035,21037],{"class":34,"line":35},[32,21008,4046],{"class":41},[32,21010,21011],{"class":4049},"b-table",[32,21013,361],{"class":41},[32,21015,21016],{"class":4053},"items",[32,21018,172],{"class":41},[32,21020,16306],{"class":16305},[32,21022,21016],{"class":41},[32,21024,16306],{"class":16305},[32,21026,361],{"class":41},[32,21028,20936],{"class":4053},[32,21030,172],{"class":41},[32,21032,16306],{"class":16305},[32,21034,20936],{"class":41},[32,21036,16306],{"class":16305},[32,21038,4062],{"class":41},[32,21040,21041],{"class":34,"line":45},[32,21042,21043],{"class":41},"  \u003Ctemplate #cell(tags)=\"data\">\n",[32,21045,21046],{"class":34,"line":51},[32,21047,21048],{"class":41},"    \u003Cspan v-for=\"tag in data.item.tags\" :key=\"tag\">\n",[32,21050,21051],{"class":34,"line":90},[32,21052,21053],{"class":41},"      {{ tag }}\n",[32,21055,21056],{"class":34,"line":99},[32,21057,21058],{"class":41},"    \u003C\u002Fspan>\n",[32,21060,21061],{"class":34,"line":106},[32,21062,21063],{"class":41},"  \u003C\u002Ftemplate>\n",[32,21065,21066,21068,21070],{"class":34,"line":114},[32,21067,4105],{"class":41},[32,21069,21011],{"class":4049},[32,21071,4062],{"class":41},[11,21073,16416,21074],{},[412,21075,21078],{"href":21076,"rel":21077},"https:\u002F\u002Fbootstrap-vue.org\u002Fdocs\u002Fcomponents\u002Ftable#tables",[416],"BootstrapVue Table",[15,21080,2004],{"id":2003},[11,21082,21083,21084,21086],{},"原文主要以三張截圖記錄 ",[29,21085,20936],{}," 與巢狀資料的用法，整理時改成文字與最小範例。這是 Vue 2 時代的 BootstrapVue API，實作時應以專案實際使用的版本為準。",[368,21088,21089],{},"html pre.shiki code .sYRkA, html code.shiki .sYRkA{--shiki-default:#6F42C1;--shiki-dark:#FFA657}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 .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 .spddc, html code.shiki .spddc{--shiki-default:#032F62;--shiki-dark:#E6EDF3}",{"title":27,"searchDepth":51,"depth":51,"links":21091},[21092,21093,21094],{"id":20936,"depth":45,"text":20936},{"id":20994,"depth":45,"text":20994},{"id":2003,"depth":45,"text":2004},"記錄 BootstrapVue b-table 的 fields、label 與巢狀資料顯示方式。",{},"\u002Fposts\u002Fbootstrap-vue-table","2020-05-01",[],{"title":20928,"description":21095},"posts\u002F20200501.bootstrap-vue-table",[21103,4113],"BootstrapVue","NyZjPh_oPeGLSpfow6T_V7_aNQ64nf1hU1ZtgENj3Nw",{"id":21106,"title":21107,"body":21108,"category":4012,"description":21156,"draft":380,"extension":381,"image":382,"meta":21157,"navigation":102,"path":21158,"publishedAt":21159,"relatedExperiments":21160,"seo":21161,"stem":21162,"tags":21163,"updatedAt":17035,"__hash__":21165},"posts\u002Fposts\u002F20200502.seo-links.md","為什麼 SSR 對 SEO 有幫助",{"type":8,"value":21109,"toc":21153},[21110,21113,21116],[11,21111,21112],{},"這邊記錄一些當時學習 SEO 的資料連結。",[15,21114,21115],{"id":21115},"當時參考的文章",[4538,21117,21118,21125,21132,21139,21146],{},[4541,21119,21120],{},[412,21121,21124],{"href":21122,"rel":21123},"https:\u002F\u002Fwww.seoseo.com.tw\u002Farticle_detail_591.html",[416],"SEO 優化入門",[4541,21126,21127],{},[412,21128,21131],{"href":21129,"rel":21130},"https:\u002F\u002Fwww.yesharris.com\u002Flearning-seo-menu\u002F",[416],"SEO 學習選單",[4541,21133,21134],{},[412,21135,21138],{"href":21136,"rel":21137},"https:\u002F\u002Ftransbiz.com.tw\u002Fseo-guide\u002F",[416],"SEO 教學指南",[4541,21140,21141],{},[412,21142,21145],{"href":21143,"rel":21144},"https:\u002F\u002Fwww.awoo.com.tw\u002Fblog\u002Ftechnical-or-content\u002F",[416],"SEO 應重技術還是內容",[4541,21147,21148],{},[412,21149,21152],{"href":21150,"rel":21151},"https:\u002F\u002Franking.works\u002FSEO%E6%95%99%E5%AD%B8\u002FSEO",[416],"SEO 教學",{"title":27,"searchDepth":51,"depth":51,"links":21154},[21155],{"id":21115,"depth":45,"text":21115},"記錄 2020 年學習 Nuxt SSR 與 SEO 時留下的基本理解和參考資料。",{},"\u002Fposts\u002Fseo-links","2020-05-02",[],{"title":21107,"description":21156},"posts\u002F20200502.seo-links",[21164],"SEO","-I8kAnuX1zFATbhA8bPEcrX2IU9e8XZ7J_69Y0cbTSM",{"id":21167,"title":21168,"body":21169,"category":378,"description":21356,"draft":380,"extension":381,"image":382,"meta":21357,"navigation":102,"path":21358,"publishedAt":21359,"relatedExperiments":21360,"seo":21361,"stem":21362,"tags":21363,"updatedAt":17035,"__hash__":21365},"posts\u002Fposts\u002F20200505.nuxt-dynamic-routing.md","Nuxt 動態路由：程式式與宣告式兩種轉址方式",{"type":8,"value":21170,"toc":21351},[21171,21177,21180,21185,21235,21238,21244,21323,21330,21332,21348],[11,21172,21173,21174,21176],{},"這邊記錄 Nuxt 2 動態路由的使用方式。假設用 ",[29,21175,16454],{}," 跑出一份帶有 ID 的資料，可以用程式式或宣告式寫法轉向對應頁面。",[15,21178,21179],{"id":21179},"程式式",[11,21181,4675,21182,5240],{},[29,21183,21184],{},"this.$router.push()",[22,21186,21188],{"className":24,"code":21187,"language":26,"meta":27,"style":27},"this.$router.push({\n  name: \"courses-course_id-main\",\n  params: { course_id: course.id },\n  query: { lesson_id: lesson.id },\n  hash: \"#ratings\",\n});\n",[29,21189,21190,21202,21211,21216,21221,21231],{"__ignoreMap":27},[32,21191,21192,21194,21197,21200],{"class":34,"line":35},[32,21193,1083],{"class":351},[32,21195,21196],{"class":41},".$router.",[32,21198,21199],{"class":217},"push",[32,21201,1143],{"class":41},[32,21203,21204,21206,21209],{"class":34,"line":45},[32,21205,11580],{"class":41},[32,21207,21208],{"class":175},"\"courses-course_id-main\"",[32,21210,547],{"class":41},[32,21212,21213],{"class":34,"line":51},[32,21214,21215],{"class":41},"  params: { course_id: course.id },\n",[32,21217,21218],{"class":34,"line":90},[32,21219,21220],{"class":41},"  query: { lesson_id: lesson.id },\n",[32,21222,21223,21226,21229],{"class":34,"line":99},[32,21224,21225],{"class":41},"  hash: ",[32,21227,21228],{"class":175},"\"#ratings\"",[32,21230,547],{"class":41},[32,21232,21233],{"class":34,"line":106},[32,21234,792],{"class":41},[15,21236,21237],{"id":21237},"宣告式",[11,21239,21240,21241,5240],{},"取得 ID 與參數後，使用 ",[29,21242,21243],{},"nuxt-link",[22,21245,21247],{"className":8665,"code":21246,"language":4112,"meta":27,"style":27},"\u003Cnuxt-link\n  :to=\"{\n    name: 'courses-course_id-main',\n    params: { course_id: course.id },\n    query: { lesson_id: lesson.id },\n    hash: '#ratings',\n  }\"\n>\n  test\n\u003C\u002Fnuxt-link>\n",[29,21248,21249,21256,21269,21279,21284,21289,21299,21306,21310,21315],{"__ignoreMap":27},[32,21250,21251,21253],{"class":34,"line":35},[32,21252,4046],{"class":41},[32,21254,21255],{"class":4049},"nuxt-link\n",[32,21257,21258,21261,21263,21265,21267],{"class":34,"line":45},[32,21259,21260],{"class":41},"  :",[32,21262,6416],{"class":4053},[32,21264,172],{"class":41},[32,21266,16306],{"class":16305},[32,21268,5252],{"class":41},[32,21270,21271,21274,21277],{"class":34,"line":51},[32,21272,21273],{"class":41},"    name: ",[32,21275,21276],{"class":175},"'courses-course_id-main'",[32,21278,547],{"class":41},[32,21280,21281],{"class":34,"line":90},[32,21282,21283],{"class":41},"    params: { course_id: course.id },\n",[32,21285,21286],{"class":34,"line":99},[32,21287,21288],{"class":41},"    query: { lesson_id: lesson.id },\n",[32,21290,21291,21294,21297],{"class":34,"line":106},[32,21292,21293],{"class":41},"    hash: ",[32,21295,21296],{"class":175},"'#ratings'",[32,21298,547],{"class":41},[32,21300,21301,21303],{"class":34,"line":114},[32,21302,9758],{"class":41},[32,21304,21305],{"class":16305},"\"\n",[32,21307,21308],{"class":34,"line":120},[32,21309,4062],{"class":41},[32,21311,21312],{"class":34,"line":127},[32,21313,21314],{"class":41},"  test\n",[32,21316,21317,21319,21321],{"class":34,"line":132},[32,21318,4105],{"class":41},[32,21320,21243],{"class":4049},[32,21322,4062],{"class":41},[11,21324,21325,21326,21329],{},"其中 ",[29,21327,21328],{},"hash"," 可以作為錨點使用。",[15,21331,2004],{"id":2003},[11,21333,21334,21335,21338,21339,11762,21342,11762,21345,21347],{},"這是 Nuxt 2 的命名路由與元件寫法。Nuxt 3 使用 ",[29,21336,21337],{},"\u003CNuxtLink>"," 與 Vue Router 4；程式式、宣告式導航以及 ",[29,21340,21341],{},"params",[29,21343,21344],{},"query",[29,21346,21328],{}," 的概念仍在，但自動產生的路由名稱要以目前專案為準。",[368,21349,21350],{},"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 .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}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}",{"title":27,"searchDepth":51,"depth":51,"links":21352},[21353,21354,21355],{"id":21179,"depth":45,"text":21179},{"id":21237,"depth":45,"text":21237},{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 以 this.$router.push 與 nuxt-link 前往動態路由的兩種寫法。",{},"\u002Fposts\u002Fnuxt-dynamic-routing","2020-05-05",[],{"title":21168,"description":21356},"posts\u002F20200505.nuxt-dynamic-routing",[16540,21364],"路由","rLtivGENSgqWL-A-rHfsHuoEn2bnnbQ3djhioZsxakU",{"id":21367,"title":21368,"body":21369,"category":378,"description":21437,"draft":380,"extension":381,"image":382,"meta":21438,"navigation":102,"path":21439,"publishedAt":21440,"relatedExperiments":21441,"seo":21442,"stem":21443,"tags":21444,"updatedAt":14476,"__hash__":21446},"posts\u002Fposts\u002F20200729.chrome-focus-outline.md","消除 Chrome 按鈕的黑色外框",{"type":8,"value":21370,"toc":21434},[21371,21374,21419,21421,21432],[11,21372,21373],{},"最近 Chrome 更新後，點選按鈕時會出現黑色外框。當時確認加入以下 CSS 後就會消失：",[22,21375,21377],{"className":5412,"code":21376,"language":1140,"meta":27,"style":27},"*,\n*:focus,\n*:hover {\n  outline: none !important;\n}\n",[29,21378,21379,21385,21394,21402,21415],{"__ignoreMap":27},[32,21380,21381,21383],{"class":34,"line":35},[32,21382,6078],{"class":4049},[32,21384,547],{"class":41},[32,21386,21387,21389,21392],{"class":34,"line":45},[32,21388,6078],{"class":4049},[32,21390,21391],{"class":4053},":focus",[32,21393,547],{"class":41},[32,21395,21396,21398,21400],{"class":34,"line":51},[32,21397,6078],{"class":4049},[32,21399,15376],{"class":4053},[32,21401,703],{"class":41},[32,21403,21404,21407,21409,21411,21413],{"class":34,"line":90},[32,21405,21406],{"class":351},"  outline",[32,21408,5269],{"class":41},[32,21410,14826],{"class":351},[32,21412,12027],{"class":38},[32,21414,96],{"class":41},[32,21416,21417],{"class":34,"line":99},[32,21418,54],{"class":41},[15,21420,2004],{"id":2003},[11,21422,21423,21424,21427,21428,21431],{},"這段全域移除 ",[29,21425,21426],{},"outline"," 的做法不應沿用。外框是鍵盤操作的重要焦點提示；若要調整外觀，應保留清楚可辨認的 ",[29,21429,21430],{},":focus-visible"," 樣式，而不是把所有元素的焦點指示全部關掉。",[368,21433,12771],{},{"title":27,"searchDepth":51,"depth":51,"links":21435},[21436],{"id":2003,"depth":45,"text":2004},"記錄 Chrome 更新後，當時用全域 outline none 移除按鈕焦點外框的寫法。",{},"\u002Fposts\u002Fchrome-focus-outline","2020-07-29",[],{"title":21368,"description":21437},"posts\u002F20200729.chrome-focus-outline",[1757,21445],"Chrome","Qu8MDMfEuWxGqI3dsyfYBU45VG9icLrAPfxQqM14e1Y",{"id":21448,"title":21449,"body":21450,"category":378,"description":22139,"draft":380,"extension":381,"image":382,"meta":22140,"navigation":102,"path":22141,"publishedAt":22142,"relatedExperiments":22143,"seo":22144,"stem":22145,"tags":22146,"updatedAt":14476,"__hash__":22147},"posts\u002Fposts\u002F20200820.js-array-methods.md","JavaScript 陣列方法整理：forEach、map、filter、find、some、every、sort、reduce",{"type":8,"value":21451,"toc":22120},[21452,21459,21470,21512,21519,21529,21610,21613,21660,21666,21679,21723,21730,21735,21824,21831,21880,21887,21936,21942,22017,22023,22026,22106,22108,22117],[15,21453,21455,21458],{"id":21454},"foreach對每個元素執行動作",[29,21456,21457],{},"forEach()","：對每個元素執行動作",[4538,21460,21461,21464,21467],{},[4541,21462,21463],{},"將陣列元素逐一帶入函式",[4541,21465,21466],{},"不會產生新的陣列",[4541,21468,21469],{},"如果元素是物件，可以在函式裡修改物件內容",[22,21471,21473],{"className":24,"code":21472,"language":26,"meta":27,"style":27},"books.forEach(function (book) {\n  book.total = book.discount * book.price;\n});\n",[29,21474,21475,21493,21508],{"__ignoreMap":27},[32,21476,21477,21480,21482,21484,21486,21488,21491],{"class":34,"line":35},[32,21478,21479],{"class":41},"books.",[32,21481,8290],{"class":217},[32,21483,477],{"class":41},[32,21485,665],{"class":38},[32,21487,900],{"class":41},[32,21489,21490],{"class":903},"book",[32,21492,520],{"class":41},[32,21494,21495,21498,21500,21503,21505],{"class":34,"line":45},[32,21496,21497],{"class":41},"  book.total ",[32,21499,172],{"class":38},[32,21501,21502],{"class":41}," book.discount ",[32,21504,6078],{"class":38},[32,21506,21507],{"class":41}," book.price;\n",[32,21509,21510],{"class":34,"line":51},[32,21511,792],{"class":41},[15,21513,21515,21518],{"id":21514},"map把執行結果存到新陣列",[29,21516,21517],{},"map()","：把執行結果存到新陣列",[4538,21520,21521,21523,21526],{},[4541,21522,21463],{},[4541,21524,21525],{},"將回傳結果組成另一個陣列",[4541,21527,21528],{},"常用於抽取或轉換必要資訊",[22,21530,21532],{"className":24,"code":21531,"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,21533,21534,21569,21594,21606],{"__ignoreMap":27},[32,21535,21536,21538,21541,21543,21545,21547,21549,21551,21553,21555,21557,21559,21561,21563,21565,21567],{"class":34,"line":35},[32,21537,166],{"class":38},[32,21539,21540],{"class":41}," numbers ",[32,21542,172],{"class":38},[32,21544,8261],{"class":41},[32,21546,6544],{"class":351},[32,21548,635],{"class":41},[32,21550,12112],{"class":351},[32,21552,635],{"class":41},[32,21554,13611],{"class":351},[32,21556,635],{"class":41},[32,21558,13619],{"class":351},[32,21560,635],{"class":41},[32,21562,10613],{"class":351},[32,21564,635],{"class":41},[32,21566,13634],{"class":351},[32,21568,8282],{"class":41},[32,21570,21571,21573,21576,21578,21581,21583,21585,21587,21589,21592],{"class":34,"line":45},[32,21572,166],{"class":38},[32,21574,21575],{"class":41}," squared ",[32,21577,172],{"class":38},[32,21579,21580],{"class":41}," numbers.",[32,21582,11271],{"class":217},[32,21584,477],{"class":41},[32,21586,665],{"class":38},[32,21588,900],{"class":41},[32,21590,21591],{"class":903},"number",[32,21593,520],{"class":41},[32,21595,21596,21598,21601,21603],{"class":34,"line":51},[32,21597,11115],{"class":38},[32,21599,21600],{"class":41}," number ",[32,21602,6078],{"class":38},[32,21604,21605],{"class":41}," number;\n",[32,21607,21608],{"class":34,"line":90},[32,21609,792],{"class":41},[11,21611,21612],{},"物件轉換範例：",[22,21614,21616],{"className":24,"code":21615,"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,21617,21618,21631,21637,21642,21652,21656],{"__ignoreMap":27},[32,21619,21620,21622,21625,21627,21629],{"class":34,"line":35},[32,21621,665],{"class":38},[32,21623,21624],{"class":217}," convert",[32,21626,477],{"class":41},[32,21628,8296],{"class":903},[32,21630,520],{"class":41},[32,21632,21633,21635],{"class":34,"line":45},[32,21634,11115],{"class":38},[32,21636,703],{"class":41},[32,21638,21639],{"class":34,"line":51},[32,21640,21641],{"class":41},"    name: obj.name,\n",[32,21643,21644,21647,21649],{"class":34,"line":90},[32,21645,21646],{"class":41},"    total: obj.price ",[32,21648,6078],{"class":38},[32,21650,21651],{"class":41}," obj.discount,\n",[32,21653,21654],{"class":34,"line":99},[32,21655,1007],{"class":41},[32,21657,21658],{"class":34,"line":106},[32,21659,54],{"class":41},[15,21661,21663,21665],{"id":21662},"filter留下符合條件的元素",[29,21664,17920],{},"：留下符合條件的元素",[4538,21667,21668,21676],{},[4541,21669,21670,21671,11762,21673,21675],{},"依函式回傳的 ",[29,21672,6206],{},[29,21674,9746],{}," 決定是否保留",[4541,21677,21678],{},"回傳新的陣列",[22,21680,21682],{"className":24,"code":21681,"language":26,"meta":27,"style":27},"var result = numbers.filter(function (number) {\n  return number > 3;\n});\n",[29,21683,21684,21706,21719],{"__ignoreMap":27},[32,21685,21686,21688,21690,21692,21694,21696,21698,21700,21702,21704],{"class":34,"line":35},[32,21687,166],{"class":38},[32,21689,340],{"class":41},[32,21691,172],{"class":38},[32,21693,21580],{"class":41},[32,21695,17883],{"class":217},[32,21697,477],{"class":41},[32,21699,665],{"class":38},[32,21701,900],{"class":41},[32,21703,21591],{"class":903},[32,21705,520],{"class":41},[32,21707,21708,21710,21712,21714,21717],{"class":34,"line":45},[32,21709,11115],{"class":38},[32,21711,21600],{"class":41},[32,21713,1615],{"class":38},[32,21715,21716],{"class":351}," 3",[32,21718,96],{"class":41},[32,21720,21721],{"class":34,"line":51},[32,21722,792],{"class":41},[15,21724,21726,21729],{"id":21725},"find找到第一個符合條件的元素",[29,21727,21728],{},"find()","：找到第一個符合條件的元素",[4538,21731,21732],{},[4541,21733,21734],{},"回傳第一個符合條件的元素，不是陣列",[22,21736,21738],{"className":24,"code":21737,"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,21739,21740,21771,21796,21820],{"__ignoreMap":27},[32,21741,21742,21744,21747,21749,21751,21754,21756,21759,21761,21764,21766,21769],{"class":34,"line":35},[32,21743,166],{"class":38},[32,21745,21746],{"class":41}," dnaList ",[32,21748,172],{"class":38},[32,21750,8261],{"class":41},[32,21752,21753],{"class":175},"\"ATC\"",[32,21755,635],{"class":41},[32,21757,21758],{"class":175},"\"AGC\"",[32,21760,635],{"class":41},[32,21762,21763],{"class":175},"\"AAA\"",[32,21765,635],{"class":41},[32,21767,21768],{"class":175},"\"TTG\"",[32,21770,8282],{"class":41},[32,21772,21773,21775,21777,21779,21782,21785,21787,21789,21791,21794],{"class":34,"line":45},[32,21774,166],{"class":38},[32,21776,340],{"class":41},[32,21778,172],{"class":38},[32,21780,21781],{"class":41}," dnaList.",[32,21783,21784],{"class":217},"find",[32,21786,477],{"class":41},[32,21788,665],{"class":38},[32,21790,900],{"class":41},[32,21792,21793],{"class":903},"dna",[32,21795,520],{"class":41},[32,21797,21798,21800,21803,21805,21807,21810,21812,21814,21816,21818],{"class":34,"line":51},[32,21799,11115],{"class":38},[32,21801,21802],{"class":41}," dna.",[32,21804,1106],{"class":217},[32,21806,477],{"class":41},[32,21808,21809],{"class":175},"\"TG\"",[32,21811,483],{"class":41},[32,21813,1615],{"class":38},[32,21815,1119],{"class":38},[32,21817,6544],{"class":351},[32,21819,96],{"class":41},[32,21821,21822],{"class":34,"line":90},[32,21823,792],{"class":41},[15,21825,21827,21830],{"id":21826},"some是否有元素符合條件",[29,21828,21829],{},"some()","：是否有元素符合條件",[22,21832,21834],{"className":24,"code":21833,"language":26,"meta":27,"style":27},"var hasEven = numbers.some(function (number) {\n  return number % 2 === 0;\n});\n",[29,21835,21836,21860,21876],{"__ignoreMap":27},[32,21837,21838,21840,21843,21845,21847,21850,21852,21854,21856,21858],{"class":34,"line":35},[32,21839,166],{"class":38},[32,21841,21842],{"class":41}," hasEven ",[32,21844,172],{"class":38},[32,21846,21580],{"class":41},[32,21848,21849],{"class":217},"some",[32,21851,477],{"class":41},[32,21853,665],{"class":38},[32,21855,900],{"class":41},[32,21857,21591],{"class":903},[32,21859,520],{"class":41},[32,21861,21862,21864,21866,21868,21870,21872,21874],{"class":34,"line":45},[32,21863,11115],{"class":38},[32,21865,21600],{"class":41},[32,21867,14333],{"class":38},[32,21869,11123],{"class":351},[32,21871,994],{"class":38},[32,21873,1523],{"class":351},[32,21875,96],{"class":41},[32,21877,21878],{"class":34,"line":51},[32,21879,792],{"class":41},[15,21881,21883,21886],{"id":21882},"every是否所有元素都符合條件",[29,21884,21885],{},"every()","：是否所有元素都符合條件",[22,21888,21890],{"className":24,"code":21889,"language":26,"meta":27,"style":27},"var allEven = numbers.every(function (number) {\n  return number % 2 === 0;\n});\n",[29,21891,21892,21916,21932],{"__ignoreMap":27},[32,21893,21894,21896,21899,21901,21903,21906,21908,21910,21912,21914],{"class":34,"line":35},[32,21895,166],{"class":38},[32,21897,21898],{"class":41}," allEven ",[32,21900,172],{"class":38},[32,21902,21580],{"class":41},[32,21904,21905],{"class":217},"every",[32,21907,477],{"class":41},[32,21909,665],{"class":38},[32,21911,900],{"class":41},[32,21913,21591],{"class":903},[32,21915,520],{"class":41},[32,21917,21918,21920,21922,21924,21926,21928,21930],{"class":34,"line":45},[32,21919,11115],{"class":38},[32,21921,21600],{"class":41},[32,21923,14333],{"class":38},[32,21925,11123],{"class":351},[32,21927,994],{"class":38},[32,21929,1523],{"class":351},[32,21931,96],{"class":41},[32,21933,21934],{"class":34,"line":51},[32,21935,792],{"class":41},[15,21937,21939,21941],{"id":21938},"sort依比較函式排序",[29,21940,17916],{},"：依比較函式排序",[22,21943,21945],{"className":24,"code":21944,"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,21946,21947,21976,21980,22001,22013],{"__ignoreMap":27},[32,21948,21949,21951,21954,21956,21959,21962,21965,21968,21970,21973],{"class":34,"line":35},[32,21950,166],{"class":38},[32,21952,21953],{"class":41}," members ",[32,21955,172],{"class":38},[32,21957,21958],{"class":41}," [{ year: ",[32,21960,21961],{"class":351},"27",[32,21963,21964],{"class":41}," }, { year: ",[32,21966,21967],{"class":351},"14",[32,21969,21964],{"class":41},[32,21971,21972],{"class":351},"50",[32,21974,21975],{"class":41}," }];\n",[32,21977,21978],{"class":34,"line":45},[32,21979,103],{"emptyLinePlaceholder":102},[32,21981,21982,21985,21987,21989,21991,21993,21995,21997,21999],{"class":34,"line":51},[32,21983,21984],{"class":41},"members.",[32,21986,17839],{"class":217},[32,21988,477],{"class":41},[32,21990,665],{"class":38},[32,21992,900],{"class":41},[32,21994,412],{"class":903},[32,21996,635],{"class":41},[32,21998,17848],{"class":903},[32,22000,520],{"class":41},[32,22002,22003,22005,22008,22010],{"class":34,"line":90},[32,22004,11115],{"class":38},[32,22006,22007],{"class":41}," a.year ",[32,22009,6628],{"class":38},[32,22011,22012],{"class":41}," b.year;\n",[32,22014,22015],{"class":34,"line":99},[32,22016,792],{"class":41},[15,22018,22020,22022],{"id":22019},"reduce依規則縮減陣列",[29,22021,10928],{},"：依規則縮減陣列",[11,22024,22025],{},"每次取出一個值，和暫存結果一起運算；可以用在加總、分類或組合字串。",[22,22027,22029],{"className":24,"code":22028,"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,22030,22031,22056,22086,22097],{"__ignoreMap":27},[32,22032,22033,22035,22038,22040,22043,22045,22048,22050,22052,22054],{"class":34,"line":35},[32,22034,166],{"class":38},[32,22036,22037],{"class":41}," books ",[32,22039,172],{"class":38},[32,22041,22042],{"class":41}," [{ price: ",[32,22044,11370],{"class":351},[32,22046,22047],{"class":41}," }, { price: ",[32,22049,14812],{"class":351},[32,22051,22047],{"class":41},[32,22053,19451],{"class":351},[32,22055,21975],{"class":41},[32,22057,22058,22060,22063,22065,22068,22071,22073,22075,22077,22080,22082,22084],{"class":34,"line":45},[32,22059,166],{"class":38},[32,22061,22062],{"class":41}," total ",[32,22064,172],{"class":38},[32,22066,22067],{"class":41}," books.",[32,22069,22070],{"class":217},"reduce",[32,22072,477],{"class":41},[32,22074,665],{"class":38},[32,22076,900],{"class":41},[32,22078,22079],{"class":903},"sum",[32,22081,635],{"class":41},[32,22083,21490],{"class":903},[32,22085,520],{"class":41},[32,22087,22088,22090,22093,22095],{"class":34,"line":51},[32,22089,11115],{"class":38},[32,22091,22092],{"class":41}," sum ",[32,22094,224],{"class":38},[32,22096,21507],{"class":41},[32,22098,22099,22102,22104],{"class":34,"line":90},[32,22100,22101],{"class":41},"}, ",[32,22103,12022],{"class":351},[32,22105,230],{"class":41},[15,22107,2004],{"id":2003},[11,22109,22110,22111,22113,22114,22116],{},"原筆記中的 ",[29,22112,17916],{}," 比較函式回傳布林值，這不符合比較函式應回傳負數、零或正數的規則，整理時改成數值相減。",[29,22115,17916],{}," 會直接改變原陣列；其餘方法是否改到原資料，也取決於 callback 裡有沒有修改物件。",[368,22118,22119],{},"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":22121},[22122,22124,22126,22128,22130,22132,22134,22136,22138],{"id":21454,"depth":45,"text":22123},"forEach()：對每個元素執行動作",{"id":21514,"depth":45,"text":22125},"map()：把執行結果存到新陣列",{"id":21662,"depth":45,"text":22127},"filter()：留下符合條件的元素",{"id":21725,"depth":45,"text":22129},"find()：找到第一個符合條件的元素",{"id":21826,"depth":45,"text":22131},"some()：是否有元素符合條件",{"id":21882,"depth":45,"text":22133},"every()：是否所有元素都符合條件",{"id":21938,"depth":45,"text":22135},"sort()：依比較函式排序",{"id":22019,"depth":45,"text":22137},"reduce()：依規則縮減陣列",{"id":2003,"depth":45,"text":2004},"整理 2020 年學習的八個 JavaScript 陣列方法及簡短範例。",{},"\u002Fposts\u002Fjs-array-methods","2020-08-20",[],{"title":21449,"description":22139},"posts\u002F20200820.js-array-methods",[390,17943],"_ldSkMazg7nH74MRxLeV_Iz3PV2tNbCNe_Pp9O_RDpQ",{"id":22149,"title":22150,"body":22151,"category":4012,"description":22452,"draft":380,"extension":381,"image":382,"meta":22453,"navigation":102,"path":22454,"publishedAt":22455,"relatedExperiments":22456,"seo":22457,"stem":22458,"tags":22459,"updatedAt":14476,"__hash__":22462},"posts\u002Fposts\u002F20200827.http-status-codes.md","HTTP 狀態碼整理：開發時真正會用到的那幾個",{"type":8,"value":22152,"toc":22443},[22153,22160,22164,22178,22182,22232,22236,22280,22284,22370,22374,22412,22415,22431,22433],[11,22154,22155,22156,22159],{},"狀態碼要熟悉。當時先記下 ",[29,22157,22158],{},"302"," 可以用在重新導向，例如 HTTP 轉到 HTTPS，並整理 HTTP 狀態碼的五大分類。",[15,22161,22163],{"id":22162},"_1xx參考資訊","1xx：參考資訊",[4538,22165,22166,22172],{},[4541,22167,22168,22171],{},[29,22169,22170],{},"100 Continue","：繼續",[4541,22173,22174,22177],{},[29,22175,22176],{},"101 Switching Protocols","：切換通訊協定",[15,22179,22181],{"id":22180},"_2xx成功","2xx：成功",[4538,22183,22184,22190,22196,22202,22208,22214,22220,22226],{},[4541,22185,22186,22189],{},[29,22187,22188],{},"200 OK","：請求成功",[4541,22191,22192,22195],{},[29,22193,22194],{},"201 Created","：已建立",[4541,22197,22198,22201],{},[29,22199,22200],{},"202 Accepted","：已接受",[4541,22203,22204,22207],{},[29,22205,22206],{},"203 Non-Authoritative Information","：非授權資訊",[4541,22209,22210,22213],{},[29,22211,22212],{},"204 No Content","：無內容",[4541,22215,22216,22219],{},[29,22217,22218],{},"205 Reset Content","：重設內容",[4541,22221,22222,22225],{},[29,22223,22224],{},"206 Partial Content","：部分內容",[4541,22227,22228,22231],{},[29,22229,22230],{},"207 Multi-Status","：多重狀態（WebDAV）",[15,22233,22235],{"id":22234},"_3xx重新導向","3xx：重新導向",[4538,22237,22238,22244,22250,22256,22262,22268,22274],{},[4541,22239,22240,22243],{},[29,22241,22242],{},"301 Moved Permanently","：資源永久改變網址",[4541,22245,22246,22249],{},[29,22247,22248],{},"302 Found","：資源暫時位於不同網址",[4541,22251,22252,22255],{},[29,22253,22254],{},"303 See Other","：改到另一個網址查看結果，常見於 POST 後改用 GET",[4541,22257,22258,22261],{},[29,22259,22260],{},"304 Not Modified","：內容未變更，可使用本機快取",[4541,22263,22264,22267],{},[29,22265,22266],{},"305 Use Proxy","：需透過指定 Proxy",[4541,22269,22270,22273],{},[29,22271,22272],{},"306","：未使用",[4541,22275,22276,22279],{},[29,22277,22278],{},"307 Temporary Redirect","：暫時重新導向",[15,22281,22283],{"id":22282},"_4xx用戶端錯誤","4xx：用戶端錯誤",[4538,22285,22286,22292,22298,22304,22310,22316,22322,22328,22334,22340,22346,22352,22358,22364],{},[4541,22287,22288,22291],{},[29,22289,22290],{},"400 Bad Request","：錯誤的請求",[4541,22293,22294,22297],{},[29,22295,22296],{},"401 Unauthorized","：需要驗證",[4541,22299,22300,22303],{},[29,22301,22302],{},"403 Forbidden","：禁止存取",[4541,22305,22306,22309],{},[29,22307,22308],{},"404 Not Found","：找不到資源",[4541,22311,22312,22315],{},[29,22313,22314],{},"405 Method Not Allowed","：不允許使用這個 HTTP 方法",[4541,22317,22318,22321],{},[29,22319,22320],{},"406 Not Acceptable","：無法提供用戶端接受的內容",[4541,22323,22324,22327],{},[29,22325,22326],{},"407 Proxy Authentication Required","：需要 Proxy 驗證",[4541,22329,22330,22333],{},[29,22331,22332],{},"412 Precondition Failed","：指定條件失敗",[4541,22335,22336,22339],{},[29,22337,22338],{},"413 Content Too Large","：請求內容太大",[4541,22341,22342,22345],{},[29,22343,22344],{},"414 URI Too Long","：URI 太長",[4541,22347,22348,22351],{},[29,22349,22350],{},"415 Unsupported Media Type","：不支援的媒體類型",[4541,22353,22354,22357],{},[29,22355,22356],{},"416 Range Not Satisfiable","：無法滿足要求的範圍",[4541,22359,22360,22363],{},[29,22361,22362],{},"417 Expectation Failed","：無法滿足 Expect 標頭",[4541,22365,22366,22369],{},[29,22367,22368],{},"423 Locked","：資源已鎖定",[15,22371,22373],{"id":22372},"_5xx伺服器錯誤","5xx：伺服器錯誤",[4538,22375,22376,22382,22388,22394,22400,22406],{},[4541,22377,22378,22381],{},[29,22379,22380],{},"500 Internal Server Error","：內部伺服器錯誤",[4541,22383,22384,22387],{},[29,22385,22386],{},"501 Not Implemented","：伺服器未實作要求的功能",[4541,22389,22390,22393],{},[29,22391,22392],{},"502 Bad Gateway","：閘道或 Proxy 收到無效回應",[4541,22395,22396,22399],{},[29,22397,22398],{},"503 Service Unavailable","：服務無法使用",[4541,22401,22402,22405],{},[29,22403,22404],{},"504 Gateway Timeout","：閘道逾時",[4541,22407,22408,22411],{},[29,22409,22410],{},"505 HTTP Version Not Supported","：不支援的 HTTP 版本",[15,22413,22414],{"id":22414},"當時參考的資料",[4538,22416,22417,22424],{},[4541,22418,22419],{},[412,22420,22423],{"href":22421,"rel":22422},"https:\u002F\u002Fzh.wikipedia.org\u002Fwiki\u002FHTTP%E7%8A%B6%E6%80%81%E7%A0%81",[416],"HTTP 狀態碼",[4541,22425,22426],{},[412,22427,22430],{"href":22428,"rel":22429},"https:\u002F\u002Fblog.miniasp.com\u002Fpost\u002F2009\u002F01\u002F16\u002FWeb-developer-should-know-about-HTTP-Status-Code",[416],"Web 開發人員應了解的 HTTP 狀態碼",[15,22432,2004],{"id":2003},[11,22434,22435,22436,22439,22440,3775],{},"原稿還列了許多舊版 IIS 專屬的子狀態碼；整理時保留通用代碼，IIS 細節應依實際版本文件查詢。狀態碼的正式名稱與語意也應以現行 HTTP 規格為準，例如 ",[29,22437,22438],{},"413"," 現行名稱是 ",[29,22441,22442],{},"Content Too Large",{"title":27,"searchDepth":51,"depth":51,"links":22444},[22445,22446,22447,22448,22449,22450,22451],{"id":22162,"depth":45,"text":22163},{"id":22180,"depth":45,"text":22181},{"id":22234,"depth":45,"text":22235},{"id":22282,"depth":45,"text":22283},{"id":22372,"depth":45,"text":22373},{"id":22414,"depth":45,"text":22414},{"id":2003,"depth":45,"text":2004},"2020 年學習 HTTP 狀態碼時，留下的五大分類與常見代碼筆記。",{},"\u002Fposts\u002Fhttp-status-codes","2020-08-27",[],{"title":22150,"description":22452},"posts\u002F20200827.http-status-codes",[22460,22461],"HTTP","網路","Ctl9Eib9vFTbSutTM5DvSJaUN0L8dCalHextyjIk_dY",{"id":22464,"title":22465,"body":22466,"category":378,"description":22694,"draft":380,"extension":381,"image":382,"meta":22695,"navigation":102,"path":22696,"publishedAt":22455,"relatedExperiments":22697,"seo":22698,"stem":22699,"tags":22700,"updatedAt":14476,"__hash__":22702},"posts\u002Fposts\u002F20200827.nuxt-middleware-auth.md","Nuxt 2 Middleware：進頁面前做登入驗證",{"type":8,"value":22467,"toc":22688},[22468,22471,22474,22478,22484,22587,22590,22655,22658,22660,22676,22678,22685],[11,22469,22470],{},"最近接觸 Nuxt，覺得有點棘手，所以持續記錄 middleware 的使用方式。",[11,22472,22473],{},"Vue 專案可以使用 Vue Router 的導航守衛；Nuxt 則提供 middleware，在使用者進入頁面前先做篩選與必要驗證。",[15,22475,22477],{"id":22476},"新增-middleware","新增 middleware",[11,22479,5134,22480,22483],{},[29,22481,22482],{},"middleware"," 資料夾新增 JavaScript 檔案：",[22,22485,22487],{"className":24,"code":22486,"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,22488,22489,22494,22518,22530,22544,22548,22560,22575,22579,22583],{"__ignoreMap":27},[32,22490,22491],{"class":34,"line":35},[32,22492,22493],{"class":608},"\u002F\u002F middleware\u002Fauth.js\n",[32,22495,22496,22498,22500,22502,22505,22508,22510,22513,22516],{"class":34,"line":45},[32,22497,5038],{"class":38},[32,22499,5041],{"class":38},[32,22501,897],{"class":38},[32,22503,22504],{"class":5049}," ({ ",[32,22506,22507],{"class":903},"route",[32,22509,635],{"class":5049},[32,22511,22512],{"class":903},"redirect",[32,22514,22515],{"class":5049}," }) ",[32,22517,5252],{"class":41},[32,22519,22520,22522,22525,22527],{"class":34,"line":51},[32,22521,1021],{"class":38},[32,22523,22524],{"class":41}," (route.meta[",[32,22526,12022],{"class":351},[32,22528,22529],{"class":41},"].requiresAuth) {\n",[32,22531,22532,22534,22537,22539,22542],{"class":34,"line":90},[32,22533,9409],{"class":38},[32,22535,22536],{"class":351}," isAuthenticated",[32,22538,894],{"class":38},[32,22540,22541],{"class":351}," false",[32,22543,96],{"class":41},[32,22545,22546],{"class":34,"line":99},[32,22547,103],{"emptyLinePlaceholder":102},[32,22549,22550,22552,22554,22557],{"class":34,"line":106},[32,22551,5554],{"class":38},[32,22553,900],{"class":41},[32,22555,22556],{"class":38},"!",[32,22558,22559],{"class":41},"isAuthenticated) {\n",[32,22561,22562,22565,22568,22570,22573],{"class":34,"line":114},[32,22563,22564],{"class":38},"      return",[32,22566,22567],{"class":217}," redirect",[32,22569,477],{"class":41},[32,22571,22572],{"class":175},"\"\u002F\"",[32,22574,230],{"class":41},[32,22576,22577],{"class":34,"line":120},[32,22578,5591],{"class":41},[32,22580,22581],{"class":34,"line":127},[32,22582,1203],{"class":41},[32,22584,22585],{"class":34,"line":132},[32,22586,54],{"class":41},[15,22588,22589],{"id":22589},"在頁面使用",[22,22591,22593],{"className":8665,"code":22592,"language":4112,"meta":27,"style":27},"\u003Cscript>\nexport default {\n  middleware: \"auth\",\n  meta: {\n    requiresAuth: true,\n  },\n};\n\u003C\u002Fscript>\n",[29,22594,22595,22603,22611,22621,22626,22635,22641,22647],{"__ignoreMap":27},[32,22596,22597,22599,22601],{"class":34,"line":35},[32,22598,4046],{"class":41},[32,22600,4125],{"class":4049},[32,22602,4062],{"class":41},[32,22604,22605,22607,22609],{"class":34,"line":45},[32,22606,5038],{"class":38},[32,22608,5041],{"class":38},[32,22610,703],{"class":5049},[32,22612,22613,22616,22619],{"class":34,"line":51},[32,22614,22615],{"class":41},"  middleware: ",[32,22617,22618],{"class":175},"\"auth\"",[32,22620,547],{"class":5049},[32,22622,22623],{"class":34,"line":90},[32,22624,22625],{"class":41},"  meta: {\n",[32,22627,22628,22631,22633],{"class":34,"line":99},[32,22629,22630],{"class":41},"    requiresAuth: ",[32,22632,6206],{"class":351},[32,22634,547],{"class":41},[32,22636,22637,22639],{"class":34,"line":106},[32,22638,9758],{"class":41},[32,22640,547],{"class":5049},[32,22642,22643,22645],{"class":34,"line":114},[32,22644,9765],{"class":5049},[32,22646,96],{"class":41},[32,22648,22649,22651,22653],{"class":34,"line":120},[32,22650,4105],{"class":41},[32,22652,4125],{"class":4049},[32,22654,4062],{"class":41},[11,22656,22657],{},"沒有通過驗證時，就會導向 middleware 設定的頁面。",[15,22659,22414],{"id":22414},[4538,22661,22662,22669],{},[4541,22663,22664],{},[412,22665,22668],{"href":22666,"rel":22667},"https:\u002F\u002Fhsiangfeng.github.io\u002Fvue\u002F20190816\u002F3627128539\u002F",[416],"Nuxt middleware 使用方式",[4541,22670,22671],{},[412,22672,22675],{"href":22673,"rel":22674},"https:\u002F\u002Fgithub.com\u002Fhsiangfeng\u002FNuxt-routeAuth\u002Ftree\u002Fmaster\u002Fmiddleware",[416],"Nuxt routeAuth 範例",[15,22677,2004],{"id":2003},[11,22679,22680,22681,22684],{},"這是 Nuxt 2 的舊寫法。Nuxt 3 改用 route middleware API，不能直接沿用 ",[29,22682,22683],{},"route.meta[0]","。此外，前端 middleware 只能控制畫面導向，真正受保護的資料與操作仍必須由後端驗證權限。",[368,22686,22687],{},"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":22689},[22690,22691,22692,22693],{"id":22476,"depth":45,"text":22477},{"id":22589,"depth":45,"text":22589},{"id":22414,"depth":45,"text":22414},{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 middleware 檔案驗證頁面權限，未通過時重新導向的做法。",{},"\u002Fposts\u002Fnuxt-middleware-auth",[],{"title":22465,"description":22694},"posts\u002F20200827.nuxt-middleware-auth",[16540,22701],"驗證","F_fTLdu7pBcIoVh3ojEudz2B_S1VCD2oUUDbC1yjIzs",{"id":22704,"title":22705,"body":22706,"category":378,"description":22814,"draft":380,"extension":381,"image":382,"meta":22815,"navigation":102,"path":22816,"publishedAt":22817,"relatedExperiments":22818,"seo":22819,"stem":22820,"tags":22821,"updatedAt":14476,"__hash__":22823},"posts\u002Fposts\u002F20200830.nuxt-config-redirect.md","Nuxt 2 設定重新導向：nuxt.config.js 的 extendRoutes",{"type":8,"value":22707,"toc":22811},[22708,22711,22717,22795,22797,22808],[11,22709,22710],{},"這邊記錄 router 重新導向。",[11,22712,22713,22714,22716],{},"可以在 ",[29,22715,20826],{}," 新增重新導向，但比較麻煩的是修改後要重啟伺服器：",[22,22718,22720],{"className":24,"code":22719,"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,22721,22722,22730,22735,22747,22756,22765,22775,22779,22783,22789],{"__ignoreMap":27},[32,22723,22724,22726,22728],{"class":34,"line":35},[32,22725,5038],{"class":38},[32,22727,5041],{"class":38},[32,22729,703],{"class":5049},[32,22731,22732],{"class":34,"line":45},[32,22733,22734],{"class":41},"  router: {\n",[32,22736,22737,22740,22742,22745],{"class":34,"line":51},[32,22738,22739],{"class":217},"    extendRoutes",[32,22741,477],{"class":41},[32,22743,22744],{"class":903},"routes",[32,22746,520],{"class":41},[32,22748,22749,22752,22754],{"class":34,"line":90},[32,22750,22751],{"class":41},"      routes.",[32,22753,21199],{"class":217},[32,22755,1143],{"class":41},[32,22757,22758,22761,22763],{"class":34,"line":99},[32,22759,22760],{"class":41},"        path: ",[32,22762,22572],{"class":175},[32,22764,547],{"class":41},[32,22766,22767,22770,22773],{"class":34,"line":106},[32,22768,22769],{"class":41},"        redirect: ",[32,22771,22772],{"class":175},"\"\u002FLogin\"",[32,22774,547],{"class":41},[32,22776,22777],{"class":34,"line":114},[32,22778,20063],{"class":41},[32,22780,22781],{"class":34,"line":120},[32,22782,4204],{"class":41},[32,22784,22785,22787],{"class":34,"line":127},[32,22786,9758],{"class":41},[32,22788,547],{"class":5049},[32,22790,22791,22793],{"class":34,"line":132},[32,22792,9765],{"class":5049},[32,22794,96],{"class":41},[15,22796,2004],{"id":2003},[11,22798,22799,22800,22803,22804,22807],{},"這是 Nuxt 2 的 ",[29,22801,22802],{},"extendRoutes"," 寫法。Nuxt 3／4 可依部署需求使用 ",[29,22805,22806],{},"routeRules","、route middleware 或伺服器端路由處理重新導向；應選擇會回傳正確 HTTP 狀態碼、符合 SEO 與快取需求的方式。",[368,22809,22810],{},"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":22812},[22813],{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 在 nuxt.config.js 新增重新導向規則，以及修改後要重啟伺服器的情況。",{},"\u002Fposts\u002Fnuxt-config-redirect","2020-08-30",[],{"title":22705,"description":22814},"posts\u002F20200830.nuxt-config-redirect",[16540,22822],"重新導向","8_DfYaO6cgP5oRwnUs-L8BdV_she-Rv4KBQDJtvPaxk",{"id":22825,"title":22826,"body":22827,"category":378,"description":22947,"draft":380,"extension":381,"image":382,"meta":22948,"navigation":102,"path":22949,"publishedAt":22950,"relatedExperiments":22951,"seo":22952,"stem":22953,"tags":22954,"updatedAt":14476,"__hash__":22956},"posts\u002Fposts\u002F20200901.nuxt-cors-proxy-module.md","Nuxt 2 解決 CORS：用 @nuxtjs\u002Fproxy 把 Nuxt 當成代理伺服器",{"type":8,"value":22828,"toc":22943},[22829,22832,22835,22838,22840,22854,22860,22936,22938,22941],[11,22830,22831],{},"這邊記錄使用 axios 串接後端 API 時遇到的 CORS 問題。",[11,22833,22834],{},"CORS（Cross-Origin Resource Sharing，跨來源資源共用）基於瀏覽器的安全性考量，載入其他網域的資源時會受到限制。當後端 API 沒有提供允許跨來源存取的設定時，就必須採取其他方法。",[11,22836,22837],{},"安裝 proxy 後，可以把 Nuxt 的 Web Server 當成 Proxy Server。瀏覽器先向提供網頁的伺服器發出請求，再由它向真正的後端伺服器取得資料。",[15,22839,15872],{"id":15872},[22,22841,22843],{"className":2057,"code":22842,"language":2059,"meta":27,"style":27},"npm install @nuxtjs\u002Fproxy\n",[29,22844,22845],{"__ignoreMap":27},[32,22846,22847,22849,22851],{"class":34,"line":35},[32,22848,4625],{"class":2066},[32,22850,4650],{"class":175},[32,22852,22853],{"class":175}," @nuxtjs\u002Fproxy\n",[11,22855,22856,22857,22859],{},"安裝完成後，在 ",[29,22858,20826],{}," 設定：",[22,22861,22863],{"className":24,"code":22862,"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,22864,22865,22873,22884,22889,22896,22906,22920,22924,22930],{"__ignoreMap":27},[32,22866,22867,22869,22871],{"class":34,"line":35},[32,22868,5038],{"class":38},[32,22870,5041],{"class":38},[32,22872,703],{"class":5049},[32,22874,22875,22877,22880,22882],{"class":34,"line":45},[32,22876,20845],{"class":41},[32,22878,22879],{"class":175},"\"@nuxtjs\u002Fproxy\"",[32,22881,17276],{"class":41},[32,22883,547],{"class":5049},[32,22885,22886],{"class":34,"line":51},[32,22887,22888],{"class":41},"  proxy: {\n",[32,22890,22891,22894],{"class":34,"line":90},[32,22892,22893],{"class":175},"    \"\u002Fapi\u002F\"",[32,22895,5261],{"class":41},[32,22897,22898,22901,22904],{"class":34,"line":99},[32,22899,22900],{"class":41},"      target: ",[32,22902,22903],{"class":175},"\"https:\u002F\u002Fbackend.example.com\"",[32,22905,547],{"class":41},[32,22907,22908,22911,22914,22916,22918],{"class":34,"line":106},[32,22909,22910],{"class":41},"      pathRewrite: { ",[32,22912,22913],{"class":175},"\"^\u002Fapi\u002F\"",[32,22915,5269],{"class":41},[32,22917,7268],{"class":175},[32,22919,16188],{"class":41},[32,22921,22922],{"class":34,"line":114},[32,22923,4204],{"class":41},[32,22925,22926,22928],{"class":34,"line":120},[32,22927,9758],{"class":41},[32,22929,547],{"class":5049},[32,22931,22932,22934],{"class":34,"line":127},[32,22933,9765],{"class":5049},[32,22935,96],{"class":41},[15,22937,2004],{"id":2003},[11,22939,22940],{},"這是 Nuxt 2 的模組與設定方式，不能直接套用到 Nuxt 3／4。代理只能轉送事先限定的 API，不應做成接受任意網址的通用 Proxy；若涉及機密金鑰，也只能在伺服器端讀取。",[368,22942,20876],{},{"title":27,"searchDepth":51,"depth":51,"links":22944},[22945,22946],{"id":15872,"depth":45,"text":15872},{"id":2003,"depth":45,"text":2004},"記錄串接後端 API 遇到 CORS 時，安裝 @nuxtjs\u002Fproxy 轉送請求的方式。",{},"\u002Fposts\u002Fnuxt-cors-proxy-module","2020-09-01",[],{"title":22826,"description":22947},"posts\u002F20200901.nuxt-cors-proxy-module",[16540,22955],"CORS","-gRCSDkflIsgshPt_q3XQzrct4u-ZbPTNbM5nSNqPk8",{"id":22958,"title":22959,"body":22960,"category":378,"description":23328,"draft":380,"extension":381,"image":382,"meta":23329,"navigation":102,"path":23330,"publishedAt":23331,"relatedExperiments":23332,"seo":23333,"stem":23334,"tags":23335,"updatedAt":14476,"__hash__":23336},"posts\u002Fposts\u002F20200908.vee-validate-v3-setup.md","vee-validate 表單驗證安裝紀錄（v3，Options API）",{"type":8,"value":22961,"toc":23321},[22962,22965,22968,22984,22990,23114,23117,23120,23172,23175,23182,23248,23251,23254,23260,23266,23306,23313,23315,23318],[11,22963,22964],{},"最近調整驗證表單時使用 vee-validate，遇到一些挫折，研究了幾天，在這邊簡單記錄。",[15,22966,22967],{"id":22967},"安裝與導入",[22,22969,22971],{"className":2057,"code":22970,"language":2059,"meta":27,"style":27},"npm install vee-validate --save\n",[29,22972,22973],{"__ignoreMap":27},[32,22974,22975,22977,22979,22982],{"class":34,"line":35},[32,22976,4625],{"class":2066},[32,22978,4650],{"class":175},[32,22980,22981],{"class":175}," vee-validate",[32,22983,8638],{"class":351},[11,22985,22986,22987,22989],{},"建立 plugin，並在 ",[29,22988,20826],{}," 引入。當時的基本導入方式：",[22,22991,22993],{"className":24,"code":22992,"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,22994,22995,23007,23013,23018,23023,23028,23039,23053,23057,23070,23082,23086,23100],{"__ignoreMap":27},[32,22996,22997,22999,23001,23003,23005],{"class":34,"line":35},[32,22998,8794],{"class":38},[32,23000,8847],{"class":41},[32,23002,8850],{"class":38},[32,23004,20598],{"class":175},[32,23006,96],{"class":41},[32,23008,23009,23011],{"class":34,"line":45},[32,23010,8794],{"class":38},[32,23012,703],{"class":41},[32,23014,23015],{"class":34,"line":51},[32,23016,23017],{"class":41},"  ValidationObserver,\n",[32,23019,23020],{"class":34,"line":90},[32,23021,23022],{"class":41},"  ValidationProvider,\n",[32,23024,23025],{"class":34,"line":99},[32,23026,23027],{"class":41},"  extend,\n",[32,23029,23030,23032,23034,23037],{"class":34,"line":106},[32,23031,562],{"class":41},[32,23033,8850],{"class":38},[32,23035,23036],{"class":175}," \"vee-validate\"",[32,23038,96],{"class":41},[32,23040,23041,23043,23046,23048,23051],{"class":34,"line":114},[32,23042,8794],{"class":38},[32,23044,23045],{"class":41}," { email, required } ",[32,23047,8850],{"class":38},[32,23049,23050],{"class":175}," \"vee-validate\u002Fdist\u002Frules\"",[32,23052,96],{"class":41},[32,23054,23055],{"class":34,"line":120},[32,23056,103],{"emptyLinePlaceholder":102},[32,23058,23059,23062,23064,23067],{"class":34,"line":127},[32,23060,23061],{"class":217},"extend",[32,23063,477],{"class":41},[32,23065,23066],{"class":175},"\"required\"",[32,23068,23069],{"class":41},", required);\n",[32,23071,23072,23074,23076,23079],{"class":34,"line":132},[32,23073,23061],{"class":217},[32,23075,477],{"class":41},[32,23077,23078],{"class":175},"\"email\"",[32,23080,23081],{"class":41},", email);\n",[32,23083,23084],{"class":34,"line":141},[32,23085,103],{"emptyLinePlaceholder":102},[32,23087,23088,23090,23092,23094,23097],{"class":34,"line":147},[32,23089,8892],{"class":41},[32,23091,9603],{"class":217},[32,23093,477],{"class":41},[32,23095,23096],{"class":175},"\"ValidationObserver\"",[32,23098,23099],{"class":41},", ValidationObserver);\n",[32,23101,23102,23104,23106,23108,23111],{"class":34,"line":275},[32,23103,8892],{"class":41},[32,23105,9603],{"class":217},[32,23107,477],{"class":41},[32,23109,23110],{"class":175},"\"ValidationProvider\"",[32,23112,23113],{"class":41},", ValidationProvider);\n",[15,23115,23116],{"id":23116},"欄位驗證",[11,23118,23119],{},"以 Email 為例：",[22,23121,23123],{"className":8665,"code":23122,"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,23124,23125,23154,23159,23164],{"__ignoreMap":27},[32,23126,23127,23129,23132,23135,23137,23140,23143,23145,23147,23150,23152],{"class":34,"line":35},[32,23128,4046],{"class":41},[32,23130,23131],{"class":4049},"ValidationProvider",[32,23133,23134],{"class":4053}," rules",[32,23136,172],{"class":41},[32,23138,23139],{"class":175},"\"required|email\"",[32,23141,23142],{"class":4053}," v-slot",[32,23144,172],{"class":41},[32,23146,16306],{"class":16305},[32,23148,23149],{"class":41},"{ errors }",[32,23151,16306],{"class":16305},[32,23153,4062],{"class":41},[32,23155,23156],{"class":34,"line":45},[32,23157,23158],{"class":41},"  \u003Cinput v-model=\"email\" type=\"email\">\n",[32,23160,23161],{"class":34,"line":51},[32,23162,23163],{"class":41},"  \u003Cspan>{{ errors[0] }}\u003C\u002Fspan>\n",[32,23165,23166,23168,23170],{"class":34,"line":90},[32,23167,4105],{"class":41},[32,23169,23131],{"class":4049},[32,23171,4062],{"class":41},[15,23173,23174],{"id":23174},"表單送出",[11,23176,23177,23178,23181],{},"引入 ",[29,23179,23180],{},"ValidationObserver","，再把 form 包起來：",[22,23183,23185],{"className":8665,"code":23184,"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,23186,23187,23230,23235,23240],{"__ignoreMap":27},[32,23188,23189,23191,23193,23196,23198,23201,23204,23206,23209,23212,23215,23217,23220,23222,23224,23226,23228],{"class":34,"line":35},[32,23190,4046],{"class":41},[32,23192,23180],{"class":4049},[32,23194,23195],{"class":4053}," ref",[32,23197,172],{"class":41},[32,23199,23200],{"class":175},"\"observer\"",[32,23202,23203],{"class":4053}," tag",[32,23205,172],{"class":41},[32,23207,23208],{"class":175},"\"form\"",[32,23210,23211],{"class":41}," @",[32,23213,23214],{"class":4053},"submit",[32,23216,1278],{"class":41},[32,23218,23219],{"class":4053},"prevent",[32,23221,172],{"class":41},[32,23223,16306],{"class":16305},[32,23225,23214],{"class":41},[32,23227,16306],{"class":16305},[32,23229,4062],{"class":41},[32,23231,23232],{"class":34,"line":45},[32,23233,23234],{"class":41},"  \u003C!-- 欄位 -->\n",[32,23236,23237],{"class":34,"line":51},[32,23238,23239],{"class":41},"  \u003Cbutton type=\"submit\">送出\u003C\u002Fbutton>\n",[32,23241,23242,23244,23246],{"class":34,"line":90},[32,23243,4105],{"class":41},[32,23245,23180],{"class":4049},[32,23247,4062],{"class":41},[15,23249,23250],{"id":23250},"當時遇到的問題",[11,23252,23253],{},"匯入 validation rules 時遇到：",[22,23255,23258],{"className":23256,"code":23257,"language":426,"meta":27},[424],"Unexpected token export\n",[29,23259,23257],{"__ignoreMap":27},[11,23261,23262,23263,23265],{},"當時在 ",[29,23264,20826],{}," 把 rules 加進轉譯設定：",[22,23267,23269],{"className":24,"code":23268,"language":26,"meta":27,"style":27},"export default {\n  build: {\n    transpile: [\"vee-validate\u002Fdist\u002Frules\"],\n  },\n};\n",[29,23270,23271,23279,23284,23294,23300],{"__ignoreMap":27},[32,23272,23273,23275,23277],{"class":34,"line":35},[32,23274,5038],{"class":38},[32,23276,5041],{"class":38},[32,23278,703],{"class":5049},[32,23280,23281],{"class":34,"line":45},[32,23282,23283],{"class":41},"  build: {\n",[32,23285,23286,23289,23292],{"class":34,"line":51},[32,23287,23288],{"class":41},"    transpile: [",[32,23290,23291],{"class":175},"\"vee-validate\u002Fdist\u002Frules\"",[32,23293,8212],{"class":41},[32,23295,23296,23298],{"class":34,"line":90},[32,23297,9758],{"class":41},[32,23299,547],{"class":5049},[32,23301,23302,23304],{"class":34,"line":99},[32,23303,9765],{"class":5049},[32,23305,96],{"class":41},[11,23307,16416,23308],{},[412,23309,23312],{"href":23310,"rel":23311},"https:\u002F\u002Fvee-validate.logaretm.com\u002Fv3\u002Fguide\u002Fcomponents\u002Fvalidation-observer.html",[416],"vee-validate ValidationObserver",[15,23314,2004],{"id":2003},[11,23316,23317],{},"這是 Nuxt 2、Vue 2 與 vee-validate 3 的舊版寫法。新版 vee-validate 的 API、套件入口與 Nuxt 整合方式不同，不能把這份安裝步驟直接套用到新專案。",[368,23319,23320],{},"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":23322},[23323,23324,23325,23326,23327],{"id":22967,"depth":45,"text":22967},{"id":23116,"depth":45,"text":23116},{"id":23174,"depth":45,"text":23174},{"id":23250,"depth":45,"text":23250},{"id":2003,"depth":45,"text":2004},"記錄 Nuxt 2 安裝 vee-validate、驗證欄位與送出表單時遇到的設定問題。",{},"\u002Fposts\u002Fvee-validate-v3-setup","2020-09-08",[],{"title":22959,"description":23328},"posts\u002F20200908.vee-validate-v3-setup",[9778,4113,4572],"3wK4ROVk_XTfdji-uZUdCVyKroNd1vwJ705zXMn5nuA",{"id":23338,"title":23339,"body":23340,"category":378,"description":23533,"draft":380,"extension":381,"image":382,"meta":23534,"navigation":102,"path":23535,"publishedAt":23536,"relatedExperiments":23537,"seo":23538,"stem":23539,"tags":23540,"updatedAt":14476,"__hash__":23543},"posts\u002Fposts\u002F20200910.moment-vue-filter.md","用 moment.js 搭配 Vue 2 全域 filter 做日期格式化",{"type":8,"value":23341,"toc":23528},[23342,23345,23347,23361,23365,23375,23473,23479,23482,23500,23516,23518,23525],[11,23343,23344],{},"這邊記錄 moment 日期格式的使用方式。",[15,23346,15872],{"id":15872},[22,23348,23350],{"className":2057,"code":23349,"language":2059,"meta":27,"style":27},"npm install moment\n",[29,23351,23352],{"__ignoreMap":27},[32,23353,23354,23356,23358],{"class":34,"line":35},[32,23355,4625],{"class":2066},[32,23357,4650],{"class":175},[32,23359,23360],{"class":175}," moment\n",[15,23362,23364],{"id":23363},"建立-filter","建立 filter",[11,23366,7086,23367,23370,23371,23374],{},[29,23368,23369],{},"filter.js","，放在 ",[29,23372,23373],{},"plugins"," 資料夾：",[22,23376,23378],{"className":24,"code":23377,"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,23379,23380,23392,23406,23410,23442,23457,23469],{"__ignoreMap":27},[32,23381,23382,23384,23386,23388,23390],{"class":34,"line":35},[32,23383,8794],{"class":38},[32,23385,8847],{"class":41},[32,23387,8850],{"class":38},[32,23389,20598],{"class":175},[32,23391,96],{"class":41},[32,23393,23394,23396,23399,23401,23404],{"class":34,"line":45},[32,23395,8794],{"class":38},[32,23397,23398],{"class":41}," moment ",[32,23400,8850],{"class":38},[32,23402,23403],{"class":175}," \"moment\"",[32,23405,96],{"class":41},[32,23407,23408],{"class":34,"line":51},[32,23409,103],{"emptyLinePlaceholder":102},[32,23411,23412,23414,23416,23418,23421,23424,23426,23428,23431,23433,23436,23438,23440],{"class":34,"line":90},[32,23413,8892],{"class":41},[32,23415,17883],{"class":217},[32,23417,477],{"class":41},[32,23419,23420],{"class":175},"\"dateFormat\"",[32,23422,23423],{"class":41},", (",[32,23425,19628],{"class":903},[32,23427,635],{"class":41},[32,23429,23430],{"class":903},"format",[32,23432,894],{"class":38},[32,23434,23435],{"class":175}," \"YYYY-MM-DD\"",[32,23437,483],{"class":41},[32,23439,5090],{"class":38},[32,23441,703],{"class":41},[32,23443,23444,23446,23449,23451,23454],{"class":34,"line":99},[32,23445,4157],{"class":38},[32,23447,23448],{"class":351}," datetime",[32,23450,894],{"class":38},[32,23452,23453],{"class":217}," moment",[32,23455,23456],{"class":41},"(value);\n",[32,23458,23459,23461,23464,23466],{"class":34,"line":106},[32,23460,11115],{"class":38},[32,23462,23463],{"class":41}," datetime.",[32,23465,23430],{"class":217},[32,23467,23468],{"class":41},"(format);\n",[32,23470,23471],{"class":34,"line":114},[32,23472,792],{"class":41},[11,23474,23475,23476,23478],{},"再到 ",[29,23477,20826],{}," 引入這支 plugin。",[11,23480,23481],{},"模板使用方式：",[22,23483,23485],{"className":8665,"code":23484,"language":4112,"meta":27,"style":27},"\u003Cspan>{{ date | dateFormat(\"YYYY-MM-DD\") }}\u003C\u002Fspan>\n",[29,23486,23487],{"__ignoreMap":27},[32,23488,23489,23491,23493,23496,23498],{"class":34,"line":35},[32,23490,4046],{"class":41},[32,23492,32],{"class":4049},[32,23494,23495],{"class":41},">{{ date | dateFormat(\"YYYY-MM-DD\") }}\u003C\u002F",[32,23497,32],{"class":4049},[32,23499,4062],{"class":41},[4538,23501,23502,23509],{},[4541,23503,23504],{},[412,23505,23508],{"href":23506,"rel":23507},"https:\u002F\u002Fmomentjs.com\u002F",[416],"Moment.js",[4541,23510,23511],{},[412,23512,23515],{"href":23513,"rel":23514},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10208995",[416],"當時參考的 Vue filter 文章",[15,23517,2004],{"id":2003},[11,23519,23520,23521,23524],{},"這是 Vue 2 的全域 filter 語法；Vue 3 已移除 filters。Moment.js 目前仍可維護既有專案，但官方將它視為 legacy project，新功能通常會優先考慮原生 ",[29,23522,23523],{},"Intl"," 或其他日期工具。",[368,23526,23527],{},"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":23529},[23530,23531,23532],{"id":15872,"depth":45,"text":15872},{"id":23363,"depth":45,"text":23364},{"id":2003,"depth":45,"text":2004},"記錄安裝 moment.js，並在 Vue 2 全域 filter 格式化日期的方式。",{},"\u002Fposts\u002Fmoment-vue-filter","2020-09-10",[],{"title":23339,"description":23533},"posts\u002F20200910.moment-vue-filter",[4113,23541,23542],"moment.js","日期","pJQFFOlvHdwLszVBVKiHMzcIVHYF7X8BmVvJDriCvbo",{"id":23545,"title":23546,"body":23547,"category":378,"description":23763,"draft":380,"extension":381,"image":382,"meta":23764,"navigation":102,"path":23765,"publishedAt":23766,"relatedExperiments":23767,"seo":23768,"stem":23769,"tags":23770,"updatedAt":14476,"__hash__":23772},"posts\u002Fposts\u002F20220409.vue-cli4-project-setup.md","vue-cli4 專案建立",{"type":8,"value":23548,"toc":23754},[23549,23552,23555,23569,23574,23577,23580,23586,23589,23595,23598,23601,23607,23610,23616,23619,23625,23628,23634,23637,23645,23651,23656,23662,23665,23671,23674,23680,23683,23689,23692,23694,23705,23708,23752],[15,23550,23551],{"id":23551},"建立流程",[151,23553,23554],{"id":23554},"建立項目指令",[22,23556,23558],{"className":2057,"code":23557,"language":2059,"meta":27,"style":27},"vue create 專案名稱\n",[29,23559,23560],{"__ignoreMap":27},[32,23561,23562,23564,23566],{"class":34,"line":35},[32,23563,4112],{"class":2066},[32,23565,4799],{"class":175},[32,23567,23568],{"class":175}," 專案名稱\n",[2184,23570,23571],{},[11,23572,23573],{},"專案名稱不能有大寫字母。",[151,23575,23576],{"id":23576},"設定項目",[11,23578,23579],{},"選擇最後一個手動選擇：",[11,23581,23582],{},[10761,23583],{"alt":23584,"src":23585},"Vue CLI 4.5.13 的 preset 選單","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F01.png",[11,23587,23588],{},"手動選擇項目：",[11,23590,23591],{},[10761,23592],{"alt":23593,"src":23594},"Vue CLI 的功能勾選清單","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F02.png",[11,23596,23597],{},"Unit Testing 是 Vue.js 官方維護的單元測試套件，可搭配 Jest；Vue CLI 能自動配置所需環境。E2E Testing：",[11,23599,23600],{},"選擇 Vue 3 模式：",[11,23602,23603],{},[10761,23604],{"alt":23605,"src":23606},"Vue CLI 選擇 Vue.js 版本","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F03.png",[11,23608,23609],{},"選擇是否將 hash 模式寫在 router：",[11,23611,23612],{},[10761,23613],{"alt":23614,"src":23615},"Vue CLI 詢問是否使用 history mode","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F04.png",[11,23617,23618],{},"選擇 node-sass：",[11,23620,23621],{},[10761,23622],{"alt":23623,"src":23624},"Vue CLI 選擇 CSS 前處理器","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F05.png",[11,23626,23627],{},"選擇 Airbnb 模式：",[11,23629,23630],{},[10761,23631],{"alt":23632,"src":23633},"Vue CLI 選擇 linter 設定","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F06.png",[11,23635,23636],{},"選擇檢查程式碼的時機，Airbnb 檢查後修正錯誤再提交：",[4538,23638,23639,23642],{},[4541,23640,23641],{},"存檔時檢查",[4541,23643,23644],{},"提交時檢查",[11,23646,23647],{},[10761,23648],{"alt":23649,"src":23650},"Vue CLI 詢問 lint 功能","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F07.png",[11,23652,23653,23654,5240],{},"設定檔放在 ",[29,23655,4945],{},[11,23657,23658],{},[10761,23659],{"alt":23660,"src":23661},"Vue CLI 詢問設定檔放置位置","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F08.png",[11,23663,23664],{},"是否將剛才的設定做為一份預設檔案：",[11,23666,23667],{},[10761,23668],{"alt":23669,"src":23670},"Vue CLI 詢問是否儲存 preset","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F09.png",[11,23672,23673],{},"開始建立：",[11,23675,23676],{},[10761,23677],{"alt":23678,"src":23679},"Vue CLI 開始建立專案","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F10.png",[15,23681,23682],{"id":23682},"遇到的問題",[11,23684,23685],{},[10761,23686],{"alt":23687,"src":23688},"Vue CLI 顯示專案名稱不能有大寫字母","\u002Fimages\u002Fposts\u002Fvue-cli4-project-setup\u002F11.png",[11,23690,23691],{},"專案名稱不能使用大寫字母。",[15,23693,2004],{"id":2003},[11,23695,23696,23697,23700,23701,23704],{},"這是 2022 年 Vue CLI 4 的互動式建立流程，包含當時的 ",[29,23698,23699],{},"node-sass"," 選項。現在建立 Vue 專案通常會使用官方的 ",[29,23702,23703],{},"create-vue","／Vite 流程；不要直接照舊選項建立新專案。",[15,23706,23707],{"id":23707},"參考相關文件",[4538,23709,23710,23717,23724,23731,23738,23745],{},[4541,23711,23712],{},[412,23713,23716],{"href":23714,"rel":23715},"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,23718,23719],{},[412,23720,23723],{"href":23721,"rel":23722},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10277447",[416],"hash 與 history 模式",[4541,23725,23726],{},[412,23727,23730],{"href":23728,"rel":23729},"https:\u002F\u002Fcli.vuejs.org\u002Fzh\u002Fguide\u002Fcreating-a-project.html#vue-create",[416],"Vue CLI 官方文件",[4541,23732,23733],{},[412,23734,23737],{"href":23735,"rel":23736},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10216606",[416],"Vue CLI 3 安裝與建立 Vue 專案",[4541,23739,23740],{},[412,23741,23744],{"href":23742,"rel":23743},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10275591",[416],"Vue Test Utils + Jest",[4541,23746,23747],{},[412,23748,23751],{"href":23749,"rel":23750},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10279077",[416],"Cypress 基本介紹",[368,23753,12937],{},{"title":27,"searchDepth":51,"depth":51,"links":23755},[23756,23760,23761,23762],{"id":23551,"depth":45,"text":23551,"children":23757},[23758,23759],{"id":23554,"depth":51,"text":23554},{"id":23576,"depth":51,"text":23576},{"id":23682,"depth":45,"text":23682},{"id":2003,"depth":45,"text":2004},{"id":23707,"depth":45,"text":23707},"紀錄使用 Vue CLI 4 建立 Vue 專案時的選項。",{},"\u002Fposts\u002Fvue-cli4-project-setup","2022-04-09",[],{"title":23546,"description":23763},"posts\u002F20220409.vue-cli4-project-setup",[5396,23771,4853,4847],"Vue3","6Km4mCJ45YUPFqNKDT1nGh4debzFHpLrodCsFMXv0Bg",{"id":23774,"title":23775,"body":23776,"category":378,"description":26012,"draft":380,"extension":381,"image":382,"meta":26013,"navigation":102,"path":26014,"publishedAt":26015,"relatedExperiments":26016,"seo":26017,"stem":26018,"tags":26019,"updatedAt":14476,"__hash__":26021},"posts\u002Fposts\u002F20240505.pinia-vuex-state-management.md","Pinia \u002F Vuex 狀態管理及差異",{"type":8,"value":23777,"toc":25993},[23778,23781,23784,23788,23795,23798,23833,23836,23839,23842,23865,23869,23872,23875,23901,23904,24009,24016,24018,24022,24036,24040,24130,24134,24151,24156,24190,24193,24197,24200,24555,24564,24567,24842,24846,24852,24911,24922,24947,24951,24962,25341,25349,25352,25537,25543,25547,25550,25555,25721,25726,25906,25920,25923,25926,25929,25956,25959,25961,25964,25967,25990],[11,23779,23780],{},"元件之間要共用資料時，用 props 一層一層傳很快就會受不了。狀態管理就是把這些資料抽出來放在一個共用的地方。",[11,23782,23783],{},"Vue 生態裡先有 Vuex，後來有了 Pinia。這篇整理兩者的差異，以及 Pinia 實際怎麼寫。",[15,23785,23787],{"id":23786},"vuex-概要","Vuex 概要",[11,23789,23790,23791,23794],{},"Vuex 是 Vue 官方早期提供的狀態管理庫，核心是",[12390,23792,23793],{},"集中式存儲","：整個應用共用一棵狀態樹（store），各個元件都能存取或修改同一份狀態。",[11,23796,23797],{},"四個核心概念：",[6426,23799,23800,23806,23818,23827],{},[4541,23801,23802,23805],{},[12390,23803,23804],{},"State（狀態）","：響應式的物件，放應用層級的所有資料。元件透過 getter 讀取。",[4541,23807,23808,5240,23811,23814,23815,23817],{},[12390,23809,23810],{},"Mutation（突變）",[12390,23812,23813],{},"唯一","允許修改狀態的地方，而且必須是同步的。接收 ",[29,23816,19903],{}," 當第一個參數，加上可選的 payload。",[4541,23819,23820,23823,23824,23826],{},[12390,23821,23822],{},"Action（動作）","：處理非同步操作或批次呼叫多個 mutation。接收 ",[29,23825,7449],{}," 物件。",[4541,23828,23829,23832],{},[12390,23830,23831],{},"Module（模組）","：把 store 拆成模組，各自有自己的 state、mutations、actions、getters。",[11,23834,23835],{},"「非同步的事情放 action、真正改狀態的動作放 mutation」這個設計是為了讓每一次狀態變更都可追蹤——Vue DevTools 能列出每一個 mutation，出問題時倒著看就知道狀態是被誰改的。",[151,23837,23838],{"id":23838},"遇到的瓶頸",[11,23840,23841],{},"規模上來之後，這套設計的代價開始浮現：",[4538,23843,23844,23850,23856],{},[4541,23845,23846,23849],{},[12390,23847,23848],{},"模組結構讓狀態分散","在多個模組裡，追蹤與管理變得困難。",[4541,23851,23852,23855],{},[12390,23853,23854],{},"API 冗長","。改一個值要先定義 mutation、再定義 action、再在元件裡 dispatch，中間隔了兩層。",[4541,23857,23858,3775,23861,23864],{},[12390,23859,23860],{},"TypeScript 支援不好",[29,23862,23863],{},"commit('someMutation', payload)"," 是字串，型別推不出來，打錯字要到執行期才會發現。",[15,23866,23868],{"id":23867},"pinia-概要","Pinia 概要",[11,23870,23871],{},"為了解決這些問題，Vue 團隊開發了 Pinia，用來取代 Vuex 的全域資料管理函式庫。",[11,23873,23874],{},"主要特點：",[6426,23876,23877,23883,23889,23895],{},[4541,23878,23879,23882],{},[12390,23880,23881],{},"與 Composition API 緊密整合","：可以用組合式的方式組織與重用邏輯。",[4541,23884,23885,23888],{},[12390,23886,23887],{},"扁平的 store 結構","：每個 store 都是獨立的實例，有自己的 state、getters、actions，不用巢狀模組。",[4541,23890,23891,23894],{},[12390,23892,23893],{},"TypeScript 支援良好","：大量使用型別推斷，不需要額外寫型別包裝。",[4541,23896,23897,23900],{},[12390,23898,23899],{},"輕量","：壓縮後約 1KB，並支援自訂 plugin。",[15,23902,23903],{"id":23903},"兩者的差異",[13574,23905,23906,23917],{},[13577,23907,23908],{},[13580,23909,23910,23912,23914],{},[13583,23911,13685],{},[13583,23913,4844],{},[13583,23915,23916],{},"Pinia",[13590,23918,23919,23933,23947,23958,23974,23985,23998],{},[13580,23920,23921,23924,23927],{},[13595,23922,23923],{},"Mutations",[13595,23925,23926],{},"必須有",[13595,23928,23929,23932],{},[12390,23930,23931],{},"移除","，直接在 action 改 state",[13580,23934,23935,23938,23944],{},[13595,23936,23937],{},"模組 namespace",[13595,23939,23940,23941],{},"要自己設定 ",[29,23942,23943],{},"namespaced",[13595,23945,23946],{},"自動，每個 store 天生獨立",[13580,23948,23949,23952,23955],{},[13595,23950,23951],{},"TypeScript",[13595,23953,23954],{},"需要額外的型別包裝",[13595,23956,23957],{},"型別推斷",[13580,23959,23960,23963,23969],{},[13595,23961,23962],{},"取得 state",[13595,23964,23965,23966,23968],{},"要傳 ",[29,23967,19903],{}," 參數",[13595,23970,23971,23972],{},"直接用 ",[29,23973,1083],{},[13580,23975,23976,23979,23982],{},[13595,23977,23978],{},"SSR",[13595,23980,23981],{},"支援但設定繁瑣",[13595,23983,23984],{},"原生支援",[13580,23986,23987,23990,23993],{},[13595,23988,23989],{},"Nuxt 3",[13595,23991,23992],{},"不支援",[13595,23994,23995],{},[12390,23996,23997],{},"完整支援",[13580,23999,24000,24003,24006],{},[13595,24001,24002],{},"體積",[13595,24004,24005],{},"較大",[13595,24007,24008],{},"約 1KB",[11,24010,24011,24012,24015],{},"最大的差異是",[12390,24013,24014],{},"移除了 Mutations","。少了一層之後寫法簡潔很多，代價是從程式碼上看不出它是 Flux 架構——但實務上，多數人本來就覺得 mutation 這層是多餘的儀式。",[15,24017,15872],{"id":15872},[151,24019,24021],{"id":24020},"vue-專案","Vue 專案",[22,24023,24025],{"className":2057,"code":24024,"language":2059,"meta":27,"style":27},"npm install pinia\n",[29,24026,24027],{"__ignoreMap":27},[32,24028,24029,24031,24033],{"class":34,"line":35},[32,24030,4625],{"class":2066},[32,24032,4650],{"class":175},[32,24034,24035],{"class":175}," pinia\n",[11,24037,24038,5240],{},[29,24039,5137],{},[22,24041,24045],{"className":24042,"code":24043,"language":24044,"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,24046,24047,24059,24071,24083,24087,24102,24117],{"__ignoreMap":27},[32,24048,24049,24051,24054,24056],{"class":34,"line":35},[32,24050,8794],{"class":38},[32,24052,24053],{"class":41}," { createApp } ",[32,24055,8850],{"class":38},[32,24057,24058],{"class":175}," 'vue'\n",[32,24060,24061,24063,24066,24068],{"class":34,"line":45},[32,24062,8794],{"class":38},[32,24064,24065],{"class":41}," { createPinia } ",[32,24067,8850],{"class":38},[32,24069,24070],{"class":175}," 'pinia'\n",[32,24072,24073,24075,24078,24080],{"class":34,"line":51},[32,24074,8794],{"class":38},[32,24076,24077],{"class":41}," App ",[32,24079,8850],{"class":38},[32,24081,24082],{"class":175}," '.\u002FApp.vue'\n",[32,24084,24085],{"class":34,"line":90},[32,24086,103],{"emptyLinePlaceholder":102},[32,24088,24089,24091,24094,24096,24099],{"class":34,"line":99},[32,24090,6617],{"class":38},[32,24092,24093],{"class":351}," app",[32,24095,894],{"class":38},[32,24097,24098],{"class":217}," createApp",[32,24100,24101],{"class":41},"(App)\n",[32,24103,24104,24107,24109,24111,24114],{"class":34,"line":106},[32,24105,24106],{"class":41},"app.",[32,24108,8895],{"class":217},[32,24110,477],{"class":41},[32,24112,24113],{"class":217},"createPinia",[32,24115,24116],{"class":41},"())\n",[32,24118,24119,24121,24124,24126,24128],{"class":34,"line":114},[32,24120,24106],{"class":41},[32,24122,24123],{"class":217},"mount",[32,24125,477],{"class":41},[32,24127,4178],{"class":175},[32,24129,515],{"class":41},[151,24131,24133],{"id":24132},"nuxt-專案","Nuxt 專案",[22,24135,24137],{"className":2057,"code":24136,"language":2059,"meta":27,"style":27},"npm install pinia @pinia\u002Fnuxt\n",[29,24138,24139],{"__ignoreMap":27},[32,24140,24141,24143,24145,24148],{"class":34,"line":35},[32,24142,4625],{"class":2066},[32,24144,4650],{"class":175},[32,24146,24147],{"class":175}," pinia",[32,24149,24150],{"class":175}," @pinia\u002Fnuxt\n",[11,24152,24153,5240],{},[29,24154,24155],{},"nuxt.config.ts",[22,24157,24161],{"className":24158,"code":24159,"language":24160,"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,24162,24163,24174,24185],{"__ignoreMap":27},[32,24164,24165,24167,24169,24172],{"class":34,"line":35},[32,24166,5038],{"class":38},[32,24168,5041],{"class":38},[32,24170,24171],{"class":217}," defineNuxtConfig",[32,24173,1143],{"class":5049},[32,24175,24176,24178,24181,24183],{"class":34,"line":45},[32,24177,20845],{"class":41},[32,24179,24180],{"class":175},"'@pinia\u002Fnuxt'",[32,24182,17276],{"class":41},[32,24184,547],{"class":5049},[32,24186,24187],{"class":34,"line":51},[32,24188,24189],{"class":5049},"})\n",[11,24191,24192],{},"Nuxt 模組會自動處理 SSR 的狀態注水（hydration），不用自己搬狀態。",[15,24194,24196],{"id":24195},"寫法一options-風格","寫法一：Options 風格",[11,24198,24199],{},"跟 Vuex 比較像，適合從 Vuex 搬過來：",[22,24201,24203],{"className":24042,"code":24202,"language":24044,"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,24204,24205,24210,24221,24225,24248,24260,24265,24270,24275,24286,24297,24326,24331,24336,24340,24344,24348,24359,24392,24399,24410,24418,24428,24433,24474,24482,24493,24497,24501,24513,24543,24547,24551],{"__ignoreMap":27},[32,24206,24207],{"class":34,"line":35},[32,24208,24209],{"class":608},"\u002F\u002F src\u002Fstores\u002Fcart.js\n",[32,24211,24212,24214,24217,24219],{"class":34,"line":45},[32,24213,8794],{"class":38},[32,24215,24216],{"class":41}," { defineStore } ",[32,24218,8850],{"class":38},[32,24220,24070],{"class":175},[32,24222,24223],{"class":34,"line":51},[32,24224,103],{"emptyLinePlaceholder":102},[32,24226,24227,24229,24232,24235,24237,24240,24242,24245],{"class":34,"line":90},[32,24228,5038],{"class":38},[32,24230,24231],{"class":38}," const",[32,24233,24234],{"class":351}," useCartStore",[32,24236,894],{"class":38},[32,24238,24239],{"class":217}," defineStore",[32,24241,477],{"class":41},[32,24243,24244],{"class":175},"'cart'",[32,24246,24247],{"class":41},", {\n",[32,24249,24250,24253,24255,24257],{"class":34,"line":99},[32,24251,24252],{"class":217},"  state",[32,24254,5087],{"class":41},[32,24256,5090],{"class":38},[32,24258,24259],{"class":41}," ({\n",[32,24261,24262],{"class":34,"line":106},[32,24263,24264],{"class":41},"    items: []\n",[32,24266,24267],{"class":34,"line":114},[32,24268,24269],{"class":41},"  }),\n",[32,24271,24272],{"class":34,"line":120},[32,24273,24274],{"class":41},"  getters: {\n",[32,24276,24277,24280,24282,24284],{"class":34,"line":127},[32,24278,24279],{"class":217},"    totalCost",[32,24281,477],{"class":41},[32,24283,19903],{"class":903},[32,24285,520],{"class":41},[32,24287,24288,24290,24293,24295],{"class":34,"line":132},[32,24289,22564],{"class":38},[32,24291,24292],{"class":41}," state.items.",[32,24294,22070],{"class":217},[32,24296,539],{"class":41},[32,24298,24299,24302,24305,24307,24310,24312,24314,24316,24318,24321,24323],{"class":34,"line":141},[32,24300,24301],{"class":41},"        (",[32,24303,24304],{"class":903},"total",[32,24306,635],{"class":41},[32,24308,24309],{"class":903},"item",[32,24311,483],{"class":41},[32,24313,5090],{"class":38},[32,24315,22062],{"class":41},[32,24317,224],{"class":38},[32,24319,24320],{"class":41}," item.price ",[32,24322,6078],{"class":38},[32,24324,24325],{"class":41}," item.quantity,\n",[32,24327,24328],{"class":34,"line":147},[32,24329,24330],{"class":351},"        0\n",[32,24332,24333],{"class":34,"line":275},[32,24334,24335],{"class":41},"      )\n",[32,24337,24338],{"class":34,"line":282},[32,24339,5591],{"class":41},[32,24341,24342],{"class":34,"line":295},[32,24343,5639],{"class":41},[32,24345,24346],{"class":34,"line":605},[32,24347,20005],{"class":41},[32,24349,24350,24353,24355,24357],{"class":34,"line":612},[32,24351,24352],{"class":217},"    addItem",[32,24354,477],{"class":41},[32,24356,24309],{"class":903},[32,24358,520],{"class":41},[32,24360,24361,24363,24366,24368,24370,24373,24375,24377,24380,24382,24384,24387,24389],{"class":34,"line":617},[32,24362,17391],{"class":38},[32,24364,24365],{"class":351}," existingItem",[32,24367,894],{"class":38},[32,24369,4234],{"class":351},[32,24371,24372],{"class":41},".items.",[32,24374,21784],{"class":217},[32,24376,8293],{"class":41},[32,24378,24379],{"class":903},"i",[32,24381,483],{"class":41},[32,24383,5090],{"class":38},[32,24385,24386],{"class":41}," i.id ",[32,24388,5560],{"class":38},[32,24390,24391],{"class":41}," item.id)\n",[32,24393,24394,24396],{"class":34,"line":644},[32,24395,1071],{"class":38},[32,24397,24398],{"class":41}," (existingItem) {\n",[32,24400,24401,24403,24406,24408],{"class":34,"line":649},[32,24402,17430],{"class":38},[32,24404,24405],{"class":351}," newItem",[32,24407,894],{"class":38},[32,24409,703],{"class":41},[32,24411,24412,24415],{"class":34,"line":671},[32,24413,24414],{"class":38},"          ...",[32,24416,24417],{"class":41},"existingItem,\n",[32,24419,24420,24423,24425],{"class":34,"line":690},[32,24421,24422],{"class":41},"          quantity: existingItem.quantity ",[32,24424,224],{"class":38},[32,24426,24427],{"class":41}," item.quantity\n",[32,24429,24430],{"class":34,"line":696},[32,24431,24432],{"class":41},"        }\n",[32,24434,24435,24437,24440,24442,24444,24446,24448,24450,24452,24454,24456,24459,24461,24464,24466,24469,24471],{"class":34,"line":706},[32,24436,17471],{"class":351},[32,24438,24439],{"class":41},".items ",[32,24441,172],{"class":38},[32,24443,4234],{"class":351},[32,24445,24372],{"class":41},[32,24447,11271],{"class":217},[32,24449,8293],{"class":41},[32,24451,24379],{"class":903},[32,24453,483],{"class":41},[32,24455,5090],{"class":38},[32,24457,24458],{"class":41}," (i.id ",[32,24460,5560],{"class":38},[32,24462,24463],{"class":41}," item.id ",[32,24465,316],{"class":38},[32,24467,24468],{"class":41}," newItem ",[32,24470,322],{"class":38},[32,24472,24473],{"class":41}," i))\n",[32,24475,24476,24478,24480],{"class":34,"line":721},[32,24477,9477],{"class":41},[32,24479,565],{"class":38},[32,24481,703],{"class":41},[32,24483,24484,24486,24488,24490],{"class":34,"line":728},[32,24485,17471],{"class":351},[32,24487,24372],{"class":41},[32,24489,21199],{"class":217},[32,24491,24492],{"class":41},"(item)\n",[32,24494,24495],{"class":34,"line":737},[32,24496,1193],{"class":41},[32,24498,24499],{"class":34,"line":742},[32,24500,4204],{"class":41},[32,24502,24503,24506,24508,24511],{"class":34,"line":747},[32,24504,24505],{"class":217},"    removeItem",[32,24507,477],{"class":41},[32,24509,24510],{"class":903},"itemId",[32,24512,520],{"class":41},[32,24514,24515,24518,24520,24522,24524,24526,24528,24530,24532,24534,24536,24538,24540],{"class":34,"line":752},[32,24516,24517],{"class":351},"      this",[32,24519,24439],{"class":41},[32,24521,172],{"class":38},[32,24523,4234],{"class":351},[32,24525,24372],{"class":41},[32,24527,17883],{"class":217},[32,24529,8293],{"class":41},[32,24531,24309],{"class":903},[32,24533,483],{"class":41},[32,24535,5090],{"class":38},[32,24537,24463],{"class":41},[32,24539,1553],{"class":38},[32,24541,24542],{"class":41}," itemId)\n",[32,24544,24545],{"class":34,"line":773},[32,24546,5591],{"class":41},[32,24548,24549],{"class":34,"line":789},[32,24550,1203],{"class":41},[32,24552,24553],{"class":34,"line":795},[32,24554,24189],{"class":41},[11,24556,24557,24560,24561,24563],{},[29,24558,24559],{},"defineStore"," 的第一個參數 ",[29,24562,24244],{}," 是這個 store 的唯一 ID，DevTools 會用它來標示。",[11,24565,24566],{},"在元件裡使用：",[22,24568,24570],{"className":8665,"code":24569,"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,24571,24572,24577,24585,24593,24606,24614,24638,24643,24665,24674,24683,24696,24704,24712,24716,24727,24741,24755,24759,24772,24776,24801,24805,24819,24830,24834],{"__ignoreMap":27},[32,24573,24574],{"class":34,"line":35},[32,24575,24576],{"class":608},"\u003C!-- src\u002Fcomponents\u002FCart.vue -->\n",[32,24578,24579,24581,24583],{"class":34,"line":45},[32,24580,4046],{"class":41},[32,24582,9623],{"class":4049},[32,24584,4062],{"class":41},[32,24586,24587,24589,24591],{"class":34,"line":51},[32,24588,4067],{"class":41},[32,24590,4050],{"class":4049},[32,24592,4062],{"class":41},[32,24594,24595,24597,24599,24602,24604],{"class":34,"line":90},[32,24596,9638],{"class":41},[32,24598,15],{"class":4049},[32,24600,24601],{"class":41},">你的購物車\u003C\u002F",[32,24603,15],{"class":4049},[32,24605,4062],{"class":41},[32,24607,24608,24610,24612],{"class":34,"line":99},[32,24609,9638],{"class":41},[32,24611,4538],{"class":4049},[32,24613,4062],{"class":41},[32,24615,24616,24619,24621,24623,24625,24628,24631,24633,24636],{"class":34,"line":106},[32,24617,24618],{"class":41},"      \u003C",[32,24620,4541],{"class":4049},[32,24622,16300],{"class":4053},[32,24624,172],{"class":41},[32,24626,24627],{"class":175},"\"item in items\"",[32,24629,24630],{"class":4053}," :key",[32,24632,172],{"class":41},[32,24634,24635],{"class":175},"\"item.id\"",[32,24637,4062],{"class":41},[32,24639,24640],{"class":34,"line":114},[32,24641,24642],{"class":41},"        {{ item.name }} - ${{ item.price }} x {{ item.quantity }}\n",[32,24644,24645,24648,24650,24653,24655,24658,24661,24663],{"class":34,"line":120},[32,24646,24647],{"class":41},"        \u003C",[32,24649,11634],{"class":4049},[32,24651,24652],{"class":4053}," @click",[32,24654,172],{"class":41},[32,24656,24657],{"class":175},"\"removeItem(item.id)\"",[32,24659,24660],{"class":41},">刪除\u003C\u002F",[32,24662,11634],{"class":4049},[32,24664,4062],{"class":41},[32,24666,24667,24670,24672],{"class":34,"line":127},[32,24668,24669],{"class":41},"      \u003C\u002F",[32,24671,4541],{"class":4049},[32,24673,4062],{"class":41},[32,24675,24676,24679,24681],{"class":34,"line":132},[32,24677,24678],{"class":41},"    \u003C\u002F",[32,24680,4538],{"class":4049},[32,24682,4062],{"class":41},[32,24684,24685,24687,24689,24692,24694],{"class":34,"line":141},[32,24686,9638],{"class":41},[32,24688,4050],{"class":4049},[32,24690,24691],{"class":41},">總費用: ${{ totalCost }}\u003C\u002F",[32,24693,4050],{"class":4049},[32,24695,4062],{"class":41},[32,24697,24698,24700,24702],{"class":34,"line":147},[32,24699,9691],{"class":41},[32,24701,4050],{"class":4049},[32,24703,4062],{"class":41},[32,24705,24706,24708,24710],{"class":34,"line":275},[32,24707,4105],{"class":41},[32,24709,9623],{"class":4049},[32,24711,4062],{"class":41},[32,24713,24714],{"class":34,"line":282},[32,24715,103],{"emptyLinePlaceholder":102},[32,24717,24718,24720,24722,24725],{"class":34,"line":295},[32,24719,4046],{"class":41},[32,24721,4125],{"class":4049},[32,24723,24724],{"class":4053}," setup",[32,24726,4062],{"class":41},[32,24728,24729,24731,24734,24736,24739],{"class":34,"line":605},[32,24730,8794],{"class":38},[32,24732,24733],{"class":41}," { storeToRefs } ",[32,24735,8850],{"class":38},[32,24737,24738],{"class":175}," \"pinia\"",[32,24740,96],{"class":41},[32,24742,24743,24745,24748,24750,24753],{"class":34,"line":612},[32,24744,8794],{"class":38},[32,24746,24747],{"class":41}," { useCartStore } ",[32,24749,8850],{"class":38},[32,24751,24752],{"class":175}," \"..\u002Fstores\u002Fcart\"",[32,24754,96],{"class":41},[32,24756,24757],{"class":34,"line":617},[32,24758,103],{"emptyLinePlaceholder":102},[32,24760,24761,24763,24766,24768,24770],{"class":34,"line":644},[32,24762,6617],{"class":38},[32,24764,24765],{"class":351}," cartStore",[32,24767,894],{"class":38},[32,24769,24234],{"class":217},[32,24771,687],{"class":41},[32,24773,24774],{"class":34,"line":649},[32,24775,103],{"emptyLinePlaceholder":102},[32,24777,24778,24780,24783,24785,24787,24790,24793,24795,24798],{"class":34,"line":671},[32,24779,6617],{"class":38},[32,24781,24782],{"class":41}," { ",[32,24784,21016],{"class":351},[32,24786,635],{"class":41},[32,24788,24789],{"class":351},"totalCost",[32,24791,24792],{"class":41}," } ",[32,24794,172],{"class":38},[32,24796,24797],{"class":217}," storeToRefs",[32,24799,24800],{"class":41},"(cartStore);\n",[32,24802,24803],{"class":34,"line":690},[32,24804,103],{"emptyLinePlaceholder":102},[32,24806,24807,24809,24812,24814,24817],{"class":34,"line":696},[32,24808,665],{"class":38},[32,24810,24811],{"class":217}," removeItem",[32,24813,477],{"class":41},[32,24815,24816],{"class":903},"id",[32,24818,520],{"class":41},[32,24820,24821,24824,24827],{"class":34,"line":706},[32,24822,24823],{"class":41},"  cartStore.",[32,24825,24826],{"class":217},"removeItem",[32,24828,24829],{"class":41},"(id);\n",[32,24831,24832],{"class":34,"line":721},[32,24833,54],{"class":41},[32,24835,24836,24838,24840],{"class":34,"line":728},[32,24837,4105],{"class":41},[32,24839,4125],{"class":4049},[32,24841,4062],{"class":41},[151,24843,24845],{"id":24844},"為什麼要用-storetorefs","為什麼要用 storeToRefs",[11,24847,24848,24849,5240],{},"這是最常踩的坑。直接解構會",[12390,24850,24851],{},"失去響應性",[22,24853,24855],{"className":24042,"code":24854,"language":24044,"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,24856,24857,24862,24882,24886,24891],{"__ignoreMap":27},[32,24858,24859],{"class":34,"line":35},[32,24860,24861],{"class":608},"\u002F\u002F 壞掉：items 變成一般變數，store 更新時畫面不會動\n",[32,24863,24864,24866,24868,24870,24872,24874,24876,24878,24880],{"class":34,"line":45},[32,24865,6617],{"class":38},[32,24867,24782],{"class":41},[32,24869,21016],{"class":351},[32,24871,635],{"class":41},[32,24873,24789],{"class":351},[32,24875,24792],{"class":41},[32,24877,172],{"class":38},[32,24879,24234],{"class":217},[32,24881,687],{"class":41},[32,24883,24884],{"class":34,"line":51},[32,24885,103],{"emptyLinePlaceholder":102},[32,24887,24888],{"class":34,"line":90},[32,24889,24890],{"class":608},"\u002F\u002F 正確：storeToRefs 把 state 與 getters 包成 ref\n",[32,24892,24893,24895,24897,24899,24901,24903,24905,24907,24909],{"class":34,"line":99},[32,24894,6617],{"class":38},[32,24896,24782],{"class":41},[32,24898,21016],{"class":351},[32,24900,635],{"class":41},[32,24902,24789],{"class":351},[32,24904,24792],{"class":41},[32,24906,172],{"class":38},[32,24908,24797],{"class":217},[32,24910,24800],{"class":41},[11,24912,24913,24914,24921],{},"但 ",[12390,24915,24916,24917,24920],{},"action 不要用 ",[29,24918,24919],{},"storeToRefs"," 取","，它們是函式、本來就不需要響應性，直接從 store 取即可：",[22,24923,24925],{"className":24042,"code":24924,"language":24044,"meta":27,"style":27},"const { addItem, removeItem } = cartStore;\n",[29,24926,24927],{"__ignoreMap":27},[32,24928,24929,24931,24933,24936,24938,24940,24942,24944],{"class":34,"line":35},[32,24930,6617],{"class":38},[32,24932,24782],{"class":41},[32,24934,24935],{"class":351},"addItem",[32,24937,635],{"class":41},[32,24939,24826],{"class":351},[32,24941,24792],{"class":41},[32,24943,172],{"class":38},[32,24945,24946],{"class":41}," cartStore;\n",[15,24948,24950],{"id":24949},"寫法二setup-風格","寫法二：setup 風格",[11,24952,24953,24954,24957,24958,24961],{},"用 Composition API 的方式寫，跟平常寫元件邏輯一模一樣——",[29,24955,24956],{},"ref"," 就是 state、",[29,24959,24960],{},"computed"," 就是 getter、function 就是 action。",[22,24963,24965],{"className":24158,"code":24964,"language":24160,"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,24966,24967,24979,24983,24993,25003,25012,25021,25029,25038,25042,25046,25070,25075,25094,25112,25116,25121,25145,25167,25171,25176,25207,25238,25246,25254,25259,25277,25294,25298,25302,25308,25313,25318,25323,25328,25333,25337],{"__ignoreMap":27},[32,24968,24969,24971,24974,24976],{"class":34,"line":35},[32,24970,8794],{"class":38},[32,24972,24973],{"class":41}," { getElectionGroups, getCounties } ",[32,24975,8850],{"class":38},[32,24977,24978],{"class":175}," '~\u002Fassets\u002Fapi\u002Felection'\n",[32,24980,24981],{"class":34,"line":45},[32,24982,103],{"emptyLinePlaceholder":102},[32,24984,24985,24988,24991],{"class":34,"line":51},[32,24986,24987],{"class":38},"interface",[32,24989,24990],{"class":2066}," Candidate",[32,24992,703],{"class":41},[32,24994,24995,24998,25000],{"class":34,"line":90},[32,24996,24997],{"class":903},"  id",[32,24999,322],{"class":38},[32,25001,25002],{"class":351}," string\n",[32,25004,25005,25008,25010],{"class":34,"line":99},[32,25006,25007],{"class":903},"  society",[32,25009,322],{"class":38},[32,25011,25002],{"class":351},[32,25013,25014,25017,25019],{"class":34,"line":106},[32,25015,25016],{"class":903},"  societyEng",[32,25018,322],{"class":38},[32,25020,25002],{"class":351},[32,25022,25023,25025,25027],{"class":34,"line":114},[32,25024,9859],{"class":903},[32,25026,322],{"class":38},[32,25028,25002],{"class":351},[32,25030,25031,25034,25036],{"class":34,"line":120},[32,25032,25033],{"class":903},"  subName",[32,25035,322],{"class":38},[32,25037,25002],{"class":351},[32,25039,25040],{"class":34,"line":127},[32,25041,54],{"class":41},[32,25043,25044],{"class":34,"line":132},[32,25045,103],{"emptyLinePlaceholder":102},[32,25047,25048,25050,25052,25055,25057,25059,25061,25064,25066,25068],{"class":34,"line":141},[32,25049,5038],{"class":38},[32,25051,24231],{"class":38},[32,25053,25054],{"class":351}," useCandidateAndCountyStore",[32,25056,894],{"class":38},[32,25058,24239],{"class":217},[32,25060,477],{"class":41},[32,25062,25063],{"class":175},"'candidatesAndCounty'",[32,25065,11359],{"class":41},[32,25067,5090],{"class":38},[32,25069,703],{"class":41},[32,25071,25072],{"class":34,"line":147},[32,25073,25074],{"class":608},"  \u002F\u002F state\n",[32,25076,25077,25079,25082,25084,25086,25088,25091],{"class":34,"line":275},[32,25078,4157],{"class":38},[32,25080,25081],{"class":351}," candidates",[32,25083,894],{"class":38},[32,25085,23195],{"class":217},[32,25087,4046],{"class":41},[32,25089,25090],{"class":2066},"Candidate",[32,25092,25093],{"class":41},"[]>([])\n",[32,25095,25096,25098,25101,25103,25105,25107,25110],{"class":34,"line":282},[32,25097,4157],{"class":38},[32,25099,25100],{"class":351}," counties",[32,25102,894],{"class":38},[32,25104,23195],{"class":217},[32,25106,4046],{"class":41},[32,25108,25109],{"class":351},"string",[32,25111,25093],{"class":41},[32,25113,25114],{"class":34,"line":295},[32,25115,103],{"emptyLinePlaceholder":102},[32,25117,25118],{"class":34,"line":605},[32,25119,25120],{"class":608},"  \u002F\u002F getters\n",[32,25122,25123,25125,25128,25130,25133,25135,25137,25140,25142],{"class":34,"line":612},[32,25124,4157],{"class":38},[32,25126,25127],{"class":351}," candidatesGetter",[32,25129,894],{"class":38},[32,25131,25132],{"class":217}," computed",[32,25134,17421],{"class":41},[32,25136,5090],{"class":38},[32,25138,25139],{"class":41}," candidates.value ",[32,25141,1036],{"class":38},[32,25143,25144],{"class":41}," [])\n",[32,25146,25147,25149,25152,25154,25156,25158,25160,25163,25165],{"class":34,"line":617},[32,25148,4157],{"class":38},[32,25150,25151],{"class":351}," countiesGetter",[32,25153,894],{"class":38},[32,25155,25132],{"class":217},[32,25157,17421],{"class":41},[32,25159,5090],{"class":38},[32,25161,25162],{"class":41}," counties.value ",[32,25164,1036],{"class":38},[32,25166,25144],{"class":41},[32,25168,25169],{"class":34,"line":644},[32,25170,103],{"emptyLinePlaceholder":102},[32,25172,25173],{"class":34,"line":649},[32,25174,25175],{"class":608},"  \u002F\u002F actions\n",[32,25177,25178,25180,25183,25185,25188,25191,25193,25196,25198,25201,25203,25205],{"class":34,"line":671},[32,25179,4157],{"class":38},[32,25181,25182],{"class":217}," fetchCandidatesAndCounties",[32,25184,894],{"class":38},[32,25186,25187],{"class":38}," async",[32,25189,25190],{"class":41}," ()",[32,25192,322],{"class":38},[32,25194,25195],{"class":2066}," Promise",[32,25197,4046],{"class":41},[32,25199,25200],{"class":351},"void",[32,25202,12542],{"class":41},[32,25204,5090],{"class":38},[32,25206,703],{"class":41},[32,25208,25209,25211,25213,25216,25218,25221,25223,25225,25228,25230,25232,25235],{"class":34,"line":690},[32,25210,9409],{"class":38},[32,25212,8261],{"class":41},[32,25214,25215],{"class":351},"candidatesData",[32,25217,635],{"class":41},[32,25219,25220],{"class":351},"countiesData",[32,25222,10616],{"class":41},[32,25224,172],{"class":38},[32,25226,25227],{"class":38}," await",[32,25229,25195],{"class":351},[32,25231,1278],{"class":41},[32,25233,25234],{"class":217},"all",[32,25236,25237],{"class":41},"([\n",[32,25239,25240,25243],{"class":34,"line":696},[32,25241,25242],{"class":217},"      getElectionGroups",[32,25244,25245],{"class":41},"(),\n",[32,25247,25248,25251],{"class":34,"line":706},[32,25249,25250],{"class":217},"      getCounties",[32,25252,25253],{"class":41},"()\n",[32,25255,25256],{"class":34,"line":721},[32,25257,25258],{"class":41},"    ])\n",[32,25260,25261,25264,25266,25269,25272,25274],{"class":34,"line":728},[32,25262,25263],{"class":41},"    candidates.value ",[32,25265,172],{"class":38},[32,25267,25268],{"class":41}," candidatesData ",[32,25270,25271],{"class":38},"as",[32,25273,24990],{"class":2066},[32,25275,25276],{"class":41},"[]\n",[32,25278,25279,25282,25284,25287,25289,25292],{"class":34,"line":737},[32,25280,25281],{"class":41},"    counties.value ",[32,25283,172],{"class":38},[32,25285,25286],{"class":41}," countiesData ",[32,25288,25271],{"class":38},[32,25290,25291],{"class":351}," string",[32,25293,25276],{"class":41},[32,25295,25296],{"class":34,"line":742},[32,25297,1203],{"class":41},[32,25299,25300],{"class":34,"line":747},[32,25301,103],{"emptyLinePlaceholder":102},[32,25303,25304,25306],{"class":34,"line":752},[32,25305,11115],{"class":38},[32,25307,703],{"class":41},[32,25309,25310],{"class":34,"line":773},[32,25311,25312],{"class":41},"    candidates,\n",[32,25314,25315],{"class":34,"line":789},[32,25316,25317],{"class":41},"    candidatesGetter,\n",[32,25319,25320],{"class":34,"line":795},[32,25321,25322],{"class":41},"    counties,\n",[32,25324,25325],{"class":34,"line":800},[32,25326,25327],{"class":41},"    countiesGetter,\n",[32,25329,25330],{"class":34,"line":816},[32,25331,25332],{"class":41},"    fetchCandidatesAndCounties\n",[32,25334,25335],{"class":34,"line":824},[32,25336,1203],{"class":41},[32,25338,25339],{"class":34,"line":833},[32,25340,24189],{"class":41},[11,25342,25343,25348],{},[12390,25344,25345,25346],{},"要記得 ",[29,25347,4428],{},"——沒有回傳的東西外面拿不到，這是 setup 寫法最常見的錯誤。",[11,25350,25351],{},"在元件裡用起來完全一樣：",[22,25353,25355],{"className":8665,"code":25354,"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,25356,25357,25374,25384,25396,25400,25413,25436,25440,25445,25458,25466,25470,25478,25486,25508,25513,25521,25529],{"__ignoreMap":27},[32,25358,25359,25361,25363,25365,25367,25369,25372],{"class":34,"line":35},[32,25360,4046],{"class":41},[32,25362,4125],{"class":4049},[32,25364,24724],{"class":4053},[32,25366,8677],{"class":4053},[32,25368,172],{"class":41},[32,25370,25371],{"class":175},"\"ts\"",[32,25373,4062],{"class":41},[32,25375,25376,25378,25380,25382],{"class":34,"line":45},[32,25377,8794],{"class":38},[32,25379,24733],{"class":41},[32,25381,8850],{"class":38},[32,25383,24070],{"class":175},[32,25385,25386,25388,25391,25393],{"class":34,"line":51},[32,25387,8794],{"class":38},[32,25389,25390],{"class":41}," { useCandidateAndCountyStore } ",[32,25392,8850],{"class":38},[32,25394,25395],{"class":175}," '~\u002Fstore\u002FcandidatesAndCounty'\n",[32,25397,25398],{"class":34,"line":90},[32,25399,103],{"emptyLinePlaceholder":102},[32,25401,25402,25404,25407,25409,25411],{"class":34,"line":99},[32,25403,6617],{"class":38},[32,25405,25406],{"class":351}," store",[32,25408,894],{"class":38},[32,25410,25054],{"class":217},[32,25412,25253],{"class":41},[32,25414,25415,25417,25419,25422,25424,25427,25429,25431,25433],{"class":34,"line":106},[32,25416,6617],{"class":38},[32,25418,24782],{"class":41},[32,25420,25421],{"class":351},"candidatesGetter",[32,25423,635],{"class":41},[32,25425,25426],{"class":351},"countiesGetter",[32,25428,24792],{"class":41},[32,25430,172],{"class":38},[32,25432,24797],{"class":217},[32,25434,25435],{"class":41},"(store)\n",[32,25437,25438],{"class":34,"line":114},[32,25439,103],{"emptyLinePlaceholder":102},[32,25441,25442],{"class":34,"line":120},[32,25443,25444],{"class":608},"\u002F\u002F 進頁面就抓資料\n",[32,25446,25447,25450,25453,25456],{"class":34,"line":127},[32,25448,25449],{"class":38},"await",[32,25451,25452],{"class":41}," store.",[32,25454,25455],{"class":217},"fetchCandidatesAndCounties",[32,25457,25253],{"class":41},[32,25459,25460,25462,25464],{"class":34,"line":132},[32,25461,4105],{"class":41},[32,25463,4125],{"class":4049},[32,25465,4062],{"class":41},[32,25467,25468],{"class":34,"line":141},[32,25469,103],{"emptyLinePlaceholder":102},[32,25471,25472,25474,25476],{"class":34,"line":147},[32,25473,4046],{"class":41},[32,25475,9623],{"class":4049},[32,25477,4062],{"class":41},[32,25479,25480,25482,25484],{"class":34,"line":275},[32,25481,4067],{"class":41},[32,25483,4538],{"class":4049},[32,25485,4062],{"class":41},[32,25487,25488,25490,25492,25494,25496,25499,25501,25503,25506],{"class":34,"line":282},[32,25489,9638],{"class":41},[32,25491,4541],{"class":4049},[32,25493,16300],{"class":4053},[32,25495,172],{"class":41},[32,25497,25498],{"class":175},"\"c in candidatesGetter\"",[32,25500,24630],{"class":4053},[32,25502,172],{"class":41},[32,25504,25505],{"class":175},"\"c.id\"",[32,25507,4062],{"class":41},[32,25509,25510],{"class":34,"line":295},[32,25511,25512],{"class":41},"      {{ c.name }}（{{ c.society }}）\n",[32,25514,25515,25517,25519],{"class":34,"line":605},[32,25516,24678],{"class":41},[32,25518,4541],{"class":4049},[32,25520,4062],{"class":41},[32,25522,25523,25525,25527],{"class":34,"line":612},[32,25524,9691],{"class":41},[32,25526,4538],{"class":4049},[32,25528,4062],{"class":41},[32,25530,25531,25533,25535],{"class":34,"line":617},[32,25532,4105],{"class":41},[32,25534,9623],{"class":4049},[32,25536,4062],{"class":41},[11,25538,25539,25540,25542],{},"兩種寫法可以混用，同一個專案裡不同 store 用不同寫法沒問題。setup 風格對 TypeScript 比較友善，型別直接從 ",[29,25541,24956],{}," 推導出來。",[15,25544,25546],{"id":25545},"store-之間互相呼叫","store 之間互相呼叫",[11,25548,25549],{},"Pinia 的 store 就是函式，要用別的 store 直接呼叫它就好，不需要像 Vuex 那樣處理 namespace。",[11,25551,25552,5240],{},[29,25553,25554],{},"stores\u002Fuser.ts",[22,25556,25558],{"className":24158,"code":25557,"language":24160,"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,25559,25560,25584,25613,25633,25637,25672,25692,25702,25706,25710,25717],{"__ignoreMap":27},[32,25561,25562,25564,25566,25569,25571,25573,25575,25578,25580,25582],{"class":34,"line":35},[32,25563,5038],{"class":38},[32,25565,24231],{"class":38},[32,25567,25568],{"class":351}," useUserStore",[32,25570,894],{"class":38},[32,25572,24239],{"class":217},[32,25574,477],{"class":41},[32,25576,25577],{"class":175},"'user'",[32,25579,11359],{"class":41},[32,25581,5090],{"class":38},[32,25583,703],{"class":41},[32,25585,25586,25588,25591,25593,25595,25597,25599,25602,25605,25608,25611],{"class":34,"line":45},[32,25587,4157],{"class":38},[32,25589,25590],{"class":351}," token",[32,25592,894],{"class":38},[32,25594,23195],{"class":217},[32,25596,4046],{"class":41},[32,25598,25109],{"class":351},[32,25600,25601],{"class":38}," |",[32,25603,25604],{"class":351}," null",[32,25606,25607],{"class":41},">(",[32,25609,25610],{"class":351},"null",[32,25612,515],{"class":41},[32,25614,25615,25617,25620,25622,25624,25626,25628,25630],{"class":34,"line":51},[32,25616,4157],{"class":38},[32,25618,25619],{"class":351}," isLoggedIn",[32,25621,894],{"class":38},[32,25623,25132],{"class":217},[32,25625,17421],{"class":41},[32,25627,5090],{"class":38},[32,25629,1490],{"class":38},[32,25631,25632],{"class":41},"token.value)\n",[32,25634,25635],{"class":34,"line":90},[32,25636,103],{"emptyLinePlaceholder":102},[32,25638,25639,25641,25644,25646,25648,25650,25653,25655,25657,25659,25662,25664,25666,25668,25670],{"class":34,"line":99},[32,25640,4157],{"class":38},[32,25642,25643],{"class":217}," login",[32,25645,894],{"class":38},[32,25647,25187],{"class":38},[32,25649,900],{"class":41},[32,25651,25652],{"class":903},"email",[32,25654,322],{"class":38},[32,25656,25291],{"class":351},[32,25658,635],{"class":41},[32,25660,25661],{"class":903},"password",[32,25663,322],{"class":38},[32,25665,25291],{"class":351},[32,25667,483],{"class":41},[32,25669,5090],{"class":38},[32,25671,703],{"class":41},[32,25673,25674,25676,25679,25681,25683,25686,25689],{"class":34,"line":106},[32,25675,9409],{"class":38},[32,25677,25678],{"class":351}," res",[32,25680,894],{"class":38},[32,25682,25227],{"class":38},[32,25684,25685],{"class":41}," api.",[32,25687,25688],{"class":217},"login",[32,25690,25691],{"class":41},"(email, password)\n",[32,25693,25694,25697,25699],{"class":34,"line":114},[32,25695,25696],{"class":41},"    token.value ",[32,25698,172],{"class":38},[32,25700,25701],{"class":41}," res.token\n",[32,25703,25704],{"class":34,"line":120},[32,25705,1203],{"class":41},[32,25707,25708],{"class":34,"line":127},[32,25709,103],{"emptyLinePlaceholder":102},[32,25711,25712,25714],{"class":34,"line":132},[32,25713,11115],{"class":38},[32,25715,25716],{"class":41}," { token, isLoggedIn, login }\n",[32,25718,25719],{"class":34,"line":141},[32,25720,24189],{"class":41},[11,25722,25723,5240],{},[29,25724,25725],{},"stores\u002Fcart.ts",[22,25727,25729],{"className":24158,"code":25728,"language":24160,"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,25730,25731,25743,25747,25769,25787,25791,25807,25812,25825,25829,25840,25857,25861,25865,25877,25887,25891,25895,25902],{"__ignoreMap":27},[32,25732,25733,25735,25738,25740],{"class":34,"line":35},[32,25734,8794],{"class":38},[32,25736,25737],{"class":41}," { useUserStore } ",[32,25739,8850],{"class":38},[32,25741,25742],{"class":175}," '.\u002Fuser'\n",[32,25744,25745],{"class":34,"line":45},[32,25746,103],{"emptyLinePlaceholder":102},[32,25748,25749,25751,25753,25755,25757,25759,25761,25763,25765,25767],{"class":34,"line":51},[32,25750,5038],{"class":38},[32,25752,24231],{"class":38},[32,25754,24234],{"class":351},[32,25756,894],{"class":38},[32,25758,24239],{"class":217},[32,25760,477],{"class":41},[32,25762,24244],{"class":175},[32,25764,11359],{"class":41},[32,25766,5090],{"class":38},[32,25768,703],{"class":41},[32,25770,25771,25773,25776,25778,25780,25782,25785],{"class":34,"line":90},[32,25772,4157],{"class":38},[32,25774,25775],{"class":351}," items",[32,25777,894],{"class":38},[32,25779,23195],{"class":217},[32,25781,4046],{"class":41},[32,25783,25784],{"class":2066},"CartItem",[32,25786,25093],{"class":41},[32,25788,25789],{"class":34,"line":99},[32,25790,103],{"emptyLinePlaceholder":102},[32,25792,25793,25795,25797,25799,25801,25803,25805],{"class":34,"line":106},[32,25794,4157],{"class":38},[32,25796,2923],{"class":217},[32,25798,894],{"class":38},[32,25800,25187],{"class":38},[32,25802,11398],{"class":41},[32,25804,5090],{"class":38},[32,25806,703],{"class":41},[32,25808,25809],{"class":34,"line":114},[32,25810,25811],{"class":608},"    \u002F\u002F 在 action 裡呼叫，不要放在 store 的最外層\n",[32,25813,25814,25816,25819,25821,25823],{"class":34,"line":120},[32,25815,9409],{"class":38},[32,25817,25818],{"class":351}," userStore",[32,25820,894],{"class":38},[32,25822,25568],{"class":217},[32,25824,25253],{"class":41},[32,25826,25827],{"class":34,"line":127},[32,25828,103],{"emptyLinePlaceholder":102},[32,25830,25831,25833,25835,25837],{"class":34,"line":132},[32,25832,5554],{"class":38},[32,25834,900],{"class":41},[32,25836,22556],{"class":38},[32,25838,25839],{"class":41},"userStore.isLoggedIn) {\n",[32,25841,25842,25845,25847,25850,25852,25855],{"class":34,"line":141},[32,25843,25844],{"class":38},"      throw",[32,25846,4165],{"class":38},[32,25848,25849],{"class":217}," Error",[32,25851,477],{"class":41},[32,25853,25854],{"class":175},"'請先登入'",[32,25856,515],{"class":41},[32,25858,25859],{"class":34,"line":147},[32,25860,5591],{"class":41},[32,25862,25863],{"class":34,"line":275},[32,25864,103],{"emptyLinePlaceholder":102},[32,25866,25867,25870,25872,25874],{"class":34,"line":282},[32,25868,25869],{"class":38},"    await",[32,25871,25685],{"class":41},[32,25873,3763],{"class":217},[32,25875,25876],{"class":41},"(items.value, userStore.token)\n",[32,25878,25879,25882,25884],{"class":34,"line":295},[32,25880,25881],{"class":41},"    items.value ",[32,25883,172],{"class":38},[32,25885,25886],{"class":41}," []\n",[32,25888,25889],{"class":34,"line":605},[32,25890,1203],{"class":41},[32,25892,25893],{"class":34,"line":612},[32,25894,103],{"emptyLinePlaceholder":102},[32,25896,25897,25899],{"class":34,"line":617},[32,25898,11115],{"class":38},[32,25900,25901],{"class":41}," { items, checkout }\n",[32,25903,25904],{"class":34,"line":644},[32,25905,24189],{"class":41},[11,25907,25908,25915,25916,25919],{},[12390,25909,25910,25911,25914],{},"關鍵是 ",[29,25912,25913],{},"useUserStore()"," 要寫在 action 裡面，不要寫在 store 的最外層。"," 寫在外層時，那行程式會在模組載入當下就執行，而那時候 Pinia 實例可能還沒建立好（尤其在 SSR 環境），會拿到 ",[29,25917,25918],{},"getActivePinia was called with no active Pinia"," 這個錯誤。",[11,25921,25922],{},"要注意兩個 store 互相引用會形成循環相依。就 JavaScript 模組來說這是可行的，但如果 A 跟 B 頻繁互相呼叫，通常代表它們該合併成一個 store，或該把共用的邏輯抽成一般的 composable。",[15,25924,25925],{"id":25925},"什麼時候該用狀態管理",[11,25927,25928],{},"不是所有共用資料都需要 store。判斷標準大致是：",[4538,25930,25931,25937,25943],{},[4541,25932,25933,25936],{},[12390,25934,25935],{},"父子元件之間"," → props 與 emit 就夠了",[4541,25938,25939,25942],{},[12390,25940,25941],{},"跨多層、多個分支的元件"," → 用 store",[4541,25944,25945,25948,25949,11762,25952,25955],{},[12390,25946,25947],{},"只是伺服器資料的快取","（列表、詳情） → Nuxt 的 ",[29,25950,25951],{},"useFetch",[29,25953,25954],{},"useAsyncData"," 通常就夠，不必進 store",[11,25957,25958],{},"過早引入狀態管理，只會讓資料流變得更難追。",[15,25960,2004],{"id":2003},[11,25962,25963],{},"本文保留 Vuex 與 Pinia 的比較筆記。不同 Vue、Nuxt 與 Pinia 版本的支援範圍可能不同，新專案請以各套件目前文件確認。",[15,25965,25966],{"id":25966},"相關連結",[4538,25968,25969,25976,25983],{},[4541,25970,25971],{},[412,25972,25975],{"href":25973,"rel":25974},"https:\u002F\u002Fpinia.vuejs.org\u002F",[416],"Pinia 官方文件",[4541,25977,25978],{},[412,25979,25982],{"href":25980,"rel":25981},"https:\u002F\u002Fstackblitz.com\u002Fgithub\u002Fpiniajs\u002Fexample-vue-3-vite?file=src%2Fstores%2Fcart.ts",[416],"Pinia 官方範例（StackBlitz）",[4541,25984,25985],{},[412,25986,25989],{"href":25987,"rel":25988},"https:\u002F\u002Fwww.vuemastery.com\u002Fblog\u002Fadvantages-of-pinia-vs-vuex\u002F",[416],"Advantages of Pinia vs Vuex",[368,25991,25992],{},"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":25994},[25995,25998,25999,26000,26004,26007,26008,26009,26010,26011],{"id":23786,"depth":45,"text":23787,"children":25996},[25997],{"id":23838,"depth":51,"text":23838},{"id":23867,"depth":45,"text":23868},{"id":23903,"depth":45,"text":23903},{"id":15872,"depth":45,"text":15872,"children":26001},[26002,26003],{"id":24020,"depth":51,"text":24021},{"id":24132,"depth":51,"text":24133},{"id":24195,"depth":45,"text":24196,"children":26005},[26006],{"id":24844,"depth":51,"text":24845},{"id":24949,"depth":45,"text":24950},{"id":25545,"depth":45,"text":25546},{"id":25925,"depth":45,"text":25925},{"id":2003,"depth":45,"text":2004},{"id":25966,"depth":45,"text":25966},"紀錄 Vuex、Pinia 的狀態管理概念、差異與用法。",{},"\u002Fposts\u002Fpinia-vuex-state-management","2024-05-05",[],{"title":23775,"description":26012},"posts\u002F20240505.pinia-vuex-state-management",[23916,4844,23771,26020,16540],"狀態管理","RDWbM3jg6LXqr1hxfbo57b2-7cL5GnLOFp4Mj-4bfR0",{"id":26023,"title":26024,"body":26025,"category":378,"description":28673,"draft":380,"extension":381,"image":382,"meta":28674,"navigation":102,"path":28675,"publishedAt":28676,"relatedExperiments":28677,"seo":28678,"stem":28679,"tags":28680,"updatedAt":14476,"__hash__":28682},"posts\u002Fposts\u002F20250724.nuxt3-setup-notes.md","Nuxt 筆記",{"type":8,"value":26026,"toc":28633},[26027,26031,26034,26037,26040,26052,26058,26061,26086,26089,26095,26098,26104,26107,26120,26122,26129,26132,26149,26157,26195,26198,26201,26204,26208,26230,26234,26240,26342,26356,26369,26372,26375,26381,26545,26548,26594,26613,26622,26625,26631,26634,26643,26689,26701,26704,26707,26719,26734,26805,26808,26818,26864,26867,26870,26876,27062,27065,27068,27074,27219,27237,27241,27247,27386,27395,27398,27401,27407,27416,27422,27435,27438,27441,27447,27450,27455,27565,27572,27576,27768,27776,27779,27784,27882,27888,27928,27948,27951,27959,27965,27984,28001,28004,28007,28025,28029,28063,28067,28073,28107,28114,28117,28138,28167,28171,28187,28191,28219,28224,28328,28334,28338,28341,28357,28361,28364,28379,28382,28388,28391,28404,28407,28411,28423,28427,28444,28450,28500,28503,28586,28588,28591,28593,28630],[15,26028,26030],{"id":26029},"安裝-nuxt-cli","安裝 Nuxt CLI",[11,26032,26033],{},"nuxi 全名是 Nuxt CLI（Nuxt Command Line Interface），是 Nuxt 官方提供的標準工具。它之於 Nuxt，就像 Vue CLI 之於 Vue——用來建立與管理專案。",[151,26035,26036],{"id":26036},"環境準備",[11,26038,26039],{},"為了確保 nuxi 不會拿到快取的舊版本，可以先清一次 npx 快取：",[22,26041,26043],{"className":2057,"code":26042,"language":2059,"meta":27,"style":27},"npx clear-npx-cache\n",[29,26044,26045],{"__ignoreMap":27},[32,26046,26047,26049],{"class":34,"line":35},[32,26048,16476],{"class":2066},[32,26050,26051],{"class":175}," clear-npx-cache\n",[11,26053,26054,26055,3775],{},"Node.js 需要 ",[12390,26056,26057],{},"v16.10.0 以上",[151,26059,26060],{"id":26060},"建立專案",[22,26062,26064],{"className":2057,"code":26063,"language":2059,"meta":27,"style":27},"npx nuxi@latest init \u003Cproject-name>\n",[29,26065,26066],{"__ignoreMap":27},[32,26067,26068,26070,26073,26075,26078,26081,26084],{"class":34,"line":35},[32,26069,16476],{"class":2066},[32,26071,26072],{"class":175}," nuxi@latest",[32,26074,8581],{"class":175},[32,26076,26077],{"class":38}," \u003C",[32,26079,26080],{"class":175},"project-nam",[32,26082,26083],{"class":41},"e",[32,26085,4062],{"class":38},[11,26087,26088],{},"執行後會問幾個問題，一路照預設走就好：",[22,26090,26093],{"className":26091,"code":26092,"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,26094,26092],{"__ignoreMap":27},[11,26096,26097],{},"裝完的專案長這樣（只有最基本的幾個檔案，其他資料夾要自己開）：",[22,26099,26102],{"className":26100,"code":26101,"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,26103,26101],{"__ignoreMap":27},[11,26105,26106],{},"啟動：",[22,26108,26110],{"className":2057,"code":26109,"language":2059,"meta":27,"style":27},"npm run dev\n",[29,26111,26112],{"__ignoreMap":27},[32,26113,26114,26116,26118],{"class":34,"line":35},[32,26115,4625],{"class":2066},[32,26117,4743],{"class":175},[32,26119,10438],{"class":175},[15,26121,23951],{"id":24160},[11,26123,26124,26125,26128],{},"Nuxt 3 內建支援 TypeScript，設定放在專案根目錄的 ",[29,26126,26127],{},"tsconfig.json","。我習慣在開發時就開型別檢查，出錯當下就看到，不要等到 build。",[11,26130,26131],{},"安裝 Vue 的型別檢查工具：",[22,26133,26135],{"className":2057,"code":26134,"language":2059,"meta":27,"style":27},"npm install -D vue-tsc\n",[29,26136,26137],{"__ignoreMap":27},[32,26138,26139,26141,26143,26146],{"class":34,"line":35},[32,26140,4625],{"class":2066},[32,26142,4650],{"class":175},[32,26144,26145],{"class":351}," -D",[32,26147,26148],{"class":175}," vue-tsc\n",[11,26150,5134,26151,26153,26154,5240],{},[29,26152,24155],{}," 打開 ",[29,26155,26156],{},"typeCheck",[22,26158,26162],{"className":26159,"code":26160,"language":26161,"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,26163,26164,26174,26179,26187,26191],{"__ignoreMap":27},[32,26165,26166,26168,26170,26172],{"class":34,"line":35},[32,26167,5038],{"class":38},[32,26169,5041],{"class":38},[32,26171,24171],{"class":217},[32,26173,1143],{"class":5049},[32,26175,26176],{"class":34,"line":45},[32,26177,26178],{"class":41},"  typescript: {\n",[32,26180,26181,26184],{"class":34,"line":51},[32,26182,26183],{"class":41},"    typeCheck: ",[32,26185,26186],{"class":351},"true\n",[32,26188,26189],{"class":34,"line":90},[32,26190,1203],{"class":41},[32,26192,26193],{"class":34,"line":99},[32,26194,24189],{"class":5049},[15,26196,4853],{"id":26197},"eslint",[11,26199,26200],{},"ESLint 是 JavaScript 的 linter，用來檢查程式碼風格（縮排、單雙引號⋯⋯）並找出語法問題。在團隊裡它的價值更明顯：大家寫出來的東西會長得一樣，code review 就不用花時間在排版上吵架。",[11,26202,26203],{},"它可以直接套用大公司的規則配置（Google、Airbnb），也可以自己客製。這裡選 Nuxt 官方提供的那組。",[151,26205,26207],{"id":26206},"_1-安裝套件","1. 安裝套件",[22,26209,26211],{"className":2057,"code":26210,"language":2059,"meta":27,"style":27},"npm install -D eslint @nuxtjs\u002Feslint-config-typescript eslint-plugin-vue\n",[29,26212,26213],{"__ignoreMap":27},[32,26214,26215,26217,26219,26221,26224,26227],{"class":34,"line":35},[32,26216,4625],{"class":2066},[32,26218,4650],{"class":175},[32,26220,26145],{"class":351},[32,26222,26223],{"class":175}," eslint",[32,26225,26226],{"class":175}," @nuxtjs\u002Feslint-config-typescript",[32,26228,26229],{"class":175}," eslint-plugin-vue\n",[151,26231,26233],{"id":26232},"_2-建立設定檔","2. 建立設定檔",[11,26235,26236,26237,5240],{},"專案根目錄新增 ",[29,26238,26239],{},".eslintrc.js",[22,26241,26243],{"className":24,"code":26242,"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,26244,26245,26257,26262,26271,26278,26282,26292,26297,26307,26315,26319,26324,26334,26338],{"__ignoreMap":27},[32,26246,26247,26249,26251,26253,26255],{"class":34,"line":35},[32,26248,7130],{"class":351},[32,26250,1278],{"class":41},[32,26252,7135],{"class":351},[32,26254,894],{"class":38},[32,26256,703],{"class":41},[32,26258,26259],{"class":34,"line":45},[32,26260,26261],{"class":41},"  env: {\n",[32,26263,26264,26267,26269],{"class":34,"line":51},[32,26265,26266],{"class":41},"    browser: ",[32,26268,6206],{"class":351},[32,26270,547],{"class":41},[32,26272,26273,26276],{"class":34,"line":90},[32,26274,26275],{"class":41},"    es2023: ",[32,26277,26186],{"class":351},[32,26279,26280],{"class":34,"line":99},[32,26281,5639],{"class":41},[32,26283,26284,26287,26290],{"class":34,"line":106},[32,26285,26286],{"class":41},"  extends: [",[32,26288,26289],{"class":175},"'@nuxtjs\u002Feslint-config-typescript'",[32,26291,8212],{"class":41},[32,26293,26294],{"class":34,"line":114},[32,26295,26296],{"class":41},"  parserOptions: {\n",[32,26298,26299,26302,26305],{"class":34,"line":120},[32,26300,26301],{"class":41},"    ecmaVersion: ",[32,26303,26304],{"class":351},"2023",[32,26306,547],{"class":41},[32,26308,26309,26312],{"class":34,"line":127},[32,26310,26311],{"class":41},"    sourceType: ",[32,26313,26314],{"class":175},"'module'\n",[32,26316,26317],{"class":34,"line":132},[32,26318,5639],{"class":41},[32,26320,26321],{"class":34,"line":141},[32,26322,26323],{"class":41},"  rules: {\n",[32,26325,26326,26329,26331],{"class":34,"line":147},[32,26327,26328],{"class":175},"    'no-undef'",[32,26330,5269],{"class":41},[32,26332,26333],{"class":175},"'off'\n",[32,26335,26336],{"class":34,"line":275},[32,26337,1203],{"class":41},[32,26339,26340],{"class":34,"line":282},[32,26341,54],{"class":41},[11,26343,26344,26347,26348,26351,26352,26355],{},[29,26345,26346],{},"extends"," 是陣列，放要擴展的規則配置。",[29,26349,26350],{},"@nuxtjs\u002Feslint-config-typescript"," 是官方針對 Nuxt + TypeScript 的規則；如果專案沒用 TypeScript，改用 ",[29,26353,26354],{},"@nuxtjs\u002Feslint-config"," 即可。",[11,26357,26358,26361,26362,3750,26365,26368],{},[29,26359,26360],{},"no-undef"," 要關掉，是因為 Nuxt 有大量自動匯入的 API（",[29,26363,26364],{},"useRoute",[29,26366,26367],{},"defineNuxtConfig","⋯⋯），ESLint 看不到它們的宣告，開著會滿江紅。",[15,26370,26371],{"id":26371},"預設目錄結構",[11,26373,26374],{},"Nuxt 3 是「約定優於設定」，資料夾名稱本身就是設定，所以要先知道每個資料夾在幹嘛。",[22,26376,26379],{"className":26377,"code":26378,"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,26380,26378],{"__ignoreMap":27},[13574,26382,26383,26392],{},[13577,26384,26385],{},[13580,26386,26387,26390],{},[13583,26388,26389],{},"目錄／檔案",[13583,26391,14529],{},[13590,26393,26394,26407,26419,26429,26439,26449,26472,26482,26492,26505,26515,26531],{},[13580,26395,26396,26401],{},[13595,26397,26398],{},[29,26399,26400],{},".nuxt\u002F",[13595,26402,26403,26404],{},"開發環境下自動產生的 Vue 網站，",[12390,26405,26406],{},"不要手動改",[13580,26408,26409,26414],{},[13595,26410,26411],{},[29,26412,26413],{},".output\u002F",[13595,26415,26416,26417],{},"build 的產出，每次建置都會重新產生，",[12390,26418,26406],{},[13580,26420,26421,26426],{},[13595,26422,26423],{},[29,26424,26425],{},"assets\u002F",[13595,26427,26428],{},"需要被 Vite 處理的靜態資源（CSS\u002FSASS、字型、圖片）",[13580,26430,26431,26436],{},[13595,26432,26433],{},[29,26434,26435],{},"components\u002F",[13595,26437,26438],{},"Vue 元件，Nuxt 會自動載入，不用 import",[13580,26440,26441,26446],{},[13595,26442,26443],{},[29,26444,26445],{},"composables\u002F",[13595,26447,26448],{},"組合式函數，同樣自動載入",[13580,26450,26451,26456],{},[13595,26452,26453],{},[29,26454,26455],{},"content\u002F",[13595,26457,26458,26459,11762,26462,11762,26465,11762,26468,26471],{},"給 Nuxt Content 用，放 ",[29,26460,26461],{},".md",[29,26463,26464],{},".yml",[29,26466,26467],{},".csv",[29,26469,26470],{},".json","，做檔案式 CMS",[13580,26473,26474,26479],{},[13595,26475,26476],{},[29,26477,26478],{},"layouts\u002F",[13595,26480,26481],{},"版面模板，提供跨頁面重複使用的外框",[13580,26483,26484,26489],{},[13595,26485,26486],{},[29,26487,26488],{},"middleware\u002F",[13595,26490,26491],{},"路由中間件，導航到下一頁之前執行（例如權限驗證）",[13580,26493,26494,26499],{},[13595,26495,26496],{},[29,26497,26498],{},"pages\u002F",[13595,26500,26501,26502],{},"頁面，",[12390,26503,26504],{},"檔案結構直接決定路由",[13580,26506,26507,26512],{},[13595,26508,26509],{},[29,26510,26511],{},"plugins\u002F",[13595,26513,26514],{},"外掛，會自動載入",[13580,26516,26517,26522],{},[13595,26518,26519],{},[29,26520,26521],{},"public\u002F",[13595,26523,26524,26525,3750,26528,18240],{},"直接放在網站根目錄的檔案（",[29,26526,26527],{},"robots.txt",[29,26529,26530],{},"favicon.ico",[13580,26532,26533,26538],{},[13595,26534,26535],{},[29,26536,26537],{},"server\u002F",[13595,26539,26540,26541,26544],{},"後端邏輯（API、routes、middleware），",[12390,26542,26543],{},"不自動載入","但支援 HMR",[11,26546,26547],{},"幾個檔案：",[4538,26549,26550,26558,26569,26577,26584],{},[4541,26551,26552,26557],{},[12390,26553,26554],{},[29,26555,26556],{},".nuxtignore","：建置時要忽略的檔案",[4541,26559,26560,26565,26566],{},[12390,26561,26562],{},[29,26563,26564],{},"app.config.ts","：執行期會暴露給客戶端的設定，",[12390,26567,26568],{},"不要放任何機密",[4541,26570,26571,26576],{},[12390,26572,26573],{},[29,26574,26575],{},"app.vue","：Nuxt 3 網站的入口元件",[4541,26578,26579,26583],{},[12390,26580,26581],{},[29,26582,24155],{},"：專案設定檔",[4541,26585,26586,26590,26591,26593],{},[12390,26587,26588],{},[29,26589,26127],{},"：Nuxt 3 會在 ",[29,26592,26400],{}," 底下自動產一份含路徑別名的設定，根目錄這份用來擴展或覆蓋它",[11,26595,26596,7090,26598,26600,26601,19816,26606,26608,26609,26612],{},[29,26597,26425],{},[29,26599,26521],{}," 最容易搞混：",[12390,26602,26603,26605],{},[29,26604,26425],{}," 裡的東西要在 JS\u002FCSS 裡 import 才會被處理",[29,26607,26521],{}," 則是原封不動搬到根目錄，用絕對路徑 ",[29,26610,26611],{},"\u002Fxxx.png"," 引用。",[11,26614,26615,26616,7218,26618,26621],{},"目錄名稱也可以改，在 ",[29,26617,24155],{},[29,26619,26620],{},"dir"," 參數調整，但不是每個都能改，能改的只有官方列出的那幾個。",[15,26623,26624],{"id":26624},"檔案系統路由",[11,26626,26627,26628,26630],{},"Nuxt 的核心特性是「檔案系統路由器（file system router）」——",[29,26629,26498],{}," 底下每一個 Vue 檔案都會產生一個對應的 URL。底層還是 vue-router，只是路由表由檔名自動推出來，不用自己維護。",[151,26632,26633],{"id":26633},"建立第一個頁面",[11,26635,12908,26636,26639,26640,26642],{},[29,26637,26638],{},"pages\u002Findex.vue","，然後把 ",[29,26641,26575],{}," 改成：",[22,26644,26646],{"className":8665,"code":26645,"language":4112,"meta":27,"style":27},"\u003Ctemplate>\n  \u003Cdiv>\n    \u003CNuxtPage \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[29,26647,26648,26656,26664,26673,26681],{"__ignoreMap":27},[32,26649,26650,26652,26654],{"class":34,"line":35},[32,26651,4046],{"class":41},[32,26653,9623],{"class":4049},[32,26655,4062],{"class":41},[32,26657,26658,26660,26662],{"class":34,"line":45},[32,26659,4067],{"class":41},[32,26661,4050],{"class":4049},[32,26663,4062],{"class":41},[32,26665,26666,26668,26671],{"class":34,"line":51},[32,26667,9638],{"class":41},[32,26669,26670],{"class":4049},"NuxtPage",[32,26672,16945],{"class":41},[32,26674,26675,26677,26679],{"class":34,"line":90},[32,26676,9691],{"class":41},[32,26678,4050],{"class":4049},[32,26680,4062],{"class":41},[32,26682,26683,26685,26687],{"class":34,"line":99},[32,26684,4105],{"class":41},[32,26686,9623],{"class":4049},[32,26688,4062],{"class":41},[11,26690,26691,26693,26694,26700],{},[29,26692,17021],{}," 就是路由頁面被塞進來的位置。",[12390,26695,26696,26697,26699],{},"一旦建立了 ",[29,26698,26498],{}," 目錄，就一定要有這個元件","，否則什麼都不會顯示。",[151,26702,26703],{"id":26703},"查看自動產生的路由",[11,26705,26706],{},"想看 Nuxt 實際產出的路由表長什麼樣，可以 build 之後翻產物：",[22,26708,26709],{"className":2057,"code":4973,"language":2059,"meta":27,"style":27},[29,26710,26711],{"__ignoreMap":27},[32,26712,26713,26715,26717],{"class":34,"line":35},[32,26714,4625],{"class":2066},[32,26716,4743],{"class":175},[32,26718,4755],{"class":175},[11,26720,26721,26722,26725,26726,26729,26730,26733],{},"打開 ",[29,26723,26724],{},".output\u002Fserver\u002Fchunks\u002Fapp\u002Fserver.mjs","，搜尋 ",[29,26727,26728],{},"const _routes =","，或直接搜尋你剛建立的檔名（例如 ",[29,26731,26732],{},"about","），就會看到類似這樣的結構：",[22,26735,26737],{"className":24,"code":26736,"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,26738,26739,26750,26754,26763,26773,26791,26795,26800],{"__ignoreMap":27},[32,26740,26741,26743,26746,26748],{"class":34,"line":35},[32,26742,6617],{"class":38},[32,26744,26745],{"class":351}," _routes",[32,26747,894],{"class":38},[32,26749,17768],{"class":41},[32,26751,26752],{"class":34,"line":45},[32,26753,6526],{"class":41},[32,26755,26756,26758,26761],{"class":34,"line":51},[32,26757,21273],{"class":41},[32,26759,26760],{"class":175},"\"about\"",[32,26762,547],{"class":41},[32,26764,26765,26768,26771],{"class":34,"line":90},[32,26766,26767],{"class":41},"    path: ",[32,26769,26770],{"class":175},"\"\u002Fabout\"",[32,26772,547],{"class":41},[32,26774,26775,26778,26780,26782,26784,26786,26789],{"class":34,"line":99},[32,26776,26777],{"class":217},"    component",[32,26779,5087],{"class":41},[32,26781,5090],{"class":38},[32,26783,5093],{"class":38},[32,26785,477],{"class":41},[32,26787,26788],{"class":175},"'.\u002F_nuxt\u002Fabout-xxxxxxxx.mjs'",[32,26790,515],{"class":41},[32,26792,26793],{"class":34,"line":106},[32,26794,5639],{"class":41},[32,26796,26797],{"class":34,"line":114},[32,26798,26799],{"class":38},"  ...\n",[32,26801,26802],{"class":34,"line":120},[32,26803,26804],{"class":41},"]\n",[151,26806,26807],{"id":26807},"路由連結",[11,26809,26810,26811,26813,26814,26817],{},"用 ",[29,26812,21337],{}," 而不是 ",[29,26815,26816],{},"\u003Ca>","，才會走前端導航不重新載入整頁：",[22,26819,26821],{"className":8665,"code":26820,"language":4112,"meta":27,"style":27},"\u003CNuxtLink to=\"\u002Fabout\">前往 About\u003C\u002FNuxtLink>\n\u003CNuxtLink to=\"\u002Fcontact\">前往 Contact\u003C\u002FNuxtLink>\n",[29,26822,26823,26844],{"__ignoreMap":27},[32,26824,26825,26827,26830,26833,26835,26837,26840,26842],{"class":34,"line":35},[32,26826,4046],{"class":41},[32,26828,26829],{"class":4049},"NuxtLink",[32,26831,26832],{"class":4053}," to",[32,26834,172],{"class":41},[32,26836,26770],{"class":175},[32,26838,26839],{"class":41},">前往 About\u003C\u002F",[32,26841,26829],{"class":4049},[32,26843,4062],{"class":41},[32,26845,26846,26848,26850,26852,26854,26857,26860,26862],{"class":34,"line":45},[32,26847,4046],{"class":41},[32,26849,26829],{"class":4049},[32,26851,26832],{"class":4053},[32,26853,172],{"class":41},[32,26855,26856],{"class":175},"\"\u002Fcontact\"",[32,26858,26859],{"class":41},">前往 Contact\u003C\u002F",[32,26861,26829],{"class":4049},[32,26863,4062],{"class":41},[151,26865,26866],{"id":26866},"動態路由",[11,26868,26869],{},"檔名用中括號包起來就是動態參數：",[22,26871,26874],{"className":26872,"code":26873,"language":426,"meta":27},[424],".\u002Fpages\u002F\n└── users\u002F\n    └── [id].vue\n",[29,26875,26873],{"__ignoreMap":27},[22,26877,26879],{"className":8665,"code":26878,"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,26880,26881,26889,26904,26919,26939,26954,26959,26979,26987,26995,27003,27011,27015,27025,27039,27054],{"__ignoreMap":27},[32,26882,26883,26885,26887],{"class":34,"line":35},[32,26884,4046],{"class":41},[32,26886,9623],{"class":4049},[32,26888,4062],{"class":41},[32,26890,26891,26893,26895,26897,26899,26902],{"class":34,"line":45},[32,26892,4067],{"class":41},[32,26894,4050],{"class":4049},[32,26896,9897],{"class":4053},[32,26898,172],{"class":41},[32,26900,26901],{"class":175},"\"bg-white py-24\"",[32,26903,4062],{"class":41},[32,26905,26906,26908,26910,26912,26914,26917],{"class":34,"line":51},[32,26907,9638],{"class":41},[32,26909,4050],{"class":4049},[32,26911,9897],{"class":4053},[32,26913,172],{"class":41},[32,26915,26916],{"class":175},"\"flex flex-col items-center\"",[32,26918,4062],{"class":41},[32,26920,26921,26923,26925,26927,26929,26932,26935,26937],{"class":34,"line":90},[32,26922,24618],{"class":41},[32,26924,12608],{"class":4049},[32,26926,9897],{"class":4053},[32,26928,172],{"class":41},[32,26930,26931],{"class":175},"\"text-3xl text-gray-600\"",[32,26933,26934],{"class":41},">這裡是 Users 動態路由頁面\u003C\u002F",[32,26936,12608],{"class":4049},[32,26938,4062],{"class":41},[32,26940,26941,26943,26945,26947,26949,26952],{"class":34,"line":99},[32,26942,24618],{"class":41},[32,26944,11],{"class":4049},[32,26946,9897],{"class":4053},[32,26948,172],{"class":41},[32,26950,26951],{"class":175},"\"my-8 text-3xl text-gray-600\"",[32,26953,4062],{"class":41},[32,26955,26956],{"class":34,"line":106},[32,26957,26958],{"class":41},"        匹配到的 Id:\n",[32,26960,26961,26963,26965,26967,26969,26972,26975,26977],{"class":34,"line":114},[32,26962,24647],{"class":41},[32,26964,32],{"class":4049},[32,26966,9897],{"class":4053},[32,26968,172],{"class":41},[32,26970,26971],{"class":175},"\"text-5xl font-semibold text-blue-600\"",[32,26973,26974],{"class":41},">{{ id }}\u003C\u002F",[32,26976,32],{"class":4049},[32,26978,4062],{"class":41},[32,26980,26981,26983,26985],{"class":34,"line":120},[32,26982,24669],{"class":41},[32,26984,11],{"class":4049},[32,26986,4062],{"class":41},[32,26988,26989,26991,26993],{"class":34,"line":127},[32,26990,24678],{"class":41},[32,26992,4050],{"class":4049},[32,26994,4062],{"class":41},[32,26996,26997,26999,27001],{"class":34,"line":132},[32,26998,9691],{"class":41},[32,27000,4050],{"class":4049},[32,27002,4062],{"class":41},[32,27004,27005,27007,27009],{"class":34,"line":141},[32,27006,4105],{"class":41},[32,27008,9623],{"class":4049},[32,27010,4062],{"class":41},[32,27012,27013],{"class":34,"line":147},[32,27014,103],{"emptyLinePlaceholder":102},[32,27016,27017,27019,27021,27023],{"class":34,"line":275},[32,27018,4046],{"class":41},[32,27020,4125],{"class":4049},[32,27022,24724],{"class":4053},[32,27024,4062],{"class":41},[32,27026,27027,27029,27032,27034,27037],{"class":34,"line":282},[32,27028,6617],{"class":38},[32,27030,27031],{"class":351}," route",[32,27033,894],{"class":38},[32,27035,27036],{"class":217}," useRoute",[32,27038,25253],{"class":41},[32,27040,27041,27043,27045,27047,27049,27051],{"class":34,"line":295},[32,27042,6617],{"class":38},[32,27044,24782],{"class":41},[32,27046,24816],{"class":351},[32,27048,24792],{"class":41},[32,27050,172],{"class":38},[32,27052,27053],{"class":41}," route.params\n",[32,27055,27056,27058,27060],{"class":34,"line":605},[32,27057,4105],{"class":41},[32,27059,4125],{"class":4049},[32,27061,4062],{"class":41},[151,27063,27064],{"id":27064},"匹配所有層級",[11,27066,27067],{},"三個點加參數名，可以吃掉後面所有層級：",[22,27069,27072],{"className":27070,"code":27071,"language":426,"meta":27},[424],".\u002Fpages\u002F\n└── catch-all\u002F\n    └── [...slug].vue\n",[29,27073,27071],{"__ignoreMap":27},[22,27075,27077],{"className":8665,"code":27076,"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,27078,27079,27087,27101,27115,27135,27155,27175,27195,27203,27211],{"__ignoreMap":27},[32,27080,27081,27083,27085],{"class":34,"line":35},[32,27082,4046],{"class":41},[32,27084,9623],{"class":4049},[32,27086,4062],{"class":41},[32,27088,27089,27091,27093,27095,27097,27099],{"class":34,"line":45},[32,27090,4067],{"class":41},[32,27092,4050],{"class":4049},[32,27094,9897],{"class":4053},[32,27096,172],{"class":41},[32,27098,26901],{"class":175},[32,27100,4062],{"class":41},[32,27102,27103,27105,27107,27109,27111,27113],{"class":34,"line":51},[32,27104,9638],{"class":41},[32,27106,4050],{"class":4049},[32,27108,9897],{"class":4053},[32,27110,172],{"class":41},[32,27112,26916],{"class":175},[32,27114,4062],{"class":41},[32,27116,27117,27119,27121,27123,27125,27128,27131,27133],{"class":34,"line":90},[32,27118,24618],{"class":41},[32,27120,12608],{"class":4049},[32,27122,9897],{"class":4053},[32,27124,172],{"class":41},[32,27126,27127],{"class":175},"\"text-4xl text-gray-800\"",[32,27129,27130],{"class":41},">這是 catch-all\u002F... 下的頁面\u003C\u002F",[32,27132,12608],{"class":4049},[32,27134,4062],{"class":41},[32,27136,27137,27139,27141,27143,27145,27148,27151,27153],{"class":34,"line":99},[32,27138,24618],{"class":41},[32,27140,11],{"class":4049},[32,27142,9897],{"class":4053},[32,27144,172],{"class":41},[32,27146,27147],{"class":175},"\"mt-8 text-3xl text-gray-600\"",[32,27149,27150],{"class":41},">匹配到的 Params:\u003C\u002F",[32,27152,11],{"class":4049},[32,27154,4062],{"class":41},[32,27156,27157,27159,27161,27163,27165,27168,27171,27173],{"class":34,"line":106},[32,27158,24618],{"class":41},[32,27160,11],{"class":4049},[32,27162,9897],{"class":4053},[32,27164,172],{"class":41},[32,27166,27167],{"class":175},"\"my-4 text-5xl font-semibold text-violet-500\"",[32,27169,27170],{"class":41},">{{ $route.params.slug }}\u003C\u002F",[32,27172,11],{"class":4049},[32,27174,4062],{"class":41},[32,27176,27177,27179,27181,27183,27185,27188,27191,27193],{"class":34,"line":114},[32,27178,24618],{"class":41},[32,27180,32],{"class":4049},[32,27182,9897],{"class":4053},[32,27184,172],{"class":41},[32,27186,27187],{"class":175},"\"text-xl text-gray-400\"",[32,27189,27190],{"class":41},">每個陣列元素對應一個層級\u003C\u002F",[32,27192,32],{"class":4049},[32,27194,4062],{"class":41},[32,27196,27197,27199,27201],{"class":34,"line":120},[32,27198,24678],{"class":41},[32,27200,4050],{"class":4049},[32,27202,4062],{"class":41},[32,27204,27205,27207,27209],{"class":34,"line":127},[32,27206,9691],{"class":41},[32,27208,4050],{"class":4049},[32,27210,4062],{"class":41},[32,27212,27213,27215,27217],{"class":34,"line":132},[32,27214,4105],{"class":41},[32,27216,9623],{"class":4049},[32,27218,4062],{"class":41},[11,27220,27221,27222,7090,27225,27228,27229,27232,27233,27236],{},"輸入 ",[29,27223,27224],{},"\u002Fcatch-all\u002Fhello",[29,27226,27227],{},"\u002Fcatch-all\u002Fhello\u002Fworld"," 都會進到這頁，差別在 ",[29,27230,27231],{},"slug"," 是一個",[12390,27234,27235],{},"陣列","，每個元素對應一個層級。",[151,27238,27240],{"id":27239},"_404-頁面","404 頁面",[11,27242,27243,27244,27246],{},"把 catch-all 放在 ",[29,27245,26498],{}," 根目錄，所有沒被匹配到的路由都會交給它：",[22,27248,27250],{"className":8665,"code":27249,"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,27251,27252,27260,27274,27288,27308,27328,27336,27344,27352,27356,27366,27378],{"__ignoreMap":27},[32,27253,27254,27256,27258],{"class":34,"line":35},[32,27255,4046],{"class":41},[32,27257,9623],{"class":4049},[32,27259,4062],{"class":41},[32,27261,27262,27264,27266,27268,27270,27272],{"class":34,"line":45},[32,27263,4067],{"class":41},[32,27265,4050],{"class":4049},[32,27267,9897],{"class":4053},[32,27269,172],{"class":41},[32,27271,26901],{"class":175},[32,27273,4062],{"class":41},[32,27275,27276,27278,27280,27282,27284,27286],{"class":34,"line":51},[32,27277,9638],{"class":41},[32,27279,4050],{"class":4049},[32,27281,9897],{"class":4053},[32,27283,172],{"class":41},[32,27285,26916],{"class":175},[32,27287,4062],{"class":41},[32,27289,27290,27292,27294,27296,27298,27301,27304,27306],{"class":34,"line":90},[32,27291,24618],{"class":41},[32,27293,12608],{"class":4049},[32,27295,9897],{"class":4053},[32,27297,172],{"class":41},[32,27299,27300],{"class":175},"\"text-8xl font-semibold text-red-500\"",[32,27302,27303],{"class":41},">404\u003C\u002F",[32,27305,12608],{"class":4049},[32,27307,4062],{"class":41},[32,27309,27310,27312,27314,27316,27318,27321,27324,27326],{"class":34,"line":99},[32,27311,24618],{"class":41},[32,27313,11],{"class":4049},[32,27315,9897],{"class":4053},[32,27317,172],{"class":41},[32,27319,27320],{"class":175},"\"my-8 text-3xl text-gray-800\"",[32,27322,27323],{"class":41},">Not Found\u003C\u002F",[32,27325,11],{"class":4049},[32,27327,4062],{"class":41},[32,27329,27330,27332,27334],{"class":34,"line":106},[32,27331,24678],{"class":41},[32,27333,4050],{"class":4049},[32,27335,4062],{"class":41},[32,27337,27338,27340,27342],{"class":34,"line":114},[32,27339,9691],{"class":41},[32,27341,4050],{"class":4049},[32,27343,4062],{"class":41},[32,27345,27346,27348,27350],{"class":34,"line":120},[32,27347,4105],{"class":41},[32,27349,9623],{"class":4049},[32,27351,4062],{"class":41},[32,27353,27354],{"class":34,"line":127},[32,27355,103],{"emptyLinePlaceholder":102},[32,27357,27358,27360,27362,27364],{"class":34,"line":132},[32,27359,4046],{"class":41},[32,27361,4125],{"class":4049},[32,27363,24724],{"class":4053},[32,27365,4062],{"class":41},[32,27367,27368,27371,27373,27376],{"class":34,"line":141},[32,27369,27370],{"class":217},"setResponseStatus",[32,27372,477],{"class":41},[32,27374,27375],{"class":351},"404",[32,27377,515],{"class":41},[32,27379,27380,27382,27384],{"class":34,"line":147},[32,27381,4105],{"class":41},[32,27383,4125],{"class":4049},[32,27385,4062],{"class":41},[11,27387,27388,27394],{},[12390,27389,27390,27393],{},[29,27391,27392],{},"setResponseStatus(404)"," 不能省","。少了它畫面上雖然寫著 404，HTTP 狀態碼卻是 200，搜尋引擎會把這些不存在的頁面通通收錄進去。",[151,27396,27397],{"id":27397},"多層目錄與巢狀路由",[11,27399,27400],{},"目錄結構直接對應路徑層級：",[22,27402,27405],{"className":27403,"code":27404,"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,27406,27404],{"__ignoreMap":27},[11,27408,27409,27410,5240],{},"巢狀路由則是",[12390,27411,27412,27413,27415],{},"同名的資料夾與 ",[29,27414,5141],{}," 檔並存",[22,27417,27420],{"className":27418,"code":27419,"language":426,"meta":27},[424],".\u002Fpages\u002F\n├── docs\u002F\n│   ├── doc-1.vue\n│   └── doc-2.vue\n└── docs.vue\n",[29,27421,27419],{"__ignoreMap":27},[11,27423,27424,27427,27428,27430,27431,27434],{},[29,27425,27426],{},"docs.vue"," 是外層容器（裡面要放 ",[29,27429,17021],{},"），",[29,27432,27433],{},"docs\u002F"," 底下的檔案會被渲染進去。",[11,27436,27437],{},"靠目錄結構與中括號就能涵蓋大部分情境，實務上很少需要手動定義路由規則。",[15,27439,13203],{"id":27440},"layout",[11,27442,27443,27444,27446],{},"版面模板放在 ",[29,27445,26478],{},"，同樣會自動載入。",[151,27448,27449],{"id":27449},"預設模板",[11,27451,12908,27452,5240],{},[29,27453,27454],{},"layouts\u002Fdefault.vue",[22,27456,27458],{"className":8665,"code":27457,"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,27459,27460,27468,27483,27503,27522,27532,27549,27557],{"__ignoreMap":27},[32,27461,27462,27464,27466],{"class":34,"line":35},[32,27463,4046],{"class":41},[32,27465,9623],{"class":4049},[32,27467,4062],{"class":41},[32,27469,27470,27472,27474,27476,27478,27481],{"class":34,"line":45},[32,27471,4067],{"class":41},[32,27473,4050],{"class":4049},[32,27475,9897],{"class":4053},[32,27477,172],{"class":41},[32,27479,27480],{"class":175},"\"bg-sky-100 py-2\"",[32,27482,4062],{"class":41},[32,27484,27485,27487,27489,27491,27493,27496,27499,27501],{"class":34,"line":51},[32,27486,9638],{"class":41},[32,27488,11],{"class":4049},[32,27490,9897],{"class":4053},[32,27492,172],{"class":41},[32,27494,27495],{"class":175},"\"px-6 py-4 text-2xl text-gray-700\"",[32,27497,27498],{"class":41},">這是預設的布局，全部頁面都會使用到\u003C\u002F",[32,27500,11],{"class":4049},[32,27502,4062],{"class":41},[32,27504,27505,27507,27510,27512,27514,27517,27520],{"class":34,"line":90},[32,27506,9638],{"class":41},[32,27508,27509],{"class":4049},"slot",[32,27511,5668],{"class":4053},[32,27513,172],{"class":41},[32,27515,27516],{"class":175},"\"header\"",[32,27518,8160],{"class":27519},"sAjPK",[32,27521,4062],{"class":41},[32,27523,27524,27526,27528,27530],{"class":34,"line":99},[32,27525,9638],{"class":41},[32,27527,27509],{"class":4049},[32,27529,8160],{"class":27519},[32,27531,4062],{"class":41},[32,27533,27534,27536,27538,27540,27542,27545,27547],{"class":34,"line":106},[32,27535,9638],{"class":41},[32,27537,27509],{"class":4049},[32,27539,5668],{"class":4053},[32,27541,172],{"class":41},[32,27543,27544],{"class":175},"\"footer\"",[32,27546,8160],{"class":27519},[32,27548,4062],{"class":41},[32,27550,27551,27553,27555],{"class":34,"line":114},[32,27552,9691],{"class":41},[32,27554,4050],{"class":4049},[32,27556,4062],{"class":41},[32,27558,27559,27561,27563],{"class":34,"line":120},[32,27560,4105],{"class":41},[32,27562,9623],{"class":4049},[32,27564,4062],{"class":41},[11,27566,27567,27568,27571],{},"模板裡一定要有一個未命名的 ",[29,27569,27570],{},"\u003Cslot \u002F>","，那是採用這個模板的頁面內容會出現的位置。",[151,27573,27575],{"id":27574},"在-appvue-掛上-nuxtlayout","在 app.vue 掛上 NuxtLayout",[22,27577,27579],{"className":8665,"code":27578,"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,27580,27581,27589,27597,27617,27633,27647,27667,27675,27688,27696,27704,27716,27736,27744,27752,27760],{"__ignoreMap":27},[32,27582,27583,27585,27587],{"class":34,"line":35},[32,27584,4046],{"class":41},[32,27586,9623],{"class":4049},[32,27588,4062],{"class":41},[32,27590,27591,27593,27595],{"class":34,"line":45},[32,27592,4067],{"class":41},[32,27594,4050],{"class":4049},[32,27596,4062],{"class":41},[32,27598,27599,27601,27603,27605,27607,27610,27613,27615],{"class":34,"line":51},[32,27600,9638],{"class":41},[32,27602,11],{"class":4049},[32,27604,9897],{"class":4053},[32,27606,172],{"class":41},[32,27608,27609],{"class":175},"\"pb-4 text-2xl text-slate-600\"",[32,27611,27612],{"class":41},">這裡是最外層 app.vue\u003C\u002F",[32,27614,11],{"class":4049},[32,27616,4062],{"class":41},[32,27618,27619,27621,27624,27626,27628,27631],{"class":34,"line":90},[32,27620,9638],{"class":41},[32,27622,27623],{"class":4049},"NuxtLayout",[32,27625,5668],{"class":4053},[32,27627,172],{"class":41},[32,27629,27630],{"class":175},"\"default\"",[32,27632,4062],{"class":41},[32,27634,27635,27637,27639,27642,27645],{"class":34,"line":99},[32,27636,24618],{"class":41},[32,27638,9623],{"class":4049},[32,27640,27641],{"class":41}," #",[32,27643,27644],{"class":4053},"header",[32,27646,4062],{"class":41},[32,27648,27649,27651,27653,27655,27657,27660,27663,27665],{"class":34,"line":106},[32,27650,24647],{"class":41},[32,27652,11],{"class":4049},[32,27654,9897],{"class":4053},[32,27656,172],{"class":41},[32,27658,27659],{"class":175},"\"px-6 pt-4 text-xl text-green-500\"",[32,27661,27662],{"class":41},">這段會放置在 header 插槽\u003C\u002F",[32,27664,11],{"class":4049},[32,27666,4062],{"class":41},[32,27668,27669,27671,27673],{"class":34,"line":114},[32,27670,24669],{"class":41},[32,27672,9623],{"class":4049},[32,27674,4062],{"class":41},[32,27676,27677,27679,27681,27683,27686],{"class":34,"line":120},[32,27678,24618],{"class":41},[32,27680,9623],{"class":4049},[32,27682,27641],{"class":41},[32,27684,27685],{"class":4053},"default",[32,27687,4062],{"class":41},[32,27689,27690,27692,27694],{"class":34,"line":127},[32,27691,24647],{"class":41},[32,27693,26670],{"class":4049},[32,27695,16945],{"class":41},[32,27697,27698,27700,27702],{"class":34,"line":132},[32,27699,24669],{"class":41},[32,27701,9623],{"class":4049},[32,27703,4062],{"class":41},[32,27705,27706,27708,27710,27712,27714],{"class":34,"line":141},[32,27707,24618],{"class":41},[32,27709,9623],{"class":4049},[32,27711,27641],{"class":41},[32,27713,14417],{"class":4053},[32,27715,4062],{"class":41},[32,27717,27718,27720,27722,27724,27726,27729,27732,27734],{"class":34,"line":147},[32,27719,24647],{"class":41},[32,27721,11],{"class":4049},[32,27723,9897],{"class":4053},[32,27725,172],{"class":41},[32,27727,27728],{"class":175},"\"px-6 pt-4 text-xl text-blue-500\"",[32,27730,27731],{"class":41},">這段會放置在 footer 插槽\u003C\u002F",[32,27733,11],{"class":4049},[32,27735,4062],{"class":41},[32,27737,27738,27740,27742],{"class":34,"line":275},[32,27739,24669],{"class":41},[32,27741,9623],{"class":4049},[32,27743,4062],{"class":41},[32,27745,27746,27748,27750],{"class":34,"line":282},[32,27747,24678],{"class":41},[32,27749,27623],{"class":4049},[32,27751,4062],{"class":41},[32,27753,27754,27756,27758],{"class":34,"line":295},[32,27755,9691],{"class":41},[32,27757,4050],{"class":4049},[32,27759,4062],{"class":41},[32,27761,27762,27764,27766],{"class":34,"line":605},[32,27763,4105],{"class":41},[32,27765,9623],{"class":4049},[32,27767,4062],{"class":41},[11,27769,27770,27772,27773,27775],{},[29,27771,18859],{}," 預設就是 ",[29,27774,27685],{},"，這裡明寫出來只是避免誤會。",[151,27777,27778],{"id":27778},"指定其他模板",[11,27780,12908,27781,5240],{},[29,27782,27783],{},"layouts\u002Fcustom.vue",[22,27785,27787],{"className":8665,"code":27786,"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,27788,27789,27797,27812,27826,27848,27856,27866,27874],{"__ignoreMap":27},[32,27790,27791,27793,27795],{"class":34,"line":35},[32,27792,4046],{"class":41},[32,27794,9623],{"class":4049},[32,27796,4062],{"class":41},[32,27798,27799,27801,27803,27805,27807,27810],{"class":34,"line":45},[32,27800,4067],{"class":41},[32,27802,4050],{"class":4049},[32,27804,9897],{"class":4053},[32,27806,172],{"class":41},[32,27808,27809],{"class":175},"\"bg-rose-100 py-2\"",[32,27811,4062],{"class":41},[32,27813,27814,27816,27818,27820,27822,27824],{"class":34,"line":51},[32,27815,9638],{"class":41},[32,27817,11],{"class":4049},[32,27819,9897],{"class":4053},[32,27821,172],{"class":41},[32,27823,27495],{"class":175},[32,27825,4062],{"class":41},[32,27827,27828,27831,27833,27835,27837,27840,27843,27845],{"class":34,"line":90},[32,27829,27830],{"class":41},"      使用 \u003C",[32,27832,32],{"class":4049},[32,27834,9897],{"class":4053},[32,27836,172],{"class":41},[32,27838,27839],{"class":175},"\"font-bold text-rose-500\"",[32,27841,27842],{"class":41},">Custom\u003C\u002F",[32,27844,32],{"class":4049},[32,27846,27847],{"class":41},"> 布局\n",[32,27849,27850,27852,27854],{"class":34,"line":99},[32,27851,24678],{"class":41},[32,27853,11],{"class":4049},[32,27855,4062],{"class":41},[32,27857,27858,27860,27862,27864],{"class":34,"line":106},[32,27859,9638],{"class":41},[32,27861,27509],{"class":4049},[32,27863,8160],{"class":27519},[32,27865,4062],{"class":41},[32,27867,27868,27870,27872],{"class":34,"line":114},[32,27869,9691],{"class":41},[32,27871,4050],{"class":4049},[32,27873,4062],{"class":41},[32,27875,27876,27878,27880],{"class":34,"line":120},[32,27877,4105],{"class":41},[32,27879,9623],{"class":4049},[32,27881,4062],{"class":41},[11,27883,27884,27885,5240],{},"在要套用的頁面用 ",[29,27886,27887],{},"definePageMeta",[22,27889,27891],{"className":8665,"code":27890,"language":4112,"meta":27,"style":27},"\u003Cscript setup>\ndefinePageMeta({\n  layout: 'custom'\n})\n\u003C\u002Fscript>\n",[29,27892,27893,27903,27909,27916,27920],{"__ignoreMap":27},[32,27894,27895,27897,27899,27901],{"class":34,"line":35},[32,27896,4046],{"class":41},[32,27898,4125],{"class":4049},[32,27900,24724],{"class":4053},[32,27902,4062],{"class":41},[32,27904,27905,27907],{"class":34,"line":45},[32,27906,27887],{"class":217},[32,27908,1143],{"class":41},[32,27910,27911,27913],{"class":34,"line":51},[32,27912,16990],{"class":41},[32,27914,27915],{"class":175},"'custom'\n",[32,27917,27918],{"class":34,"line":90},[32,27919,24189],{"class":41},[32,27921,27922,27924,27926],{"class":34,"line":99},[32,27923,4105],{"class":41},[32,27925,4125],{"class":4049},[32,27927,4062],{"class":41},[11,27929,27930,27933,27934,27937,27938,27940,27941,27944,27945,3775],{},[12390,27931,27932],{},"模板名稱一律是 kebab-case","。檔名寫 ",[29,27935,27936],{},"customLayout.vue"," 的話，要傳給 ",[29,27939,27440],{}," 的值是 ",[29,27942,27943],{},"custom-layout","，不是 ",[29,27946,27947],{},"customLayout",[15,27949,27950],{"id":27950},"元件",[11,27952,27953,27955,27956,5240],{},[29,27954,26435],{}," 底下的元件會被自動載入，不需要 import。命名規則是",[12390,27957,27958],{},"用路徑推出元件名稱",[22,27960,27963],{"className":27961,"code":27962,"language":426,"meta":27},[424],".\u002Fcomponents\u002F\n├── AppHeader.vue          → \u003CAppHeader \u002F>\n└── base\u002F\n    └── Button.vue         → \u003CBaseButton \u002F>\n",[29,27964,27962],{"__ignoreMap":27},[11,27966,27967,27968,14772,27971,26813,27974,27977,27978,27980,27981,3775],{},"子資料夾名稱會變成元件名稱的前綴，所以 ",[29,27969,27970],{},"base\u002FButton.vue",[29,27972,27973],{},"\u003CBaseButton \u002F>",[29,27975,27976],{},"\u003CButton \u002F>","。想關掉這個行為，在 ",[29,27979,24155],{}," 設 ",[29,27982,27983],{},"components: { pathPrefix: false }",[11,27985,27986,27987,10450,27990,27993,27994,27997,27998,28000],{},"檔名加上 ",[29,27988,27989],{},".client",[29,27991,27992],{},".server"," 後綴可以決定它只在哪一端渲染，例如 ",[29,27995,27996],{},"Chart.client.vue"," 只在瀏覽器渲染——用到 ",[29,27999,11437],{}," 的元件很需要這個。",[15,28002,23916],{"id":28003},"pinia",[11,28005,28006],{},"Pinia 是取代 Vuex 的全域狀態管理函式庫，比較輕量，適合中小型專案。",[22,28008,28010],{"className":2057,"code":28009,"language":2059,"meta":27,"style":27},"npm install pinia @pinia\u002Fnuxt --save-dev\n",[29,28011,28012],{"__ignoreMap":27},[32,28013,28014,28016,28018,28020,28023],{"class":34,"line":35},[32,28015,4625],{"class":2066},[32,28017,4650],{"class":175},[32,28019,24147],{"class":175},[32,28021,28022],{"class":175}," @pinia\u002Fnuxt",[32,28024,7066],{"class":351},[11,28026,28027,5240],{},[29,28028,24155],{},[22,28030,28032],{"className":26159,"code":28031,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: [\n    '@pinia\u002Fnuxt'\n  ]\n})\n",[29,28033,28034,28044,28049,28054,28059],{"__ignoreMap":27},[32,28035,28036,28038,28040,28042],{"class":34,"line":35},[32,28037,5038],{"class":38},[32,28039,5041],{"class":38},[32,28041,24171],{"class":217},[32,28043,1143],{"class":5049},[32,28045,28046],{"class":34,"line":45},[32,28047,28048],{"class":41},"  modules: [\n",[32,28050,28051],{"class":34,"line":51},[32,28052,28053],{"class":175},"    '@pinia\u002Fnuxt'\n",[32,28055,28056],{"class":34,"line":90},[32,28057,28058],{"class":41},"  ]\n",[32,28060,28061],{"class":34,"line":99},[32,28062,24189],{"class":5049},[151,28064,28066],{"id":28065},"踩坑pinia-或相依套件裝不起來","踩坑：Pinia 或相依套件裝不起來",[11,28068,28069,28070,28072],{},"裝的時候如果一直卡在相依衝突，在 ",[29,28071,4945],{}," 加上：",[22,28074,28076],{"className":5243,"code":28075,"language":5245,"meta":27,"style":27},"{\n  \"overrides\": {\n    \"vue\": \"latest\"\n  }\n}\n",[29,28077,28078,28082,28089,28099,28103],{"__ignoreMap":27},[32,28079,28080],{"class":34,"line":35},[32,28081,5252],{"class":41},[32,28083,28084,28087],{"class":34,"line":45},[32,28085,28086],{"class":5257},"  \"overrides\"",[32,28088,5261],{"class":41},[32,28090,28091,28094,28096],{"class":34,"line":51},[32,28092,28093],{"class":5257},"    \"vue\"",[32,28095,5269],{"class":41},[32,28097,28098],{"class":175},"\"latest\"\n",[32,28100,28101],{"class":34,"line":90},[32,28102,1203],{"class":41},[32,28104,28105],{"class":34,"line":99},[32,28106,54],{"class":41},[11,28108,28109,28110,28113],{},"原因是 Pinia 與 Nuxt 各自宣告的 vue 版本範圍對不上，npm 解不出一組共同的答案。",[29,28111,28112],{},"overrides"," 直接指定用哪一版，繞過解析。",[15,28115,4847],{"id":28116},"sass",[22,28118,28120],{"className":2057,"code":28119,"language":2059,"meta":27,"style":27},"npm install node-sass sass-loader sass -D\n",[29,28121,28122],{"__ignoreMap":27},[32,28123,28124,28126,28128,28130,28132,28135],{"class":34,"line":35},[32,28125,4625],{"class":2066},[32,28127,4650],{"class":175},[32,28129,8632],{"class":175},[32,28131,8635],{"class":175},[32,28133,28134],{"class":175}," sass",[32,28136,28137],{"class":351}," -D\n",[22,28139,28141],{"className":26159,"code":28140,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  css: ['~\u002Fassets\u002Fscss\u002Fapp.scss']\n})\n",[29,28142,28143,28153,28163],{"__ignoreMap":27},[32,28144,28145,28147,28149,28151],{"class":34,"line":35},[32,28146,5038],{"class":38},[32,28148,5041],{"class":38},[32,28150,24171],{"class":217},[32,28152,1143],{"class":5049},[32,28154,28155,28158,28161],{"class":34,"line":45},[32,28156,28157],{"class":41},"  css: [",[32,28159,28160],{"class":175},"'~\u002Fassets\u002Fscss\u002Fapp.scss'",[32,28162,26804],{"class":41},[32,28164,28165],{"class":34,"line":51},[32,28166,24189],{"class":5049},[15,28168,28170],{"id":28169},"tailwind-css","Tailwind CSS",[22,28172,28174],{"className":2057,"code":28173,"language":2059,"meta":27,"style":27},"npm install -D @nuxtjs\u002Ftailwindcss\n",[29,28175,28176],{"__ignoreMap":27},[32,28177,28178,28180,28182,28184],{"class":34,"line":35},[32,28179,4625],{"class":2066},[32,28181,4650],{"class":175},[32,28183,26145],{"class":351},[32,28185,28186],{"class":175}," @nuxtjs\u002Ftailwindcss\n",[11,28188,28189,5240],{},[29,28190,24155],{},[22,28192,28194],{"className":26159,"code":28193,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: ['@nuxtjs\u002Ftailwindcss']\n})\n",[29,28195,28196,28206,28215],{"__ignoreMap":27},[32,28197,28198,28200,28202,28204],{"class":34,"line":35},[32,28199,5038],{"class":38},[32,28201,5041],{"class":38},[32,28203,24171],{"class":217},[32,28205,1143],{"class":5049},[32,28207,28208,28210,28213],{"class":34,"line":45},[32,28209,20845],{"class":41},[32,28211,28212],{"class":175},"'@nuxtjs\u002Ftailwindcss'",[32,28214,26804],{"class":41},[32,28216,28217],{"class":34,"line":51},[32,28218,24189],{"class":5049},[11,28220,28221,5240],{},[29,28222,28223],{},"tailwind.config.js",[22,28225,28227],{"className":24,"code":28226,"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,28228,28229,28243,28255,28260,28267,28274,28281,28288,28295,28300,28305,28310,28315,28319,28324],{"__ignoreMap":27},[32,28230,28231,28234,28237,28240],{"class":34,"line":35},[32,28232,28233],{"class":608},"\u002F** ",[32,28235,28236],{"class":38},"@type",[32,28238,28239],{"class":2066}," {import('tailwindcss').Config}",[32,28241,28242],{"class":608}," *\u002F\n",[32,28244,28245,28247,28249,28251,28253],{"class":34,"line":45},[32,28246,7130],{"class":351},[32,28248,1278],{"class":41},[32,28250,7135],{"class":351},[32,28252,894],{"class":38},[32,28254,703],{"class":41},[32,28256,28257],{"class":34,"line":51},[32,28258,28259],{"class":41},"  content: [\n",[32,28261,28262,28265],{"class":34,"line":90},[32,28263,28264],{"class":175},"    '.\u002Fcomponents\u002F**\u002F*.{vue,js,ts}'",[32,28266,547],{"class":41},[32,28268,28269,28272],{"class":34,"line":99},[32,28270,28271],{"class":175},"    '.\u002Flayouts\u002F**\u002F*.vue'",[32,28273,547],{"class":41},[32,28275,28276,28279],{"class":34,"line":106},[32,28277,28278],{"class":175},"    '.\u002Fpages\u002F**\u002F*.vue'",[32,28280,547],{"class":41},[32,28282,28283,28286],{"class":34,"line":114},[32,28284,28285],{"class":175},"    '.\u002Fcomposables\u002F**\u002F*.{js,ts}'",[32,28287,547],{"class":41},[32,28289,28290,28293],{"class":34,"line":120},[32,28291,28292],{"class":175},"    '.\u002Fplugins\u002F**\u002F*.{js,ts}'",[32,28294,547],{"class":41},[32,28296,28297],{"class":34,"line":127},[32,28298,28299],{"class":175},"    '.\u002Fapp.{js,ts,vue}'\n",[32,28301,28302],{"class":34,"line":132},[32,28303,28304],{"class":41},"  ],\n",[32,28306,28307],{"class":34,"line":141},[32,28308,28309],{"class":41},"  theme: {\n",[32,28311,28312],{"class":34,"line":147},[32,28313,28314],{"class":41},"    extend: {}\n",[32,28316,28317],{"class":34,"line":275},[32,28318,5639],{"class":41},[32,28320,28321],{"class":34,"line":282},[32,28322,28323],{"class":41},"  plugins: []\n",[32,28325,28326],{"class":34,"line":295},[32,28327,54],{"class":41},[11,28329,28330,28333],{},[29,28331,28332],{},"content"," 這個陣列很關鍵——Tailwind 只會產出這些檔案裡真的出現過的 class。漏掉某個資料夾，那裡的樣式在正式環境就會整組消失（開發環境常常看不出來）。",[151,28335,28337],{"id":28336},"搭配-prettier-自動排序","搭配 Prettier 自動排序",[11,28339,28340],{},"class 一多就很難一眼確認有沒有重複，官方的 Prettier 外掛可以自動照推薦順序排列：",[22,28342,28344],{"className":2057,"code":28343,"language":2059,"meta":27,"style":27},"npm install -D prettier-plugin-tailwindcss\n",[29,28345,28346],{"__ignoreMap":27},[32,28347,28348,28350,28352,28354],{"class":34,"line":35},[32,28349,4625],{"class":2066},[32,28351,4650],{"class":175},[32,28353,26145],{"class":351},[32,28355,28356],{"class":175}," prettier-plugin-tailwindcss\n",[15,28358,28360],{"id":28359},"附錄nuxt-2-的-create-nuxt-app","附錄：Nuxt 2 的 create-nuxt-app",[11,28362,28363],{},"Nuxt 2 用的是另一支 CLI，會問一長串問題：",[22,28365,28367],{"className":2057,"code":28366,"language":2059,"meta":27,"style":27},"npx create-nuxt-app my-nuxt-project\n",[29,28368,28369],{"__ignoreMap":27},[32,28370,28371,28373,28376],{"class":34,"line":35},[32,28372,16476],{"class":2066},[32,28374,28375],{"class":175}," create-nuxt-app",[32,28377,28378],{"class":175}," my-nuxt-project\n",[11,28380,28381],{},"逐題的選項大致如下：",[22,28383,28386],{"className":28384,"code":28385,"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,28387,28385],{"__ignoreMap":27},[11,28389,28390],{},"ESLint 與 Prettier 兩個都會出現在 linting 那題，它們的分工是：",[4538,28392,28393,28398],{},[4541,28394,28395,28397],{},[12390,28396,4853],{},"：靜態分析工具，找出程式碼裡的問題，也管風格",[4541,28399,28400,28403],{},[12390,28401,28402],{},"Prettier","：純格式化工具，只管排版，不管品質",[11,28405,28406],{},"通常兩個一起用——ESLint 負責分析，Prettier 負責排版。",[151,28408,28410],{"id":28409},"nuxt-2-裝-pinia","Nuxt 2 裝 Pinia",[22,28412,28413],{"className":2057,"code":24024,"language":2059,"meta":27,"style":27},[29,28414,28415],{"__ignoreMap":27},[32,28416,28417,28419,28421],{"class":34,"line":35},[32,28418,4625],{"class":2066},[32,28420,4650],{"class":175},[32,28422,24035],{"class":175},[151,28424,28426],{"id":28425},"nuxt-2-裝-sass","Nuxt 2 裝 Sass",[22,28428,28430],{"className":2057,"code":28429,"language":2059,"meta":27,"style":27},"npm install node-sass sass-loader --save-dev\n",[29,28431,28432],{"__ignoreMap":27},[32,28433,28434,28436,28438,28440,28442],{"class":34,"line":35},[32,28435,4625],{"class":2066},[32,28437,4650],{"class":175},[32,28439,8632],{"class":175},[32,28441,8635],{"class":175},[32,28443,7066],{"class":351},[11,28445,5134,28446,7218,28448,28072],{},[29,28447,20826],{},[29,28449,7225],{},[22,28451,28453],{"className":24,"code":28452,"language":26,"meta":27,"style":27},"build: {\n  loaders: {\n    scss: { implementation: require('sass') }\n  }\n}\n",[29,28454,28455,28461,28468,28492,28496],{"__ignoreMap":27},[32,28456,28457,28459],{"class":34,"line":35},[32,28458,7225],{"class":2066},[32,28460,5261],{"class":41},[32,28462,28463,28466],{"class":34,"line":45},[32,28464,28465],{"class":2066},"  loaders",[32,28467,5261],{"class":41},[32,28469,28470,28473,28476,28479,28481,28484,28486,28489],{"class":34,"line":51},[32,28471,28472],{"class":2066},"    scss",[32,28474,28475],{"class":41},": { ",[32,28477,28478],{"class":2066},"implementation",[32,28480,5269],{"class":41},[32,28482,28483],{"class":217},"require",[32,28485,477],{"class":41},[32,28487,28488],{"class":175},"'sass'",[32,28490,28491],{"class":41},") }\n",[32,28493,28494],{"class":34,"line":90},[32,28495,1203],{"class":41},[32,28497,28498],{"class":34,"line":99},[32,28499,54],{"class":41},[11,28501,28502],{},"TypeScript 版本：",[22,28504,28506],{"className":26159,"code":28505,"language":26161,"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,28507,28508,28520,28524,28539,28543,28548,28561,28565,28569,28573,28577],{"__ignoreMap":27},[32,28509,28510,28512,28515,28517],{"class":34,"line":35},[32,28511,8794],{"class":38},[32,28513,28514],{"class":41}," { Configuration } ",[32,28516,8850],{"class":38},[32,28518,28519],{"class":175}," '@nuxt\u002Ftypes'\n",[32,28521,28522],{"class":34,"line":45},[32,28523,103],{"emptyLinePlaceholder":102},[32,28525,28526,28528,28530,28532,28535,28537],{"class":34,"line":51},[32,28527,6617],{"class":38},[32,28529,3425],{"class":351},[32,28531,322],{"class":38},[32,28533,28534],{"class":2066}," Configuration",[32,28536,894],{"class":38},[32,28538,703],{"class":41},[32,28540,28541],{"class":34,"line":90},[32,28542,23283],{"class":41},[32,28544,28545],{"class":34,"line":99},[32,28546,28547],{"class":41},"    loaders: {\n",[32,28549,28550,28553,28555,28557,28559],{"class":34,"line":106},[32,28551,28552],{"class":41},"      scss: { implementation: ",[32,28554,28483],{"class":217},[32,28556,477],{"class":41},[32,28558,28488],{"class":175},[32,28560,28491],{"class":41},[32,28562,28563],{"class":34,"line":114},[32,28564,5591],{"class":41},[32,28566,28567],{"class":34,"line":120},[32,28568,1203],{"class":41},[32,28570,28571],{"class":34,"line":127},[32,28572,54],{"class":41},[32,28574,28575],{"class":34,"line":132},[32,28576,103],{"emptyLinePlaceholder":102},[32,28578,28579,28581,28583],{"class":34,"line":141},[32,28580,5038],{"class":38},[32,28582,5041],{"class":38},[32,28584,28585],{"class":41}," config\n",[15,28587,2004],{"id":2003},[11,28589,28590],{},"本文是 Nuxt 3 與當時依賴版本的筆記。Nuxt、ESLint、Sass、Tailwind 與 Pinia 的設定方式已可能不同；新專案請採目前版本的官方初始化流程，不直接複製舊設定。",[15,28592,4536],{"id":4536},[4538,28594,28595,28602,28609,28616,28623],{},[4541,28596,28597],{},[412,28598,28601],{"href":28599,"rel":28600},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fgetting-started\u002Finstallation",[416],"Nuxt 3 官方文件",[4541,28603,28604],{},[412,28605,28608],{"href":28606,"rel":28607},"https:\u002F\u002Fithelp.ithome.com.tw\u002Farticles\u002F10295432",[416],"iThome：Nuxt 3 教學",[4541,28610,28611],{},[412,28612,28615],{"href":28613,"rel":28614},"https:\u002F\u002Fwww.penguin-cho.com\u002Fposts\u002Fnuxt3-pinia",[416],"Nuxt 3 + Pinia",[4541,28617,28618],{},[412,28619,28622],{"href":28620,"rel":28621},"https:\u002F\u002Fpinia.vuejs.org\u002Fssr\u002Fnuxt.html",[416],"Pinia 官方文件（Nuxt SSR）",[4541,28624,28625],{},[412,28626,28629],{"href":28627,"rel":28628},"https:\u002F\u002Fhackmd.io\u002F@Yan06\u002FSJgkRrhej",[416],"Nuxt 3 配置入門",[368,28631,28632],{},"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":28634},[28635,28639,28640,28644,28645,28654,28659,28660,28663,28664,28667,28671,28672],{"id":26029,"depth":45,"text":26030,"children":28636},[28637,28638],{"id":26036,"depth":51,"text":26036},{"id":26060,"depth":51,"text":26060},{"id":24160,"depth":45,"text":23951},{"id":26197,"depth":45,"text":4853,"children":28641},[28642,28643],{"id":26206,"depth":51,"text":26207},{"id":26232,"depth":51,"text":26233},{"id":26371,"depth":45,"text":26371},{"id":26624,"depth":45,"text":26624,"children":28646},[28647,28648,28649,28650,28651,28652,28653],{"id":26633,"depth":51,"text":26633},{"id":26703,"depth":51,"text":26703},{"id":26807,"depth":51,"text":26807},{"id":26866,"depth":51,"text":26866},{"id":27064,"depth":51,"text":27064},{"id":27239,"depth":51,"text":27240},{"id":27397,"depth":51,"text":27397},{"id":27440,"depth":45,"text":13203,"children":28655},[28656,28657,28658],{"id":27449,"depth":51,"text":27449},{"id":27574,"depth":51,"text":27575},{"id":27778,"depth":51,"text":27778},{"id":27950,"depth":45,"text":27950},{"id":28003,"depth":45,"text":23916,"children":28661},[28662],{"id":28065,"depth":51,"text":28066},{"id":28116,"depth":45,"text":4847},{"id":28169,"depth":45,"text":28170,"children":28665},[28666],{"id":28336,"depth":51,"text":28337},{"id":28359,"depth":45,"text":28360,"children":28668},[28669,28670],{"id":28409,"depth":51,"text":28410},{"id":28425,"depth":51,"text":28426},{"id":2003,"depth":45,"text":2004},{"id":4536,"depth":45,"text":4536},"紀錄 Nuxt 3 的安裝、目錄、路由、Layout 與相關套件設定。",{},"\u002Fposts\u002Fnuxt3-setup-notes","2025-07-24",[],{"title":26024,"description":28673},"posts\u002F20250724.nuxt3-setup-notes",[28681,23771,23916,28170,4853,23951],"Nuxt3","tb0qwFvd7FhIfiIEo2aKM64gP_RL2ynB0lpBNlRqPrc",{"id":28684,"title":28685,"body":28686,"category":378,"description":29216,"draft":380,"extension":381,"image":382,"meta":29217,"navigation":102,"path":29218,"publishedAt":29219,"relatedExperiments":29220,"seo":29221,"stem":29222,"tags":29223,"updatedAt":29219,"__hash__":29224},"posts\u002Fposts\u002F20260506.vite-vue3-tailwind4-shadcn-vue.md","Vite + Vue 3 + Tailwind CSS 4 + shadcn-vue 安裝心得與常見踩坑",{"type":8,"value":28687,"toc":29197},[28688,28691,28714,28718,28722,28733,28736,28740,28751,28755,28758,28761,28772,28775,28779,28782,28793,28796,28798,28822,28826,28833,28836,28845,28848,28864,28867,28933,28941,28944,28967,28970,28981,28999,29002,29015,29021,29029,29032,29038,29041,29044,29052,29058,29062,29065,29068,29073,29076,29080,29083,29087,29090,29093,29095,29098,29102,29104,29110,29113,29116,29135,29138,29154,29157,29194],[15,28689,28690],{"id":28690},"專案環境",[4538,28692,28693,28696,28699,28701,28703,28705,28708,28711],{},[4541,28694,28695],{},"Vite 7",[4541,28697,28698],{},"Vue 3",[4541,28700,23951],{},[4541,28702,23916],{},[4541,28704,4841],{},[4541,28706,28707],{},"unplugin-vue-router",[4541,28709,28710],{},"Tailwind CSS 4",[4541,28712,28713],{},"shadcn-vue",[15,28715,28717],{"id":28716},"_1-vite-與-vike-的差異","1. Vite 與 Vike 的差異",[151,28719,28721],{"id":28720},"vite","Vite",[4538,28723,28724,28727,28730],{},[4541,28725,28726],{},"前端建置工具（Build Tool）",[4541,28728,28729],{},"提供快速開發伺服器（HMR）",[4541,28731,28732],{},"不內建 Router、SSR",[11,28734,28735],{},"適合： - SPA - 後台系統 - Vue \u002F React 專案",[151,28737,28739],{"id":28738},"vike","Vike",[4538,28741,28742,28745,28748],{},[4541,28743,28744],{},"建立在 Vite 之上的 Web Framework",[4541,28746,28747],{},"提供 SSR、Routing、SEO 等能力",[4541,28749,28750],{},"類似 Next.js（React）或 Nuxt（Vue）",[15,28752,28754],{"id":28753},"_2-vue-專案一定要安裝-vue-router-嗎","2. Vue 專案一定要安裝 vue-router 嗎？",[11,28756,28757],{},"如果只有一個畫面，可以不用。",[11,28759,28760],{},"只要有：",[4538,28762,28763,28766,28769],{},[4541,28764,28765],{},"\u002Flogin",[4541,28767,28768],{},"\u002Fdashboard",[4541,28770,28771],{},"\u002Fhouse\u002F:id",[11,28773,28774],{},"就需要 vue-router。",[151,28776,28778],{"id":28777},"unplugin-vue-router-不是-router","unplugin-vue-router 不是 Router",[11,28780,28781],{},"它只是：",[4538,28783,28784,28787,28790],{},[4541,28785,28786],{},"自動產生 routes",[4541,28788,28789],{},"提供型別安全",[4541,28791,28792],{},"使用檔案式路由",[11,28794,28795],{},"底層仍然是 vue-router。",[11,28797,6399],{},[22,28799,28801],{"className":2057,"code":28800,"language":2059,"meta":27,"style":27},"npm install vue-router\nnpm install -D unplugin-vue-router\n",[29,28802,28803,28811],{"__ignoreMap":27},[32,28804,28805,28807,28809],{"class":34,"line":35},[32,28806,4625],{"class":2066},[32,28808,4650],{"class":175},[32,28810,9164],{"class":175},[32,28812,28813,28815,28817,28819],{"class":34,"line":45},[32,28814,4625],{"class":2066},[32,28816,4650],{"class":175},[32,28818,26145],{"class":351},[32,28820,28821],{"class":175}," unplugin-vue-router\n",[15,28823,28825],{"id":28824},"_3-tailwind-css-4-的重大變更","3. Tailwind CSS 4 的重大變更",[11,28827,28828,28829,28832],{},"Tailwind CSS 4 已經不能再把 ",[29,28830,28831],{},"tailwindcss"," 當作 PostCSS Plugin 使用。",[11,28834,28835],{},"以前：",[22,28837,28839],{"className":24,"code":28838,"language":26,"meta":27,"style":27},"tailwindcss\n",[29,28840,28841],{"__ignoreMap":27},[32,28842,28843],{"class":34,"line":35},[32,28844,28838],{"class":41},[11,28846,28847],{},"現在需要：",[22,28849,28851],{"className":2057,"code":28850,"language":2059,"meta":27,"style":27},"npm install -D @tailwindcss\u002Fpostcss\n",[29,28852,28853],{"__ignoreMap":27},[32,28854,28855,28857,28859,28861],{"class":34,"line":35},[32,28856,4625],{"class":2066},[32,28858,4650],{"class":175},[32,28860,26145],{"class":351},[32,28862,28863],{"class":175}," @tailwindcss\u002Fpostcss\n",[11,28865,28866],{},"PostCSS：",[22,28868,28870],{"className":24,"code":28869,"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,28871,28872,28884,28896,28900,28908,28913,28918,28923,28929],{"__ignoreMap":27},[32,28873,28874,28876,28879,28881],{"class":34,"line":35},[32,28875,8794],{"class":38},[32,28877,28878],{"class":41}," tailwindcss ",[32,28880,8850],{"class":38},[32,28882,28883],{"class":175}," \"@tailwindcss\u002Fpostcss\"\n",[32,28885,28886,28888,28891,28893],{"class":34,"line":45},[32,28887,8794],{"class":38},[32,28889,28890],{"class":41}," autoprefixer ",[32,28892,8850],{"class":38},[32,28894,28895],{"class":175}," \"autoprefixer\"\n",[32,28897,28898],{"class":34,"line":51},[32,28899,103],{"emptyLinePlaceholder":102},[32,28901,28902,28904,28906],{"class":34,"line":90},[32,28903,5038],{"class":38},[32,28905,5041],{"class":38},[32,28907,703],{"class":5049},[32,28909,28910],{"class":34,"line":99},[32,28911,28912],{"class":41},"  plugins: {\n",[32,28914,28915],{"class":34,"line":106},[32,28916,28917],{"class":41},"    tailwindcss,\n",[32,28919,28920],{"class":34,"line":114},[32,28921,28922],{"class":41},"    autoprefixer,\n",[32,28924,28925,28927],{"class":34,"line":120},[32,28926,9758],{"class":41},[32,28928,547],{"class":5049},[32,28930,28931],{"class":34,"line":127},[32,28932,54],{"class":5049},[15,28934,28936,28937,28940],{"id":28935},"_4-packagejson-使用-type-module-要注意","4. package.json 使用 ",[29,28938,28939],{},"\"type\": \"module\""," 要注意",[11,28942,28943],{},"如果 package.json：",[22,28945,28947],{"className":5243,"code":28946,"language":5245,"meta":27,"style":27},"{\n  \"type\": \"module\"\n}\n",[29,28948,28949,28953,28963],{"__ignoreMap":27},[32,28950,28951],{"class":34,"line":35},[32,28952,5252],{"class":41},[32,28954,28955,28958,28960],{"class":34,"line":45},[32,28956,28957],{"class":5257},"  \"type\"",[32,28959,5269],{"class":41},[32,28961,28962],{"class":175},"\"module\"\n",[32,28964,28965],{"class":34,"line":51},[32,28966,54],{"class":41},[11,28968,28969],{},"代表：",[4538,28971,28972,28978],{},[4541,28973,28974,28977],{},[29,28975,28976],{},".js"," 會被視為 ESM",[4541,28979,28980],{},"不可使用：",[22,28982,28984],{"className":24,"code":28983,"language":26,"meta":27,"style":27},"module.exports = {}\n",[29,28985,28986],{"__ignoreMap":27},[32,28987,28988,28990,28992,28994,28996],{"class":34,"line":35},[32,28989,7130],{"class":351},[32,28991,1278],{"class":41},[32,28993,7135],{"class":351},[32,28995,894],{"class":38},[32,28997,28998],{"class":41}," {}\n",[11,29000,29001],{},"必須改成：",[22,29003,29005],{"className":24,"code":29004,"language":26,"meta":27,"style":27},"export default {}\n",[29,29006,29007],{"__ignoreMap":27},[32,29008,29009,29011,29013],{"class":34,"line":35},[32,29010,5038],{"class":38},[32,29012,5041],{"class":38},[32,29014,28998],{"class":5049},[11,29016,29017,29018,3775],{},"或者把設定檔改成 ",[29,29019,29020],{},".cjs",[15,29022,29024,29025,29028],{"id":29023},"_5-為什麼-npx-tailwindcss-init-p-失敗","5. 為什麼 ",[29,29026,29027],{},"npx tailwindcss init -p"," 失敗？",[11,29030,29031],{},"錯誤：",[22,29033,29036],{"className":29034,"code":29035,"language":426,"meta":27},[424],"npm error could not determine executable to run\n",[29,29037,29035],{"__ignoreMap":27},[11,29039,29040],{},"在 Tailwind CSS 4 已經不一定需要依賴這個指令。",[11,29042,29043],{},"可以直接：",[4538,29045,29046,29049],{},[4541,29047,29048],{},"手動建立 Tailwind Config",[4541,29050,29051],{},"或直接使用官方新的設定方式",[11,29053,29054,29055,3775],{},"因此不用執著於 ",[29,29056,29057],{},"init -p",[15,29059,29061],{"id":29060},"_6-shadcn-vue-是否可以使用","6. shadcn-vue 是否可以使用？",[11,29063,29064],{},"可以。",[11,29066,29067],{},"React 使用：",[4538,29069,29070],{},[4541,29071,29072],{},"shadcn\u002Fui",[11,29074,29075],{},"Vue 使用：",[4538,29077,29078],{},[4541,29079,28713],{},[11,29081,29082],{},"不能直接把 React 的 shadcn\u002Fui 放進 Vue 專案。",[15,29084,29086],{"id":29085},"_7-element-plus-shadcn-vue","7. Element Plus → shadcn-vue",[11,29088,29089],{},"常見對照：",[11,29091,29092],{},"Element Plus   shadcn-vue",[10525,29094],{},[11,29096,29097],{},"el-card        Card\nel-button      Button\nel-input       Input\nel-select      Select\nel-dialog      Dialog\nel-slider      Slider\nel-table       Table",[15,29099,29101],{"id":29100},"_8-git-push-出現-invalid-username-or-token","8. Git Push 出現 Invalid username or token",[11,29103,2427],{},[22,29105,29108],{"className":29106,"code":29107,"language":426,"meta":27},[424],"Password authentication is not supported\n",[29,29109,29107],{"__ignoreMap":27},[11,29111,29112],{},"代表目前還在使用 HTTPS。",[11,29114,29115],{},"建議改用 SSH：",[22,29117,29119],{"className":2057,"code":29118,"language":2059,"meta":27,"style":27},"git remote set-url origin git@github.com:USER\u002FREPO.git\n",[29,29120,29121],{"__ignoreMap":27},[32,29122,29123,29125,29127,29130,29132],{"class":34,"line":35},[32,29124,2126],{"class":2066},[32,29126,12866],{"class":175},[32,29128,29129],{"class":175}," set-url",[32,29131,12871],{"class":175},[32,29133,29134],{"class":175}," git@github.com:USER\u002FREPO.git\n",[11,29136,29137],{},"測試：",[22,29139,29141],{"className":2057,"code":29140,"language":2059,"meta":27,"style":27},"ssh -T git@github.com\n",[29,29142,29143],{"__ignoreMap":27},[32,29144,29145,29148,29151],{"class":34,"line":35},[32,29146,29147],{"class":2066},"ssh",[32,29149,29150],{"class":351}," -T",[32,29152,29153],{"class":175}," git@github.com\n",[15,29155,29156],{"id":29156},"本次重點整理",[4538,29158,29159,29162,29165,29168,29171,29177,29188,29191],{},[4541,29160,29161],{},"Vite 是 Build Tool，不是 Framework。",[4541,29163,29164],{},"Vike 提供 SSR 與 Routing。",[4541,29166,29167],{},"Vue 多頁面專案需要 vue-router。",[4541,29169,29170],{},"unplugin-vue-router 只是自動產生 routes。",[4541,29172,29173,29174,3775],{},"Tailwind CSS 4 已改用 ",[29,29175,29176],{},"@tailwindcss\u002Fpostcss",[4541,29178,29179,29181,29182,29185,29186,3775],{},[29,29180,28939],{}," 專案要使用 ESM (",[29,29183,29184],{},"export default",") 或 ",[29,29187,29020],{},[4541,29189,29190],{},"Vue 專案請使用 shadcn-vue，不是 React 的 shadcn\u002Fui。",[4541,29192,29193],{},"GitHub 建議使用 SSH 推送，不要使用密碼。",[368,29195,29196],{},"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":29198},[29199,29200,29204,29207,29208,29210,29212,29213,29214,29215],{"id":28690,"depth":45,"text":28690},{"id":28716,"depth":45,"text":28717,"children":29201},[29202,29203],{"id":28720,"depth":51,"text":28721},{"id":28738,"depth":51,"text":28739},{"id":28753,"depth":45,"text":28754,"children":29205},[29206],{"id":28777,"depth":51,"text":28778},{"id":28824,"depth":45,"text":28825},{"id":28935,"depth":45,"text":29209},"4. package.json 使用 \"type\": \"module\" 要注意",{"id":29023,"depth":45,"text":29211},"5. 為什麼 npx tailwindcss init -p 失敗？",{"id":29060,"depth":45,"text":29061},{"id":29085,"depth":45,"text":29086},{"id":29100,"depth":45,"text":29101},{"id":29156,"depth":45,"text":29156},"記錄用 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":28685,"description":29216},"posts\u002F20260506.vite-vue3-tailwind4-shadcn-vue",[28721,23771,28710,28713],"ipF_6dy1h87-9ZQ-SEwWcghcwFuGrYJpFiS4LncEL0M",{"id":29226,"title":29227,"body":29228,"category":29319,"description":29320,"draft":380,"extension":381,"image":382,"meta":29321,"navigation":102,"path":29322,"publishedAt":392,"relatedExperiments":29323,"seo":29325,"stem":29326,"tags":29327,"updatedAt":6716,"__hash__":29330},"posts\u002Fposts\u002F20260805.hello.md","自由實驗室開張",{"type":8,"value":29229,"toc":29316},[29230,29233,29236,29239,29242,29245,29313],[11,29231,29232],{},"很開心，終於有一個屬於自己的部落格了！\n其實從好幾年前開始，我就一直想做自己的部落格，只是每次做到一半，都覺得好像少了點什麼。\n光是名字就想了很久，也因此拖了很長一段時間。",[11,29234,29235],{},"這次原本也沒有想得這麼複雜，只是想做一個放小工具的站台。\n結果做到一半才發現，站名不但太泛用，還剛好跟其他同類型的網站撞名。\n看到的時候只覺得……\n真的超級無敵尷尬。\n最後乾脆決定整個打掉重來。",[11,29237,29238],{},"重新整理的過程中，我也開始覺得，如果只拿來放小工具好像有點可惜。\n既然本來就有自己的部落格，也有很多平常寫下來的東西，那不如全部放在一起。\n文章、小工具、小遊戲、互動實驗，甚至一些突然想到、單純只是想做看看的東西，都可以丟進來。\n不用特別限制它一定要是什麼。\n「自由實驗室」也就這樣慢慢成形了。\n所以往後這個網站上，應該會出現很多奇奇怪怪的東西。\n技術文章可能旁邊突然出現一個小遊戲，過幾天又多了一個不知道拿來幹嘛的小工具。\n想做什麼就做什麼。\n大概就是這個地方存在的原因。",[15,29240,29241],{"id":29241},"技術選擇",[11,29243,29244],{},"這次也順便把整個網站重新整理了一次，目前主要使用這些技術：",[13574,29246,29247,29259],{},[13577,29248,29249],{},[13580,29250,29251,29253,29256],{},[13583,29252,13685],{},[13583,29254,29255],{},"選擇",[13583,29257,29258],{},"原因",[13590,29260,29261,29272,29283,29292,29302],{},[13580,29262,29263,29266,29269],{},[13595,29264,29265],{},"框架",[13595,29267,29268],{},"Nuxt 4",[13595,29270,29271],{},"想繼續熟悉 Nuxt，也很適合拿來做內容型網站",[13580,29273,29274,29277,29280],{},[13595,29275,29276],{},"樣式",[13595,29278,29279],{},"Tailwind CSS v4",[13595,29281,29282],{},"寫樣式方便，網站要慢慢調整也比較自由",[13580,29284,29285,29287,29289],{},[13595,29286,27950],{},[13595,29288,28713],{},[13595,29290,29291],{},"元件直接放在專案裡，需要修改時可以自己調整",[13580,29293,29294,29296,29299],{},[13595,29295,22701],{},[13595,29297,29298],{},"Zod",[13595,29300,29301],{},"可以統一處理資料與 Content frontmatter 的格式驗證",[13580,29303,29304,29307,29310],{},[13595,29305,29306],{},"部署",[13595,29308,29309],{},"Cloudflare Workers",[13595,29311,29312],{},"部署方便，也可以直接搭配自己的網域",[11,29314,29315],{},"目前網站還在慢慢整理中。\n以前寫過的文章也會陸續搬回來，有些甚至已經是很多年前留下來的內容了。\n就先一點一點整理吧。\n至少這次，終於真的把它做出來了。",{"title":27,"searchDepth":51,"depth":51,"links":29317},[29318],{"id":29241,"depth":45,"text":29241},"project","原本只是想做一個小工具站，做到一半卻因為撞名決定整個重來，最後變成現在的自由實驗室。",{},"\u002Fposts\u002Fhello",[29324],"bmi-calculator",{"title":29227,"description":29320},"posts\u002F20260805.hello",[16540,29328,29329],"Cloudflare","重構","GDqPOiGjUiqmnYHJ-q9L4C3qENyU0WuYEWnCz6LuxhA",{"id":29332,"title":29333,"body":29334,"category":378,"description":30617,"draft":380,"extension":381,"image":382,"meta":30618,"navigation":102,"path":30619,"publishedAt":30620,"relatedExperiments":30621,"seo":30622,"stem":30623,"tags":30624,"updatedAt":30620,"__hash__":30627},"posts\u002Fposts\u002F20260818.nuxt4-project-setup.md","Nuxt 4 現在怎麼開專案：app\u002F 目錄、@nuxt\u002Feslint 與 Tailwind 4",{"type":8,"value":29335,"toc":30601},[29336,29355,29362,29365,29374,29396,29402,29440,29445,29449,29473,29479,29497,29500,29526,29530,29536,29582,29588,29592,29595,29622,29629,29631,29642,29653,29658,29692,29710,29732,29736,29744,29763,29791,29803,29856,29866,29870,29876,29895,29959,29964,30013,30016,30059,30068,30072,30083,30123,30126,30137,30140,30144,30158,30283,30290,30299,30303,30306,30342,30357,30382,30385,30501,30504,30507,30554,30560,30562,30598],[11,29337,29338,29339,29342,29343,3750,29346,3750,29348,29351,29352,29354],{},"之前寫過 ",[412,29340,29341],{"href":28675},"Nuxt 3 專案建立筆記","，那篇裡的 ",[29,29344,29345],{},"npx nuxi@latest init",[29,29347,26239],{},[29,29349,29350],{},"@nuxtjs\u002Ftailwindcss"," + ",[29,29353,28223],{}," 現在照著做都會撞牆。",[11,29356,29357,29358,29361],{},"Nuxt 4 的改動不算多，但",[12390,29359,29360],{},"每一項都在你開專案的第一個小時就會遇到","，所以值得單獨記一次。這篇的設定都是這個站自己在跑的。",[15,29363,29364],{"id":29364},"建專案",[11,29366,29367,29370,29371,29373],{},[29,29368,29369],{},"nuxi"," 這個獨立指令已經併回 ",[29,29372,16942],{}," 本身，現在的入口是：",[22,29375,29377],{"className":2057,"code":29376,"language":2059,"meta":27,"style":27},"npm create nuxt@latest \u003Cproject-name>\n",[29,29378,29379],{"__ignoreMap":27},[32,29380,29381,29383,29385,29388,29390,29392,29394],{"class":34,"line":35},[32,29382,4625],{"class":2066},[32,29384,4799],{"class":175},[32,29386,29387],{"class":175}," nuxt@latest",[32,29389,26077],{"class":38},[32,29391,26080],{"class":175},[32,29393,26083],{"class":41},[32,29395,4062],{"class":38},[11,29397,29398,29399,29401],{},"裝完之後，日常指令都掛在 ",[29,29400,16942],{}," 底下：",[22,29403,29405],{"className":2057,"code":29404,"language":2059,"meta":27,"style":27},"nuxt dev\nnuxt build\nnuxt preview\nnuxt typecheck\nnuxt prepare\n",[29,29406,29407,29413,29419,29426,29433],{"__ignoreMap":27},[32,29408,29409,29411],{"class":34,"line":35},[32,29410,16942],{"class":2066},[32,29412,10438],{"class":175},[32,29414,29415,29417],{"class":34,"line":45},[32,29416,16942],{"class":2066},[32,29418,4755],{"class":175},[32,29420,29421,29423],{"class":34,"line":51},[32,29422,16942],{"class":2066},[32,29424,29425],{"class":175}," preview\n",[32,29427,29428,29430],{"class":34,"line":90},[32,29429,16942],{"class":2066},[32,29431,29432],{"class":175}," typecheck\n",[32,29434,29435,29437],{"class":34,"line":99},[32,29436,16942],{"class":2066},[32,29438,29439],{"class":175}," prepare\n",[11,29441,29442,29444],{},[29,29443,29345],{}," 還能動，但它只是轉呼叫上面那個，文件已經不提了。",[15,29446,29448],{"id":29447},"最大的改動srcdir-變成-app","最大的改動：srcDir 變成 app\u002F",[11,29450,29451,29452,3750,29454,3750,29456,3750,29458,29460,29461,3750,29464,29466,29467,5240],{},"Nuxt 3 的 ",[29,29453,26498],{},[29,29455,26435],{},[29,29457,26445],{},[29,29459,26478],{}," 都在根目錄，跟 ",[29,29462,29463],{},"node_modules\u002F",[29,29465,26413],{},"、設定檔混在一起。Nuxt 4 把",[12390,29468,29469,29470],{},"前端的部分整組搬進 ",[29,29471,29472],{},"app\u002F",[22,29474,29477],{"className":29475,"code":29476,"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,29478,29476],{"__ignoreMap":27},[11,29480,29481,29493,29494,29496],{},[12390,29482,29483,29484,3750,29486,3750,29488,7090,29490],{},"留在根目錄的是 ",[29,29485,26537],{},[29,29487,26455],{},[29,29489,26521],{},[29,29491,29492],{},"modules\u002F","。判準很單純：",[29,29495,29472],{}," 底下的東西會被打包進前端 bundle，其他的不會。",[11,29498,29499],{},"實務上的影響：",[4538,29501,29502,29517,29523],{},[4541,29503,29504,29507,29508,29510,29511,14772,29514],{},[29,29505,29506],{},"~\u002F"," 別名現在指向 ",[29,29509,29472],{},"，所以 ",[29,29512,29513],{},"~\u002Fcomponents\u002FFoo.vue",[29,29515,29516],{},"app\u002Fcomponents\u002FFoo.vue",[4541,29518,29519,29520,29522],{},"從 ",[29,29521,29472],{}," 底下要引用根目錄的設定檔，得用相對路徑往上跳一層",[4541,29524,29525],{},"檔案監看的範圍縮小了，dev server 啟動與 HMR 都比較快",[151,29527,29529],{"id":29528},"從-nuxt-3-升上來","從 Nuxt 3 升上來",[11,29531,29532,29533,29535],{},"不想一次搬完的話，",[29,29534,24155],{}," 可以留在舊行為：",[22,29537,29539],{"className":26159,"code":29538,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  srcDir: '.',\n  dir: {\n    app: 'app'\n  }\n})\n",[29,29540,29541,29551,29561,29566,29574,29578],{"__ignoreMap":27},[32,29542,29543,29545,29547,29549],{"class":34,"line":35},[32,29544,5038],{"class":38},[32,29546,5041],{"class":38},[32,29548,24171],{"class":217},[32,29550,1143],{"class":5049},[32,29552,29553,29556,29559],{"class":34,"line":45},[32,29554,29555],{"class":41},"  srcDir: ",[32,29557,29558],{"class":175},"'.'",[32,29560,547],{"class":5049},[32,29562,29563],{"class":34,"line":51},[32,29564,29565],{"class":41},"  dir: {\n",[32,29567,29568,29571],{"class":34,"line":90},[32,29569,29570],{"class":41},"    app: ",[32,29572,29573],{"class":175},"'app'\n",[32,29575,29576],{"class":34,"line":99},[32,29577,1203],{"class":41},[32,29579,29580],{"class":34,"line":106},[32,29581,24189],{"class":5049},[11,29583,29584,29585,29587],{},"但這只是緩衝。新專案直接用 ",[29,29586,29472],{},"，不要為了省一次搬檔案而長期背著一份跟文件不一致的結構。",[15,29589,29591],{"id":29590},"compatibilitydate","compatibilityDate",[11,29593,29594],{},"Nuxt 4 的設定檔多了一個一定要填的欄位：",[22,29596,29598],{"className":26159,"code":29597,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  compatibilityDate: '2025-07-15'\n})\n",[29,29599,29600,29610,29618],{"__ignoreMap":27},[32,29601,29602,29604,29606,29608],{"class":34,"line":35},[32,29603,5038],{"class":38},[32,29605,5041],{"class":38},[32,29607,24171],{"class":217},[32,29609,1143],{"class":5049},[32,29611,29612,29615],{"class":34,"line":45},[32,29613,29614],{"class":41},"  compatibilityDate: ",[32,29616,29617],{"class":175},"'2025-07-15'\n",[32,29619,29620],{"class":34,"line":51},[32,29621,24189],{"class":5049},[11,29623,29624,29625,29628],{},"它鎖住 Nitro 與各家部署平台的行為版本。",[12390,29626,29627],{},"沒填的話升級 Nuxt 時可能會靜靜地換掉某些預設值","——填一個日期，之後升版行為就不會自己漂移，等你有空再往前推。",[15,29630,23951],{"id":24160},[11,29632,29633,29634,29637,29638,29641],{},"型別檢查不用再自己裝 ",[29,29635,29636],{},"vue-tsc"," 加 ",[29,29639,29640],{},"typeCheck: true"," 了，直接有指令：",[22,29643,29645],{"className":2057,"code":29644,"language":2059,"meta":27,"style":27},"nuxt typecheck\n",[29,29646,29647],{"__ignoreMap":27},[32,29648,29649,29651],{"class":34,"line":35},[32,29650,16942],{"class":2066},[32,29652,29432],{"class":175},[11,29654,29655,29657],{},[29,29656,24155],{}," 只留 strict 就好：",[22,29659,29661],{"className":26159,"code":29660,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  typescript: {\n    strict: true\n  }\n})\n",[29,29662,29663,29673,29677,29684,29688],{"__ignoreMap":27},[32,29664,29665,29667,29669,29671],{"class":34,"line":35},[32,29666,5038],{"class":38},[32,29668,5041],{"class":38},[32,29670,24171],{"class":217},[32,29672,1143],{"class":5049},[32,29674,29675],{"class":34,"line":45},[32,29676,26178],{"class":41},[32,29678,29679,29682],{"class":34,"line":51},[32,29680,29681],{"class":41},"    strict: ",[32,29683,26186],{"class":351},[32,29685,29686],{"class":34,"line":90},[32,29687,1203],{"class":41},[32,29689,29690],{"class":34,"line":99},[32,29691,24189],{"class":5049},[11,29693,29694,29695,3750,29697,3750,29699,29702,29703,29705,29706,29709],{},"Nuxt 4 會為 ",[29,29696,29472],{},[29,29698,26537],{},[29,29700,29701],{},"shared\u002F"," 各產生一份獨立的 tsconfig，所以在 ",[29,29704,26537],{}," 底下寫 ",[29,29707,29708],{},"document.querySelector"," 會直接被型別擋下來——Nuxt 3 是不會的。",[2184,29711,29712],{},[11,29713,29714,29723,29724,29727,29728,29731],{},[12390,29715,29716,29719,29720],{},[29,29717,29718],{},"nuxt typecheck"," 內部會跑 ",[29,29721,29722],{},"nuxt prepare","。如果專案用了 ",[29,29725,29726],{},"@nuxt\u002Fcontent","，它會重建本機的 content 資料庫，",[12390,29729,29730],{},"dev server 開著的時候跑會把 dev 那邊的文章清空","。停掉 dev 再跑。",[15,29733,29735],{"id":29734},"eslint改用-nuxteslint","ESLint：改用 @nuxt\u002Feslint",[11,29737,29738,29740,29741,29743],{},[29,29739,26239],{}," 這種 legacy config 已經不再是 ESLint 的預設，",[29,29742,26350],{}," 也停在原地了。現在的做法是官方的模組：",[22,29745,29747],{"className":2057,"code":29746,"language":2059,"meta":27,"style":27},"npm install -D @nuxt\u002Feslint eslint\n",[29,29748,29749],{"__ignoreMap":27},[32,29750,29751,29753,29755,29757,29760],{"class":34,"line":35},[32,29752,4625],{"class":2066},[32,29754,4650],{"class":175},[32,29756,26145],{"class":351},[32,29758,29759],{"class":175}," @nuxt\u002Feslint",[32,29761,29762],{"class":175}," eslint\n",[22,29764,29766],{"className":26159,"code":29765,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  modules: ['@nuxt\u002Feslint']\n})\n",[29,29767,29768,29778,29787],{"__ignoreMap":27},[32,29769,29770,29772,29774,29776],{"class":34,"line":35},[32,29771,5038],{"class":38},[32,29773,5041],{"class":38},[32,29775,24171],{"class":217},[32,29777,1143],{"class":5049},[32,29779,29780,29782,29785],{"class":34,"line":45},[32,29781,20845],{"class":41},[32,29783,29784],{"class":175},"'@nuxt\u002Feslint'",[32,29786,26804],{"class":41},[32,29788,29789],{"class":34,"line":51},[32,29790,24189],{"class":5049},[11,29792,29793,29794,29796,29797,5240],{},"跑一次 ",[29,29795,29722],{},"，它會",[12390,29798,29799,29800],{},"自動產生一份 ",[29,29801,29802],{},"eslint.config.mjs",[22,29804,29806],{"className":24,"code":29805,"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,29807,29808,29820,29824,29835,29839,29848,29852],{"__ignoreMap":27},[32,29809,29810,29812,29815,29817],{"class":34,"line":35},[32,29811,8794],{"class":38},[32,29813,29814],{"class":41}," withNuxt ",[32,29816,8850],{"class":38},[32,29818,29819],{"class":175}," '.\u002F.nuxt\u002Feslint.config.mjs'\n",[32,29821,29822],{"class":34,"line":45},[32,29823,103],{"emptyLinePlaceholder":102},[32,29825,29826,29828,29830,29833],{"class":34,"line":51},[32,29827,5038],{"class":38},[32,29829,5041],{"class":38},[32,29831,29832],{"class":217}," withNuxt",[32,29834,1143],{"class":5049},[32,29836,29837],{"class":34,"line":90},[32,29838,26323],{"class":41},[32,29840,29841,29844,29846],{"class":34,"line":99},[32,29842,29843],{"class":175},"    'vue\u002Fmulti-word-component-names'",[32,29845,5269],{"class":41},[32,29847,26333],{"class":175},[32,29849,29850],{"class":34,"line":106},[32,29851,1203],{"class":41},[32,29853,29854],{"class":34,"line":114},[32,29855,24189],{"class":5049},[11,29857,29858,29859,29862,29863,29865],{},"它比手寫設定好的地方在於：規則是",[12390,29860,29861],{},"依你實際安裝的模組產生的","，Nuxt 自動匯入的那些 API 也已經登記好，不用再像以前那樣為了消掉滿江紅的 ",[29,29864,26360],{}," 而整條關掉。",[15,29867,29869],{"id":29868},"tailwind-4不再有-tailwindconfigjs","Tailwind 4：不再有 tailwind.config.js",[11,29871,29872,29873,29875],{},"這是變動最大的一塊。",[29,29874,29350],{}," 那條路已經不需要了，Tailwind 4 自己提供 Vite plugin：",[22,29877,29879],{"className":2057,"code":29878,"language":2059,"meta":27,"style":27},"npm install -D tailwindcss @tailwindcss\u002Fvite\n",[29,29880,29881],{"__ignoreMap":27},[32,29882,29883,29885,29887,29889,29892],{"class":34,"line":35},[32,29884,4625],{"class":2066},[32,29886,4650],{"class":175},[32,29888,26145],{"class":351},[32,29890,29891],{"class":175}," tailwindcss",[32,29893,29894],{"class":175}," @tailwindcss\u002Fvite\n",[22,29896,29898],{"className":26159,"code":29897,"language":26161,"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,29899,29900,29911,29915,29925,29936,29941,29951,29955],{"__ignoreMap":27},[32,29901,29902,29904,29906,29908],{"class":34,"line":35},[32,29903,8794],{"class":38},[32,29905,28878],{"class":41},[32,29907,8850],{"class":38},[32,29909,29910],{"class":175}," '@tailwindcss\u002Fvite'\n",[32,29912,29913],{"class":34,"line":45},[32,29914,103],{"emptyLinePlaceholder":102},[32,29916,29917,29919,29921,29923],{"class":34,"line":51},[32,29918,5038],{"class":38},[32,29920,5041],{"class":38},[32,29922,24171],{"class":217},[32,29924,1143],{"class":5049},[32,29926,29927,29929,29932,29934],{"class":34,"line":90},[32,29928,28157],{"class":41},[32,29930,29931],{"class":175},"'~\u002Fassets\u002Fcss\u002Fmain.css'",[32,29933,17276],{"class":41},[32,29935,547],{"class":5049},[32,29937,29938],{"class":34,"line":99},[32,29939,29940],{"class":41},"  vite: {\n",[32,29942,29943,29946,29948],{"class":34,"line":106},[32,29944,29945],{"class":41},"    plugins: [",[32,29947,28831],{"class":217},[32,29949,29950],{"class":41},"()]\n",[32,29952,29953],{"class":34,"line":114},[32,29954,1203],{"class":41},[32,29956,29957],{"class":34,"line":120},[32,29958,24189],{"class":5049},[11,29960,29961,5240],{},[29,29962,29963],{},"app\u002Fassets\u002Fcss\u002Fmain.css",[22,29965,29967],{"className":5412,"code":29966,"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,29968,29969,29978,29982,29989,29999,30009],{"__ignoreMap":27},[32,29970,29971,29973,29976],{"class":34,"line":35},[32,29972,8744],{"class":38},[32,29974,29975],{"class":175}," \"tailwindcss\"",[32,29977,96],{"class":41},[32,29979,29980],{"class":34,"line":45},[32,29981,103],{"emptyLinePlaceholder":102},[32,29983,29984,29987],{"class":34,"line":51},[32,29985,29986],{"class":38},"@theme",[32,29988,703],{"class":41},[32,29990,29991,29994,29997],{"class":34,"line":90},[32,29992,29993],{"class":41},"  --color-brand: ",[32,29995,29996],{"class":27519},"#000000",[32,29998,96],{"class":41},[32,30000,30001,30004,30007],{"class":34,"line":99},[32,30002,30003],{"class":41},"  --font-sans: \"Noto Sans TC\", ",[32,30005,30006],{"class":4049},"sans-serif",[32,30008,96],{"class":41},[32,30010,30011],{"class":34,"line":106},[32,30012,54],{"class":41},[11,30014,30015],{},"三個要注意的：",[6426,30017,30018,30032,30041],{},[4541,30019,30020,30025,30026,30028,30029,30031],{},[12390,30021,30022,30023],{},"沒有 ",[29,30024,28223],{},"。主題設定改用 CSS 的 ",[29,30027,29986],{}," 區塊寫，跑 ",[29,30030,29027],{}," 會直接失敗。",[4541,30033,30034,30040],{},[12390,30035,30036,30037,30039],{},"不用再維護 ",[29,30038,28332],{}," 陣列","。Tailwind 4 自動掃描，以前那種「漏掉一個資料夾、正式站樣式整組消失」的坑沒有了。",[4541,30042,30043,30052,30053,30056,30057,3775],{},[12390,30044,30045,30048,30049],{},[29,30046,30047],{},"@apply"," 在 scoped style 裡要先 ",[29,30050,30051],{},"@reference","。單檔元件的 ",[29,30054,30055],{},"\u003Cstyle scoped>"," 是獨立編譯的，看不到主檔案的 ",[29,30058,8744],{},[11,30060,30061,30062,30064,30065,3775],{},"Tailwind 4 本身的其他變更（PostCSS 設定、",[29,30063,29986],{}," 的用法）另外寫在 ",[412,30066,30067],{"href":29218},"Vite + Vue 3 + Tailwind CSS 4 + shadcn-vue 安裝心得",[15,30069,30071],{"id":30070},"狀態管理先問要不要-pinia","狀態管理：先問要不要 Pinia",[11,30073,30074,30075,30078,30079,30082],{},"Nuxt 3 那篇裡裝 Pinia 是預設動作。實際上 Nuxt 內建的 ",[29,30076,30077],{},"useState"," 已經能處理大部分情況——它是 ",[12390,30080,30081],{},"SSR 友善的共用 ref","，伺服器端算出來的值會被序列化帶到瀏覽器：",[22,30084,30086],{"className":26159,"code":30085,"language":26161,"meta":27,"style":27},"export const useCounter = () => useState\u003Cnumber>('counter', () => 0)\n",[29,30087,30088],{"__ignoreMap":27},[32,30089,30090,30092,30094,30097,30099,30101,30103,30106,30108,30110,30112,30115,30117,30119,30121],{"class":34,"line":35},[32,30091,5038],{"class":38},[32,30093,24231],{"class":38},[32,30095,30096],{"class":217}," useCounter",[32,30098,894],{"class":38},[32,30100,11398],{"class":41},[32,30102,5090],{"class":38},[32,30104,30105],{"class":217}," useState",[32,30107,4046],{"class":41},[32,30109,21591],{"class":351},[32,30111,25607],{"class":41},[32,30113,30114],{"class":175},"'counter'",[32,30116,11359],{"class":41},[32,30118,5090],{"class":38},[32,30120,1523],{"class":351},[32,30122,515],{"class":41},[11,30124,30125],{},"在任何元件裡呼叫同一個 key 就拿到同一份狀態。什麼時候才真的需要 Pinia：",[4538,30127,30128,30131,30134],{},[4541,30129,30130],{},"需要 store 的 actions／getters 組織一大包邏輯",[4541,30132,30133],{},"需要 devtools 的時間旅行除錯",[4541,30135,30136],{},"已經有一套 Pinia store 要從別的專案搬過來",[11,30138,30139],{},"不然多一層抽象只是多一層要維護的東西。",[15,30141,30143],{"id":30142},"資料取得預渲染一定要-await","資料取得：預渲染一定要 await",[11,30145,30146,30147,7090,30149,30151,30152,5240],{},"這是最容易吃虧的一個。",[29,30148,25954],{},[29,30150,25951],{}," 回傳的是 ref，",[12390,30153,30154,30155,30157],{},"在 setup 階段沒有 ",[29,30156,25449],{},"，預渲染就會在資料回來之前先把 HTML 吐出去",[22,30159,30161],{"className":8665,"code":30160,"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,30162,30163,30179,30184,30226,30230,30235,30275],{"__ignoreMap":27},[32,30164,30165,30167,30169,30171,30173,30175,30177],{"class":34,"line":35},[32,30166,4046],{"class":41},[32,30168,4125],{"class":4049},[32,30170,24724],{"class":4053},[32,30172,8677],{"class":4053},[32,30174,172],{"class":41},[32,30176,25371],{"class":175},[32,30178,4062],{"class":41},[32,30180,30181],{"class":34,"line":45},[32,30182,30183],{"class":608},"\u002F\u002F ✗ 預渲染出來的 HTML 裡 posts 是空的\n",[32,30185,30186,30188,30190,30192,30194,30197,30199,30201,30204,30206,30209,30211,30213,30216,30218,30220,30222,30224],{"class":34,"line":51},[32,30187,6617],{"class":38},[32,30189,24782],{"class":41},[32,30191,16150],{"class":903},[32,30193,5269],{"class":41},[32,30195,30196],{"class":351},"posts",[32,30198,24792],{"class":41},[32,30200,172],{"class":38},[32,30202,30203],{"class":217}," useAsyncData",[32,30205,477],{"class":41},[32,30207,30208],{"class":175},"'posts'",[32,30210,11359],{"class":41},[32,30212,5090],{"class":38},[32,30214,30215],{"class":217}," queryCollection",[32,30217,477],{"class":41},[32,30219,30208],{"class":175},[32,30221,533],{"class":41},[32,30223,25234],{"class":217},[32,30225,24116],{"class":41},[32,30227,30228],{"class":34,"line":90},[32,30229,103],{"emptyLinePlaceholder":102},[32,30231,30232],{"class":34,"line":99},[32,30233,30234],{"class":608},"\u002F\u002F ✓\n",[32,30236,30237,30239,30241,30243,30245,30247,30249,30251,30253,30255,30257,30259,30261,30263,30265,30267,30269,30271,30273],{"class":34,"line":106},[32,30238,6617],{"class":38},[32,30240,24782],{"class":41},[32,30242,16150],{"class":903},[32,30244,5269],{"class":41},[32,30246,30196],{"class":351},[32,30248,24792],{"class":41},[32,30250,172],{"class":38},[32,30252,25227],{"class":38},[32,30254,30203],{"class":217},[32,30256,477],{"class":41},[32,30258,30208],{"class":175},[32,30260,11359],{"class":41},[32,30262,5090],{"class":38},[32,30264,30215],{"class":217},[32,30266,477],{"class":41},[32,30268,30208],{"class":175},[32,30270,533],{"class":41},[32,30272,25234],{"class":217},[32,30274,24116],{"class":41},[32,30276,30277,30279,30281],{"class":34,"line":114},[32,30278,4105],{"class":41},[32,30280,4125],{"class":4049},[32,30282,4062],{"class":41},[11,30284,30285,30286,30289],{},"畫面上看不出差別——瀏覽器端 hydrate 完照樣有資料。",[12390,30287,30288],{},"壞掉的是原始 HTML","，爬蟲跟社群分享卡片讀到的就是空的。這種問題不會有錯誤訊息，只能自己記得。",[11,30291,30292,30293,7218,30295,30298],{},"同一份資料在多個元件用時，",[29,30294,25954],{},[12390,30296,30297],{},"key 要一致","，Nuxt 才會共用同一次請求而不是各打各的。",[15,30300,30302],{"id":30301},"部署nitro-preset","部署：Nitro preset",[11,30304,30305],{},"後端由 Nitro 負責，換部署目標基本上就是換一行：",[22,30307,30309],{"className":26159,"code":30308,"language":26161,"meta":27,"style":27},"export default defineNuxtConfig({\n  nitro: {\n    preset: 'cloudflare_module'\n  }\n})\n",[29,30310,30311,30321,30326,30334,30338],{"__ignoreMap":27},[32,30312,30313,30315,30317,30319],{"class":34,"line":35},[32,30314,5038],{"class":38},[32,30316,5041],{"class":38},[32,30318,24171],{"class":217},[32,30320,1143],{"class":5049},[32,30322,30323],{"class":34,"line":45},[32,30324,30325],{"class":41},"  nitro: {\n",[32,30327,30328,30331],{"class":34,"line":51},[32,30329,30330],{"class":41},"    preset: ",[32,30332,30333],{"class":175},"'cloudflare_module'\n",[32,30335,30336],{"class":34,"line":90},[32,30337,1203],{"class":41},[32,30339,30340],{"class":34,"line":99},[32,30341,24189],{"class":5049},[11,30343,30344,30345,3750,30348,3750,30351,3750,30354,3775],{},"常見的還有 ",[29,30346,30347],{},"node-server",[29,30349,30350],{},"vercel",[29,30352,30353],{},"netlify",[29,30355,30356],{},"static",[11,30358,30359,30362,30363,30365,30366,30369,30370,30373,30374,30381],{},[12390,30360,30361],{},"要注意 preset 之間的執行環境差異不會被型別擋下來。"," 這個站踩過一個：workerd 在請求階段解不了動態 ",[29,30364,5027],{},"，配上 ",[29,30367,30368],{},"defineAsyncComponent"," 會安靜地渲染出空白而不是報錯——",[29,30371,30372],{},"npm run dev"," 走 vite-node、預渲染是建置時在 Node 跑的，兩者都碰不到那個限制。",[12390,30375,30376,30377,30380],{},"請求時才 SSR 的頁面一定要用 ",[29,30378,30379],{},"nuxt preview"," 在真正的 runtime 驗過","，靜態伺服器看不到 worker 的行為。",[15,30383,30384],{"id":30384},"對照表",[13574,30386,30387,30397],{},[13577,30388,30389],{},[13580,30390,30391,30393,30395],{},[13583,30392,13685],{},[13583,30394,23989],{},[13583,30396,29268],{},[13590,30398,30399,30412,30424,30440,30457,30475,30487],{},[13580,30400,30401,30403,30407],{},[13595,30402,29364],{},[13595,30404,30405],{},[29,30406,29345],{},[13595,30408,30409],{},[29,30410,30411],{},"npm create nuxt@latest",[13580,30413,30414,30417,30420],{},[13595,30415,30416],{},"前端原始碼位置",[13595,30418,30419],{},"根目錄",[13595,30421,30422],{},[29,30423,29472],{},[13580,30425,30426,30429,30436],{},[13595,30427,30428],{},"型別檢查",[13595,30430,30431,30432,29351,30434],{},"自己裝 ",[29,30433,29636],{},[29,30435,29640],{},[13595,30437,30438],{},[29,30439,29718],{},[13580,30441,30442,30444,30450],{},[13595,30443,4853],{},[13595,30445,30446,29351,30448],{},[29,30447,26239],{},[29,30449,26350],{},[13595,30451,30452,29351,30455],{},[29,30453,30454],{},"@nuxt\u002Feslint",[29,30456,29802],{},[13580,30458,30459,30462,30468],{},[13595,30460,30461],{},"Tailwind",[13595,30463,30464,29351,30466],{},[29,30465,29350],{},[29,30467,28223],{},[13595,30469,30470,29351,30473],{},[29,30471,30472],{},"@tailwindcss\u002Fvite",[29,30474,29986],{},[13580,30476,30477,30480,30483],{},[13595,30478,30479],{},"相容性鎖定",[13595,30481,30482],{},"無",[13595,30484,30485],{},[29,30486,29591],{},[13580,30488,30489,30492,30495],{},[13595,30490,30491],{},"全域狀態",[13595,30493,30494],{},"大多直接上 Pinia",[13595,30496,30497,30498,30500],{},"先看 ",[29,30499,30077],{}," 夠不夠",[15,30502,30503],{"id":30503},"沒有變的部分",[11,30505,30506],{},"Nuxt 3 那篇裡有一半以上仍然完全適用，不用重學：",[4538,30508,30509,30519,30524,30533,30538,30546],{},[4541,30510,30511,30512,3750,30515,30518],{},"檔案系統路由（",[29,30513,30514],{},"[id].vue",[29,30516,30517],{},"[...slug].vue","、巢狀路由）",[4541,30520,30521,30522],{},"404 頁面與 ",[29,30523,27392],{},[4541,30525,30526,3750,30528,3750,30530],{},[29,30527,17021],{},[29,30529,21337],{},[29,30531,30532],{},"\u003CNuxtLayout>",[4541,30534,30535,30536],{},"Layout 與具名插槽、",[29,30537,27887],{},[4541,30539,30540,30541,30543,30544,18240],{},"元件自動載入與路徑前綴命名（",[29,30542,27970],{}," → ",[29,30545,27973],{},[4541,30547,30548,30550,30551,30553],{},[29,30549,27989],{}," \u002F ",[29,30552,27992],{}," 後綴",[11,30555,30556,30557,30559],{},"差別只在檔案現在放 ",[29,30558,29472],{}," 底下。",[15,30561,4536],{"id":4536},[4538,30563,30564,30571,30578,30584,30591],{},[4541,30565,30566],{},[412,30567,30570],{"href":30568,"rel":30569},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fgetting-started\u002Fupgrade",[416],"Nuxt 4 升級指南",[4541,30572,30573],{},[412,30574,30577],{"href":30575,"rel":30576},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fguide\u002Fdirectory-structure\u002Fapp",[416],"Nuxt 目錄結構",[4541,30579,30580],{},[412,30581,30454],{"href":30582,"rel":30583},"https:\u002F\u002Feslint.nuxt.com\u002F",[416],[4541,30585,30586],{},[412,30587,30590],{"href":30588,"rel":30589},"https:\u002F\u002Ftailwindcss.com\u002Fdocs\u002Finstallation\u002Fusing-vite",[416],"Tailwind CSS 4：Vite plugin",[4541,30592,30593],{},[412,30594,30597],{"href":30595,"rel":30596},"https:\u002F\u002Fnitro.build\u002Fdeploy",[416],"Nitro 部署 preset",[368,30599,30600],{},"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":30602},[30603,30604,30607,30608,30609,30610,30611,30612,30613,30614,30615,30616],{"id":29364,"depth":45,"text":29364},{"id":29447,"depth":45,"text":29448,"children":30605},[30606],{"id":29528,"depth":51,"text":29529},{"id":29590,"depth":45,"text":29591},{"id":24160,"depth":45,"text":23951},{"id":29734,"depth":45,"text":29735},{"id":29868,"depth":45,"text":29869},{"id":30070,"depth":45,"text":30071},{"id":30142,"depth":45,"text":30143},{"id":30301,"depth":45,"text":30302},{"id":30384,"depth":45,"text":30384},{"id":30503,"depth":45,"text":30503},{"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":29333,"description":30617},"posts\u002F20260818.nuxt4-project-setup",[30625,23771,28710,4853,23951,30626],"Nuxt4","Nitro","ODepHVQEFuCgJscw6ddZRJ5orBW31R4ETthbWRXh3GE",{"id":10851,"title":10852,"body":30629,"category":378,"description":10962,"draft":380,"extension":381,"image":382,"meta":30704,"navigation":102,"path":10964,"publishedAt":10965,"relatedExperiments":30705,"seo":30706,"stem":10968,"tags":30707,"updatedAt":10848,"__hash__":10971},{"type":8,"value":30630,"toc":30697},[30631,30633,30635,30643,30647,30649,30655,30659,30661,30665,30667,30669,30673,30679,30683,30685,30687,30691,30693],[11,30632,10857],{},[15,30634,10860],{"id":10860},[11,30636,10863,30637,7090,30639,10870,30641,10874],{},[29,30638,10866],{},[29,30640,10869],{},[29,30642,10873],{},[11,30644,30645],{},[10761,30646],{"alt":10879,"src":10880},[15,30648,10883],{"id":10883},[11,30650,10886,30651,10889,30653,10892],{},[29,30652,10866],{},[29,30654,10869],{},[11,30656,30657],{},[10761,30658],{"alt":10897,"src":10898},[11,30660,10901],{},[11,30662,30663],{},[10761,30664],{"alt":10906,"src":10907},[15,30666,10910],{"id":10910},[11,30668,10913],{},[11,30670,30671],{},[10761,30672],{"alt":10918,"src":10919},[11,30674,30675,10925,30677,3775],{},[29,30676,10924],{},[29,30678,10928],{},[11,30680,30681],{},[10761,30682],{"alt":10933,"src":10934},[15,30684,10937],{"id":10937},[11,30686,10940],{},[11,30688,30689],{},[10761,30690],{"alt":10945,"src":10946},[15,30692,2004],{"id":2003},[11,30694,10951,30695,3775],{},[29,30696,10954],{},{"title":27,"searchDepth":51,"depth":51,"links":30698},[30699,30700,30701,30702,30703],{"id":10860,"depth":45,"text":10860},{"id":10883,"depth":45,"text":10883},{"id":10910,"depth":45,"text":10910},{"id":10937,"depth":45,"text":10937},{"id":2003,"depth":45,"text":2004},{},[],{"title":10852,"description":10962},[390,10846,10970],[30709,30710],{"title":10974,"path":11064,"stem":11068,"description":11062,"category":378,"publishedAt":11065,"children":-1},{"title":10735,"path":10840,"stem":10844,"description":10838,"category":378,"publishedAt":10841,"children":-1},1787756612748]