[{"data":1,"prerenderedAt":1182},["ShallowReactive",2],{"\u002Fblog\u002Fprogramming\u002Fvue-recursive-component":3,"relation-articles\u002Fblog\u002Fprogramming\u002Fvue-recursive-componentシステム開発":1087,"recommented-articles\u002Fblog\u002Fprogramming\u002Fvue-recursive-componentシステム開発":1136},{"id":4,"title":5,"body":6,"category":1073,"createdAt":1074,"description":1075,"extension":1076,"isRecommend":1077,"meta":1078,"navigation":191,"path":1079,"seo":1080,"stem":1081,"subCategory":1082,"tags":1083,"thumbnail":1084,"updatedAt":1085,"__hash__":1086},"blog\u002Fblog\u002Fprogramming\u002Fvue-recursive-component.md","Vueで再帰的コンポーネントを作成する方法【Vue3】",{"type":7,"value":8,"toc":1066},"minimark",[9,13,17,24,27,30,33,48,55,58,64,69,79,576,602,608,1013,1019,1025,1028,1032,1035,1041,1051,1054,1059,1062],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16],"p",{},"この記事ではVue.jsで再帰的コンポーネントの作成方法を解説します。",[14,18,19,20,23],{},"再帰的コンポーネントとは、あるコンポーネントが自身を呼び出しているようなコンポーネントを指します。",[21,22],"br",{},"\n例えば、ディレクトリ構造やスレッド形式のコメント欄等をコンポーネント化する際に使うことが考えられます。",[14,25,26],{},"今回は、ディレクトリ構造を表現するコンポーネントを作成してみます。",[10,28,29],{"id":29},"再帰的コンポーネントの基本",[14,31,32],{},"Vue.jsで再帰的コンポーネントを作成するのは簡単です。",[14,34,35,36,38,39,43,44,47],{},"コンポーネントはデフォルトで自身を呼び出すことができます。",[21,37],{},"\n例えば、",[40,41,42],"code",{},"FooBar.vue"," というファイル名のコンポーネントは、そのテンプレート内で ",[40,45,46],{},"\u003CFooBar\u002F>"," として呼び出せます。",[14,49,50,51,54],{},"自身を呼び出すだけではコンポーネントが無限に描画されていくので、あとは描画の条件を",[40,52,53],{},"v-if","などを利用して制御します。",[10,56,57],{"id":57},"ディレクトリ構造を再帰的コンポーネントで再現する",[14,59,60,61,63],{},"再帰的コンポーネントの例として、ディレクトリ構造を表現するコンポーネントを作成します。",[21,62],{},"\nコンポーネントの見た目は以下のようになります。",[65,66],"img",{"alt":67,"src":68},"今回作成するコンポーネント","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_vue-recursive-component_sample.webp",[14,70,71,72,75,76,78],{},"ディレクトリ構造を再現する再帰的コンポーネント",[40,73,74],{},"DirectoryTree.vue","は、以下のように作成しました。",[21,77],{},"\n（CSSは一部省略）",[80,81,86],"pre",{"className":82,"code":83,"filename":74,"language":84,"meta":85,"style":85},"language-vue shiki shiki-themes github-dark","\u003Cscript setup lang=\"ts\">\ninterface Props {\n  type: string;\n  name: string;\n  children?: Array\u003Cany>;\n}\n\nconst props = withDefaults(defineProps\u003CProps>(), {\n  type: \"\",\n  name: \"\",\n  children: () => [],\n});\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ctemplate v-if=\"props.type === 'directory'\">\n    \u003Cli>\n      \u003Cspan class=\"directory\">{{ props.name }}\u003C\u002Fspan>\n      \u003Cul>\n        \u003Cdiv v-for=\"child in props.children\">\n          \u003CDirectoryTree\n            :type=\"child.type\"\n            :name=\"child.name\"\n            :children=\"child.children\"\n          >\u003C\u002FDirectoryTree>\n        \u003C\u002Fdiv>\n      \u003C\u002Ful>\n    \u003C\u002Fli>\n  \u003C\u002Ftemplate>\n\n  \u003Ctemplate v-else>\n    \u003Cli>\n      \u003Cspan class=\"file\">\n        {{ props.name }}\n      \u003C\u002Fspan>\n    \u003C\u002Fli>\n  \u003C\u002Ftemplate>\n\u003C\u002Ftemplate>\n","vue","",[40,87,88,118,131,148,160,180,186,193,222,234,244,258,264,274,279,289,316,327,350,360,379,388,407,424,441,452,462,472,482,492,497,509,518,534,540,549,558,567],{"__ignoreMap":85},[89,90,93,97,101,105,108,111,115],"span",{"class":91,"line":92},"line",1,[89,94,96],{"class":95},"s95oV","\u003C",[89,98,100],{"class":99},"s4JwU","script",[89,102,104],{"class":103},"svObZ"," setup",[89,106,107],{"class":103}," lang",[89,109,110],{"class":95},"=",[89,112,114],{"class":113},"sU2Wk","\"ts\"",[89,116,117],{"class":95},">\n",[89,119,121,125,128],{"class":91,"line":120},2,[89,122,124],{"class":123},"snl16","interface",[89,126,127],{"class":103}," Props",[89,129,130],{"class":95}," {\n",[89,132,134,138,141,145],{"class":91,"line":133},3,[89,135,137],{"class":136},"s9osk","  type",[89,139,140],{"class":123},":",[89,142,144],{"class":143},"sDLfK"," string",[89,146,147],{"class":95},";\n",[89,149,151,154,156,158],{"class":91,"line":150},4,[89,152,153],{"class":136},"  name",[89,155,140],{"class":123},[89,157,144],{"class":143},[89,159,147],{"class":95},[89,161,163,166,169,172,174,177],{"class":91,"line":162},5,[89,164,165],{"class":136},"  children",[89,167,168],{"class":123},"?:",[89,170,171],{"class":103}," Array",[89,173,96],{"class":95},[89,175,176],{"class":143},"any",[89,178,179],{"class":95},">;\n",[89,181,183],{"class":91,"line":182},6,[89,184,185],{"class":95},"}\n",[89,187,189],{"class":91,"line":188},7,[89,190,192],{"emptyLinePlaceholder":191},true,"\n",[89,194,196,199,202,205,208,211,214,216,219],{"class":91,"line":195},8,[89,197,198],{"class":123},"const",[89,200,201],{"class":143}," props",[89,203,204],{"class":123}," =",[89,206,207],{"class":103}," withDefaults",[89,209,210],{"class":95},"(",[89,212,213],{"class":103},"defineProps",[89,215,96],{"class":95},[89,217,218],{"class":103},"Props",[89,220,221],{"class":95},">(), {\n",[89,223,225,228,231],{"class":91,"line":224},9,[89,226,227],{"class":95},"  type: ",[89,229,230],{"class":113},"\"\"",[89,232,233],{"class":95},",\n",[89,235,237,240,242],{"class":91,"line":236},10,[89,238,239],{"class":95},"  name: ",[89,241,230],{"class":113},[89,243,233],{"class":95},[89,245,247,249,252,255],{"class":91,"line":246},11,[89,248,165],{"class":103},[89,250,251],{"class":95},": () ",[89,253,254],{"class":123},"=>",[89,256,257],{"class":95}," [],\n",[89,259,261],{"class":91,"line":260},12,[89,262,263],{"class":95},"});\n",[89,265,267,270,272],{"class":91,"line":266},13,[89,268,269],{"class":95},"\u003C\u002F",[89,271,100],{"class":99},[89,273,117],{"class":95},[89,275,277],{"class":91,"line":276},14,[89,278,192],{"emptyLinePlaceholder":191},[89,280,282,284,287],{"class":91,"line":281},15,[89,283,96],{"class":95},[89,285,286],{"class":99},"template",[89,288,117],{"class":95},[89,290,292,295,297,300,302,305,308,311,314],{"class":91,"line":291},16,[89,293,294],{"class":95},"  \u003C",[89,296,286],{"class":99},[89,298,299],{"class":123}," v-if",[89,301,110],{"class":95},[89,303,304],{"class":113},"\"",[89,306,307],{"class":95},"props.type ",[89,309,310],{"class":123},"===",[89,312,313],{"class":113}," 'directory'\"",[89,315,117],{"class":95},[89,317,319,322,325],{"class":91,"line":318},17,[89,320,321],{"class":95},"    \u003C",[89,323,324],{"class":99},"li",[89,326,117],{"class":95},[89,328,330,333,335,338,340,343,346,348],{"class":91,"line":329},18,[89,331,332],{"class":95},"      \u003C",[89,334,89],{"class":99},[89,336,337],{"class":103}," class",[89,339,110],{"class":95},[89,341,342],{"class":113},"\"directory\"",[89,344,345],{"class":95},">{{ props.name }}\u003C\u002F",[89,347,89],{"class":99},[89,349,117],{"class":95},[89,351,353,355,358],{"class":91,"line":352},19,[89,354,332],{"class":95},[89,356,357],{"class":99},"ul",[89,359,117],{"class":95},[89,361,363,366,369,372,374,377],{"class":91,"line":362},20,[89,364,365],{"class":95},"        \u003C",[89,367,368],{"class":99},"div",[89,370,371],{"class":103}," v-for",[89,373,110],{"class":95},[89,375,376],{"class":113},"\"child in props.children\"",[89,378,117],{"class":95},[89,380,382,385],{"class":91,"line":381},21,[89,383,384],{"class":95},"          \u003C",[89,386,387],{"class":99},"DirectoryTree\n",[89,389,391,394,397,399,401,404],{"class":91,"line":390},22,[89,392,393],{"class":95},"            :",[89,395,396],{"class":103},"type",[89,398,110],{"class":95},[89,400,304],{"class":113},[89,402,403],{"class":95},"child.type",[89,405,406],{"class":113},"\"\n",[89,408,410,412,415,417,419,422],{"class":91,"line":409},23,[89,411,393],{"class":95},[89,413,414],{"class":103},"name",[89,416,110],{"class":95},[89,418,304],{"class":113},[89,420,421],{"class":95},"child.name",[89,423,406],{"class":113},[89,425,427,429,432,434,436,439],{"class":91,"line":426},24,[89,428,393],{"class":95},[89,430,431],{"class":103},"children",[89,433,110],{"class":95},[89,435,304],{"class":113},[89,437,438],{"class":95},"child.children",[89,440,406],{"class":113},[89,442,444,447,450],{"class":91,"line":443},25,[89,445,446],{"class":95},"          >\u003C\u002F",[89,448,449],{"class":99},"DirectoryTree",[89,451,117],{"class":95},[89,453,455,458,460],{"class":91,"line":454},26,[89,456,457],{"class":95},"        \u003C\u002F",[89,459,368],{"class":99},[89,461,117],{"class":95},[89,463,465,468,470],{"class":91,"line":464},27,[89,466,467],{"class":95},"      \u003C\u002F",[89,469,357],{"class":99},[89,471,117],{"class":95},[89,473,475,478,480],{"class":91,"line":474},28,[89,476,477],{"class":95},"    \u003C\u002F",[89,479,324],{"class":99},[89,481,117],{"class":95},[89,483,485,488,490],{"class":91,"line":484},29,[89,486,487],{"class":95},"  \u003C\u002F",[89,489,286],{"class":99},[89,491,117],{"class":95},[89,493,495],{"class":91,"line":494},30,[89,496,192],{"emptyLinePlaceholder":191},[89,498,500,502,504,507],{"class":91,"line":499},31,[89,501,294],{"class":95},[89,503,286],{"class":99},[89,505,506],{"class":123}," v-else",[89,508,117],{"class":95},[89,510,512,514,516],{"class":91,"line":511},32,[89,513,321],{"class":95},[89,515,324],{"class":99},[89,517,117],{"class":95},[89,519,521,523,525,527,529,532],{"class":91,"line":520},33,[89,522,332],{"class":95},[89,524,89],{"class":99},[89,526,337],{"class":103},[89,528,110],{"class":95},[89,530,531],{"class":113},"\"file\"",[89,533,117],{"class":95},[89,535,537],{"class":91,"line":536},34,[89,538,539],{"class":95},"        {{ props.name }}\n",[89,541,543,545,547],{"class":91,"line":542},35,[89,544,467],{"class":95},[89,546,89],{"class":99},[89,548,117],{"class":95},[89,550,552,554,556],{"class":91,"line":551},36,[89,553,477],{"class":95},[89,555,324],{"class":99},[89,557,117],{"class":95},[89,559,561,563,565],{"class":91,"line":560},37,[89,562,487],{"class":95},[89,564,286],{"class":99},[89,566,117],{"class":95},[89,568,570,572,574],{"class":91,"line":569},38,[89,571,269],{"class":95},[89,573,286],{"class":99},[89,575,117],{"class":95},[14,577,578,581,582,584,585,588,589],{},[40,579,580],{},"props","の",[40,583,396],{},"が",[40,586,587],{},"directory","のときはディレクトリのため再度、自身のコンポーネント名である",[590,591,592,593,595,581,597,584,599,601],"directory-tree",{},"を呼び出します。",[21,594],{},[40,596,580],{},[40,598,396],{},[40,600,587],{},"のときはファイルのため、ファイル名のみを描画しています。",[14,603,604,605,75],{},"このコンポーネントを呼び出す親コンポーネント",[40,606,607],{},"App.vue",[80,609,611],{"className":82,"code":610,"filename":607,"language":84,"meta":85,"style":85},"\u003Cscript setup lang=\"ts\">\nimport { ref } from \"vue\";\nimport DirectoryTree from \".\u002FDirectoryTree.vue\";\n\nconst tree = ref([\n  {\n    type: \"directory\",\n    name: \"Dir1\",\n    children: [\n      {\n        type: \"file\",\n        name: \"File1\",\n      },\n      {\n        type: \"directory\",\n        name: \"Dir2\",\n        children: [\n          {\n            type: \"file\",\n            name: \"File2\",\n          },\n          {\n            type: \"directory\",\n            name: \"Dir3\",\n            children: [\n              {\n                type: \"file\",\n                name: \"File3\",\n              },\n              {\n                type: \"file\",\n                name: \"File4\",\n              },\n            ],\n          },\n        ],\n      },\n    ],\n  },\n  {\n    type: \"file\",\n    name: \"File5\",\n  },\n]);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CDirectoryTree :type=\"'directory'\" :name=\"'\u002F'\" :children=\"tree\">\u003C\u002FDirectoryTree>\n\u003C\u002Ftemplate>\n",[40,612,613,629,645,659,663,678,683,692,702,707,712,721,731,736,740,748,757,762,767,776,786,791,795,803,812,817,822,831,841,846,850,858,867,871,876,880,885,889,894,900,905,914,924,929,935,944,949,958,1004],{"__ignoreMap":85},[89,614,615,617,619,621,623,625,627],{"class":91,"line":92},[89,616,96],{"class":95},[89,618,100],{"class":99},[89,620,104],{"class":103},[89,622,107],{"class":103},[89,624,110],{"class":95},[89,626,114],{"class":113},[89,628,117],{"class":95},[89,630,631,634,637,640,643],{"class":91,"line":120},[89,632,633],{"class":123},"import",[89,635,636],{"class":95}," { ref } ",[89,638,639],{"class":123},"from",[89,641,642],{"class":113}," \"vue\"",[89,644,147],{"class":95},[89,646,647,649,652,654,657],{"class":91,"line":133},[89,648,633],{"class":123},[89,650,651],{"class":95}," DirectoryTree ",[89,653,639],{"class":123},[89,655,656],{"class":113}," \".\u002FDirectoryTree.vue\"",[89,658,147],{"class":95},[89,660,661],{"class":91,"line":150},[89,662,192],{"emptyLinePlaceholder":191},[89,664,665,667,670,672,675],{"class":91,"line":162},[89,666,198],{"class":123},[89,668,669],{"class":143}," tree",[89,671,204],{"class":123},[89,673,674],{"class":103}," ref",[89,676,677],{"class":95},"([\n",[89,679,680],{"class":91,"line":182},[89,681,682],{"class":95},"  {\n",[89,684,685,688,690],{"class":91,"line":188},[89,686,687],{"class":95},"    type: ",[89,689,342],{"class":113},[89,691,233],{"class":95},[89,693,694,697,700],{"class":91,"line":195},[89,695,696],{"class":95},"    name: ",[89,698,699],{"class":113},"\"Dir1\"",[89,701,233],{"class":95},[89,703,704],{"class":91,"line":224},[89,705,706],{"class":95},"    children: [\n",[89,708,709],{"class":91,"line":236},[89,710,711],{"class":95},"      {\n",[89,713,714,717,719],{"class":91,"line":246},[89,715,716],{"class":95},"        type: ",[89,718,531],{"class":113},[89,720,233],{"class":95},[89,722,723,726,729],{"class":91,"line":260},[89,724,725],{"class":95},"        name: ",[89,727,728],{"class":113},"\"File1\"",[89,730,233],{"class":95},[89,732,733],{"class":91,"line":266},[89,734,735],{"class":95},"      },\n",[89,737,738],{"class":91,"line":276},[89,739,711],{"class":95},[89,741,742,744,746],{"class":91,"line":281},[89,743,716],{"class":95},[89,745,342],{"class":113},[89,747,233],{"class":95},[89,749,750,752,755],{"class":91,"line":291},[89,751,725],{"class":95},[89,753,754],{"class":113},"\"Dir2\"",[89,756,233],{"class":95},[89,758,759],{"class":91,"line":318},[89,760,761],{"class":95},"        children: [\n",[89,763,764],{"class":91,"line":329},[89,765,766],{"class":95},"          {\n",[89,768,769,772,774],{"class":91,"line":352},[89,770,771],{"class":95},"            type: ",[89,773,531],{"class":113},[89,775,233],{"class":95},[89,777,778,781,784],{"class":91,"line":362},[89,779,780],{"class":95},"            name: ",[89,782,783],{"class":113},"\"File2\"",[89,785,233],{"class":95},[89,787,788],{"class":91,"line":381},[89,789,790],{"class":95},"          },\n",[89,792,793],{"class":91,"line":390},[89,794,766],{"class":95},[89,796,797,799,801],{"class":91,"line":409},[89,798,771],{"class":95},[89,800,342],{"class":113},[89,802,233],{"class":95},[89,804,805,807,810],{"class":91,"line":426},[89,806,780],{"class":95},[89,808,809],{"class":113},"\"Dir3\"",[89,811,233],{"class":95},[89,813,814],{"class":91,"line":443},[89,815,816],{"class":95},"            children: [\n",[89,818,819],{"class":91,"line":454},[89,820,821],{"class":95},"              {\n",[89,823,824,827,829],{"class":91,"line":464},[89,825,826],{"class":95},"                type: ",[89,828,531],{"class":113},[89,830,233],{"class":95},[89,832,833,836,839],{"class":91,"line":474},[89,834,835],{"class":95},"                name: ",[89,837,838],{"class":113},"\"File3\"",[89,840,233],{"class":95},[89,842,843],{"class":91,"line":484},[89,844,845],{"class":95},"              },\n",[89,847,848],{"class":91,"line":494},[89,849,821],{"class":95},[89,851,852,854,856],{"class":91,"line":499},[89,853,826],{"class":95},[89,855,531],{"class":113},[89,857,233],{"class":95},[89,859,860,862,865],{"class":91,"line":511},[89,861,835],{"class":95},[89,863,864],{"class":113},"\"File4\"",[89,866,233],{"class":95},[89,868,869],{"class":91,"line":520},[89,870,845],{"class":95},[89,872,873],{"class":91,"line":536},[89,874,875],{"class":95},"            ],\n",[89,877,878],{"class":91,"line":542},[89,879,790],{"class":95},[89,881,882],{"class":91,"line":551},[89,883,884],{"class":95},"        ],\n",[89,886,887],{"class":91,"line":560},[89,888,735],{"class":95},[89,890,891],{"class":91,"line":569},[89,892,893],{"class":95},"    ],\n",[89,895,897],{"class":91,"line":896},39,[89,898,899],{"class":95},"  },\n",[89,901,903],{"class":91,"line":902},40,[89,904,682],{"class":95},[89,906,908,910,912],{"class":91,"line":907},41,[89,909,687],{"class":95},[89,911,531],{"class":113},[89,913,233],{"class":95},[89,915,917,919,922],{"class":91,"line":916},42,[89,918,696],{"class":95},[89,920,921],{"class":113},"\"File5\"",[89,923,233],{"class":95},[89,925,927],{"class":91,"line":926},43,[89,928,899],{"class":95},[89,930,932],{"class":91,"line":931},44,[89,933,934],{"class":95},"]);\n",[89,936,938,940,942],{"class":91,"line":937},45,[89,939,269],{"class":95},[89,941,100],{"class":99},[89,943,117],{"class":95},[89,945,947],{"class":91,"line":946},46,[89,948,192],{"emptyLinePlaceholder":191},[89,950,952,954,956],{"class":91,"line":951},47,[89,953,96],{"class":95},[89,955,286],{"class":99},[89,957,117],{"class":95},[89,959,961,963,965,968,970,972,975,977,979,981,984,986,988,990,992,995,997,1000,1002],{"class":91,"line":960},48,[89,962,294],{"class":95},[89,964,449],{"class":99},[89,966,967],{"class":95}," :",[89,969,396],{"class":103},[89,971,110],{"class":95},[89,973,974],{"class":113},"\"'directory'\"",[89,976,967],{"class":95},[89,978,414],{"class":103},[89,980,110],{"class":95},[89,982,983],{"class":113},"\"'\u002F'\"",[89,985,967],{"class":95},[89,987,431],{"class":103},[89,989,110],{"class":95},[89,991,304],{"class":113},[89,993,994],{"class":95},"tree",[89,996,304],{"class":113},[89,998,999],{"class":95},">\u003C\u002F",[89,1001,449],{"class":99},[89,1003,117],{"class":95},[89,1005,1007,1009,1011],{"class":91,"line":1006},49,[89,1008,269],{"class":95},[89,1010,286],{"class":99},[89,1012,117],{"class":95},[14,1014,1015,1016,1018],{},"ディレクトリ構造を持つリアクティブな変数を",[40,1017,994],{},"として定義します。",[14,1020,1021,1022,1024],{},"DirectoryTreeに",[40,1023,994],{},"を受け渡すことで、ディレクトリ構造を描画することができます。",[14,1026,1027],{},"上記のコードは以下のプレイグラウンドで確認することができます。",[1029,1030],"link-card",{"url":1031},"https:\u002F\u002Fplay.vuejs.org\u002F#eNqtVE1y0zAUvsobbZrONAm0ZWOcMIWWGVhAB7qruzC2nKooskeS02QyWTDDDTgAV+QIPMmWLTtuyoIsMtb7\u002Fd7P97bkoigmq5KSgIQqkazQoKguC+CxWMwiolVE5pFgyyKXGrYgaQY7yGS+hCN0O3rd6C6ZpInO5eZGUlpbTKYdqUlkPCKR5EJp0MZyZmKObiMBsDV\u002FAHpT0AAikjrfiJxUGhEvrQajvmyEyT3jqaQiABvE\u002FOpAfrCMcdq4+LHeo6INBrBrvgai7EPqwTrtKAag9QIfhNiH2Q3uQz0QdRhyD\u002FbZnvIJ6AOJni2hX8Z+sn4p\u002FyPL+T9kuXuyna3GSStJ9bLYBtD4+V\u002FVMuNxd4xbH04rgiGd8KHpsuCxpvgy0cMOUVzuwORAFh41QzyKSKM02Yxy6gvd3Ax3TaRaMw+7VMS04dTDQE6Q6sjKjC0mDyoXeA9skRFJ8mWB5cjPhWbI2ogEbjQRiTnPHz9amZYlrTuFPvc0+T4gf1BrI4vItaSKylU7RUQbywXVlfrq6ye6xu9GuczT0nT5gPILVTkvDcbK7G0pUoTt2Vm0H+y1YmJxo67WmgrlijJA2wlHBG\u002FVuwOlt3DPJmfWLxI77OLewXvusgpNZRYnFK5lXih\u002FtZSWiBM3xy2WJ3BjfhPAhZTxJozFZo4aROGua2HjzeCR6ftLmsUl12qU0owJalOF9n8+Oj7p7nNvl+tnew9GxzCbw63hw+6ZvW5esBqzDIu2mCYmE8xmM+jstWMCZ\u002FWXfakiFpDwWCl0927ZfLutKpwYoLDbIQw09V1L7r3wnbIV4shyiZFsOcBEHcNV16BonAZ56X6On9bdltUysbGpaVrZmMeAjcfayq4F1LUd4LEHdool+h2YNi0Ip3VbO6zvz4hy1RwkbwzdIVT3zkvTn0Tj5k9kGEAPTaj0hlPAQ1TQ1FqX3FFuiYRjuH4v7P4DFHGaIhvGTHDc6LFCQuoATs+LtTWwRADgzPlzpjRaYfxxtekiF9Q3NWAnzYYFwTeKq0KdO3IKrwVmiMif379+RGTP1fTlsNfP1gt7Y6DMye4vz7jXHg==",[10,1033,1034],{"id":1034},"まとめ",[14,1036,1037,1038,1040],{},"今回は再帰的コンポーネントの作成方法を解説しました。",[21,1039],{},"\nVue.jsではあるコンポーネント内で自身を呼び出すことができるため、簡単に再帰的コンポーネントを作成することができます。",[14,1042,1043,1044,1047,1048,1050],{},"既に誰かがまとめていると思ったのですが、Vue3かつ",[40,1045,1046],{},"\u003Cscript setup>","構文で書かれた例がまだなかったためまとめてみました。",[21,1049],{},"\n参考になれば幸いです。",[10,1052,1053],{"id":1053},"参考",[357,1055,1056],{},[324,1057,1058],{},"Vue.js公式 再帰的コンポーネント",[1029,1060],{"url":1061},"https:\u002F\u002Fja.vuejs.org\u002Fapi\u002Fsfc-script-setup.html#recursive-components",[1063,1064,1065],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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);}",{"title":85,"searchDepth":120,"depth":120,"links":1067},[1068,1069,1070,1071,1072],{"id":12,"depth":120,"text":12},{"id":29,"depth":120,"text":29},{"id":57,"depth":120,"text":57},{"id":1034,"depth":120,"text":1034},{"id":1053,"depth":120,"text":1053},"システム開発","2024\u002F01\u002F29","Vue3で再帰的コンポーネントを作成する方法を解説します。","md",false,{},"\u002Fblog\u002Fprogramming\u002Fvue-recursive-component",{"title":5,"description":1075},"blog\u002Fprogramming\u002Fvue-recursive-component","Vue.js",[1082],"https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_vue-define-model_vue.webp","2024\u002F02\u002F19","Z0ZPUEXKmozJDkfNN-GC7KrI9jo8c6YWDfy0JFiRXq8",[1088,1098,1106,1112,1121,1127],{"id":1089,"path":1090,"title":1091,"category":1073,"tags":1092,"thumbnail":1095,"createdAt":1096,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Faws-iam-passkey.md","\u002Fblog\u002Fprogramming\u002Faws-iam-passkey","AWS IAMでPasskeyが利用可能に Windows PCで指紋認証を設定してみました",[1093,1094],"AWS","Windows","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002F2024-08-22_11-12-41_nvre36gj.webp","2024\u002F08\u002F22",null,{"id":1099,"path":1100,"title":1101,"category":1073,"tags":1102,"thumbnail":1104,"createdAt":1105,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Freact-tutorial-vue.md","\u002Fblog\u002Fprogramming\u002Freact-tutorial-vue","React公式チュートリアルをVueでも書いて比較してみた",[1103,1082],"React.js","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_react-vue_react-vue.webp","2024\u002F06\u002F22",{"id":1107,"path":1108,"title":1109,"category":1073,"tags":1110,"thumbnail":1084,"createdAt":1111,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Fvue-scoped-css.md","\u002Fblog\u002Fprogramming\u002Fvue-scoped-css","Vueのスコープ付きCSSで子コンポーネントにCSSを適用する【Vue3】",[1082],"2024\u002F06\u002F12",{"id":1113,"path":1114,"title":1115,"category":1073,"tags":1116,"thumbnail":1119,"createdAt":1120,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Fvercel-vs-amplify.md","\u002Fblog\u002Fprogramming\u002Fvercel-vs-amplify","Vercel(Hobby)→AWS Amplify 移行して分かった両者の違い",[1117,1118],"Vercel","Amplify","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_vercel-vs-amplify_vercel-amplify.webp","2024\u002F05\u002F17",{"id":1122,"path":1123,"title":1124,"category":1073,"tags":1125,"thumbnail":1084,"createdAt":1126,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Fvue-playground.md","\u002Fblog\u002Fprogramming\u002Fvue-playground","手軽に使えるVueプレイグラウンド環境。Vue SFC Playground解説",[1082],"2024\u002F04\u002F08",{"id":1128,"path":1129,"title":1130,"category":1073,"tags":1131,"thumbnail":1134,"createdAt":1135,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Ftailwind-css-v4-install.md","\u002Fblog\u002Fprogramming\u002Ftailwind-css-v4-install","Vite、TailwindCSS v4環境を構築【Tailwind CSS v4-alpha】",[1132,1133],"Tailwind CSS","Vite","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_tailwind-css-v4-install_tailwind-css.webp","2024\u002F03\u002F07",[1137,1139,1150,1156,1166,1175],{"id":1099,"path":1100,"title":1101,"category":1073,"tags":1138,"thumbnail":1104,"createdAt":1105,"updatedAt":1097},[1103,1082],{"id":1140,"path":1141,"title":1142,"category":1073,"tags":1143,"thumbnail":1147,"createdAt":1148,"updatedAt":1149},"blog\u002Fblog\u002Fprogramming\u002Fnpm-develop.md","\u002Fblog\u002Fprogramming\u002Fnpm-develop","フロントエンド開発体験を向上させる10のnpmライブラリ【2024年版】",[1144,1145,1146],"JavaScript","TypeScript","npm","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_npm-develop_thumbnail.webp","2024\u002F01\u002F14","2024\u002F01\u002F19",{"id":1151,"path":1152,"title":1153,"category":1073,"tags":1154,"thumbnail":1084,"createdAt":1155,"updatedAt":1135},"blog\u002Fblog\u002Fprogramming\u002Fvue-define-model.md","\u002Fblog\u002Fprogramming\u002Fvue-define-model","VueのdefineModelを活用した入力コンポーネントの作成方法【Vue3.4】",[1082],"2024\u002F01\u002F07",{"id":1157,"path":1158,"title":1159,"category":1073,"tags":1160,"thumbnail":1163,"createdAt":1164,"updatedAt":1165},"blog\u002Fblog\u002Fprogramming\u002Fnuxt-storybook.md","\u002Fblog\u002Fprogramming\u002Fnuxt-storybook","Nuxt3にStorybookを導入する方法",[1161,1162],"NuxtJS","Storybook","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_nuxt-storybook_thumbnail.webp","2023\u002F11\u002F22","2024\u002F03\u002F18",{"id":1167,"path":1168,"title":1169,"category":1073,"tags":1170,"thumbnail":1173,"createdAt":1174,"updatedAt":1149},"blog\u002Fblog\u002Fprogramming\u002Fnuxt-blog.md","\u002Fblog\u002Fprogramming\u002Fnuxt-blog","NuxtJSを使ってブログを作ってみた【Nuxt Content\u002FTailwindCSS\u002FdaisyUI】",[1161,1082,1171,1172],"TailwindCSS","ブログ","https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_nuxt-blog_thumbnail.webp","2023\u002F08\u002F25",{"id":1176,"path":1177,"title":1178,"category":1073,"tags":1179,"thumbnail":1180,"createdAt":1181,"updatedAt":1097},"blog\u002Fblog\u002Fprogramming\u002Fchat-scroll.md","\u002Fblog\u002Fprogramming\u002Fchat-scroll","メッセージ送受信時にスクロール位置を最下部に維持する処理を実装【TypeScript\u002FVue.js】",[1144,1145,1082],"https:\u002F\u002Fimg-blog.ashcolor.jp\u002Fimg\u002Fpc\u002Fprogramming_chat-scroll_thumbnail.webp","2023\u002F08\u002F01",1794101385526]