[{"data":1,"prerenderedAt":18125},["ShallowReactive",2],{"tag-vue":3},{"count":4,"content":5},10,[6,1436,5162,7482,9185,9733,10160,11675,14995,17458],{"id":7,"title":8,"body":9,"category":1422,"createdAt":1424,"description":1425,"extension":1426,"index":1427,"meta":1428,"navigation":339,"path":1429,"publish":339,"seo":1430,"series":1427,"seriesTitle":1427,"stem":1431,"tag":1432,"thumbnail":1434,"updatedAt":1424,"__hash__":1435},"articles\u002Farticles\u002Fmultiple-select-vue.md","multiple属性での複数選択セレクトボックスで選択した値をemitする方法。",{"type":10,"value":11,"toc":1416},"minimark",[12,16,20,23,41,176,197,200,575,582,589,593,596,604,716,727,732,735,739,743,746,1226,1232,1238,1247,1314,1331,1388,1397,1400,1403,1406,1409,1412],[13,14,15],"p",{},"こんにちはjunです。vue.jsを用いてフォームUIを作成していたところmultipule属性を付与したセレクトボックスで選択した値を$emitする方法についてメモ＆共有しようと思います。",[17,18,19],"h2",{"id":19},"vueを用いてselectの値を受け取る",[13,21,22],{},"セレクトボックスは基本的には以下の様に、プルダウン式のメニューから一つの値を選ぶ要素です。",[24,25,27,28,27,33,27,37],"select",{"name":26},"sample","\n ",[29,30,32],"option",{"value":31},"1","選択肢１",[29,34,36],{"value":35},"2","選択肢2",[29,38,40],{"value":39},"3","選択肢3",[42,43,48],"pre",{"className":44,"code":45,"language":46,"meta":47,"style":47},"language-html shiki shiki-themes material-theme-ocean","\u003Cselect name=\"sample\">\n \u003Coption value=\"1\">選択肢１\u003C\u002Foption>\n \u003Coption value=\"2\">選択肢2\u003C\u002Foption>\n \u003Coption value=\"3\">選択肢3\u003C\u002Foption>\n\u003C\u002Fselect>\n","html","",[49,50,51,81,113,140,167],"code",{"__ignoreMap":47},[52,53,56,60,63,67,70,73,76,78],"span",{"class":54,"line":55},"line",1,[52,57,59],{"class":58},"sAklC","\u003C",[52,61,24],{"class":62},"s-wAU",[52,64,66],{"class":65},"sJ14y"," name",[52,68,69],{"class":58},"=",[52,71,72],{"class":58},"\"",[52,74,26],{"class":75},"sfyAc",[52,77,72],{"class":58},[52,79,80],{"class":58},">\n",[52,82,84,87,89,92,94,96,98,100,103,106,109,111],{"class":54,"line":83},2,[52,85,86],{"class":58}," \u003C",[52,88,29],{"class":62},[52,90,91],{"class":65}," value",[52,93,69],{"class":58},[52,95,72],{"class":58},[52,97,31],{"class":75},[52,99,72],{"class":58},[52,101,102],{"class":58},">",[52,104,32],{"class":105},"s0W1g",[52,107,108],{"class":58},"\u003C\u002F",[52,110,29],{"class":62},[52,112,80],{"class":58},[52,114,116,118,120,122,124,126,128,130,132,134,136,138],{"class":54,"line":115},3,[52,117,86],{"class":58},[52,119,29],{"class":62},[52,121,91],{"class":65},[52,123,69],{"class":58},[52,125,72],{"class":58},[52,127,35],{"class":75},[52,129,72],{"class":58},[52,131,102],{"class":58},[52,133,36],{"class":105},[52,135,108],{"class":58},[52,137,29],{"class":62},[52,139,80],{"class":58},[52,141,143,145,147,149,151,153,155,157,159,161,163,165],{"class":54,"line":142},4,[52,144,86],{"class":58},[52,146,29],{"class":62},[52,148,91],{"class":65},[52,150,69],{"class":58},[52,152,72],{"class":58},[52,154,39],{"class":75},[52,156,72],{"class":58},[52,158,102],{"class":58},[52,160,40],{"class":105},[52,162,108],{"class":58},[52,164,29],{"class":62},[52,166,80],{"class":58},[52,168,170,172,174],{"class":54,"line":169},5,[52,171,108],{"class":58},[52,173,24],{"class":62},[52,175,80],{"class":58},[13,177,178,179,182,183,185,186,188,189,192,193,196],{},"基本的にinput系の値を取得するときは",[49,180,181],{},"v-model","を使用するのが定石ですが、",[49,184,181],{},"では解決できないコンポーネントの状況もあるでしょう。私も",[49,187,181],{},"という糖衣構文ではなく",[49,190,191],{},"v-bind=\"~~~\"",", ",[49,194,195],{},"@input=\"$emit(~~~~)\"","という形で入力された値を親コンポーネントに返す様にしていました。",[13,198,199],{},"一択のセレクトボックスであれば以下の様に記述できます。",[42,201,205],{"className":202,"code":203,"language":204,"meta":47,"style":47},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n \u003Cselect name=\"postName\" @input=\"$emit('newInput', $event.target.value)\">\n   \u003Coption v-for=\"val in selectBox\"\n           :value=\"val.value\" \n           :selected=\"inputValue === val.value\">\n           {{val.text}}\n   \u003C\u002Foption>\n \u003C\u002Fselect>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default{\n name:'childSelect',\n props:['inputed'],  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n data(){\n   return{\n     selector:[\n          {text:'選択肢1',value:'1'},\n          {text:'選択肢2',value:'2'},\n          {text:'選択肢3',value:'3'}\n     ],\n   }\n },\n \n}\n\u003C\u002Fscript>\n","vue",[49,206,207,216,247,267,284,300,306,316,326,335,341,351,364,384,412,424,432,443,477,506,536,544,550,556,561,566],{"__ignoreMap":47},[52,208,209,211,214],{"class":54,"line":55},[52,210,59],{"class":58},[52,212,213],{"class":62},"template",[52,215,80],{"class":58},[52,217,218,220,222,224,226,228,231,233,236,238,240,243,245],{"class":54,"line":83},[52,219,86],{"class":58},[52,221,24],{"class":62},[52,223,66],{"class":65},[52,225,69],{"class":58},[52,227,72],{"class":58},[52,229,230],{"class":75},"postName",[52,232,72],{"class":58},[52,234,235],{"class":65}," @input",[52,237,69],{"class":58},[52,239,72],{"class":58},[52,241,242],{"class":75},"$emit('newInput', $event.target.value)",[52,244,72],{"class":58},[52,246,80],{"class":58},[52,248,249,252,254,257,259,261,264],{"class":54,"line":115},[52,250,251],{"class":58},"   \u003C",[52,253,29],{"class":62},[52,255,256],{"class":65}," v-for",[52,258,69],{"class":58},[52,260,72],{"class":58},[52,262,263],{"class":75},"val in selectBox",[52,265,266],{"class":58},"\"\n",[52,268,269,272,274,276,279,281],{"class":54,"line":142},[52,270,271],{"class":65},"           :value",[52,273,69],{"class":58},[52,275,72],{"class":58},[52,277,278],{"class":75},"val.value",[52,280,72],{"class":58},[52,282,283],{"class":58}," \n",[52,285,286,289,291,293,296,298],{"class":54,"line":169},[52,287,288],{"class":65},"           :selected",[52,290,69],{"class":58},[52,292,72],{"class":58},[52,294,295],{"class":75},"inputValue === val.value",[52,297,72],{"class":58},[52,299,80],{"class":58},[52,301,303],{"class":54,"line":302},6,[52,304,305],{"class":105},"           {{val.text}}\n",[52,307,309,312,314],{"class":54,"line":308},7,[52,310,311],{"class":58},"   \u003C\u002F",[52,313,29],{"class":62},[52,315,80],{"class":58},[52,317,319,322,324],{"class":54,"line":318},8,[52,320,321],{"class":58}," \u003C\u002F",[52,323,24],{"class":62},[52,325,80],{"class":58},[52,327,329,331,333],{"class":54,"line":328},9,[52,330,108],{"class":58},[52,332,213],{"class":62},[52,334,80],{"class":58},[52,336,337],{"class":54,"line":4},[52,338,340],{"emptyLinePlaceholder":339},true,"\n",[52,342,344,346,349],{"class":54,"line":343},11,[52,345,59],{"class":58},[52,347,348],{"class":62},"script",[52,350,80],{"class":58},[52,352,354,357,361],{"class":54,"line":353},12,[52,355,356],{"class":65},"export",[52,358,360],{"class":359},"s6cf3"," default",[52,362,363],{"class":58},"{\n",[52,365,367,370,373,376,379,381],{"class":54,"line":366},13,[52,368,66],{"class":369},"s5Dmg",[52,371,372],{"class":58},":",[52,374,375],{"class":58},"'",[52,377,378],{"class":75},"childSelect",[52,380,375],{"class":58},[52,382,383],{"class":58},",\n",[52,385,387,390,392,395,397,400,402,405,408],{"class":54,"line":386},14,[52,388,389],{"class":369}," props",[52,391,372],{"class":58},[52,393,394],{"class":62},"[",[52,396,375],{"class":58},[52,398,399],{"class":75},"inputed",[52,401,375],{"class":58},[52,403,404],{"class":62},"]",[52,406,407],{"class":58},",",[52,409,411],{"class":410},"sC9rS","  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n",[52,413,415,419,422],{"class":54,"line":414},15,[52,416,418],{"class":417},"sdLwU"," data",[52,420,421],{"class":62},"()",[52,423,363],{"class":58},[52,425,427,430],{"class":54,"line":426},16,[52,428,429],{"class":359},"   return",[52,431,363],{"class":58},[52,433,435,438,440],{"class":54,"line":434},17,[52,436,437],{"class":62},"     selector",[52,439,372],{"class":58},[52,441,442],{"class":62},"[\n",[52,444,446,449,452,454,456,459,461,463,466,468,470,472,474],{"class":54,"line":445},18,[52,447,448],{"class":58},"          {",[52,450,451],{"class":62},"text",[52,453,372],{"class":58},[52,455,375],{"class":58},[52,457,458],{"class":75},"選択肢1",[52,460,375],{"class":58},[52,462,407],{"class":58},[52,464,465],{"class":62},"value",[52,467,372],{"class":58},[52,469,375],{"class":58},[52,471,31],{"class":75},[52,473,375],{"class":58},[52,475,476],{"class":58},"},\n",[52,478,480,482,484,486,488,490,492,494,496,498,500,502,504],{"class":54,"line":479},19,[52,481,448],{"class":58},[52,483,451],{"class":62},[52,485,372],{"class":58},[52,487,375],{"class":58},[52,489,36],{"class":75},[52,491,375],{"class":58},[52,493,407],{"class":58},[52,495,465],{"class":62},[52,497,372],{"class":58},[52,499,375],{"class":58},[52,501,35],{"class":75},[52,503,375],{"class":58},[52,505,476],{"class":58},[52,507,509,511,513,515,517,519,521,523,525,527,529,531,533],{"class":54,"line":508},20,[52,510,448],{"class":58},[52,512,451],{"class":62},[52,514,372],{"class":58},[52,516,375],{"class":58},[52,518,40],{"class":75},[52,520,375],{"class":58},[52,522,407],{"class":58},[52,524,465],{"class":62},[52,526,372],{"class":58},[52,528,375],{"class":58},[52,530,39],{"class":75},[52,532,375],{"class":58},[52,534,535],{"class":58},"}\n",[52,537,539,542],{"class":54,"line":538},21,[52,540,541],{"class":62},"     ]",[52,543,383],{"class":58},[52,545,547],{"class":54,"line":546},22,[52,548,549],{"class":58},"   }\n",[52,551,553],{"class":54,"line":552},23,[52,554,555],{"class":58}," },\n",[52,557,559],{"class":54,"line":558},24,[52,560,283],{"class":62},[52,562,564],{"class":54,"line":563},25,[52,565,535],{"class":58},[52,567,569,571,573],{"class":54,"line":568},26,[52,570,108],{"class":58},[52,572,348],{"class":62},[52,574,80],{"class":58},[13,576,577,578,581],{},"この様にすることで親コンポーネントでは",[49,579,580],{},"newInput","を用いてこのセレクトボックスからの値を受け取ることができます。",[13,583,584,585,588],{},"もし編集画面など、セレクトボックスに予め選択済みの設定を行う場合はpropsにvalueの値を入れておけば、一致する選択肢に",[49,586,587],{},"selected","が付与されます。",[17,590,592],{"id":591},"multipuleで複数選択を可能にする","Multipuleで複数選択を可能にする",[13,594,595],{},"チェックボックスにしては値が多く、リストの方が見やすいのでセレクトボックスから複数選択ができる様にするためには、multipleという属性を付与するだけで実装できます。",[24,597,27,598,27,600,27,602],{"name":26,"multiple":339},[29,599,32],{"value":31},[29,601,36],{"value":35},[29,603,40],{"value":39},[42,605,607],{"className":44,"code":606,"language":46,"meta":47,"style":47},"\u003Cselect name=\"sample\" multiple>\n \u003Coption value=\"1\">選択肢１\u003C\u002Foption>\n \u003Coption value=\"2\">選択肢2\u003C\u002Foption>\n \u003Coption value=\"3\">選択肢3\u003C\u002Foption>\n\u003C\u002Fselect>\n",[49,608,609,630,656,682,708],{"__ignoreMap":47},[52,610,611,613,615,617,619,621,623,625,628],{"class":54,"line":55},[52,612,59],{"class":58},[52,614,24],{"class":62},[52,616,66],{"class":65},[52,618,69],{"class":58},[52,620,72],{"class":58},[52,622,26],{"class":75},[52,624,72],{"class":58},[52,626,627],{"class":65}," multiple",[52,629,80],{"class":58},[52,631,632,634,636,638,640,642,644,646,648,650,652,654],{"class":54,"line":83},[52,633,86],{"class":58},[52,635,29],{"class":62},[52,637,91],{"class":65},[52,639,69],{"class":58},[52,641,72],{"class":58},[52,643,31],{"class":75},[52,645,72],{"class":58},[52,647,102],{"class":58},[52,649,32],{"class":105},[52,651,108],{"class":58},[52,653,29],{"class":62},[52,655,80],{"class":58},[52,657,658,660,662,664,666,668,670,672,674,676,678,680],{"class":54,"line":115},[52,659,86],{"class":58},[52,661,29],{"class":62},[52,663,91],{"class":65},[52,665,69],{"class":58},[52,667,72],{"class":58},[52,669,35],{"class":75},[52,671,72],{"class":58},[52,673,102],{"class":58},[52,675,36],{"class":105},[52,677,108],{"class":58},[52,679,29],{"class":62},[52,681,80],{"class":58},[52,683,684,686,688,690,692,694,696,698,700,702,704,706],{"class":54,"line":142},[52,685,86],{"class":58},[52,687,29],{"class":62},[52,689,91],{"class":65},[52,691,69],{"class":58},[52,693,72],{"class":58},[52,695,39],{"class":75},[52,697,72],{"class":58},[52,699,102],{"class":58},[52,701,40],{"class":105},[52,703,108],{"class":58},[52,705,29],{"class":62},[52,707,80],{"class":58},[52,709,710,712,714],{"class":54,"line":169},[52,711,108],{"class":58},[52,713,24],{"class":62},[52,715,80],{"class":58},[13,717,718,719,722,723,726],{},"実際に",[49,720,721],{},"$event.target.value","を",[49,724,725],{},"console.log()","で出力して見てみると、選択肢１をクリックしてから他の選択肢も含めましたが帰って来た結果は全て「１」でした。",[728,729],"image-render",{":src":730,":width":731},"'_mix\u002Fvue-select03-768x197.png'","'100%'",[13,733,734],{},"格納する親コンポーネントのdataもこの様に１から変化ありませんでした。",[728,736],{":src":737,":width":738},"'_mix\u002Fvue-select04.png'","'400px'",[17,740,742],{"id":741},"multipleの場合はeventtargetoptions","multipleの場合は$event.target.options",[13,744,745],{},"選択された値は全て配列で帰ってくる様に調整をします。inputされた時、以下の様に値を取得する様に変更します。",[42,747,749],{"className":202,"code":748,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n \u003Cselect name=\"postName\" @input=\"returnValeu($event)\" multiple>\n   \u003Coption v-for=\"val in selectBox\"\n           :value=\"val.value\" \n           :selected=\"inputValue === val.value\">\n           {{val.text}}\n   \u003C\u002Foption>\n \u003C\u002Fselect>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default{\n name:'childSelect',\n props:['inputed'],  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n methods:{\n  returnValeu($event){\n    let opt = Object.values($event.target.options).filter(ele=>{\n                  return ele.selected;\n              })\n    let values = opt.map(ele=>ele.value);\n    this.$emit('newInput', values);\n  }\n }\n data(){\n   return{\n     selector:[\n          {text:'選択肢1',value:'1'},\n          {text:'選択肢2',value:'2'},\n          {text:'選択肢3',value:'3'}\n     ],\n   }\n },\n \n}\n\u003C\u002Fscript>\n",[49,750,751,759,790,806,820,834,838,846,854,862,866,874,882,896,916,924,940,992,1007,1015,1047,1071,1076,1081,1089,1095,1103,1132,1161,1190,1197,1202,1207,1212,1217],{"__ignoreMap":47},[52,752,753,755,757],{"class":54,"line":55},[52,754,59],{"class":58},[52,756,213],{"class":62},[52,758,80],{"class":58},[52,760,761,763,765,767,769,771,773,775,777,779,781,784,786,788],{"class":54,"line":83},[52,762,86],{"class":58},[52,764,24],{"class":62},[52,766,66],{"class":65},[52,768,69],{"class":58},[52,770,72],{"class":58},[52,772,230],{"class":75},[52,774,72],{"class":58},[52,776,235],{"class":65},[52,778,69],{"class":58},[52,780,72],{"class":58},[52,782,783],{"class":75},"returnValeu($event)",[52,785,72],{"class":58},[52,787,627],{"class":65},[52,789,80],{"class":58},[52,791,792,794,796,798,800,802,804],{"class":54,"line":115},[52,793,251],{"class":58},[52,795,29],{"class":62},[52,797,256],{"class":65},[52,799,69],{"class":58},[52,801,72],{"class":58},[52,803,263],{"class":75},[52,805,266],{"class":58},[52,807,808,810,812,814,816,818],{"class":54,"line":142},[52,809,271],{"class":65},[52,811,69],{"class":58},[52,813,72],{"class":58},[52,815,278],{"class":75},[52,817,72],{"class":58},[52,819,283],{"class":58},[52,821,822,824,826,828,830,832],{"class":54,"line":169},[52,823,288],{"class":65},[52,825,69],{"class":58},[52,827,72],{"class":58},[52,829,295],{"class":75},[52,831,72],{"class":58},[52,833,80],{"class":58},[52,835,836],{"class":54,"line":302},[52,837,305],{"class":105},[52,839,840,842,844],{"class":54,"line":308},[52,841,311],{"class":58},[52,843,29],{"class":62},[52,845,80],{"class":58},[52,847,848,850,852],{"class":54,"line":318},[52,849,321],{"class":58},[52,851,24],{"class":62},[52,853,80],{"class":58},[52,855,856,858,860],{"class":54,"line":328},[52,857,108],{"class":58},[52,859,213],{"class":62},[52,861,80],{"class":58},[52,863,864],{"class":54,"line":4},[52,865,340],{"emptyLinePlaceholder":339},[52,867,868,870,872],{"class":54,"line":343},[52,869,59],{"class":58},[52,871,348],{"class":62},[52,873,80],{"class":58},[52,875,876,878,880],{"class":54,"line":353},[52,877,356],{"class":65},[52,879,360],{"class":359},[52,881,363],{"class":58},[52,883,884,886,888,890,892,894],{"class":54,"line":366},[52,885,66],{"class":369},[52,887,372],{"class":58},[52,889,375],{"class":58},[52,891,378],{"class":75},[52,893,375],{"class":58},[52,895,383],{"class":58},[52,897,898,900,902,904,906,908,910,912,914],{"class":54,"line":386},[52,899,389],{"class":369},[52,901,372],{"class":58},[52,903,394],{"class":62},[52,905,375],{"class":58},[52,907,399],{"class":75},[52,909,375],{"class":58},[52,911,404],{"class":62},[52,913,407],{"class":58},[52,915,411],{"class":410},[52,917,918,921],{"class":54,"line":414},[52,919,920],{"class":369}," methods",[52,922,923],{"class":58},":{\n",[52,925,926,929,932,935,938],{"class":54,"line":426},[52,927,928],{"class":417},"  returnValeu",[52,930,931],{"class":62},"(",[52,933,934],{"class":105},"$event",[52,936,937],{"class":62},")",[52,939,363],{"class":58},[52,941,942,945,948,951,954,957,960,962,964,966,969,971,974,976,978,981,983,987,990],{"class":54,"line":434},[52,943,944],{"class":65},"    let",[52,946,947],{"class":105}," opt",[52,949,950],{"class":58}," =",[52,952,953],{"class":105}," Object",[52,955,956],{"class":58},".",[52,958,959],{"class":417},"values",[52,961,931],{"class":62},[52,963,934],{"class":105},[52,965,956],{"class":58},[52,967,968],{"class":105},"target",[52,970,956],{"class":58},[52,972,973],{"class":105},"options",[52,975,937],{"class":62},[52,977,956],{"class":58},[52,979,980],{"class":417},"filter",[52,982,931],{"class":62},[52,984,986],{"class":985},"s7ZW3","ele",[52,988,989],{"class":65},"=>",[52,991,363],{"class":58},[52,993,994,997,1000,1002,1004],{"class":54,"line":445},[52,995,996],{"class":359},"                  return",[52,998,999],{"class":105}," ele",[52,1001,956],{"class":58},[52,1003,587],{"class":105},[52,1005,1006],{"class":58},";\n",[52,1008,1009,1012],{"class":54,"line":479},[52,1010,1011],{"class":58},"              }",[52,1013,1014],{"class":62},")\n",[52,1016,1017,1019,1022,1024,1026,1028,1031,1033,1035,1037,1039,1041,1043,1045],{"class":54,"line":508},[52,1018,944],{"class":65},[52,1020,1021],{"class":105}," values",[52,1023,950],{"class":58},[52,1025,947],{"class":105},[52,1027,956],{"class":58},[52,1029,1030],{"class":417},"map",[52,1032,931],{"class":62},[52,1034,986],{"class":985},[52,1036,989],{"class":65},[52,1038,986],{"class":105},[52,1040,956],{"class":58},[52,1042,465],{"class":105},[52,1044,937],{"class":62},[52,1046,1006],{"class":58},[52,1048,1049,1052,1055,1057,1059,1061,1063,1065,1067,1069],{"class":54,"line":538},[52,1050,1051],{"class":58},"    this.",[52,1053,1054],{"class":417},"$emit",[52,1056,931],{"class":62},[52,1058,375],{"class":58},[52,1060,580],{"class":75},[52,1062,375],{"class":58},[52,1064,407],{"class":58},[52,1066,1021],{"class":105},[52,1068,937],{"class":62},[52,1070,1006],{"class":58},[52,1072,1073],{"class":54,"line":546},[52,1074,1075],{"class":58},"  }\n",[52,1077,1078],{"class":54,"line":552},[52,1079,1080],{"class":58}," }\n",[52,1082,1083,1085,1087],{"class":54,"line":558},[52,1084,418],{"class":417},[52,1086,421],{"class":62},[52,1088,363],{"class":58},[52,1090,1091,1093],{"class":54,"line":563},[52,1092,429],{"class":359},[52,1094,363],{"class":58},[52,1096,1097,1099,1101],{"class":54,"line":568},[52,1098,437],{"class":62},[52,1100,372],{"class":58},[52,1102,442],{"class":62},[52,1104,1106,1108,1110,1112,1114,1116,1118,1120,1122,1124,1126,1128,1130],{"class":54,"line":1105},27,[52,1107,448],{"class":58},[52,1109,451],{"class":62},[52,1111,372],{"class":58},[52,1113,375],{"class":58},[52,1115,458],{"class":75},[52,1117,375],{"class":58},[52,1119,407],{"class":58},[52,1121,465],{"class":62},[52,1123,372],{"class":58},[52,1125,375],{"class":58},[52,1127,31],{"class":75},[52,1129,375],{"class":58},[52,1131,476],{"class":58},[52,1133,1135,1137,1139,1141,1143,1145,1147,1149,1151,1153,1155,1157,1159],{"class":54,"line":1134},28,[52,1136,448],{"class":58},[52,1138,451],{"class":62},[52,1140,372],{"class":58},[52,1142,375],{"class":58},[52,1144,36],{"class":75},[52,1146,375],{"class":58},[52,1148,407],{"class":58},[52,1150,465],{"class":62},[52,1152,372],{"class":58},[52,1154,375],{"class":58},[52,1156,35],{"class":75},[52,1158,375],{"class":58},[52,1160,476],{"class":58},[52,1162,1164,1166,1168,1170,1172,1174,1176,1178,1180,1182,1184,1186,1188],{"class":54,"line":1163},29,[52,1165,448],{"class":58},[52,1167,451],{"class":62},[52,1169,372],{"class":58},[52,1171,375],{"class":58},[52,1173,40],{"class":75},[52,1175,375],{"class":58},[52,1177,407],{"class":58},[52,1179,465],{"class":62},[52,1181,372],{"class":58},[52,1183,375],{"class":58},[52,1185,39],{"class":75},[52,1187,375],{"class":58},[52,1189,535],{"class":58},[52,1191,1193,1195],{"class":54,"line":1192},30,[52,1194,541],{"class":62},[52,1196,383],{"class":58},[52,1198,1200],{"class":54,"line":1199},31,[52,1201,549],{"class":58},[52,1203,1205],{"class":54,"line":1204},32,[52,1206,555],{"class":58},[52,1208,1210],{"class":54,"line":1209},33,[52,1211,283],{"class":62},[52,1213,1215],{"class":54,"line":1214},34,[52,1216,535],{"class":58},[52,1218,1220,1222,1224],{"class":54,"line":1219},35,[52,1221,108],{"class":58},[52,1223,348],{"class":62},[52,1225,80],{"class":58},[13,1227,1228,1229,1231],{},"処理が少し長めなのでmethodに切り分けました。",[49,1230,783],{},"の中身で、イベント（選択）が発生したターゲットの要素を捉えるまでは同じですが、その中にvalueではなくてoptionsというプロパティがあります。",[13,1233,1234,1237],{},[49,1235,1236],{},"$event.target.options","は配列ですがHTMLCollectionなのでObject.valuesをもちいて、filter()が使用できる様にしています。",[13,1239,1240,1242,1243,1246],{},[49,1241,1236],{},"には選択肢の",[49,1244,1245],{},"\u003Coption>\u003C\u002Foption>","部分に関する情報が入っており、選択されたか（selected）とその値（value）というプロパティがあります。",[42,1248,1252],{"className":1249,"code":1250,"language":1251,"meta":47,"style":47},"language-javascript shiki shiki-themes material-theme-ocean","let opt = Object.values($event.target.options).filter(ele=>{\n　　return ele.selected;\n})\n","javascript",[49,1253,1254,1294,1307],{"__ignoreMap":47},[52,1255,1256,1259,1262,1264,1266,1268,1270,1273,1275,1277,1279,1282,1284,1286,1288,1290,1292],{"class":54,"line":55},[52,1257,1258],{"class":65},"let",[52,1260,1261],{"class":105}," opt ",[52,1263,69],{"class":58},[52,1265,953],{"class":105},[52,1267,956],{"class":58},[52,1269,959],{"class":417},[52,1271,1272],{"class":105},"($event",[52,1274,956],{"class":58},[52,1276,968],{"class":105},[52,1278,956],{"class":58},[52,1280,1281],{"class":105},"options)",[52,1283,956],{"class":58},[52,1285,980],{"class":417},[52,1287,931],{"class":105},[52,1289,986],{"class":985},[52,1291,989],{"class":65},[52,1293,363],{"class":58},[52,1295,1296,1299,1301,1303,1305],{"class":54,"line":83},[52,1297,1298],{"class":359},"　　return",[52,1300,999],{"class":105},[52,1302,956],{"class":58},[52,1304,587],{"class":105},[52,1306,1006],{"class":58},[52,1308,1309,1312],{"class":54,"line":115},[52,1310,1311],{"class":58},"}",[52,1313,1014],{"class":105},[13,1315,1316,1317,1319,1320,1323,1324,1327,1328,1330],{},"ここで",[49,1318,587],{},"プロパティが",[49,1321,1322],{},"true","か",[49,1325,1326],{},"false","で選択されたかがわかるので、",[49,1329,1322],{},"の要素のみ取得して新しい配列を手に入れます。その配列に対して",[42,1332,1334],{"className":1249,"code":1333,"language":1251,"meta":47,"style":47},"let values = opt.map(ele=>ele.value);\nthis.$emit('newInput', values);\n",[49,1335,1336,1366],{"__ignoreMap":47},[52,1337,1338,1340,1343,1345,1347,1349,1351,1353,1355,1357,1359,1361,1364],{"class":54,"line":55},[52,1339,1258],{"class":65},[52,1341,1342],{"class":105}," values ",[52,1344,69],{"class":58},[52,1346,947],{"class":105},[52,1348,956],{"class":58},[52,1350,1030],{"class":417},[52,1352,931],{"class":105},[52,1354,986],{"class":985},[52,1356,989],{"class":65},[52,1358,986],{"class":105},[52,1360,956],{"class":58},[52,1362,1363],{"class":105},"value)",[52,1365,1006],{"class":58},[52,1367,1368,1371,1373,1375,1377,1379,1381,1383,1386],{"class":54,"line":83},[52,1369,1370],{"class":58},"this.",[52,1372,1054],{"class":417},[52,1374,931],{"class":105},[52,1376,375],{"class":58},[52,1378,580],{"class":75},[52,1380,375],{"class":58},[52,1382,407],{"class":58},[52,1384,1385],{"class":105}," values)",[52,1387,1006],{"class":58},[13,1389,1390,1393,1394,1396],{},[49,1391,1392],{},"map()","を用いて",[49,1395,465],{},"プロパティのみを抽出したものを新しい配列として返し、それを親コンポーネントに渡します。これで選択したものを配列として渡すことが可能になります。",[17,1398,1399],{"id":1399},"値を出力してみる",[13,1401,1402],{},"先ほどの様に選択肢１から順に選択して値の変化を見てみましょう。",[728,1404],{":src":1405,":width":738},"'_mix\u002Fvue-select06-768x203-2.png'",[728,1407],{":src":1408,":width":738},"'_mix\u002Fvue-select05-1.png'",[13,1410,1411],{},"取得された値が順番順番に配列で取得できてますね。親コンポーネントにもちゃんと入っています。これでmultipule属性を持ったセレクトボックスの値を$emitすることができます。",[1413,1414,1415],"style",{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}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 pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}",{"title":47,"searchDepth":115,"depth":115,"links":1417},[1418,1419,1420,1421],{"id":19,"depth":83,"text":19},{"id":591,"depth":83,"text":592},{"id":741,"depth":83,"text":742},{"id":1399,"depth":83,"text":1399},[1423],"devstack","2026-04-15","multiple属性での複数選択セレクトボックスで選択した値をemitする方法","md",null,{},"\u002Farticles\u002Fmultiple-select-vue",{"title":8,"description":1425},"articles\u002Fmultiple-select-vue",[1433,204],"js","_mix\u002Fvue-select06-768x203.png","VP5RFAbgJFA3otr_esQFmbFyOCNxilN184p7o6oAQZo",{"id":1437,"title":1438,"body":1439,"category":5152,"createdAt":5153,"description":5154,"extension":1426,"index":1427,"meta":5155,"navigation":339,"path":5156,"publish":339,"seo":5157,"series":1427,"seriesTitle":1427,"stem":5158,"tag":5159,"thumbnail":5160,"updatedAt":5153,"__hash__":5161},"articles\u002Farticles\u002Ffilepond-crop-vue.md","Vue filepondとCropper.jsの連携とファイルアップロード",{"type":10,"value":1440,"toc":5132},[1441,1452,1455,1459,1468,1692,1695,1711,1714,1717,1720,1724,1731,1742,1748,1755,1759,1766,1839,1853,1874,1878,1885,2345,2348,2351,2354,2369,2393,2641,2651,2655,2658,2664,2670,2840,2844,2847,3339,3362,3367,3370,3384,3387,3390,3766,3778,3781,3784,3798,3801,3811,3943,3962,3965,3968,3971,3974,3983,4384,4390,4396,4412,4423,4427,4440,5101,5104,5107,5110,5117,5120,5129],[13,1442,1443,1444,1451],{},"こんにちはjunです。皆さんはファイルアップロードをJSで実装したことありますか？最近のwebサービスではアバターだったり、記事に画像のせるなど画像をアップロードするのが当たり前になっています。そのため仕事でもファイルのアップロード機能を実装しますが、Ajaxを用いてのFileインターフェースの扱いなどUIの構築が面倒なので、ライブラリを使っています。私は",[1445,1446,1450],"a",{"href":1447,"rel":1448},"https:\u002F\u002Fpqina.nl\u002Ffilepond\u002F",[1449],"nofollow","filepond","と言うものを使用して、複数アップロードやファイルのフロントバリデーションを実装します。VanillaだけでなくVue.jsやReactとの連携がしやすいので重宝しています。",[13,1453,1454],{},"今回の記事は「Filepondのアップロードを行う前にフロントでトリミングしたものをアップロードする」という単純にアップロードするだけでなく、画像を加工してからUPする機能を実装します。Line,Facebook、Twitterなどではプロフィール画像をアップロードする際に、どんな写真でも任意の範囲で１：１でトリミングできる機能があります。意外とユーザーは自身のスマホでトリミングする機能があるのを知らなかったり、機器によっては提供されていないor面倒だったりします。UX的な観点からもフロントでのトリミング機能があると便利です。",[728,1456],{":src":1457,":width":1458,":center":1322},"'filepond-crop-vue\u002Ftwitter.png'","'50%'",[13,1460,1461,1462,1467],{},"この機能を実装するにあたり、",[1445,1463,1466],{"href":1464,"rel":1465},"https:\u002F\u002Ffengyuanchen.github.io\u002Fcropperjs\u002F",[1449],"Cropper.js","のVue版を使用します。アップロードはfilepondを使用するので両者ライブラリの連携を行います。意外と苦労したので記事にしたいと思います。フロントエンド はVue CLIを用います。バックエンド側の解説はしません。バージョン情報は以下の通りです。",[42,1469,1473],{"className":1470,"code":1471,"language":1472,"meta":47,"style":47},"language-json shiki shiki-themes material-theme-ocean","\"devDependencies\": {\n    \"vue\": \"^2.6.12\",\n    \"vue-filepond\": \"^6.0.3\",\n},\n\"dependencies\": {\n    \"filepond\": \"^4.30.3\",\n    \"filepond-plugin-file-validate-type\": \"^1.2.6\",\n    \"filepond-plugin-image-crop\": \"^2.0.6\",\n    \"filepond-plugin-image-edit\": \"^1.6.3\",\n    \"filepond-plugin-image-preview\": \"^4.6.10\",\n    \"filepond-plugin-image-transform\": \"^3.8.7\",\n    \"vue-cropperjs\": \"^4.2.0\",\n}\n","json",[49,1474,1475,1489,1510,1530,1536,1549,1568,1588,1608,1628,1648,1668,1688],{"__ignoreMap":47},[52,1476,1477,1479,1482,1484,1487],{"class":54,"line":55},[52,1478,72],{"class":58},[52,1480,1481],{"class":75},"devDependencies",[52,1483,72],{"class":58},[52,1485,1486],{"class":105},": ",[52,1488,363],{"class":58},[52,1490,1491,1494,1496,1498,1500,1503,1506,1508],{"class":54,"line":83},[52,1492,1493],{"class":58},"    \"",[52,1495,204],{"class":65},[52,1497,72],{"class":58},[52,1499,372],{"class":58},[52,1501,1502],{"class":58}," \"",[52,1504,1505],{"class":75},"^2.6.12",[52,1507,72],{"class":58},[52,1509,383],{"class":58},[52,1511,1512,1514,1517,1519,1521,1523,1526,1528],{"class":54,"line":115},[52,1513,1493],{"class":58},[52,1515,1516],{"class":65},"vue-filepond",[52,1518,72],{"class":58},[52,1520,372],{"class":58},[52,1522,1502],{"class":58},[52,1524,1525],{"class":75},"^6.0.3",[52,1527,72],{"class":58},[52,1529,383],{"class":58},[52,1531,1532,1534],{"class":54,"line":142},[52,1533,1311],{"class":58},[52,1535,383],{"class":105},[52,1537,1538,1540,1543,1545,1547],{"class":54,"line":169},[52,1539,72],{"class":58},[52,1541,1542],{"class":75},"dependencies",[52,1544,72],{"class":58},[52,1546,1486],{"class":105},[52,1548,363],{"class":58},[52,1550,1551,1553,1555,1557,1559,1561,1564,1566],{"class":54,"line":302},[52,1552,1493],{"class":58},[52,1554,1450],{"class":65},[52,1556,72],{"class":58},[52,1558,372],{"class":58},[52,1560,1502],{"class":58},[52,1562,1563],{"class":75},"^4.30.3",[52,1565,72],{"class":58},[52,1567,383],{"class":58},[52,1569,1570,1572,1575,1577,1579,1581,1584,1586],{"class":54,"line":308},[52,1571,1493],{"class":58},[52,1573,1574],{"class":65},"filepond-plugin-file-validate-type",[52,1576,72],{"class":58},[52,1578,372],{"class":58},[52,1580,1502],{"class":58},[52,1582,1583],{"class":75},"^1.2.6",[52,1585,72],{"class":58},[52,1587,383],{"class":58},[52,1589,1590,1592,1595,1597,1599,1601,1604,1606],{"class":54,"line":318},[52,1591,1493],{"class":58},[52,1593,1594],{"class":65},"filepond-plugin-image-crop",[52,1596,72],{"class":58},[52,1598,372],{"class":58},[52,1600,1502],{"class":58},[52,1602,1603],{"class":75},"^2.0.6",[52,1605,72],{"class":58},[52,1607,383],{"class":58},[52,1609,1610,1612,1615,1617,1619,1621,1624,1626],{"class":54,"line":328},[52,1611,1493],{"class":58},[52,1613,1614],{"class":65},"filepond-plugin-image-edit",[52,1616,72],{"class":58},[52,1618,372],{"class":58},[52,1620,1502],{"class":58},[52,1622,1623],{"class":75},"^1.6.3",[52,1625,72],{"class":58},[52,1627,383],{"class":58},[52,1629,1630,1632,1635,1637,1639,1641,1644,1646],{"class":54,"line":4},[52,1631,1493],{"class":58},[52,1633,1634],{"class":65},"filepond-plugin-image-preview",[52,1636,72],{"class":58},[52,1638,372],{"class":58},[52,1640,1502],{"class":58},[52,1642,1643],{"class":75},"^4.6.10",[52,1645,72],{"class":58},[52,1647,383],{"class":58},[52,1649,1650,1652,1655,1657,1659,1661,1664,1666],{"class":54,"line":343},[52,1651,1493],{"class":58},[52,1653,1654],{"class":65},"filepond-plugin-image-transform",[52,1656,72],{"class":58},[52,1658,372],{"class":58},[52,1660,1502],{"class":58},[52,1662,1663],{"class":75},"^3.8.7",[52,1665,72],{"class":58},[52,1667,383],{"class":58},[52,1669,1670,1672,1675,1677,1679,1681,1684,1686],{"class":54,"line":353},[52,1671,1493],{"class":58},[52,1673,1674],{"class":65},"vue-cropperjs",[52,1676,72],{"class":58},[52,1678,372],{"class":58},[52,1680,1502],{"class":58},[52,1682,1683],{"class":75},"^4.2.0",[52,1685,72],{"class":58},[52,1687,383],{"class":58},[52,1689,1690],{"class":54,"line":366},[52,1691,535],{"class":58},[17,1693,1694],{"id":1694},"実装目標",[1696,1697,1698,1702,1705,1708],"ol",{},[1699,1700,1701],"li",{},"任意の画像をブラウザにアップロード",[1699,1703,1704],{},"画像を編集できるUIを用意し、任意でトリミングできる様にする",[1699,1706,1707],{},"任意の位置、倍率でオリジナルの画像を１：１でトリミング",[1699,1709,1710],{},"トリミングした画像をサーバーにアップロードする。",[13,1712,1713],{},"以上の機能を持ったアップローダーが実装目標です。",[17,1715,1716],{"id":1716},"初期設定",[13,1718,1719],{},"ではまず最初に必要なライブラリをインストールしていきましょう。とりあえず今はVue CLIの設定とfilepondだけインストールしましょう。Vue CLIのセットアップ解説は省きます。",[1721,1722,1723],"h3",{"id":1723},"ライブラリインストール",[42,1725,1729],{"className":1726,"code":1728,"language":451},[1727],"language-text","vue create filepond_cropper\ncd filepond_cropper\n\nnpm install filepond filepond-plugin-file-validate-type filepond-plugin-image-crop filepond-plugin-image-preview --save\nnpm install vue-filepond@6.0.3 --save-dev\n",[49,1730,1728],{"__ignoreMap":47},[13,1732,1733,1734,1736,1737],{},"このインストールで気をつけたいのが",[49,1735,1516],{},"のバージョンです。そのままインストールするとVue3に対応した最新版がインストールされ、Vue2系では動作しません。",[1445,1738,1741],{"href":1739,"rel":1740},"https:\u002F\u002Fgithub.com\u002Fpqina\u002Fvue-filepond",[1449],"本家Githubでも注意書きがあります。",[1743,1744,1745],"blockquote",{},[13,1746,1747],{},"If you want to use Vue FilePond with Vue 2, please use v6 of this plugin.",[13,1749,1750,1751,1754],{},"そのため ",[49,1752,1753],{},"npm install vue-filepond@6.0.3 --save-dev","としてバージョン６を入れる様にしてください。",[1721,1756,1758],{"id":1757},"vueレンダリング準備","Vueレンダリング準備",[13,1760,1761,1762,1765],{},"ライブラリのインストールが終わりましたら、最初にある",[49,1763,1764],{},"src\u002Fmain.js","でvueでfilepondを使用できる様にします。",[42,1767,1770],{"className":1249,"code":1768,"filename":1769,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\n\nimport vueFilePond from 'vue-filepond';\nimport FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type\u002Fdist\u002Ffilepond-plugin-file-validate-type.esm.js';\nimport FilePondPluginImagePreview from 'filepond-plugin-image-preview\u002Fdist\u002Ffilepond-plugin-image-preview.esm.js';\nimport FilePondPluginImageCrop from 'filepond-plugin-image-crop\u002Fdist\u002Ffilepond-plugin-image-crop.esm';\nconst FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview,FilePondPluginImageCrop);\nVue.component(FilePond);\n\nVue.config.productionTip = false\n\nnew Vue({\n  render: h => h(App),\n}).$mount('#app')\n","main.js",[49,1771,1772,1777,1781,1786,1791,1796,1801,1806,1811,1815,1820,1824,1829,1834],{"__ignoreMap":47},[52,1773,1774],{"class":54,"line":55},[52,1775,1776],{},"import Vue from 'vue'\n",[52,1778,1779],{"class":54,"line":83},[52,1780,340],{"emptyLinePlaceholder":339},[52,1782,1783],{"class":54,"line":115},[52,1784,1785],{},"import vueFilePond from 'vue-filepond';\n",[52,1787,1788],{"class":54,"line":142},[52,1789,1790],{},"import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type\u002Fdist\u002Ffilepond-plugin-file-validate-type.esm.js';\n",[52,1792,1793],{"class":54,"line":169},[52,1794,1795],{},"import FilePondPluginImagePreview from 'filepond-plugin-image-preview\u002Fdist\u002Ffilepond-plugin-image-preview.esm.js';\n",[52,1797,1798],{"class":54,"line":302},[52,1799,1800],{},"import FilePondPluginImageCrop from 'filepond-plugin-image-crop\u002Fdist\u002Ffilepond-plugin-image-crop.esm';\n",[52,1802,1803],{"class":54,"line":308},[52,1804,1805],{},"const FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview,FilePondPluginImageCrop);\n",[52,1807,1808],{"class":54,"line":318},[52,1809,1810],{},"Vue.component(FilePond);\n",[52,1812,1813],{"class":54,"line":328},[52,1814,340],{"emptyLinePlaceholder":339},[52,1816,1817],{"class":54,"line":4},[52,1818,1819],{},"Vue.config.productionTip = false\n",[52,1821,1822],{"class":54,"line":343},[52,1823,340],{"emptyLinePlaceholder":339},[52,1825,1826],{"class":54,"line":353},[52,1827,1828],{},"new Vue({\n",[52,1830,1831],{"class":54,"line":366},[52,1832,1833],{},"  render: h => h(App),\n",[52,1835,1836],{"class":54,"line":386},[52,1837,1838],{},"}).$mount('#app')\n",[13,1840,1841,1844,1845,1848,1849,1852],{},[49,1842,1843],{},"vueFilePond","があれば一応すぐに使用できますがここではfilepondのプラグインを使用します。プラグインを",[49,1846,1847],{},"import","して ",[49,1850,1851],{},"vueFilePond()","の引数に当てていきます。",[1854,1855,1856,1862,1868],"ul",{},[1699,1857,1858,1861],{},[49,1859,1860],{},"FilePondPluginFileValidateType","はファイルの拡張子を検証します。ここでは画像（jpg,png,gif）以外を許可しない様にします。",[1699,1863,1864,1867],{},[49,1865,1866],{},"FilePondPluginImagePreview","はブラウザにアップロードしたファイルをプレビューできる様にします。",[1699,1869,1870,1873],{},[49,1871,1872],{},"FilePondPluginImageCrop","はブラウザにアップロードしたファイルを任意のアスペクト比でトリミングしたプレビューを表示します。（実際にトリミングはしてくれない。現状はあくまでトリミング情報を提供してプレビュー表示を変えるだけ）",[17,1875,1877],{"id":1876},"まずはfilepondにアップロードできるようにする","まずはFilepondにアップロードできるようにする",[13,1879,1880,1881,1884],{},"プラグインを読み込み、",[49,1882,1883],{},"src\u002FApp.vue","を編集します。",[42,1886,1888],{"className":202,"code":1887,"filename":1883,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv>\n        \u003Cfile-pond ref=\"filepond\" v-bind=\"attrs\"\u002F>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nimport ja from 'filepond\u002Flocale\u002Fja-ja';\nimport VueCropper from 'vue-cropperjs';\nexport default {\n    name:'fileuploader',\n    data(){\n        return{\n            files:[],\n        }\n    },\n    methods:{\n        onError(res){\n            console.error(res)\n        },\n    },\n    computed:{\n        attrs(){\n            let apiserver = '\u002Fapi\u002Fv1\u002Ffile\u002Favater';\n            return {\n                allowMultiple:false,\n                'accepted-file-types':'image\u002Fjpeg,image\u002Fpng,image\u002Fgif',\n                instantUpload:false,\n                imageCropAspectRatio:'1:1',\n                server:{\n                    process: {\n                        url:apiserver,\n                        method: 'POST',\n                        withCredentials: true,\n                        onerror:(response) => this.onError(response)\n                    },\n                },\n                ...ja\n            }\n        }\n    },\n}\n\u003C\u002Fscript>\n",[49,1889,1890,1898,1908,1942,1951,1959,1967,1987,2004,2013,2029,2037,2044,2056,2061,2066,2073,2086,2102,2107,2111,2118,2125,2144,2151,2163,2184,2195,2211,2218,2227,2239,2255,2267,2295,2300,2306,2315,2321,2326,2331,2336],{"__ignoreMap":47},[52,1891,1892,1894,1896],{"class":54,"line":55},[52,1893,59],{"class":58},[52,1895,213],{"class":62},[52,1897,80],{"class":58},[52,1899,1900,1903,1906],{"class":54,"line":83},[52,1901,1902],{"class":58},"    \u003C",[52,1904,1905],{"class":62},"div",[52,1907,80],{"class":58},[52,1909,1910,1913,1916,1919,1921,1923,1925,1927,1930,1932,1934,1937,1939],{"class":54,"line":115},[52,1911,1912],{"class":58},"        \u003C",[52,1914,1915],{"class":62},"file-pond",[52,1917,1918],{"class":65}," ref",[52,1920,69],{"class":58},[52,1922,72],{"class":58},[52,1924,1450],{"class":75},[52,1926,72],{"class":58},[52,1928,1929],{"class":65}," v-bind",[52,1931,69],{"class":58},[52,1933,72],{"class":58},[52,1935,1936],{"class":75},"attrs",[52,1938,72],{"class":58},[52,1940,1941],{"class":58},"\u002F>\n",[52,1943,1944,1947,1949],{"class":54,"line":142},[52,1945,1946],{"class":58},"    \u003C\u002F",[52,1948,1905],{"class":62},[52,1950,80],{"class":58},[52,1952,1953,1955,1957],{"class":54,"line":169},[52,1954,108],{"class":58},[52,1956,213],{"class":62},[52,1958,80],{"class":58},[52,1960,1961,1963,1965],{"class":54,"line":302},[52,1962,59],{"class":58},[52,1964,348],{"class":62},[52,1966,80],{"class":58},[52,1968,1969,1971,1974,1977,1980,1983,1985],{"class":54,"line":308},[52,1970,1847],{"class":359},[52,1972,1973],{"class":105}," ja ",[52,1975,1976],{"class":359},"from",[52,1978,1979],{"class":58}," '",[52,1981,1982],{"class":75},"filepond\u002Flocale\u002Fja-ja",[52,1984,375],{"class":58},[52,1986,1006],{"class":58},[52,1988,1989,1991,1994,1996,1998,2000,2002],{"class":54,"line":318},[52,1990,1847],{"class":359},[52,1992,1993],{"class":105}," VueCropper ",[52,1995,1976],{"class":359},[52,1997,1979],{"class":58},[52,1999,1674],{"class":75},[52,2001,375],{"class":58},[52,2003,1006],{"class":58},[52,2005,2006,2008,2010],{"class":54,"line":328},[52,2007,356],{"class":359},[52,2009,360],{"class":359},[52,2011,2012],{"class":58}," {\n",[52,2014,2015,2018,2020,2022,2025,2027],{"class":54,"line":4},[52,2016,2017],{"class":62},"    name",[52,2019,372],{"class":58},[52,2021,375],{"class":58},[52,2023,2024],{"class":75},"fileuploader",[52,2026,375],{"class":58},[52,2028,383],{"class":58},[52,2030,2031,2034],{"class":54,"line":343},[52,2032,2033],{"class":62},"    data",[52,2035,2036],{"class":58},"(){\n",[52,2038,2039,2042],{"class":54,"line":353},[52,2040,2041],{"class":359},"        return",[52,2043,363],{"class":58},[52,2045,2046,2049,2051,2054],{"class":54,"line":366},[52,2047,2048],{"class":62},"            files",[52,2050,372],{"class":58},[52,2052,2053],{"class":62},"[]",[52,2055,383],{"class":58},[52,2057,2058],{"class":54,"line":386},[52,2059,2060],{"class":58},"        }\n",[52,2062,2063],{"class":54,"line":414},[52,2064,2065],{"class":58},"    },\n",[52,2067,2068,2071],{"class":54,"line":426},[52,2069,2070],{"class":62},"    methods",[52,2072,923],{"class":58},[52,2074,2075,2078,2080,2083],{"class":54,"line":434},[52,2076,2077],{"class":62},"        onError",[52,2079,931],{"class":58},[52,2081,2082],{"class":985},"res",[52,2084,2085],{"class":58},"){\n",[52,2087,2088,2091,2093,2096,2098,2100],{"class":54,"line":445},[52,2089,2090],{"class":105},"            console",[52,2092,956],{"class":58},[52,2094,2095],{"class":417},"error",[52,2097,931],{"class":62},[52,2099,2082],{"class":105},[52,2101,1014],{"class":62},[52,2103,2104],{"class":54,"line":479},[52,2105,2106],{"class":58},"        },\n",[52,2108,2109],{"class":54,"line":508},[52,2110,2065],{"class":58},[52,2112,2113,2116],{"class":54,"line":538},[52,2114,2115],{"class":62},"    computed",[52,2117,923],{"class":58},[52,2119,2120,2123],{"class":54,"line":546},[52,2121,2122],{"class":62},"        attrs",[52,2124,2036],{"class":58},[52,2126,2127,2130,2133,2135,2137,2140,2142],{"class":54,"line":552},[52,2128,2129],{"class":65},"            let",[52,2131,2132],{"class":105}," apiserver",[52,2134,950],{"class":58},[52,2136,1979],{"class":58},[52,2138,2139],{"class":75},"\u002Fapi\u002Fv1\u002Ffile\u002Favater",[52,2141,375],{"class":58},[52,2143,1006],{"class":58},[52,2145,2146,2149],{"class":54,"line":558},[52,2147,2148],{"class":359},"            return",[52,2150,2012],{"class":58},[52,2152,2153,2156,2158,2161],{"class":54,"line":563},[52,2154,2155],{"class":62},"                allowMultiple",[52,2157,372],{"class":58},[52,2159,1326],{"class":2160},"sbqyR",[52,2162,383],{"class":58},[52,2164,2165,2168,2171,2173,2175,2177,2180,2182],{"class":54,"line":568},[52,2166,2167],{"class":58},"                '",[52,2169,2170],{"class":62},"accepted-file-types",[52,2172,375],{"class":58},[52,2174,372],{"class":58},[52,2176,375],{"class":58},[52,2178,2179],{"class":75},"image\u002Fjpeg,image\u002Fpng,image\u002Fgif",[52,2181,375],{"class":58},[52,2183,383],{"class":58},[52,2185,2186,2189,2191,2193],{"class":54,"line":1105},[52,2187,2188],{"class":62},"                instantUpload",[52,2190,372],{"class":58},[52,2192,1326],{"class":2160},[52,2194,383],{"class":58},[52,2196,2197,2200,2202,2204,2207,2209],{"class":54,"line":1134},[52,2198,2199],{"class":62},"                imageCropAspectRatio",[52,2201,372],{"class":58},[52,2203,375],{"class":58},[52,2205,2206],{"class":75},"1:1",[52,2208,375],{"class":58},[52,2210,383],{"class":58},[52,2212,2213,2216],{"class":54,"line":1163},[52,2214,2215],{"class":62},"                server",[52,2217,923],{"class":58},[52,2219,2220,2223,2225],{"class":54,"line":1192},[52,2221,2222],{"class":62},"                    process",[52,2224,372],{"class":58},[52,2226,2012],{"class":58},[52,2228,2229,2232,2234,2237],{"class":54,"line":1199},[52,2230,2231],{"class":62},"                        url",[52,2233,372],{"class":58},[52,2235,2236],{"class":105},"apiserver",[52,2238,383],{"class":58},[52,2240,2241,2244,2246,2248,2251,2253],{"class":54,"line":1204},[52,2242,2243],{"class":62},"                        method",[52,2245,372],{"class":58},[52,2247,1979],{"class":58},[52,2249,2250],{"class":75},"POST",[52,2252,375],{"class":58},[52,2254,383],{"class":58},[52,2256,2257,2260,2262,2265],{"class":54,"line":1209},[52,2258,2259],{"class":62},"                        withCredentials",[52,2261,372],{"class":58},[52,2263,2264],{"class":2160}," true",[52,2266,383],{"class":58},[52,2268,2269,2272,2275,2278,2280,2283,2286,2289,2291,2293],{"class":54,"line":1214},[52,2270,2271],{"class":417},"                        onerror",[52,2273,2274],{"class":58},":(",[52,2276,2277],{"class":985},"response",[52,2279,937],{"class":58},[52,2281,2282],{"class":65}," =>",[52,2284,2285],{"class":58}," this.",[52,2287,2288],{"class":417},"onError",[52,2290,931],{"class":62},[52,2292,2277],{"class":105},[52,2294,1014],{"class":62},[52,2296,2297],{"class":54,"line":1219},[52,2298,2299],{"class":58},"                    },\n",[52,2301,2303],{"class":54,"line":2302},36,[52,2304,2305],{"class":58},"                },\n",[52,2307,2309,2312],{"class":54,"line":2308},37,[52,2310,2311],{"class":58},"                ...",[52,2313,2314],{"class":105},"ja\n",[52,2316,2318],{"class":54,"line":2317},38,[52,2319,2320],{"class":58},"            }\n",[52,2322,2324],{"class":54,"line":2323},39,[52,2325,2060],{"class":58},[52,2327,2329],{"class":54,"line":2328},40,[52,2330,2065],{"class":58},[52,2332,2334],{"class":54,"line":2333},41,[52,2335,535],{"class":58},[52,2337,2339,2341,2343],{"class":54,"line":2338},42,[52,2340,108],{"class":58},[52,2342,348],{"class":62},[52,2344,80],{"class":58},[13,2346,2347],{},"上記の通りでfilepondのコンポーネント表示されます。（スタイルなどは適宜調整してください）",[728,2349],{":src":2350,":width":1458,":center":1322},"'filepond-crop-vue\u002Ffilepond.png'",[1721,2352,2353],{"id":2353},"設定内容",[13,2355,2356,2357,2360,2361,2364,2365,2368],{},"filepondの公式ではテンプレートに",[49,2358,2359],{},"props","を設定していますが日本語化や色々設定が多いので、",[49,2362,2363],{},"computed","に記載した方がいいです。また日本語化する場合は",[49,2366,2367],{},"import ja from 'filepond\u002Flocale\u002Fja-ja';"," とインポートして展開します。",[13,2370,2371,2372,2374,2375,2380,2381,2384,2385,2388,2389,2392],{},"そしてこれらの",[49,2373,2359],{},"は",[1445,2376,2379],{"href":2377,"rel":2378},"https:\u002F\u002Fpqina.nl\u002Ffilepond\u002Fdocs\u002Fapi\u002Finstance\u002Fproperties\u002F",[1449],"本家vanilla版ドキュメント","で記載されている",[49,2382,2383],{},"properties","と同じ項目です。またfilepondのメソッドにアクセスする場合は",[49,2386,2387],{},"this.$refs.pond","と",[49,2390,2391],{},"ref","の値を使用します。今回設定した項目の解説は以下の通りです。",[42,2394,2397],{"className":2395,"code":2396,"language":1433,"meta":47,"style":47},"language-js shiki shiki-themes material-theme-ocean","return {\n    \u002F\u002F 複数ファイルのアップロードを許可するか\n    allowMultiple:false,\n\n    \u002F\u002F 許可するmime\n    'accepted-file-types':'image\u002Fjpeg,image\u002Fpng,image\u002Fgif',\n\n    \u002F\u002F ブラウザにアップしたとき、すぐにサーバーにアップロードするか。デフォルトはTrueなので注意\n    instantUpload:false,\n\n    \u002F\u002F FilePondPluginImageCrop有効時のアスペクト比。\n    imageCropAspectRatio:'1:1',\n\n    \u002F\u002F アップロードする際のajaxの設定\n    server:{\n        \u002F\u002F アップロードするときの設定\n        process: {\n            \u002F\u002F アップロード先URL\n            url:apiserver,\n\n            \u002F\u002F アップロードのメソッド（processはデフォルトでPOST）\n            method: 'POST',\n\n            \u002F\u002F withCredentialsを有効化\n            withCredentials: true,\n\n            \u002F\u002F エラー時のコールバック\n            onerror:(response) => this.onError(response)\n        },\n    },\n\n    \u002F\u002F 日本語化\n    ...ja\n}\n",[49,2398,2399,2406,2411,2422,2426,2431,2450,2454,2459,2470,2474,2479,2494,2498,2503,2510,2515,2524,2529,2540,2544,2549,2564,2568,2573,2584,2588,2593,2613,2617,2621,2625,2630,2637],{"__ignoreMap":47},[52,2400,2401,2404],{"class":54,"line":55},[52,2402,2403],{"class":359},"return",[52,2405,2012],{"class":58},[52,2407,2408],{"class":54,"line":83},[52,2409,2410],{"class":410},"    \u002F\u002F 複数ファイルのアップロードを許可するか\n",[52,2412,2413,2416,2418,2420],{"class":54,"line":115},[52,2414,2415],{"class":62},"    allowMultiple",[52,2417,372],{"class":58},[52,2419,1326],{"class":2160},[52,2421,383],{"class":58},[52,2423,2424],{"class":54,"line":142},[52,2425,340],{"emptyLinePlaceholder":339},[52,2427,2428],{"class":54,"line":169},[52,2429,2430],{"class":410},"    \u002F\u002F 許可するmime\n",[52,2432,2433,2436,2438,2440,2442,2444,2446,2448],{"class":54,"line":302},[52,2434,2435],{"class":58},"    '",[52,2437,2170],{"class":62},[52,2439,375],{"class":58},[52,2441,372],{"class":58},[52,2443,375],{"class":58},[52,2445,2179],{"class":75},[52,2447,375],{"class":58},[52,2449,383],{"class":58},[52,2451,2452],{"class":54,"line":308},[52,2453,340],{"emptyLinePlaceholder":339},[52,2455,2456],{"class":54,"line":318},[52,2457,2458],{"class":410},"    \u002F\u002F ブラウザにアップしたとき、すぐにサーバーにアップロードするか。デフォルトはTrueなので注意\n",[52,2460,2461,2464,2466,2468],{"class":54,"line":328},[52,2462,2463],{"class":62},"    instantUpload",[52,2465,372],{"class":58},[52,2467,1326],{"class":2160},[52,2469,383],{"class":58},[52,2471,2472],{"class":54,"line":4},[52,2473,340],{"emptyLinePlaceholder":339},[52,2475,2476],{"class":54,"line":343},[52,2477,2478],{"class":410},"    \u002F\u002F FilePondPluginImageCrop有効時のアスペクト比。\n",[52,2480,2481,2484,2486,2488,2490,2492],{"class":54,"line":353},[52,2482,2483],{"class":62},"    imageCropAspectRatio",[52,2485,372],{"class":58},[52,2487,375],{"class":58},[52,2489,2206],{"class":75},[52,2491,375],{"class":58},[52,2493,383],{"class":58},[52,2495,2496],{"class":54,"line":366},[52,2497,340],{"emptyLinePlaceholder":339},[52,2499,2500],{"class":54,"line":386},[52,2501,2502],{"class":410},"    \u002F\u002F アップロードする際のajaxの設定\n",[52,2504,2505,2508],{"class":54,"line":414},[52,2506,2507],{"class":62},"    server",[52,2509,923],{"class":58},[52,2511,2512],{"class":54,"line":426},[52,2513,2514],{"class":410},"        \u002F\u002F アップロードするときの設定\n",[52,2516,2517,2520,2522],{"class":54,"line":434},[52,2518,2519],{"class":62},"        process",[52,2521,372],{"class":58},[52,2523,2012],{"class":58},[52,2525,2526],{"class":54,"line":445},[52,2527,2528],{"class":410},"            \u002F\u002F アップロード先URL\n",[52,2530,2531,2534,2536,2538],{"class":54,"line":479},[52,2532,2533],{"class":62},"            url",[52,2535,372],{"class":58},[52,2537,2236],{"class":105},[52,2539,383],{"class":58},[52,2541,2542],{"class":54,"line":508},[52,2543,340],{"emptyLinePlaceholder":339},[52,2545,2546],{"class":54,"line":538},[52,2547,2548],{"class":410},"            \u002F\u002F アップロードのメソッド（processはデフォルトでPOST）\n",[52,2550,2551,2554,2556,2558,2560,2562],{"class":54,"line":546},[52,2552,2553],{"class":62},"            method",[52,2555,372],{"class":58},[52,2557,1979],{"class":58},[52,2559,2250],{"class":75},[52,2561,375],{"class":58},[52,2563,383],{"class":58},[52,2565,2566],{"class":54,"line":552},[52,2567,340],{"emptyLinePlaceholder":339},[52,2569,2570],{"class":54,"line":558},[52,2571,2572],{"class":410},"            \u002F\u002F withCredentialsを有効化\n",[52,2574,2575,2578,2580,2582],{"class":54,"line":563},[52,2576,2577],{"class":62},"            withCredentials",[52,2579,372],{"class":58},[52,2581,2264],{"class":2160},[52,2583,383],{"class":58},[52,2585,2586],{"class":54,"line":568},[52,2587,340],{"emptyLinePlaceholder":339},[52,2589,2590],{"class":54,"line":1105},[52,2591,2592],{"class":410},"            \u002F\u002F エラー時のコールバック\n",[52,2594,2595,2598,2600,2602,2604,2606,2608,2610],{"class":54,"line":1134},[52,2596,2597],{"class":417},"            onerror",[52,2599,2274],{"class":58},[52,2601,2277],{"class":985},[52,2603,937],{"class":58},[52,2605,2282],{"class":65},[52,2607,2285],{"class":58},[52,2609,2288],{"class":417},[52,2611,2612],{"class":105},"(response)\n",[52,2614,2615],{"class":54,"line":1163},[52,2616,2106],{"class":58},[52,2618,2619],{"class":54,"line":1192},[52,2620,2065],{"class":58},[52,2622,2623],{"class":54,"line":1199},[52,2624,340],{"emptyLinePlaceholder":339},[52,2626,2627],{"class":54,"line":1204},[52,2628,2629],{"class":410},"    \u002F\u002F 日本語化\n",[52,2631,2632,2635],{"class":54,"line":1209},[52,2633,2634],{"class":58},"    ...",[52,2636,2314],{"class":105},[52,2638,2639],{"class":54,"line":1214},[52,2640,535],{"class":58},[13,2642,2643,2644,2647,2648,2650],{},"ひとまず上記の設定があり、サーバー側でURLが利用可能であれば一応アップロードが可能です。ただしこれだけではトリミングされません。（プレビューはトリミングされて表示されますが）\n",[49,2645,2646],{},"instantUpload","はデフォルトで",[49,2649,1322],{},"であり、トリミング前にアップロードされますので注意が必要です。",[17,2652,2654],{"id":2653},"filepondとvue-cropperへの連携","Filepondとvue-cropperへの連携",[13,2656,2657],{},"ではアップロードはできたのでcropperと連携しましょう。新しくライブラリをインストールします。",[42,2659,2662],{"className":2660,"code":2661,"language":451},[1727],"npm install filepond-plugin-image-edit filepond-plugin-image-transform vue-cropperjs --save\n",[49,2663,2661],{"__ignoreMap":47},[13,2665,2666,2667,2669],{},"cropperのVue版とfilepondの編集APIとトリミングしてくれるプラグインをインストールします。",[49,2668,1769],{},"も変更します。",[42,2671,2673],{"className":2395,"code":2672,"filename":1769,"language":1433,"meta":47,"style":47},"import vueFilePond from 'vue-filepond';\nimport FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type\u002Fdist\u002Ffilepond-plugin-file-validate-type.esm.js';\nimport FilePondPluginImagePreview from 'filepond-plugin-image-preview\u002Fdist\u002Ffilepond-plugin-image-preview.esm.js';\nimport FilePondPluginImageCrop from 'filepond-plugin-image-crop\u002Fdist\u002Ffilepond-plugin-image-crop.esm';\nimport FilePondPluginImageEdit from 'filepond-plugin-image-edit\u002Fdist\u002Ffilepond-plugin-image-edit.esm';　\u002F\u002F 追加\nimport FilePondPluginImageTransform from 'filepond-plugin-image-transform\u002Fdist\u002Ffilepond-plugin-image-transform.esm';　\u002F\u002F 追加\nconst FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview,FilePondPluginImageCrop,FilePondPluginImageEdit,FilePondPluginImageTransform);\nVue.component(FilePond);\n",[49,2674,2675,2692,2710,2728,2746,2768,2788,2825],{"__ignoreMap":47},[52,2676,2677,2679,2682,2684,2686,2688,2690],{"class":54,"line":55},[52,2678,1847],{"class":359},[52,2680,2681],{"class":105}," vueFilePond ",[52,2683,1976],{"class":359},[52,2685,1979],{"class":58},[52,2687,1516],{"class":75},[52,2689,375],{"class":58},[52,2691,1006],{"class":58},[52,2693,2694,2696,2699,2701,2703,2706,2708],{"class":54,"line":83},[52,2695,1847],{"class":359},[52,2697,2698],{"class":105}," FilePondPluginFileValidateType ",[52,2700,1976],{"class":359},[52,2702,1979],{"class":58},[52,2704,2705],{"class":75},"filepond-plugin-file-validate-type\u002Fdist\u002Ffilepond-plugin-file-validate-type.esm.js",[52,2707,375],{"class":58},[52,2709,1006],{"class":58},[52,2711,2712,2714,2717,2719,2721,2724,2726],{"class":54,"line":115},[52,2713,1847],{"class":359},[52,2715,2716],{"class":105}," FilePondPluginImagePreview ",[52,2718,1976],{"class":359},[52,2720,1979],{"class":58},[52,2722,2723],{"class":75},"filepond-plugin-image-preview\u002Fdist\u002Ffilepond-plugin-image-preview.esm.js",[52,2725,375],{"class":58},[52,2727,1006],{"class":58},[52,2729,2730,2732,2735,2737,2739,2742,2744],{"class":54,"line":142},[52,2731,1847],{"class":359},[52,2733,2734],{"class":105}," FilePondPluginImageCrop ",[52,2736,1976],{"class":359},[52,2738,1979],{"class":58},[52,2740,2741],{"class":75},"filepond-plugin-image-crop\u002Fdist\u002Ffilepond-plugin-image-crop.esm",[52,2743,375],{"class":58},[52,2745,1006],{"class":58},[52,2747,2748,2750,2753,2755,2757,2760,2762,2765],{"class":54,"line":169},[52,2749,1847],{"class":359},[52,2751,2752],{"class":105}," FilePondPluginImageEdit ",[52,2754,1976],{"class":359},[52,2756,1979],{"class":58},[52,2758,2759],{"class":75},"filepond-plugin-image-edit\u002Fdist\u002Ffilepond-plugin-image-edit.esm",[52,2761,375],{"class":58},[52,2763,2764],{"class":58},";",[52,2766,2767],{"class":410},"　\u002F\u002F 追加\n",[52,2769,2770,2772,2775,2777,2779,2782,2784,2786],{"class":54,"line":302},[52,2771,1847],{"class":359},[52,2773,2774],{"class":105}," FilePondPluginImageTransform ",[52,2776,1976],{"class":359},[52,2778,1979],{"class":58},[52,2780,2781],{"class":75},"filepond-plugin-image-transform\u002Fdist\u002Ffilepond-plugin-image-transform.esm",[52,2783,375],{"class":58},[52,2785,2764],{"class":58},[52,2787,2767],{"class":410},[52,2789,2790,2793,2796,2798,2801,2804,2806,2809,2811,2813,2815,2818,2820,2823],{"class":54,"line":308},[52,2791,2792],{"class":65},"const",[52,2794,2795],{"class":105}," FilePond ",[52,2797,69],{"class":58},[52,2799,2800],{"class":417}," vueFilePond",[52,2802,2803],{"class":105},"(FilePondPluginFileValidateType",[52,2805,407],{"class":58},[52,2807,2808],{"class":105}," FilePondPluginImagePreview",[52,2810,407],{"class":58},[52,2812,1872],{"class":105},[52,2814,407],{"class":58},[52,2816,2817],{"class":105},"FilePondPluginImageEdit",[52,2819,407],{"class":58},[52,2821,2822],{"class":105},"FilePondPluginImageTransform)",[52,2824,1006],{"class":58},[52,2826,2827,2830,2832,2835,2838],{"class":54,"line":318},[52,2828,2829],{"class":105},"Vue",[52,2831,956],{"class":58},[52,2833,2834],{"class":417},"component",[52,2836,2837],{"class":105},"(FilePond)",[52,2839,1006],{"class":58},[1721,2841,2843],{"id":2842},"編集uiの表示","編集UIの表示",[13,2845,2846],{},"まず編集ボタンを表示できる様にします。先程のfilepondの設定に編集用コールバックの設定を追加します。",[42,2848,2850],{"className":202,"code":2849,"filename":1883,"language":204,"meta":47,"style":47},"\u003Cscript>\n\u002F\u002F 部分省略\nexport default {\n    name:'fileuploader',\n    data(){\n        return{\n            files:[],\n        }\n    },\n    methods:{\n        \u002F\u002F ...\n    },\n    computed:{\n        \u002F\u002F 追加\n        editor(){\n            return {\n                \u002F\u002F Called by FilePond to edit the image\n                \u002F\u002F - should open your image editor\n                \u002F\u002F - receives file object and image edit instructions\n                open: (file, instructions) => {\n                \u002F\u002F open editor here\n\n                },\n\n                \u002F\u002F Callback set by FilePond\n                \u002F\u002F - should be called by the editor when user confirms editing\n                \u002F\u002F - should receive output object, resulting edit information\n                onconfirm: (data) => {},\n\n                \u002F\u002F Callback set by FilePond\n                \u002F\u002F - should be called by the editor when user cancels editing\n                oncancel: () => {},\n\n                \u002F\u002F Callback set by FilePond\n                \u002F\u002F - should be called by the editor when user closes the editor\n                onclose: () => {\n                },\n            }\n        },\n        attrs(){\n            let apiserver = '\u002Fapi\u002Fv1\u002Ffile\u002Favater';\n            return {\n                imageEditEditor:this.editor, \u002F\u002F 追加\n                allowMultiple:false,\n                'accepted-file-types':'image\u002Fjpeg,image\u002Fpng,image\u002Fgif',\n                instantUpload:false,\n                imageCropAspectRatio:'1:1',\n                server:{\n                    process: {\n                        url:apiserver,\n                        method: 'POST',\n                        withCredentials: true,\n                        onerror:(response) => this.onError(response)\n                    },\n                },\n                ...ja\n            }\n        },\n        \u002F\u002F ...\n    },\n}\n\u003C\u002Fscript>\n",[49,2851,2852,2860,2865,2873,2887,2893,2899,2909,2913,2917,2923,2928,2932,2938,2943,2950,2956,2961,2966,2971,2995,3000,3004,3008,3012,3017,3022,3027,3046,3050,3054,3059,3073,3077,3081,3086,3099,3103,3107,3111,3117,3133,3139,3156,3167,3186,3197,3212,3219,3228,3239,3254,3265,3288,3293,3298,3305,3310,3315,3320,3325,3330],{"__ignoreMap":47},[52,2853,2854,2856,2858],{"class":54,"line":55},[52,2855,59],{"class":58},[52,2857,348],{"class":62},[52,2859,80],{"class":58},[52,2861,2862],{"class":54,"line":83},[52,2863,2864],{"class":410},"\u002F\u002F 部分省略\n",[52,2866,2867,2869,2871],{"class":54,"line":115},[52,2868,356],{"class":359},[52,2870,360],{"class":359},[52,2872,2012],{"class":58},[52,2874,2875,2877,2879,2881,2883,2885],{"class":54,"line":142},[52,2876,2017],{"class":62},[52,2878,372],{"class":58},[52,2880,375],{"class":58},[52,2882,2024],{"class":75},[52,2884,375],{"class":58},[52,2886,383],{"class":58},[52,2888,2889,2891],{"class":54,"line":169},[52,2890,2033],{"class":62},[52,2892,2036],{"class":58},[52,2894,2895,2897],{"class":54,"line":302},[52,2896,2041],{"class":359},[52,2898,363],{"class":58},[52,2900,2901,2903,2905,2907],{"class":54,"line":308},[52,2902,2048],{"class":62},[52,2904,372],{"class":58},[52,2906,2053],{"class":62},[52,2908,383],{"class":58},[52,2910,2911],{"class":54,"line":318},[52,2912,2060],{"class":58},[52,2914,2915],{"class":54,"line":328},[52,2916,2065],{"class":58},[52,2918,2919,2921],{"class":54,"line":4},[52,2920,2070],{"class":62},[52,2922,923],{"class":58},[52,2924,2925],{"class":54,"line":343},[52,2926,2927],{"class":410},"        \u002F\u002F ...\n",[52,2929,2930],{"class":54,"line":353},[52,2931,2065],{"class":58},[52,2933,2934,2936],{"class":54,"line":366},[52,2935,2115],{"class":62},[52,2937,923],{"class":58},[52,2939,2940],{"class":54,"line":386},[52,2941,2942],{"class":410},"        \u002F\u002F 追加\n",[52,2944,2945,2948],{"class":54,"line":414},[52,2946,2947],{"class":62},"        editor",[52,2949,2036],{"class":58},[52,2951,2952,2954],{"class":54,"line":426},[52,2953,2148],{"class":359},[52,2955,2012],{"class":58},[52,2957,2958],{"class":54,"line":434},[52,2959,2960],{"class":410},"                \u002F\u002F Called by FilePond to edit the image\n",[52,2962,2963],{"class":54,"line":445},[52,2964,2965],{"class":410},"                \u002F\u002F - should open your image editor\n",[52,2967,2968],{"class":54,"line":479},[52,2969,2970],{"class":410},"                \u002F\u002F - receives file object and image edit instructions\n",[52,2972,2973,2976,2978,2981,2984,2986,2989,2991,2993],{"class":54,"line":508},[52,2974,2975],{"class":417},"                open",[52,2977,372],{"class":58},[52,2979,2980],{"class":58}," (",[52,2982,2983],{"class":985},"file",[52,2985,407],{"class":58},[52,2987,2988],{"class":985}," instructions",[52,2990,937],{"class":58},[52,2992,2282],{"class":65},[52,2994,2012],{"class":58},[52,2996,2997],{"class":54,"line":538},[52,2998,2999],{"class":410},"                \u002F\u002F open editor here\n",[52,3001,3002],{"class":54,"line":546},[52,3003,340],{"emptyLinePlaceholder":339},[52,3005,3006],{"class":54,"line":552},[52,3007,2305],{"class":58},[52,3009,3010],{"class":54,"line":558},[52,3011,340],{"emptyLinePlaceholder":339},[52,3013,3014],{"class":54,"line":563},[52,3015,3016],{"class":410},"                \u002F\u002F Callback set by FilePond\n",[52,3018,3019],{"class":54,"line":568},[52,3020,3021],{"class":410},"                \u002F\u002F - should be called by the editor when user confirms editing\n",[52,3023,3024],{"class":54,"line":1105},[52,3025,3026],{"class":410},"                \u002F\u002F - should receive output object, resulting edit information\n",[52,3028,3029,3032,3034,3036,3039,3041,3043],{"class":54,"line":1134},[52,3030,3031],{"class":417},"                onconfirm",[52,3033,372],{"class":58},[52,3035,2980],{"class":58},[52,3037,3038],{"class":985},"data",[52,3040,937],{"class":58},[52,3042,2282],{"class":65},[52,3044,3045],{"class":58}," {},\n",[52,3047,3048],{"class":54,"line":1163},[52,3049,340],{"emptyLinePlaceholder":339},[52,3051,3052],{"class":54,"line":1192},[52,3053,3016],{"class":410},[52,3055,3056],{"class":54,"line":1199},[52,3057,3058],{"class":410},"                \u002F\u002F - should be called by the editor when user cancels editing\n",[52,3060,3061,3064,3066,3069,3071],{"class":54,"line":1204},[52,3062,3063],{"class":417},"                oncancel",[52,3065,372],{"class":58},[52,3067,3068],{"class":58}," ()",[52,3070,2282],{"class":65},[52,3072,3045],{"class":58},[52,3074,3075],{"class":54,"line":1209},[52,3076,340],{"emptyLinePlaceholder":339},[52,3078,3079],{"class":54,"line":1214},[52,3080,3016],{"class":410},[52,3082,3083],{"class":54,"line":1219},[52,3084,3085],{"class":410},"                \u002F\u002F - should be called by the editor when user closes the editor\n",[52,3087,3088,3091,3093,3095,3097],{"class":54,"line":2302},[52,3089,3090],{"class":417},"                onclose",[52,3092,372],{"class":58},[52,3094,3068],{"class":58},[52,3096,2282],{"class":65},[52,3098,2012],{"class":58},[52,3100,3101],{"class":54,"line":2308},[52,3102,2305],{"class":58},[52,3104,3105],{"class":54,"line":2317},[52,3106,2320],{"class":58},[52,3108,3109],{"class":54,"line":2323},[52,3110,2106],{"class":58},[52,3112,3113,3115],{"class":54,"line":2328},[52,3114,2122],{"class":62},[52,3116,2036],{"class":58},[52,3118,3119,3121,3123,3125,3127,3129,3131],{"class":54,"line":2333},[52,3120,2129],{"class":65},[52,3122,2132],{"class":105},[52,3124,950],{"class":58},[52,3126,1979],{"class":58},[52,3128,2139],{"class":75},[52,3130,375],{"class":58},[52,3132,1006],{"class":58},[52,3134,3135,3137],{"class":54,"line":2338},[52,3136,2148],{"class":359},[52,3138,2012],{"class":58},[52,3140,3142,3145,3148,3151,3153],{"class":54,"line":3141},43,[52,3143,3144],{"class":62},"                imageEditEditor",[52,3146,3147],{"class":58},":this.",[52,3149,3150],{"class":105},"editor",[52,3152,407],{"class":58},[52,3154,3155],{"class":410}," \u002F\u002F 追加\n",[52,3157,3159,3161,3163,3165],{"class":54,"line":3158},44,[52,3160,2155],{"class":62},[52,3162,372],{"class":58},[52,3164,1326],{"class":2160},[52,3166,383],{"class":58},[52,3168,3170,3172,3174,3176,3178,3180,3182,3184],{"class":54,"line":3169},45,[52,3171,2167],{"class":58},[52,3173,2170],{"class":62},[52,3175,375],{"class":58},[52,3177,372],{"class":58},[52,3179,375],{"class":58},[52,3181,2179],{"class":75},[52,3183,375],{"class":58},[52,3185,383],{"class":58},[52,3187,3189,3191,3193,3195],{"class":54,"line":3188},46,[52,3190,2188],{"class":62},[52,3192,372],{"class":58},[52,3194,1326],{"class":2160},[52,3196,383],{"class":58},[52,3198,3200,3202,3204,3206,3208,3210],{"class":54,"line":3199},47,[52,3201,2199],{"class":62},[52,3203,372],{"class":58},[52,3205,375],{"class":58},[52,3207,2206],{"class":75},[52,3209,375],{"class":58},[52,3211,383],{"class":58},[52,3213,3215,3217],{"class":54,"line":3214},48,[52,3216,2215],{"class":62},[52,3218,923],{"class":58},[52,3220,3222,3224,3226],{"class":54,"line":3221},49,[52,3223,2222],{"class":62},[52,3225,372],{"class":58},[52,3227,2012],{"class":58},[52,3229,3231,3233,3235,3237],{"class":54,"line":3230},50,[52,3232,2231],{"class":62},[52,3234,372],{"class":58},[52,3236,2236],{"class":105},[52,3238,383],{"class":58},[52,3240,3242,3244,3246,3248,3250,3252],{"class":54,"line":3241},51,[52,3243,2243],{"class":62},[52,3245,372],{"class":58},[52,3247,1979],{"class":58},[52,3249,2250],{"class":75},[52,3251,375],{"class":58},[52,3253,383],{"class":58},[52,3255,3257,3259,3261,3263],{"class":54,"line":3256},52,[52,3258,2259],{"class":62},[52,3260,372],{"class":58},[52,3262,2264],{"class":2160},[52,3264,383],{"class":58},[52,3266,3268,3270,3272,3274,3276,3278,3280,3282,3284,3286],{"class":54,"line":3267},53,[52,3269,2271],{"class":417},[52,3271,2274],{"class":58},[52,3273,2277],{"class":985},[52,3275,937],{"class":58},[52,3277,2282],{"class":65},[52,3279,2285],{"class":58},[52,3281,2288],{"class":417},[52,3283,931],{"class":62},[52,3285,2277],{"class":105},[52,3287,1014],{"class":62},[52,3289,3291],{"class":54,"line":3290},54,[52,3292,2299],{"class":58},[52,3294,3296],{"class":54,"line":3295},55,[52,3297,2305],{"class":58},[52,3299,3301,3303],{"class":54,"line":3300},56,[52,3302,2311],{"class":58},[52,3304,2314],{"class":105},[52,3306,3308],{"class":54,"line":3307},57,[52,3309,2320],{"class":58},[52,3311,3313],{"class":54,"line":3312},58,[52,3314,2106],{"class":58},[52,3316,3318],{"class":54,"line":3317},59,[52,3319,2927],{"class":410},[52,3321,3323],{"class":54,"line":3322},60,[52,3324,2065],{"class":58},[52,3326,3328],{"class":54,"line":3327},61,[52,3329,535],{"class":58},[52,3331,3333,3335,3337],{"class":54,"line":3332},62,[52,3334,108],{"class":58},[52,3336,348],{"class":62},[52,3338,80],{"class":58},[13,3340,3341,3343,3344,3347,3348,3350,3351,3353,3354,3356,3357],{},[49,3342,3150],{},"というプロパティーを追加しました。そしてfilepondの設定に",[49,3345,3346],{},"imageEditEditor","を追加して、",[49,3349,3150],{},"を参照する様にします。この",[49,3352,3346],{},"がないと編集UIが出現しません。",[49,3355,3150],{},"の雛形は",[1445,3358,3361],{"href":3359,"rel":3360},"https:\u002F\u002Fpqina.nl\u002Ffilepond\u002Fdocs\u002Fapi\u002Fplugins\u002Fimage-edit#integrating-other-editors",[1449],"本家ドキュメントから参照できます。",[13,3363,3364,3366],{},[49,3365,3346],{},"をしますと下図の赤矢印の様に編集ボタンが出現します。",[728,3368],{":src":3369,":width":1458,":center":1322},"'filepond-crop-vue\u002Feditui.png'",[13,3371,3372,3373,3375,3376,3379,3380,3383],{},"この編集ボタンをクリックした際は",[49,3374,3150],{},"の",[49,3377,3378],{},"open()=>{}","コールバックが実行されます。この際に",[49,3381,3382],{},"cropper","に画像データを渡し、起動する様にすればトリミングUIを表示できる様になります。",[1721,3385,3386],{"id":3386},"cropperのレンダリング",[13,3388,3389],{},"設定の前にfilepondのコンポーネントを表示する様にします。",[42,3391,3393],{"className":202,"code":3392,"filename":1883,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cfile-pond v-bind=\"attrs\"\u002F>\n    \u003Cvue-cropper\n        ref=\"cropper\"\n        :src=\"imgSrc\"\n        :aspect-ratio=\"1 \u002F 1\"\n        :view-mode=\"1\"\n    >\n    \u003C\u002Fvue-cropper>\n    \u003Cbutton variant=\"primary\" @click=\"crop\">crop\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nimport ja from 'filepond\u002Flocale\u002Fja-ja';\nimport VueCropper from 'vue-cropperjs';　 \u002F\u002F 追加\nexport default {\n    name:'fileuploader',\n    data(){\n        return{\n            files:[],\n            imgSrc:'', \u002F\u002F 追加\n        }\n    },\n    methods:{\n        onError(res){\n            \u002F\u002F ...\n        },\n        crop(){\n            \u002F\u002F 追加\n            \u002F\u002F とりあえずこのままにしておいてください。\n        }\n    },\n    computed:{\n        \u002F\u002F ...\n    },\n    components:{\n        VueCropper \u002F\u002F 追加\n    }\n}\n\u003C\u002Fscript>\n",[49,3394,3395,3403,3411,3429,3436,3449,3463,3477,3490,3495,3504,3545,3553,3561,3569,3585,3604,3612,3626,3632,3638,3648,3662,3666,3670,3676,3686,3691,3695,3702,3707,3712,3716,3720,3726,3730,3734,3741,3749,3754,3758],{"__ignoreMap":47},[52,3396,3397,3399,3401],{"class":54,"line":55},[52,3398,59],{"class":58},[52,3400,213],{"class":62},[52,3402,80],{"class":58},[52,3404,3405,3407,3409],{"class":54,"line":83},[52,3406,59],{"class":58},[52,3408,1905],{"class":62},[52,3410,80],{"class":58},[52,3412,3413,3415,3417,3419,3421,3423,3425,3427],{"class":54,"line":115},[52,3414,1902],{"class":58},[52,3416,1915],{"class":62},[52,3418,1929],{"class":65},[52,3420,69],{"class":58},[52,3422,72],{"class":58},[52,3424,1936],{"class":75},[52,3426,72],{"class":58},[52,3428,1941],{"class":58},[52,3430,3431,3433],{"class":54,"line":142},[52,3432,1902],{"class":58},[52,3434,3435],{"class":62},"vue-cropper\n",[52,3437,3438,3441,3443,3445,3447],{"class":54,"line":169},[52,3439,3440],{"class":65},"        ref",[52,3442,69],{"class":58},[52,3444,72],{"class":58},[52,3446,3382],{"class":75},[52,3448,266],{"class":58},[52,3450,3451,3454,3456,3458,3461],{"class":54,"line":302},[52,3452,3453],{"class":65},"        :src",[52,3455,69],{"class":58},[52,3457,72],{"class":58},[52,3459,3460],{"class":75},"imgSrc",[52,3462,266],{"class":58},[52,3464,3465,3468,3470,3472,3475],{"class":54,"line":308},[52,3466,3467],{"class":65},"        :aspect-ratio",[52,3469,69],{"class":58},[52,3471,72],{"class":58},[52,3473,3474],{"class":75},"1 \u002F 1",[52,3476,266],{"class":58},[52,3478,3479,3482,3484,3486,3488],{"class":54,"line":318},[52,3480,3481],{"class":65},"        :view-mode",[52,3483,69],{"class":58},[52,3485,72],{"class":58},[52,3487,31],{"class":75},[52,3489,266],{"class":58},[52,3491,3492],{"class":54,"line":328},[52,3493,3494],{"class":58},"    >\n",[52,3496,3497,3499,3502],{"class":54,"line":4},[52,3498,1946],{"class":58},[52,3500,3501],{"class":62},"vue-cropper",[52,3503,80],{"class":58},[52,3505,3506,3508,3511,3514,3516,3518,3521,3523,3526,3528,3530,3533,3535,3537,3539,3541,3543],{"class":54,"line":343},[52,3507,1902],{"class":58},[52,3509,3510],{"class":62},"button",[52,3512,3513],{"class":65}," variant",[52,3515,69],{"class":58},[52,3517,72],{"class":58},[52,3519,3520],{"class":75},"primary",[52,3522,72],{"class":58},[52,3524,3525],{"class":65}," @click",[52,3527,69],{"class":58},[52,3529,72],{"class":58},[52,3531,3532],{"class":75},"crop",[52,3534,72],{"class":58},[52,3536,102],{"class":58},[52,3538,3532],{"class":105},[52,3540,108],{"class":58},[52,3542,3510],{"class":62},[52,3544,80],{"class":58},[52,3546,3547,3549,3551],{"class":54,"line":353},[52,3548,108],{"class":58},[52,3550,1905],{"class":62},[52,3552,80],{"class":58},[52,3554,3555,3557,3559],{"class":54,"line":366},[52,3556,108],{"class":58},[52,3558,213],{"class":62},[52,3560,80],{"class":58},[52,3562,3563,3565,3567],{"class":54,"line":386},[52,3564,59],{"class":58},[52,3566,348],{"class":62},[52,3568,80],{"class":58},[52,3570,3571,3573,3575,3577,3579,3581,3583],{"class":54,"line":414},[52,3572,1847],{"class":359},[52,3574,1973],{"class":105},[52,3576,1976],{"class":359},[52,3578,1979],{"class":58},[52,3580,1982],{"class":75},[52,3582,375],{"class":58},[52,3584,1006],{"class":58},[52,3586,3587,3589,3591,3593,3595,3597,3599,3601],{"class":54,"line":426},[52,3588,1847],{"class":359},[52,3590,1993],{"class":105},[52,3592,1976],{"class":359},[52,3594,1979],{"class":58},[52,3596,1674],{"class":75},[52,3598,375],{"class":58},[52,3600,2764],{"class":58},[52,3602,3603],{"class":410},"　 \u002F\u002F 追加\n",[52,3605,3606,3608,3610],{"class":54,"line":434},[52,3607,356],{"class":359},[52,3609,360],{"class":359},[52,3611,2012],{"class":58},[52,3613,3614,3616,3618,3620,3622,3624],{"class":54,"line":445},[52,3615,2017],{"class":62},[52,3617,372],{"class":58},[52,3619,375],{"class":58},[52,3621,2024],{"class":75},[52,3623,375],{"class":58},[52,3625,383],{"class":58},[52,3627,3628,3630],{"class":54,"line":479},[52,3629,2033],{"class":62},[52,3631,2036],{"class":58},[52,3633,3634,3636],{"class":54,"line":508},[52,3635,2041],{"class":359},[52,3637,363],{"class":58},[52,3639,3640,3642,3644,3646],{"class":54,"line":538},[52,3641,2048],{"class":62},[52,3643,372],{"class":58},[52,3645,2053],{"class":62},[52,3647,383],{"class":58},[52,3649,3650,3653,3655,3658,3660],{"class":54,"line":546},[52,3651,3652],{"class":62},"            imgSrc",[52,3654,372],{"class":58},[52,3656,3657],{"class":58},"''",[52,3659,407],{"class":58},[52,3661,3155],{"class":410},[52,3663,3664],{"class":54,"line":552},[52,3665,2060],{"class":58},[52,3667,3668],{"class":54,"line":558},[52,3669,2065],{"class":58},[52,3671,3672,3674],{"class":54,"line":563},[52,3673,2070],{"class":62},[52,3675,923],{"class":58},[52,3677,3678,3680,3682,3684],{"class":54,"line":568},[52,3679,2077],{"class":62},[52,3681,931],{"class":58},[52,3683,2082],{"class":985},[52,3685,2085],{"class":58},[52,3687,3688],{"class":54,"line":1105},[52,3689,3690],{"class":410},"            \u002F\u002F ...\n",[52,3692,3693],{"class":54,"line":1134},[52,3694,2106],{"class":58},[52,3696,3697,3700],{"class":54,"line":1163},[52,3698,3699],{"class":62},"        crop",[52,3701,2036],{"class":58},[52,3703,3704],{"class":54,"line":1192},[52,3705,3706],{"class":410},"            \u002F\u002F 追加\n",[52,3708,3709],{"class":54,"line":1199},[52,3710,3711],{"class":410},"            \u002F\u002F とりあえずこのままにしておいてください。\n",[52,3713,3714],{"class":54,"line":1204},[52,3715,2060],{"class":58},[52,3717,3718],{"class":54,"line":1209},[52,3719,2065],{"class":58},[52,3721,3722,3724],{"class":54,"line":1214},[52,3723,2115],{"class":62},[52,3725,923],{"class":58},[52,3727,3728],{"class":54,"line":1219},[52,3729,2927],{"class":410},[52,3731,3732],{"class":54,"line":2302},[52,3733,2065],{"class":58},[52,3735,3736,3739],{"class":54,"line":2308},[52,3737,3738],{"class":62},"    components",[52,3740,923],{"class":58},[52,3742,3743,3746],{"class":54,"line":2317},[52,3744,3745],{"class":105},"        VueCropper ",[52,3747,3748],{"class":410},"\u002F\u002F 追加\n",[52,3750,3751],{"class":54,"line":2323},[52,3752,3753],{"class":58},"    }\n",[52,3755,3756],{"class":54,"line":2328},[52,3757,535],{"class":58},[52,3759,3760,3762,3764],{"class":54,"line":2333},[52,3761,108],{"class":58},[52,3763,348],{"class":62},[52,3765,80],{"class":58},[13,3767,3768,3771,3772,3774,3775,3777],{},[49,3769,3770],{},"import VueCropper from 'vue-cropperjs';","にてvue-cropperのコンポーネントを配置します。",[49,3773,3501],{},"はトリミングのUIを提供し、",[49,3776,3510],{},"はトリミングの実行を行ってfilepondにデータを渡すメソッドに連絡します。\nひとまず以下の様に表示されると思います。",[728,3779],{":src":3780,":width":1458,":center":1322},"'filepond-crop-vue\u002Fcropper-init.png'",[13,3782,3783],{},"なおvue-cropperのコンポーネントに設定した項目は以下の通りです。",[1854,3785,3786,3792],{},[1699,3787,3788,3791],{},[49,3789,3790],{},"aspect-ratio",":トリミングUIのアスペクト比です。",[1699,3793,3794,3797],{},[49,3795,3796],{},"view-mode",":ビューモードと呼ばれるトリミングの選択範囲を制御できます。デフォルトは0であり制限がなく、透明の領域までトリミングできてしまします。詳しくはそれぞれ設定してみて挙動を確認してください。",[1721,3799,3800],{"id":3800},"filepondからcropperへ画像を渡す",[13,3802,3803,3804,3806,3807,3810],{},"それでは編集ボタンを押したらvue-cropperへ画像を渡す様にしましょう。実際のサービスではモーダルなどを出したりした方がいいかもしれませんが、面倒なので今はそのまま表示します。",[49,3805,3150],{},"をの",[49,3808,3809],{},"open","コールバックを編集します。",[42,3812,3814],{"className":2395,"code":3813,"language":1433,"meta":47,"style":47},"editor(){\n    return {\n        \u002F\u002F Called by FilePond to edit the image\n        \u002F\u002F - should open your image editor\n        \u002F\u002F - receives file object and image edit instructions\n        open: (file, instructions) => {\n        \u002F\u002F open editor here\n            const objectURL = URL.createObjectURL(file)\n            this.imgSet =objectURL;\n            this.$refs.cropper.replace(objectURL);\n        },\n},\n",[49,3815,3816,3824,3831,3836,3841,3846,3867,3872,3896,3911,3935,3939],{"__ignoreMap":47},[52,3817,3818,3820,3822],{"class":54,"line":55},[52,3819,3150],{"class":417},[52,3821,421],{"class":105},[52,3823,363],{"class":58},[52,3825,3826,3829],{"class":54,"line":83},[52,3827,3828],{"class":359},"    return",[52,3830,2012],{"class":58},[52,3832,3833],{"class":54,"line":115},[52,3834,3835],{"class":410},"        \u002F\u002F Called by FilePond to edit the image\n",[52,3837,3838],{"class":54,"line":142},[52,3839,3840],{"class":410},"        \u002F\u002F - should open your image editor\n",[52,3842,3843],{"class":54,"line":169},[52,3844,3845],{"class":410},"        \u002F\u002F - receives file object and image edit instructions\n",[52,3847,3848,3851,3853,3855,3857,3859,3861,3863,3865],{"class":54,"line":302},[52,3849,3850],{"class":417},"        open",[52,3852,372],{"class":58},[52,3854,2980],{"class":58},[52,3856,2983],{"class":985},[52,3858,407],{"class":58},[52,3860,2988],{"class":985},[52,3862,937],{"class":58},[52,3864,2282],{"class":65},[52,3866,2012],{"class":58},[52,3868,3869],{"class":54,"line":308},[52,3870,3871],{"class":410},"        \u002F\u002F open editor here\n",[52,3873,3874,3877,3880,3882,3885,3887,3890,3892,3894],{"class":54,"line":318},[52,3875,3876],{"class":65},"            const",[52,3878,3879],{"class":105}," objectURL",[52,3881,950],{"class":58},[52,3883,3884],{"class":105}," URL",[52,3886,956],{"class":58},[52,3888,3889],{"class":417},"createObjectURL",[52,3891,931],{"class":62},[52,3893,2983],{"class":105},[52,3895,1014],{"class":62},[52,3897,3898,3901,3904,3906,3909],{"class":54,"line":328},[52,3899,3900],{"class":58},"            this.",[52,3902,3903],{"class":105},"imgSet",[52,3905,950],{"class":58},[52,3907,3908],{"class":105},"objectURL",[52,3910,1006],{"class":58},[52,3912,3913,3915,3918,3920,3922,3924,3927,3929,3931,3933],{"class":54,"line":4},[52,3914,3900],{"class":58},[52,3916,3917],{"class":105},"$refs",[52,3919,956],{"class":58},[52,3921,3382],{"class":105},[52,3923,956],{"class":58},[52,3925,3926],{"class":417},"replace",[52,3928,931],{"class":62},[52,3930,3908],{"class":105},[52,3932,937],{"class":62},[52,3934,1006],{"class":58},[52,3936,3937],{"class":54,"line":343},[52,3938,2106],{"class":58},[52,3940,3941],{"class":54,"line":353},[52,3942,476],{"class":58},[13,3944,3945,3947,3948,3950,3951,3954,3955,3957,3958,3961],{},[49,3946,3809],{},"コールバックは２つの引数があり、",[49,3949,2983],{},"はアップロードされたFileオブジェクトです。instructionsは編集する前のfilepondの編集情報です。fileオブジェクトから",[49,3952,3953],{},"URL.createObjectURL(file)","を使用することでブラウザアップロード（filepond）された画像をURLで参照できる様になります。そして",[49,3956,3460],{},"に代入し、そして",[49,3959,3960],{},"cropper.replace(objectURL);","を使用してトリミングの画像を差し替えます。",[13,3963,3964],{},"上記の様に編集して、編集ボタンを押すとトリミングUIが表示される様になり、任意のトリミング位置を設定できる様になります。",[728,3966],{":src":3967,":width":1458,":center":1322},"'filepond-crop-vue\u002Fcroppable.png'",[1721,3969,3970],{"id":3970},"cropperからfilepondへ情報を渡す",[13,3972,3973],{},"トリミングUIでは任意の範囲と位置を設定できます。トリミングした画像をfilepondに適用するためには、vue-cropperで選択したトリミングの位置や範囲などのオブジェクトをfilepondに渡すことで実現できます。（cropperで画像を加工するわけではない！）",[13,3975,3976,3977,3375,3979,3982],{},"データを渡すときは",[49,3978,3150],{},[49,3980,3981],{},"onconfirm","コールバックを利用します。vue-cropperでトリミングした際にコールバックを呼び出します。",[42,3984,3986],{"className":202,"code":3985,"filename":1883,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cfile-pond v-bind=\"attrs\"\u002F>\n    \u003Cvue-cropper\n        ref=\"cropper\"\n        :src=\"imgSrc\"\n        :aspect-ratio=\"1 \u002F 1\"\n        :view-mode=\"1\"\n    >\n    \u003C\u002Fvue-cropper>\n    \u003Cbutton variant=\"primary\" @click=\"crop\">crop\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nimport ja from 'filepond\u002Flocale\u002Fja-ja';\nimport VueCropper from 'vue-cropperjs';　 \u002F\u002F 追加\nexport default {\n    name:'fileuploader',\n    data(){\n        return{\n            files:[],\n            imgSrc:'', \u002F\u002F 追加\n        }\n    },\n    methods:{\n        onError(res){\n            \u002F\u002F ...\n        },\n        crop(){\n            \u002F\u002F 追加\n            this.editor.onconfirm()\n        }\n    },\n    computed:{\n        editor(){\n            return{\n                \u002F\u002F ...\n                onconfirm: (data) => {},\n                \u002F\u002F ...\n            }\n        }\n    },\n    components:{\n        VueCropper \u002F\u002F 追加\n    }\n}\n\u003C\u002Fscript>\n",[49,3987,3988,3996,4004,4022,4028,4040,4052,4064,4076,4080,4088,4124,4132,4140,4148,4164,4182,4190,4204,4210,4216,4226,4238,4242,4246,4252,4262,4266,4270,4276,4280,4293,4297,4301,4307,4313,4319,4324,4340,4344,4348,4352,4356,4362,4368,4372,4376],{"__ignoreMap":47},[52,3989,3990,3992,3994],{"class":54,"line":55},[52,3991,59],{"class":58},[52,3993,213],{"class":62},[52,3995,80],{"class":58},[52,3997,3998,4000,4002],{"class":54,"line":83},[52,3999,59],{"class":58},[52,4001,1905],{"class":62},[52,4003,80],{"class":58},[52,4005,4006,4008,4010,4012,4014,4016,4018,4020],{"class":54,"line":115},[52,4007,1902],{"class":58},[52,4009,1915],{"class":62},[52,4011,1929],{"class":65},[52,4013,69],{"class":58},[52,4015,72],{"class":58},[52,4017,1936],{"class":75},[52,4019,72],{"class":58},[52,4021,1941],{"class":58},[52,4023,4024,4026],{"class":54,"line":142},[52,4025,1902],{"class":58},[52,4027,3435],{"class":62},[52,4029,4030,4032,4034,4036,4038],{"class":54,"line":169},[52,4031,3440],{"class":65},[52,4033,69],{"class":58},[52,4035,72],{"class":58},[52,4037,3382],{"class":75},[52,4039,266],{"class":58},[52,4041,4042,4044,4046,4048,4050],{"class":54,"line":302},[52,4043,3453],{"class":65},[52,4045,69],{"class":58},[52,4047,72],{"class":58},[52,4049,3460],{"class":75},[52,4051,266],{"class":58},[52,4053,4054,4056,4058,4060,4062],{"class":54,"line":308},[52,4055,3467],{"class":65},[52,4057,69],{"class":58},[52,4059,72],{"class":58},[52,4061,3474],{"class":75},[52,4063,266],{"class":58},[52,4065,4066,4068,4070,4072,4074],{"class":54,"line":318},[52,4067,3481],{"class":65},[52,4069,69],{"class":58},[52,4071,72],{"class":58},[52,4073,31],{"class":75},[52,4075,266],{"class":58},[52,4077,4078],{"class":54,"line":328},[52,4079,3494],{"class":58},[52,4081,4082,4084,4086],{"class":54,"line":4},[52,4083,1946],{"class":58},[52,4085,3501],{"class":62},[52,4087,80],{"class":58},[52,4089,4090,4092,4094,4096,4098,4100,4102,4104,4106,4108,4110,4112,4114,4116,4118,4120,4122],{"class":54,"line":343},[52,4091,1902],{"class":58},[52,4093,3510],{"class":62},[52,4095,3513],{"class":65},[52,4097,69],{"class":58},[52,4099,72],{"class":58},[52,4101,3520],{"class":75},[52,4103,72],{"class":58},[52,4105,3525],{"class":65},[52,4107,69],{"class":58},[52,4109,72],{"class":58},[52,4111,3532],{"class":75},[52,4113,72],{"class":58},[52,4115,102],{"class":58},[52,4117,3532],{"class":105},[52,4119,108],{"class":58},[52,4121,3510],{"class":62},[52,4123,80],{"class":58},[52,4125,4126,4128,4130],{"class":54,"line":353},[52,4127,108],{"class":58},[52,4129,1905],{"class":62},[52,4131,80],{"class":58},[52,4133,4134,4136,4138],{"class":54,"line":366},[52,4135,108],{"class":58},[52,4137,213],{"class":62},[52,4139,80],{"class":58},[52,4141,4142,4144,4146],{"class":54,"line":386},[52,4143,59],{"class":58},[52,4145,348],{"class":62},[52,4147,80],{"class":58},[52,4149,4150,4152,4154,4156,4158,4160,4162],{"class":54,"line":414},[52,4151,1847],{"class":359},[52,4153,1973],{"class":105},[52,4155,1976],{"class":359},[52,4157,1979],{"class":58},[52,4159,1982],{"class":75},[52,4161,375],{"class":58},[52,4163,1006],{"class":58},[52,4165,4166,4168,4170,4172,4174,4176,4178,4180],{"class":54,"line":426},[52,4167,1847],{"class":359},[52,4169,1993],{"class":105},[52,4171,1976],{"class":359},[52,4173,1979],{"class":58},[52,4175,1674],{"class":75},[52,4177,375],{"class":58},[52,4179,2764],{"class":58},[52,4181,3603],{"class":410},[52,4183,4184,4186,4188],{"class":54,"line":434},[52,4185,356],{"class":359},[52,4187,360],{"class":359},[52,4189,2012],{"class":58},[52,4191,4192,4194,4196,4198,4200,4202],{"class":54,"line":445},[52,4193,2017],{"class":62},[52,4195,372],{"class":58},[52,4197,375],{"class":58},[52,4199,2024],{"class":75},[52,4201,375],{"class":58},[52,4203,383],{"class":58},[52,4205,4206,4208],{"class":54,"line":479},[52,4207,2033],{"class":62},[52,4209,2036],{"class":58},[52,4211,4212,4214],{"class":54,"line":508},[52,4213,2041],{"class":359},[52,4215,363],{"class":58},[52,4217,4218,4220,4222,4224],{"class":54,"line":538},[52,4219,2048],{"class":62},[52,4221,372],{"class":58},[52,4223,2053],{"class":62},[52,4225,383],{"class":58},[52,4227,4228,4230,4232,4234,4236],{"class":54,"line":546},[52,4229,3652],{"class":62},[52,4231,372],{"class":58},[52,4233,3657],{"class":58},[52,4235,407],{"class":58},[52,4237,3155],{"class":410},[52,4239,4240],{"class":54,"line":552},[52,4241,2060],{"class":58},[52,4243,4244],{"class":54,"line":558},[52,4245,2065],{"class":58},[52,4247,4248,4250],{"class":54,"line":563},[52,4249,2070],{"class":62},[52,4251,923],{"class":58},[52,4253,4254,4256,4258,4260],{"class":54,"line":568},[52,4255,2077],{"class":62},[52,4257,931],{"class":58},[52,4259,2082],{"class":985},[52,4261,2085],{"class":58},[52,4263,4264],{"class":54,"line":1105},[52,4265,3690],{"class":410},[52,4267,4268],{"class":54,"line":1134},[52,4269,2106],{"class":58},[52,4271,4272,4274],{"class":54,"line":1163},[52,4273,3699],{"class":62},[52,4275,2036],{"class":58},[52,4277,4278],{"class":54,"line":1192},[52,4279,3706],{"class":410},[52,4281,4282,4284,4286,4288,4290],{"class":54,"line":1199},[52,4283,3900],{"class":58},[52,4285,3150],{"class":105},[52,4287,956],{"class":58},[52,4289,3981],{"class":417},[52,4291,4292],{"class":62},"()\n",[52,4294,4295],{"class":54,"line":1204},[52,4296,2060],{"class":58},[52,4298,4299],{"class":54,"line":1209},[52,4300,2065],{"class":58},[52,4302,4303,4305],{"class":54,"line":1214},[52,4304,2115],{"class":62},[52,4306,923],{"class":58},[52,4308,4309,4311],{"class":54,"line":1219},[52,4310,2947],{"class":62},[52,4312,2036],{"class":58},[52,4314,4315,4317],{"class":54,"line":2302},[52,4316,2148],{"class":359},[52,4318,363],{"class":58},[52,4320,4321],{"class":54,"line":2308},[52,4322,4323],{"class":410},"                \u002F\u002F ...\n",[52,4325,4326,4328,4330,4332,4334,4336,4338],{"class":54,"line":2317},[52,4327,3031],{"class":417},[52,4329,372],{"class":58},[52,4331,2980],{"class":58},[52,4333,3038],{"class":985},[52,4335,937],{"class":58},[52,4337,2282],{"class":65},[52,4339,3045],{"class":58},[52,4341,4342],{"class":54,"line":2323},[52,4343,4323],{"class":410},[52,4345,4346],{"class":54,"line":2328},[52,4347,2320],{"class":58},[52,4349,4350],{"class":54,"line":2333},[52,4351,2060],{"class":58},[52,4353,4354],{"class":54,"line":2338},[52,4355,2065],{"class":58},[52,4357,4358,4360],{"class":54,"line":3141},[52,4359,3738],{"class":62},[52,4361,923],{"class":58},[52,4363,4364,4366],{"class":54,"line":3158},[52,4365,3745],{"class":105},[52,4367,3748],{"class":410},[52,4369,4370],{"class":54,"line":3169},[52,4371,3753],{"class":58},[52,4373,4374],{"class":54,"line":3188},[52,4375,535],{"class":58},[52,4377,4378,4380,4382],{"class":54,"line":3199},[52,4379,108],{"class":58},[52,4381,348],{"class":62},[52,4383,80],{"class":58},[13,4385,4386,4387,4389],{},"この時",[49,4388,3981],{},"に渡すデータは以下の様に定義する必要があります。",[42,4391,4394],{"className":4392,"code":4393,"language":451},[1727],"{\n    data: {\n        \u002F\u002F This is the same as the instructions object\n        crop: {\n            center: {\n                x: .5,\n                y: .5\n            },\n            flip: {\n                horizontal: false,\n                vertical: false\n            },\n            zoom: 1,\n            rotation: 0,\n            aspectRatio: null\n        }\n    }\n}\n",[49,4395,4393],{"__ignoreMap":47},[13,4397,4398,4399,3375,4401,4404,4405,4408,4409,4411],{},"このデータは",[49,4400,3150],{},[49,4402,4403],{},"open(file, instructions)","コールバックの",[49,4406,4407],{},"instructions","と同じ構造です。filepondはこの",[49,4410,4407],{},"の値を変更することで、プレビューの画像表示や実際にアップロードする画像のトリミングなどが実行されます。",[13,4413,4414,4415,4418,4419,4422],{},"そのためvue-cropperのトリミングによる座標位置や、トリミング範囲上記のデータに合わせて設定する必要があります。vue-cropperには",[49,4416,4417],{},"getCanvasData()","や",[49,4420,4421],{},"getData()","などのメソッドがあるため、それらを用いてvue-cropperのデータをコールバックを通してfilepondへ渡します。",[4424,4425,4426],"h4",{"id":4426},"計算を行う",[13,4428,4429,4430,4435,4436,4439],{},"しかしfilepondに渡すデータは結構クセがあり、cropperから取得できる情報の何をどこに当てはめればいいのかわかりません。",[1445,4431,4434],{"href":4432,"rel":4433},"https:\u002F\u002Fgithub.com\u002Fpqina\u002Ffilepond-plugin-image-edit\u002Fissues\u002F1",[1449],"github issueにてcropper.jsとの連携に関するissue","を発見し、今回はその値を用いることにします。",[49,4437,4438],{},"crop()","を以下の様に変更します。",[42,4441,4443],{"className":2395,"code":4442,"language":1433,"meta":47,"style":47},"crop(){\n    \u002F\u002F https:\u002F\u002Fgithub.com\u002Fpqina\u002Ffilepond-plugin-image-edit\u002Fissues\u002F1\n    \u002F* Constants. *\u002F\n    const canvasData = this.$refs.cropper.getCanvasData() \u002F\u002F Cropperjs method getCanvasData()\n    const cropData = this.$refs.cropper.getData() \u002F\u002F Cropperjs method getData()\n\n    \u002F* Ratio of selected crop area. *\u002F\n    const cropAreaRatio = cropData.height \u002F cropData.width\n\n    \u002F* Center point of crop area in percent. *\u002F\n    const percentX = (cropData.x + cropData.width \u002F 2) \u002F canvasData.naturalWidth\n    const percentY = (cropData.y + cropData.height \u002F 2) \u002F canvasData.naturalHeight\n\n    \u002F* Calculate available space round image center position. *\u002F\n    const cx = percentX > 0.5 ? 1 - percentX : percentX\n    const cy = percentY > 0.5 ? 1 - percentY : percentY\n\n    \u002F* Calculate image rectangle respecting space round image from crop area. *\u002F\n    let width = canvasData.naturalWidth\n    let height = width * cropAreaRatio\n    if (height > canvasData.naturalHeight) {\n    height = canvasData.naturalHeight\n    width = height \u002F cropAreaRatio\n    }\n    const rectWidth = cx * 2 * width\n    const rectHeight = cy * 2 * height\n\n    \u002F* Calculate zoom. *\u002F\n    const zoom = Math.max(rectWidth \u002F cropData.width, rectHeight \u002F cropData.height)\n    this.editor.onconfirm({\n    data: {\n        crop: {\n            center: {\n                x: percentX,\n                y: percentY\n            },\n            flip: {\n                horizontal: cropData.scaleX \u003C 0,\n                vertical: cropData.scaleY \u003C 0\n            },\n            zoom: zoom,\n            rotation: (Math.PI \u002F 180) * cropData.rotate,\n            aspectRatio: cropAreaRatio\n        }\n    }\n    })\n}\n",[49,4444,4445,4453,4458,4463,4492,4519,4523,4528,4554,4558,4563,4611,4652,4656,4661,4695,4723,4727,4732,4747,4764,4786,4799,4812,4816,4836,4856,4860,4865,4909,4923,4931,4939,4948,4959,4968,4973,4982,5003,5022,5026,5037,5073,5082,5086,5090,5097],{"__ignoreMap":47},[52,4446,4447,4449,4451],{"class":54,"line":55},[52,4448,3532],{"class":417},[52,4450,421],{"class":105},[52,4452,363],{"class":58},[52,4454,4455],{"class":54,"line":83},[52,4456,4457],{"class":410},"    \u002F\u002F https:\u002F\u002Fgithub.com\u002Fpqina\u002Ffilepond-plugin-image-edit\u002Fissues\u002F1\n",[52,4459,4460],{"class":54,"line":115},[52,4461,4462],{"class":410},"    \u002F* Constants. *\u002F\n",[52,4464,4465,4468,4471,4473,4475,4477,4479,4481,4483,4486,4489],{"class":54,"line":142},[52,4466,4467],{"class":65},"    const",[52,4469,4470],{"class":105}," canvasData",[52,4472,950],{"class":58},[52,4474,2285],{"class":58},[52,4476,3917],{"class":105},[52,4478,956],{"class":58},[52,4480,3382],{"class":105},[52,4482,956],{"class":58},[52,4484,4485],{"class":417},"getCanvasData",[52,4487,4488],{"class":62},"() ",[52,4490,4491],{"class":410},"\u002F\u002F Cropperjs method getCanvasData()\n",[52,4493,4494,4496,4499,4501,4503,4505,4507,4509,4511,4514,4516],{"class":54,"line":169},[52,4495,4467],{"class":65},[52,4497,4498],{"class":105}," cropData",[52,4500,950],{"class":58},[52,4502,2285],{"class":58},[52,4504,3917],{"class":105},[52,4506,956],{"class":58},[52,4508,3382],{"class":105},[52,4510,956],{"class":58},[52,4512,4513],{"class":417},"getData",[52,4515,4488],{"class":62},[52,4517,4518],{"class":410},"\u002F\u002F Cropperjs method getData()\n",[52,4520,4521],{"class":54,"line":302},[52,4522,340],{"emptyLinePlaceholder":339},[52,4524,4525],{"class":54,"line":308},[52,4526,4527],{"class":410},"    \u002F* Ratio of selected crop area. *\u002F\n",[52,4529,4530,4532,4535,4537,4539,4541,4544,4547,4549,4551],{"class":54,"line":318},[52,4531,4467],{"class":65},[52,4533,4534],{"class":105}," cropAreaRatio",[52,4536,950],{"class":58},[52,4538,4498],{"class":105},[52,4540,956],{"class":58},[52,4542,4543],{"class":105},"height",[52,4545,4546],{"class":58}," \u002F",[52,4548,4498],{"class":105},[52,4550,956],{"class":58},[52,4552,4553],{"class":105},"width\n",[52,4555,4556],{"class":54,"line":328},[52,4557,340],{"emptyLinePlaceholder":339},[52,4559,4560],{"class":54,"line":4},[52,4561,4562],{"class":410},"    \u002F* Center point of crop area in percent. *\u002F\n",[52,4564,4565,4567,4570,4572,4574,4577,4579,4582,4585,4587,4589,4592,4594,4598,4601,4604,4606,4608],{"class":54,"line":343},[52,4566,4467],{"class":65},[52,4568,4569],{"class":105}," percentX",[52,4571,950],{"class":58},[52,4573,2980],{"class":62},[52,4575,4576],{"class":105},"cropData",[52,4578,956],{"class":58},[52,4580,4581],{"class":105},"x",[52,4583,4584],{"class":58}," +",[52,4586,4498],{"class":105},[52,4588,956],{"class":58},[52,4590,4591],{"class":105},"width",[52,4593,4546],{"class":58},[52,4595,4597],{"class":4596},"sx098"," 2",[52,4599,4600],{"class":62},") ",[52,4602,4603],{"class":58},"\u002F",[52,4605,4470],{"class":105},[52,4607,956],{"class":58},[52,4609,4610],{"class":105},"naturalWidth\n",[52,4612,4613,4615,4618,4620,4622,4624,4626,4629,4631,4633,4635,4637,4639,4641,4643,4645,4647,4649],{"class":54,"line":353},[52,4614,4467],{"class":65},[52,4616,4617],{"class":105}," percentY",[52,4619,950],{"class":58},[52,4621,2980],{"class":62},[52,4623,4576],{"class":105},[52,4625,956],{"class":58},[52,4627,4628],{"class":105},"y",[52,4630,4584],{"class":58},[52,4632,4498],{"class":105},[52,4634,956],{"class":58},[52,4636,4543],{"class":105},[52,4638,4546],{"class":58},[52,4640,4597],{"class":4596},[52,4642,4600],{"class":62},[52,4644,4603],{"class":58},[52,4646,4470],{"class":105},[52,4648,956],{"class":58},[52,4650,4651],{"class":105},"naturalHeight\n",[52,4653,4654],{"class":54,"line":366},[52,4655,340],{"emptyLinePlaceholder":339},[52,4657,4658],{"class":54,"line":386},[52,4659,4660],{"class":410},"    \u002F* Calculate available space round image center position. *\u002F\n",[52,4662,4663,4665,4668,4670,4672,4675,4678,4681,4684,4687,4689,4692],{"class":54,"line":414},[52,4664,4467],{"class":65},[52,4666,4667],{"class":105}," cx",[52,4669,950],{"class":58},[52,4671,4569],{"class":105},[52,4673,4674],{"class":58}," >",[52,4676,4677],{"class":4596}," 0.5",[52,4679,4680],{"class":58}," ?",[52,4682,4683],{"class":4596}," 1",[52,4685,4686],{"class":58}," -",[52,4688,4569],{"class":105},[52,4690,4691],{"class":58}," :",[52,4693,4694],{"class":105}," percentX\n",[52,4696,4697,4699,4702,4704,4706,4708,4710,4712,4714,4716,4718,4720],{"class":54,"line":426},[52,4698,4467],{"class":65},[52,4700,4701],{"class":105}," cy",[52,4703,950],{"class":58},[52,4705,4617],{"class":105},[52,4707,4674],{"class":58},[52,4709,4677],{"class":4596},[52,4711,4680],{"class":58},[52,4713,4683],{"class":4596},[52,4715,4686],{"class":58},[52,4717,4617],{"class":105},[52,4719,4691],{"class":58},[52,4721,4722],{"class":105}," percentY\n",[52,4724,4725],{"class":54,"line":434},[52,4726,340],{"emptyLinePlaceholder":339},[52,4728,4729],{"class":54,"line":445},[52,4730,4731],{"class":410},"    \u002F* Calculate image rectangle respecting space round image from crop area. *\u002F\n",[52,4733,4734,4736,4739,4741,4743,4745],{"class":54,"line":479},[52,4735,944],{"class":65},[52,4737,4738],{"class":105}," width",[52,4740,950],{"class":58},[52,4742,4470],{"class":105},[52,4744,956],{"class":58},[52,4746,4610],{"class":105},[52,4748,4749,4751,4754,4756,4758,4761],{"class":54,"line":508},[52,4750,944],{"class":65},[52,4752,4753],{"class":105}," height",[52,4755,950],{"class":58},[52,4757,4738],{"class":105},[52,4759,4760],{"class":58}," *",[52,4762,4763],{"class":105}," cropAreaRatio\n",[52,4765,4766,4769,4771,4773,4775,4777,4779,4782,4784],{"class":54,"line":538},[52,4767,4768],{"class":359},"    if",[52,4770,2980],{"class":62},[52,4772,4543],{"class":105},[52,4774,4674],{"class":58},[52,4776,4470],{"class":105},[52,4778,956],{"class":58},[52,4780,4781],{"class":105},"naturalHeight",[52,4783,4600],{"class":62},[52,4785,363],{"class":58},[52,4787,4788,4791,4793,4795,4797],{"class":54,"line":546},[52,4789,4790],{"class":105},"    height",[52,4792,950],{"class":58},[52,4794,4470],{"class":105},[52,4796,956],{"class":58},[52,4798,4651],{"class":105},[52,4800,4801,4804,4806,4808,4810],{"class":54,"line":552},[52,4802,4803],{"class":105},"    width",[52,4805,950],{"class":58},[52,4807,4753],{"class":105},[52,4809,4546],{"class":58},[52,4811,4763],{"class":105},[52,4813,4814],{"class":54,"line":558},[52,4815,3753],{"class":58},[52,4817,4818,4820,4823,4825,4827,4829,4831,4833],{"class":54,"line":563},[52,4819,4467],{"class":65},[52,4821,4822],{"class":105}," rectWidth",[52,4824,950],{"class":58},[52,4826,4667],{"class":105},[52,4828,4760],{"class":58},[52,4830,4597],{"class":4596},[52,4832,4760],{"class":58},[52,4834,4835],{"class":105}," width\n",[52,4837,4838,4840,4843,4845,4847,4849,4851,4853],{"class":54,"line":568},[52,4839,4467],{"class":65},[52,4841,4842],{"class":105}," rectHeight",[52,4844,950],{"class":58},[52,4846,4701],{"class":105},[52,4848,4760],{"class":58},[52,4850,4597],{"class":4596},[52,4852,4760],{"class":58},[52,4854,4855],{"class":105}," height\n",[52,4857,4858],{"class":54,"line":1105},[52,4859,340],{"emptyLinePlaceholder":339},[52,4861,4862],{"class":54,"line":1134},[52,4863,4864],{"class":410},"    \u002F* Calculate zoom. *\u002F\n",[52,4866,4867,4869,4872,4874,4877,4879,4882,4884,4887,4889,4891,4893,4895,4897,4899,4901,4903,4905,4907],{"class":54,"line":1163},[52,4868,4467],{"class":65},[52,4870,4871],{"class":105}," zoom",[52,4873,950],{"class":58},[52,4875,4876],{"class":105}," Math",[52,4878,956],{"class":58},[52,4880,4881],{"class":417},"max",[52,4883,931],{"class":62},[52,4885,4886],{"class":105},"rectWidth",[52,4888,4546],{"class":58},[52,4890,4498],{"class":105},[52,4892,956],{"class":58},[52,4894,4591],{"class":105},[52,4896,407],{"class":58},[52,4898,4842],{"class":105},[52,4900,4546],{"class":58},[52,4902,4498],{"class":105},[52,4904,956],{"class":58},[52,4906,4543],{"class":105},[52,4908,1014],{"class":62},[52,4910,4911,4913,4915,4917,4919,4921],{"class":54,"line":1192},[52,4912,1051],{"class":58},[52,4914,3150],{"class":105},[52,4916,956],{"class":58},[52,4918,3981],{"class":417},[52,4920,931],{"class":62},[52,4922,363],{"class":58},[52,4924,4925,4927,4929],{"class":54,"line":1199},[52,4926,2033],{"class":62},[52,4928,372],{"class":58},[52,4930,2012],{"class":58},[52,4932,4933,4935,4937],{"class":54,"line":1204},[52,4934,3699],{"class":62},[52,4936,372],{"class":58},[52,4938,2012],{"class":58},[52,4940,4941,4944,4946],{"class":54,"line":1209},[52,4942,4943],{"class":62},"            center",[52,4945,372],{"class":58},[52,4947,2012],{"class":58},[52,4949,4950,4953,4955,4957],{"class":54,"line":1214},[52,4951,4952],{"class":62},"                x",[52,4954,372],{"class":58},[52,4956,4569],{"class":105},[52,4958,383],{"class":58},[52,4960,4961,4964,4966],{"class":54,"line":1219},[52,4962,4963],{"class":62},"                y",[52,4965,372],{"class":58},[52,4967,4722],{"class":105},[52,4969,4970],{"class":54,"line":2302},[52,4971,4972],{"class":58},"            },\n",[52,4974,4975,4978,4980],{"class":54,"line":2308},[52,4976,4977],{"class":62},"            flip",[52,4979,372],{"class":58},[52,4981,2012],{"class":58},[52,4983,4984,4987,4989,4991,4993,4996,4998,5001],{"class":54,"line":2317},[52,4985,4986],{"class":62},"                horizontal",[52,4988,372],{"class":58},[52,4990,4498],{"class":105},[52,4992,956],{"class":58},[52,4994,4995],{"class":105},"scaleX",[52,4997,86],{"class":58},[52,4999,5000],{"class":4596}," 0",[52,5002,383],{"class":58},[52,5004,5005,5008,5010,5012,5014,5017,5019],{"class":54,"line":2323},[52,5006,5007],{"class":62},"                vertical",[52,5009,372],{"class":58},[52,5011,4498],{"class":105},[52,5013,956],{"class":58},[52,5015,5016],{"class":105},"scaleY",[52,5018,86],{"class":58},[52,5020,5021],{"class":4596}," 0\n",[52,5023,5024],{"class":54,"line":2328},[52,5025,4972],{"class":58},[52,5027,5028,5031,5033,5035],{"class":54,"line":2333},[52,5029,5030],{"class":62},"            zoom",[52,5032,372],{"class":58},[52,5034,4871],{"class":105},[52,5036,383],{"class":58},[52,5038,5039,5042,5044,5046,5049,5051,5054,5056,5059,5061,5064,5066,5068,5071],{"class":54,"line":2338},[52,5040,5041],{"class":62},"            rotation",[52,5043,372],{"class":58},[52,5045,2980],{"class":62},[52,5047,5048],{"class":105},"Math",[52,5050,956],{"class":58},[52,5052,5053],{"class":105},"PI",[52,5055,4546],{"class":58},[52,5057,5058],{"class":4596}," 180",[52,5060,4600],{"class":62},[52,5062,5063],{"class":58},"*",[52,5065,4498],{"class":105},[52,5067,956],{"class":58},[52,5069,5070],{"class":105},"rotate",[52,5072,383],{"class":58},[52,5074,5075,5078,5080],{"class":54,"line":3141},[52,5076,5077],{"class":62},"            aspectRatio",[52,5079,372],{"class":58},[52,5081,4763],{"class":105},[52,5083,5084],{"class":54,"line":3158},[52,5085,2060],{"class":58},[52,5087,5088],{"class":54,"line":3169},[52,5089,3753],{"class":58},[52,5091,5092,5095],{"class":54,"line":3188},[52,5093,5094],{"class":58},"    }",[52,5096,1014],{"class":62},[52,5098,5099],{"class":54,"line":3199},[52,5100,535],{"class":58},[17,5102,5103],{"id":5103},"アップロードを行う",[13,5105,5106],{},"これでvue-cropperのトリミング情報をfilepondに渡すことができる様になりました。実際にトリミング範囲を指定してcropボタンをクリックしますと、その位置と範囲にしたがってトリミングされた範囲がプレビューされます。",[728,5108],{":src":5109,":width":1458,":center":1322},"'filepond-crop-vue\u002Fcropped.png'",[13,5111,5112,5113,5116],{},"そして最後にアップロードボタンをクリックすると渡されたデータを元に、filepondが元画像のトリミングを行いアップロードします。トリミングしてもらうためには",[49,5114,5115],{},"FilePondPluginImageTransform","がインストールされ、有効になっている必要があります。サーバー側では１：１にトリミングされた画像を確認することができます。",[17,5118,5119],{"id":5119},"まとめ",[13,5121,5122,5123,5128],{},"filepondは主にブラウザアップロードと実際のトリミング処理を行います。そしてトリミング箇所の指定は別のライブラリを用いて実装する必要があります。filepondは",[1445,5124,5127],{"href":5125,"rel":5126},"https:\u002F\u002Fpqina.nl\u002Fpintura\u002F",[1449],"Doka Image Editor","という有償ライブラリとの互換性を第一にしているそうで、cropper.jsとの連携と特に計算が方法がわかりませんでした。ひとまず上記の方法でトリミングとアップロード機能が実装できました。後はUIを整えてあげれば完成です。",[1413,5130,5131],{},"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 pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":47,"searchDepth":115,"depth":115,"links":5133},[5134,5135,5139,5142,5150,5151],{"id":1694,"depth":83,"text":1694},{"id":1716,"depth":83,"text":1716,"children":5136},[5137,5138],{"id":1723,"depth":115,"text":1723},{"id":1757,"depth":115,"text":1758},{"id":1876,"depth":83,"text":1877,"children":5140},[5141],{"id":2353,"depth":115,"text":2353},{"id":2653,"depth":83,"text":2654,"children":5143},[5144,5145,5146,5147],{"id":2842,"depth":115,"text":2843},{"id":3386,"depth":115,"text":3386},{"id":3800,"depth":115,"text":3800},{"id":3970,"depth":115,"text":3970,"children":5148},[5149],{"id":4426,"depth":142,"text":4426},{"id":5103,"depth":83,"text":5103},{"id":5119,"depth":83,"text":5119},[1423],"2025-12-09","Vueでブラウザでのトリミング機能とファイルアップロードを実装する",{},"\u002Farticles\u002Ffilepond-crop-vue",{"title":1438,"description":5154},"articles\u002Ffilepond-crop-vue",[1433,204],"filepond-crop-vue\u002Fthumbnail.png","an_V9C83Uuzs33hco6VOdrE9TtIqJVF5teLfyG0kaaE",{"id":5163,"title":5164,"body":5165,"category":7470,"createdAt":7471,"description":7472,"extension":1426,"index":55,"meta":7473,"navigation":339,"path":7474,"publish":339,"seo":7475,"series":7476,"seriesTitle":7477,"stem":7478,"tag":7479,"thumbnail":7480,"updatedAt":1427,"__hash__":7481},"series\u002Fseries\u002Fvue-laravel-app-1.md","Vue SPA x Laravelでつくる実務パチモンアプリその１：アプリの概要と環境構築",{"type":10,"value":5166,"toc":7446},[5167,5170,5187,5198,5201,5221,5224,5227,5230,5233,5236,5239,5270,5273,5310,5313,5324,5327,5330,5333,5336,5339,5348,5362,5369,5431,5445,5450,5454,5457,5510,5513,5516,5519,5537,5594,5601,5605,5608,5932,5949,5958,6016,6019,6025,6039,6048,6054,6069,6072,6075,6079,6086,6092,6095,6099,6102,6106,6112,6135,6141,6273,6284,6287,6309,6315,6321,6325,6332,6338,6341,6394,6397,6527,6534,6537,6650,6733,6736,7063,7070,7077,7080,7099,7272,7281,7293,7330,7333,7372,7378,7391,7402,7405,7418,7421,7430,7433,7436,7440,7443],[13,5168,5169],{},"こんにちはjunです。仕事で中規模プロジェクトのディレクターとしてアサインされて、半年ほどブログを書けませんでした。ようやく最近時間が出てきたので新しいシリーズ記事を作成しようと思いました。とにかく最近１年はシステムばっかり作っていました。それぞのれプロジェクトでは",[1854,5171,5172,5175,5178,5181,5184],{},[1699,5173,5174],{},"CRUDなAPI",[1699,5176,5177],{},"管理画面の構築",[1699,5179,5180],{},"ユーザー権限によるアクセス制限",[1699,5182,5183],{},"ログイン・ログアウト",[1699,5185,5186],{},"ジョブ・キューを用いた長い処理",[13,5188,5189,5190,5193,5194,5197],{},"など使用するシステムの構築を多く行い、いろいろ学ぶことできました。その中で「CRUDなAPI」を考えた「管理画面」の構築をすることが多くありました。バックエンドは",[49,5191,5192],{},"Laravel","を、フロントエンドは",[49,5195,5196],{},"Vue.js","を使用していました。Vue.jsのおかげで高速にリッチなUIを構築し、システムを開発することができました。",[13,5199,5200],{},"この知見を共有し、まとめるためにも今回は",[1854,5202,5203,5206,5209,5212,5215,5218],{},[1699,5204,5205],{},"管理画面はVue.js SPA",[1699,5207,5208],{},"web APIによるCRUD操作",[1699,5210,5211],{},"ルーティング設計",[1699,5213,5214],{},"バリデーション",[1699,5216,5217],{},"MVCによるアプリケーション設計",[1699,5219,5220],{},"laravel\u002Fpermissionを用いたユーザー権限",[13,5222,5223],{},"以上の様な機能を持ったデモアプリを作ろうと思います。Laravelを用いたシステム開発と、Vue.jsによる管理画面フロントエンド開発を解説していきます。",[17,5225,5226],{"id":5226},"作るアプリの概要",[13,5228,5229],{},"今回のアプリはn○teみたいなブログサービスを作ります。CRUDや管理画面の構築をメインに行いたいのでシンプルにいきます。",[1721,5231,5232],{"id":5232},"機能概要",[13,5234,5235],{},"ざっくりとした機能概要は以下のとおりです。",[4424,5237,5238],{"id":5238},"ユーザー系の特徴",[1854,5240,5241,5244,5247,5250,5253,5256],{},[1699,5242,5243],{},"利用する際にはユーザーとしてアカウントを作る（今回は全てゲストとする）。",[1699,5245,5246],{},"ログインはアドレスとパスワードを使用する。",[1699,5248,5249],{},"アプリを利用する一般ユーザーと管理を行う管理ユーザーが存在する。",[1699,5251,5252],{},"管理ユーザーは特定の管理用ルートから入る。",[1699,5254,5255],{},"退会可能。退会時は関連するデータは削除される。",[1699,5257,5258,5259],{},"プロフィールでは以下の項目を持つ\n",[1854,5260,5261,5264,5267],{},[1699,5262,5263],{},"ユーザー名（仮名）",[1699,5265,5266],{},"プロフィール文",[1699,5268,5269],{},"アバター写真",[4424,5271,5272],{"id":5272},"ブログ機能",[1854,5274,5275,5278,5295,5298,5301,5304,5307],{},[1699,5276,5277],{},"ブログを作成することができ、公開することができる。",[1699,5279,5280,5281],{},"ブログは以下の項目を持つ\n",[1854,5282,5283,5286,5289,5292],{},[1699,5284,5285],{},"タイトル",[1699,5287,5288],{},"内容（リッチテキスト）",[1699,5290,5291],{},"タグ（任意）",[1699,5293,5294],{},"公開日時",[1699,5296,5297],{},"下書きとして保存することができる。更新時も下書き可能。",[1699,5299,5300],{},"任意数のタグを添付できる。タグはユーザーが新しく作成できる。",[1699,5302,5303],{},"削除可能",[1699,5305,5306],{},"画像の添付が可能。",[1699,5308,5309],{},"アップロードした画像は管理できる。",[4424,5311,5312],{"id":5312},"一覧検索機能",[1854,5314,5315,5318,5321],{},[1699,5316,5317],{},"サイトトップは投稿された記事が新着順に並ぶ。",[1699,5319,5320],{},"任意のタグを選んで一覧表示することが可能。",[1699,5322,5323],{},"部分一致検索も一応可能とする。",[1721,5325,5326],{"id":5326},"アプリケーションアーキテクチャー",[13,5328,5329],{},"バックエンドにはLaravel9、管理画面はVue.js(2系)を使用して構築します。なおVue.jsはSPA構成とします。記事の一覧や詳細画面などの公開側はLaravelのレンダリングで表示します。",[728,5331],{":src":5332,":center":1322},"'vue_laravel_app\u002Farchitecture.jpg'",[13,5334,5335],{},"デザインに関してはセンスが皆無なので管理画面・公開側ともにBootstrapを使用します。",[17,5337,5338],{"id":5338},"環境構築",[13,5340,5341,5342,5347],{},"ではまずは環境構築を行っていきましょう。環境構築にはDockerを使用してLAMP環境を作ります。",[1445,5343,5346],{"href":5344,"rel":5345},"https:\u002F\u002Fwww.twilio.com\u002Fblog\u002Fget-started-docker-laravel-jp",[1449],"こちらの記事","を参考にし、",[1854,5349,5350,5353,5356,5359],{},[1699,5351,5352],{},"mysql5.7",[1699,5354,5355],{},"phpmyadmin",[1699,5357,5358],{},"apache2.4",[1699,5360,5361],{},"php8.1",[13,5363,5364,5365,5368],{},"以上の構成を作成したいと思います。ディレクトリを作成して",[49,5366,5367],{},"docker-compose.yaml","を作成します。",[42,5370,5374],{"className":5371,"code":5372,"language":5373,"meta":47,"style":47},"language-bash shiki shiki-themes material-theme-ocean","mkdir ~\u002Flaravel_vue\ncd  ~\u002Flaravel_vue\n\ntouch docker-compose.yaml\nmkdir html\nmkdir web_1\ncd web_1\ntouch Dockerfile\n","bash",[49,5375,5376,5384,5392,5396,5404,5411,5418,5424],{"__ignoreMap":47},[52,5377,5378,5381],{"class":54,"line":55},[52,5379,5380],{"class":369},"mkdir",[52,5382,5383],{"class":75}," ~\u002Flaravel_vue\n",[52,5385,5386,5389],{"class":54,"line":83},[52,5387,5388],{"class":417},"cd",[52,5390,5391],{"class":75},"  ~\u002Flaravel_vue\n",[52,5393,5394],{"class":54,"line":115},[52,5395,340],{"emptyLinePlaceholder":339},[52,5397,5398,5401],{"class":54,"line":142},[52,5399,5400],{"class":369},"touch",[52,5402,5403],{"class":75}," docker-compose.yaml\n",[52,5405,5406,5408],{"class":54,"line":169},[52,5407,5380],{"class":369},[52,5409,5410],{"class":75}," html\n",[52,5412,5413,5415],{"class":54,"line":302},[52,5414,5380],{"class":369},[52,5416,5417],{"class":75}," web_1\n",[52,5419,5420,5422],{"class":54,"line":308},[52,5421,5388],{"class":417},[52,5423,5417],{"class":75},[52,5425,5426,5428],{"class":54,"line":318},[52,5427,5400],{"class":369},[52,5429,5430],{"class":75}," Dockerfile\n",[13,5432,5433,5436,5437,5440,5441,5444],{},[49,5434,5435],{},"html\u002F","という名前で作成したディレクトリにLaravelのソースが作成され、Dockerコンテナにマウントされる様にします。",[49,5438,5439],{},"web_1\u002F","ディレクトリにはphpとapacheが構築できる",[49,5442,5443],{},"Dockerfile","を作成してビルドします。",[13,5446,5447,5449],{},[49,5448,5367],{},"でDBとapache+phpと連結したいと思います。",[1721,5451,5453],{"id":5452},"dockerfile設定","Dockerfile設定",[13,5455,5456],{},"まずはapacheとphpのイメージをDockerfileを作成します。",[42,5458,5463],{"className":5459,"code":5460,"filename":5461,"language":5462,"meta":47,"style":47},"language-dockerfie shiki shiki-themes material-theme-ocean","FROM php:8.1-apache\nRUN apt update \\\n        && apt install -y g++ libicu-dev libpq-dev libzip-dev zip zlib1g-dev \\\n        && mv \u002Fetc\u002Fapache2\u002Fmods-available\u002Frewrite.load \u002Fetc\u002Fapache2\u002Fmods-enabled\nRUN docker-php-ext-install pdo pdo_mysql\nWORKDIR \u002Fvar\u002Fwww\u002Fhtml\nRUN curl -sS https:\u002F\u002Fgetcomposer.org\u002Finstaller | php -- --install-dir=\u002Fusr\u002Flocal\u002Fbin --filename=composer\nRUN curl -fsSL https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_lts.x | bash - \\\n    && apt-get install -y nodejs\n","web_1\u002FDockerfile","dockerfie",[49,5464,5465,5470,5475,5480,5485,5490,5495,5500,5505],{"__ignoreMap":47},[52,5466,5467],{"class":54,"line":55},[52,5468,5469],{},"FROM php:8.1-apache\n",[52,5471,5472],{"class":54,"line":83},[52,5473,5474],{},"RUN apt update \\\n",[52,5476,5477],{"class":54,"line":115},[52,5478,5479],{},"        && apt install -y g++ libicu-dev libpq-dev libzip-dev zip zlib1g-dev \\\n",[52,5481,5482],{"class":54,"line":142},[52,5483,5484],{},"        && mv \u002Fetc\u002Fapache2\u002Fmods-available\u002Frewrite.load \u002Fetc\u002Fapache2\u002Fmods-enabled\n",[52,5486,5487],{"class":54,"line":169},[52,5488,5489],{},"RUN docker-php-ext-install pdo pdo_mysql\n",[52,5491,5492],{"class":54,"line":302},[52,5493,5494],{},"WORKDIR \u002Fvar\u002Fwww\u002Fhtml\n",[52,5496,5497],{"class":54,"line":308},[52,5498,5499],{},"RUN curl -sS https:\u002F\u002Fgetcomposer.org\u002Finstaller | php -- --install-dir=\u002Fusr\u002Flocal\u002Fbin --filename=composer\n",[52,5501,5502],{"class":54,"line":318},[52,5503,5504],{},"RUN curl -fsSL https:\u002F\u002Fdeb.nodesource.com\u002Fsetup_lts.x | bash - \\\n",[52,5506,5507],{"class":54,"line":328},[52,5508,5509],{},"    && apt-get install -y nodejs\n",[13,5511,5512],{},"このファイルではphpとapacheが入った環境にてLaravelの依存PHPモジュールのインストールとcomposerをインストールする内容を記述しています。そしてLaravelのアセットビルドにはnode.jsを使用するのでそのインストールも記述しています。",[1721,5514,5515],{"id":5515},"apacheの設定ファイルを作成",[13,5517,5518],{},"Laravelのドキュメントルートを設定するためにapacheの設定ファイル作成して、マウントできる様にします。",[42,5520,5522],{"className":5371,"code":5521,"language":5373,"meta":47,"style":47},"cd web_1\ntouch default.conf\n",[49,5523,5524,5530],{"__ignoreMap":47},[52,5525,5526,5528],{"class":54,"line":55},[52,5527,5388],{"class":417},[52,5529,5417],{"class":75},[52,5531,5532,5534],{"class":54,"line":83},[52,5533,5400],{"class":369},[52,5535,5536],{"class":75}," default.conf\n",[42,5538,5543],{"className":5539,"code":5540,"filename":5541,"language":5542,"meta":47,"style":47},"language-conf shiki shiki-themes material-theme-ocean","\u003CVirtualHost *:80>\n    ServerName laravel_docker\n    DocumentRoot \u002Fvar\u002Fwww\u002Fhtml\u002Fpublic\n\n    \u003CDirectory \"\u002Fvar\u002Fwww\u002Fhtml\u002Fpublic\">\n        AllowOverride All\n    \u003C\u002FDirectory>\n    ErrorLog ${APACHE_LOG_DIR}\u002Ferror.log\n    CustomLog ${APACHE_LOG_DIR}\u002Faccess.log combined\n\u003C\u002FVirtualHost>\n","default.conf","conf",[49,5544,5545,5550,5555,5560,5564,5569,5574,5579,5584,5589],{"__ignoreMap":47},[52,5546,5547],{"class":54,"line":55},[52,5548,5549],{},"\u003CVirtualHost *:80>\n",[52,5551,5552],{"class":54,"line":83},[52,5553,5554],{},"    ServerName laravel_docker\n",[52,5556,5557],{"class":54,"line":115},[52,5558,5559],{},"    DocumentRoot \u002Fvar\u002Fwww\u002Fhtml\u002Fpublic\n",[52,5561,5562],{"class":54,"line":142},[52,5563,340],{"emptyLinePlaceholder":339},[52,5565,5566],{"class":54,"line":169},[52,5567,5568],{},"    \u003CDirectory \"\u002Fvar\u002Fwww\u002Fhtml\u002Fpublic\">\n",[52,5570,5571],{"class":54,"line":302},[52,5572,5573],{},"        AllowOverride All\n",[52,5575,5576],{"class":54,"line":308},[52,5577,5578],{},"    \u003C\u002FDirectory>\n",[52,5580,5581],{"class":54,"line":318},[52,5582,5583],{},"    ErrorLog ${APACHE_LOG_DIR}\u002Ferror.log\n",[52,5585,5586],{"class":54,"line":328},[52,5587,5588],{},"    CustomLog ${APACHE_LOG_DIR}\u002Faccess.log combined\n",[52,5590,5591],{"class":54,"line":4},[52,5592,5593],{},"\u003C\u002FVirtualHost>\n",[13,5595,5596,5597,5600],{},"このファイルはコンテナの",[49,5598,5599],{},"\u002Fetc\u002Fapache2\u002Fsites-enabled\u002F000-default.conf","にマウントされます。",[1721,5602,5604],{"id":5603},"docker-composeyamlを作成","docker-compose.yamlを作成",[13,5606,5607],{},"次にdocker-comose.yamlを作成してDBとphpmyadmin",[42,5609,5614],{"className":5610,"code":5611,"filename":5612,"language":5613,"meta":47,"style":47},"language-yaml shiki shiki-themes material-theme-ocean","version: '3'\nservices: \n  web_1:\n    build: .\u002Fweb_1\n    depends_on: \n      - db\n    volumes: \n      - .\u002Fhtml\u002F:\u002Fvar\u002Fwww\u002Fhtml\u002F\n      - .\u002Fweb_1\u002Fdefault.conf:\u002Fetc\u002Fapache2\u002Fsites-enabled\u002F000-default.conf\n    ports: \n      - \"8005:80\"\n  phpmyadmin:\n    image: phpmyadmin\n    restart: always\n    ports:\n      - \"8080:80\"\n    environment:\n     - PMA_ARBITRARY=1\n     - PMA_HOST=db:3306\n     - PMA_USER=root\n     - PMA_PASSWORD=rootroot\n  db:\n    image: mysql:5.7\n    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci\n    environment:\n      MYSQL_DATABASE: preform\n      MYSQL_USER: test\n      MYSQL_PASSWORD: testtest\n      MYSQL_ROOT_PASSWORD: rootroot\n      TZ: Asia\u002FTokyo\n    ports: \n      - \"3306:3306\"\n    volumes: \n      - vue_laravel:\u002Fvar\u002Flib\u002Fmysql\nvolumes: \n  vue_laravel: {}\n","docker-comose.yaml","yaml",[49,5615,5616,5630,5639,5647,5657,5666,5674,5683,5690,5697,5706,5717,5724,5734,5744,5750,5761,5768,5776,5783,5790,5797,5804,5813,5823,5829,5839,5849,5859,5869,5879,5887,5898,5906,5913,5922],{"__ignoreMap":47},[52,5617,5618,5621,5623,5625,5627],{"class":54,"line":55},[52,5619,5620],{"class":62},"version",[52,5622,372],{"class":58},[52,5624,1979],{"class":58},[52,5626,39],{"class":75},[52,5628,5629],{"class":58},"'\n",[52,5631,5632,5635,5637],{"class":54,"line":83},[52,5633,5634],{"class":62},"services",[52,5636,372],{"class":58},[52,5638,283],{"class":105},[52,5640,5641,5644],{"class":54,"line":115},[52,5642,5643],{"class":62},"  web_1",[52,5645,5646],{"class":58},":\n",[52,5648,5649,5652,5654],{"class":54,"line":142},[52,5650,5651],{"class":62},"    build",[52,5653,372],{"class":58},[52,5655,5656],{"class":75}," .\u002Fweb_1\n",[52,5658,5659,5662,5664],{"class":54,"line":169},[52,5660,5661],{"class":62},"    depends_on",[52,5663,372],{"class":58},[52,5665,283],{"class":105},[52,5667,5668,5671],{"class":54,"line":302},[52,5669,5670],{"class":58},"      -",[52,5672,5673],{"class":75}," db\n",[52,5675,5676,5679,5681],{"class":54,"line":308},[52,5677,5678],{"class":62},"    volumes",[52,5680,372],{"class":58},[52,5682,283],{"class":105},[52,5684,5685,5687],{"class":54,"line":318},[52,5686,5670],{"class":58},[52,5688,5689],{"class":75}," .\u002Fhtml\u002F:\u002Fvar\u002Fwww\u002Fhtml\u002F\n",[52,5691,5692,5694],{"class":54,"line":328},[52,5693,5670],{"class":58},[52,5695,5696],{"class":75}," .\u002Fweb_1\u002Fdefault.conf:\u002Fetc\u002Fapache2\u002Fsites-enabled\u002F000-default.conf\n",[52,5698,5699,5702,5704],{"class":54,"line":4},[52,5700,5701],{"class":62},"    ports",[52,5703,372],{"class":58},[52,5705,283],{"class":105},[52,5707,5708,5710,5712,5715],{"class":54,"line":343},[52,5709,5670],{"class":58},[52,5711,1502],{"class":58},[52,5713,5714],{"class":75},"8005:80",[52,5716,266],{"class":58},[52,5718,5719,5722],{"class":54,"line":353},[52,5720,5721],{"class":62},"  phpmyadmin",[52,5723,5646],{"class":58},[52,5725,5726,5729,5731],{"class":54,"line":366},[52,5727,5728],{"class":62},"    image",[52,5730,372],{"class":58},[52,5732,5733],{"class":75}," phpmyadmin\n",[52,5735,5736,5739,5741],{"class":54,"line":386},[52,5737,5738],{"class":62},"    restart",[52,5740,372],{"class":58},[52,5742,5743],{"class":75}," always\n",[52,5745,5746,5748],{"class":54,"line":414},[52,5747,5701],{"class":62},[52,5749,5646],{"class":58},[52,5751,5752,5754,5756,5759],{"class":54,"line":426},[52,5753,5670],{"class":58},[52,5755,1502],{"class":58},[52,5757,5758],{"class":75},"8080:80",[52,5760,266],{"class":58},[52,5762,5763,5766],{"class":54,"line":434},[52,5764,5765],{"class":62},"    environment",[52,5767,5646],{"class":58},[52,5769,5770,5773],{"class":54,"line":445},[52,5771,5772],{"class":58},"     -",[52,5774,5775],{"class":75}," PMA_ARBITRARY=1\n",[52,5777,5778,5780],{"class":54,"line":479},[52,5779,5772],{"class":58},[52,5781,5782],{"class":75}," PMA_HOST=db:3306\n",[52,5784,5785,5787],{"class":54,"line":508},[52,5786,5772],{"class":58},[52,5788,5789],{"class":75}," PMA_USER=root\n",[52,5791,5792,5794],{"class":54,"line":538},[52,5793,5772],{"class":58},[52,5795,5796],{"class":75}," PMA_PASSWORD=rootroot\n",[52,5798,5799,5802],{"class":54,"line":546},[52,5800,5801],{"class":62},"  db",[52,5803,5646],{"class":58},[52,5805,5806,5808,5810],{"class":54,"line":552},[52,5807,5728],{"class":62},[52,5809,372],{"class":58},[52,5811,5812],{"class":75}," mysql:5.7\n",[52,5814,5815,5818,5820],{"class":54,"line":558},[52,5816,5817],{"class":62},"    command",[52,5819,372],{"class":58},[52,5821,5822],{"class":75}," mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci\n",[52,5824,5825,5827],{"class":54,"line":563},[52,5826,5765],{"class":62},[52,5828,5646],{"class":58},[52,5830,5831,5834,5836],{"class":54,"line":568},[52,5832,5833],{"class":62},"      MYSQL_DATABASE",[52,5835,372],{"class":58},[52,5837,5838],{"class":75}," preform\n",[52,5840,5841,5844,5846],{"class":54,"line":1105},[52,5842,5843],{"class":62},"      MYSQL_USER",[52,5845,372],{"class":58},[52,5847,5848],{"class":75}," test\n",[52,5850,5851,5854,5856],{"class":54,"line":1134},[52,5852,5853],{"class":62},"      MYSQL_PASSWORD",[52,5855,372],{"class":58},[52,5857,5858],{"class":75}," testtest\n",[52,5860,5861,5864,5866],{"class":54,"line":1163},[52,5862,5863],{"class":62},"      MYSQL_ROOT_PASSWORD",[52,5865,372],{"class":58},[52,5867,5868],{"class":75}," rootroot\n",[52,5870,5871,5874,5876],{"class":54,"line":1192},[52,5872,5873],{"class":62},"      TZ",[52,5875,372],{"class":58},[52,5877,5878],{"class":75}," Asia\u002FTokyo\n",[52,5880,5881,5883,5885],{"class":54,"line":1199},[52,5882,5701],{"class":62},[52,5884,372],{"class":58},[52,5886,283],{"class":105},[52,5888,5889,5891,5893,5896],{"class":54,"line":1204},[52,5890,5670],{"class":58},[52,5892,1502],{"class":58},[52,5894,5895],{"class":75},"3306:3306",[52,5897,266],{"class":58},[52,5899,5900,5902,5904],{"class":54,"line":1209},[52,5901,5678],{"class":62},[52,5903,372],{"class":58},[52,5905,283],{"class":105},[52,5907,5908,5910],{"class":54,"line":1214},[52,5909,5670],{"class":58},[52,5911,5912],{"class":75}," vue_laravel:\u002Fvar\u002Flib\u002Fmysql\n",[52,5914,5915,5918,5920],{"class":54,"line":1219},[52,5916,5917],{"class":62},"volumes",[52,5919,372],{"class":58},[52,5921,283],{"class":105},[52,5923,5924,5927,5929],{"class":54,"line":2302},[52,5925,5926],{"class":62},"  vue_laravel",[52,5928,372],{"class":58},[52,5930,5931],{"class":58}," {}\n",[13,5933,5934,5937,5938,5940,5941,5944,5945,5948],{},[49,5935,5936],{},"web_1","サービスでapacheとphpの環境をビルドします。そして",[49,5939,5435],{},"をコンテナ内の",[49,5942,5943],{},"\u002Fvar\u002Fwww\u002Fhtml\u002F","にマウントされます。ubuntuのapacheは",[49,5946,5947],{},"\u002Fetc\u002Fapache2\u002Fsites-enabled\u002F","配下にconfファイルを設置することで設定を追加したりオーバーライドできます。",[13,5950,5951,5953,5954,5957],{},[49,5952,5355],{},"サービスでphpmyadminを起動してDBの内容を編集しやすくします。",[49,5955,5956],{},"db","サービスではmysqlの環境を作成します。ボリュームの設定をして永続化を行います。以上の設定を行ったらコンテナを立ち上げます。",[42,5959,5961],{"className":5371,"code":5960,"language":5373,"meta":47,"style":47},"docker-compose up -d\n\nCreating laravel_vue_phpmyadmin_1 ... done\nCreating laravel_vue_db_1         ... done\nCreating laravel_vue_web_1_1      ... done\n",[49,5962,5963,5974,5978,5992,6004],{"__ignoreMap":47},[52,5964,5965,5968,5971],{"class":54,"line":55},[52,5966,5967],{"class":369},"docker-compose",[52,5969,5970],{"class":75}," up",[52,5972,5973],{"class":75}," -d\n",[52,5975,5976],{"class":54,"line":83},[52,5977,340],{"emptyLinePlaceholder":339},[52,5979,5980,5983,5986,5989],{"class":54,"line":115},[52,5981,5982],{"class":369},"Creating",[52,5984,5985],{"class":75}," laravel_vue_phpmyadmin_1",[52,5987,5988],{"class":75}," ...",[52,5990,5991],{"class":75}," done\n",[52,5993,5994,5996,5999,6002],{"class":54,"line":142},[52,5995,5982],{"class":369},[52,5997,5998],{"class":75}," laravel_vue_db_1",[52,6000,6001],{"class":75},"         ...",[52,6003,5991],{"class":75},[52,6005,6006,6008,6011,6014],{"class":54,"line":169},[52,6007,5982],{"class":369},[52,6009,6010],{"class":75}," laravel_vue_web_1_1",[52,6012,6013],{"class":75},"      ...",[52,6015,5991],{"class":75},[13,6017,6018],{},"そしてコンテナ内に入ってLaravelをインストールしていきます。",[42,6020,6023],{"className":6021,"code":6022,"language":451},[1727],"docker exec -it laravel_vue_web_1_1 \u002Fbin\u002Fbash\n\nroot@a790844c74d6:\u002Fvar\u002Fwww\u002Fhtml# composer \nroot@a790844c74d6:\u002Fvar\u002Fwww\u002Fhtml# composer create-project laravel\u002Flaravel .\u002F\n",[49,6024,6022],{"__ignoreMap":47},[13,6026,6027,6028,6031,6032,6035,6036,6038],{},"これで",[49,6029,6030],{},"\u002Fvar\u002Fwww\u002Fhtml","配下にLaravelプロジェクトが入ります。コンテナの",[49,6033,6034],{}," \u002Fvar\u002Fwww\u002Fhtml","はホストマシンの",[49,6037,5435],{},"に同期されます。",[13,6040,6041,6043,6044,6047],{},[49,6042,5435],{},"配下にソースが生成されたのを確認しましたら、",[49,6045,6046],{},".env","ファイルにDBの接続設定を記述します。",[42,6049,6052],{"className":6050,"code":6051,"filename":6046,"language":451,"meta":47},[1727],"DB_CONNECTION=mysql\nDB_HOST=db\nDB_PORT=3306\nDB_DATABASE=laravel\nDB_USERNAME=root\nDB_PASSWORD=rootroot\n",[49,6053,6051],{"__ignoreMap":47},[13,6055,6056,6057,6060,6061,6064,6065,6068],{},"phpmyadminとかで",[49,6058,6059],{},"laravel","データベースは作成しておいてください。",[49,6062,6063],{},"DB_HOST","はdockerのDBのサービス名を入力します。設定したらブラウザで",[49,6066,6067],{},"localhost:8005","にアクセスします。以下の様なウェルカムページが表示されれば成功です。",[728,6070],{":src":6071,":center":1322},"'vue_laravel_app\u002Flaravel_welcome.png'",[13,6073,6074],{},"（特に断りがない限り、以降ではDockerコンテナ内の操作とします。）",[17,6076,6078],{"id":6077},"laravelとvueセットアップ","LaravelとVueセットアップ",[13,6080,6081,6082,6085],{},"それではアセットと認証機能のセットアップをしましょう。今回は",[49,6083,6084],{},"laravel\u002Fbreeze","をスターターキットとして利用します。",[42,6087,6090],{"className":6088,"code":6089,"language":451},[1727],"composer require laravel\u002Fbreeze --dev\n\nphp artisan breeze:install\nBreeze scaffolding installed successfully.\nPlease execute the \"npm install && npm run dev\" command to build your assets.\n\nnpm install\nnpm run dev\nphp artisan migrate\nMigration table created successfully.\nMigrating: 2014_10_12_000000_create_users_table\nMigrated:  2014_10_12_000000_create_users_table (23.69ms)\nMigrating: 2014_10_12_100000_create_password_resets_table\nMigrated:  2014_10_12_100000_create_password_resets_table (10.45ms)\nMigrating: 2019_08_19_000000_create_failed_jobs_table\nMigrated:  2019_08_19_000000_create_failed_jobs_table (10.60ms)\nMigrating: 2019_12_14_000001_create_personal_access_tokens_table\nMigrated:  2019_12_14_000001_create_personal_access_tokens_table (14.54ms)\n",[49,6091,6089],{"__ignoreMap":47},[13,6093,6094],{},"マイグレーションが完了したので登録などができる様になっているはずです。ひとまずLaravelのセットアップは以上となります。",[17,6096,6098],{"id":6097},"とりあえずspa構成ができるかチェック","とりあえずSPA構成ができるかチェック",[13,6100,6101],{},"次は管理画面のフロントエンドのセットアップをしていきます。管理画面はvue.jsで作成し、公開側コンテンツはLaravelのサーバーサイドレンダリングをします。ここではSPA構成のセットアップをします。",[1721,6103,6105],{"id":6104},"spaのビューとルートの設定","SPAのビューとルートの設定",[13,6107,6108,6111],{},[49,6109,6110],{},"\u002Fsystem","配下を管理画面として構築していきます。以下の様なビューテンプレートとルートを作成します。",[42,6113,6118],{"className":6114,"code":6115,"filename":6116,"language":6117,"meta":47,"style":47},"language-php shiki shiki-themes material-theme-ocean","Route::get('\u002Fsystem\u002F{path?}', function () {\n    return view('admin');\n})->where('path', '.*')->name('admin');\n","routes\u002Fweb.php","php",[49,6119,6120,6125,6130],{"__ignoreMap":47},[52,6121,6122],{"class":54,"line":55},[52,6123,6124],{},"Route::get('\u002Fsystem\u002F{path?}', function () {\n",[52,6126,6127],{"class":54,"line":83},[52,6128,6129],{},"    return view('admin');\n",[52,6131,6132],{"class":54,"line":115},[52,6133,6134],{},"})->where('path', '.*')->name('admin');\n",[13,6136,6137,6138,6140],{},"このルートは",[49,6139,6110],{},"配下すべてのルートに対してadminビューを返すことを示しています。",[42,6142,6145],{"className":6114,"code":6143,"filename":6144,"language":6117,"meta":47,"style":47},"\u003C!DOCTYPE html>\n\u003Chtml lang=\"{{ str_replace('_', '-', app()->getLocale()) }}\">\n    \u003Chead>\n        \u003Cmeta charset=\"utf-8\">\n        \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        \u003Cmeta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n\n        \u003Ctitle>{{ config('app.name', 'Laravel') }}\u003C\u002Ftitle>\n\n        \u003C!-- Fonts -->\n        \u003Clink rel=\"stylesheet\" href=\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Nunito:wght@400;600;700&display=swap\">\n\n        \u003C!-- Styles -->\n        \u003Clink rel=\"stylesheet\" href=\"{{ asset('css\u002Fapp.css') }}\">\n\n    \u003C\u002Fhead>\n    \u003Cbody>\n        \u003Cdiv class=\"font-sans text-gray-900 antialiased\">\n            \u003Cdiv id=\"app\">\n                \u003Crouter-view\u002F>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n    \u003C\u002Fbody>\n    \u003C!-- Scripts -->\n    \u003Cscript src=\"{{ asset('js\u002Fadmin\u002Findex.js') }}\" defer>\u003C\u002Fscript>\n\u003C\u002Fhtml>\n","resources\u002Fview\u002Fadmin.blade.php",[49,6146,6147,6152,6157,6162,6167,6172,6177,6181,6186,6190,6195,6200,6204,6209,6214,6218,6223,6228,6233,6238,6243,6248,6253,6258,6263,6268],{"__ignoreMap":47},[52,6148,6149],{"class":54,"line":55},[52,6150,6151],{},"\u003C!DOCTYPE html>\n",[52,6153,6154],{"class":54,"line":83},[52,6155,6156],{},"\u003Chtml lang=\"{{ str_replace('_', '-', app()->getLocale()) }}\">\n",[52,6158,6159],{"class":54,"line":115},[52,6160,6161],{},"    \u003Chead>\n",[52,6163,6164],{"class":54,"line":142},[52,6165,6166],{},"        \u003Cmeta charset=\"utf-8\">\n",[52,6168,6169],{"class":54,"line":169},[52,6170,6171],{},"        \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",[52,6173,6174],{"class":54,"line":302},[52,6175,6176],{},"        \u003Cmeta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n",[52,6178,6179],{"class":54,"line":308},[52,6180,340],{"emptyLinePlaceholder":339},[52,6182,6183],{"class":54,"line":318},[52,6184,6185],{},"        \u003Ctitle>{{ config('app.name', 'Laravel') }}\u003C\u002Ftitle>\n",[52,6187,6188],{"class":54,"line":328},[52,6189,340],{"emptyLinePlaceholder":339},[52,6191,6192],{"class":54,"line":4},[52,6193,6194],{},"        \u003C!-- Fonts -->\n",[52,6196,6197],{"class":54,"line":343},[52,6198,6199],{},"        \u003Clink rel=\"stylesheet\" href=\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Nunito:wght@400;600;700&display=swap\">\n",[52,6201,6202],{"class":54,"line":353},[52,6203,340],{"emptyLinePlaceholder":339},[52,6205,6206],{"class":54,"line":366},[52,6207,6208],{},"        \u003C!-- Styles -->\n",[52,6210,6211],{"class":54,"line":386},[52,6212,6213],{},"        \u003Clink rel=\"stylesheet\" href=\"{{ asset('css\u002Fapp.css') }}\">\n",[52,6215,6216],{"class":54,"line":414},[52,6217,340],{"emptyLinePlaceholder":339},[52,6219,6220],{"class":54,"line":426},[52,6221,6222],{},"    \u003C\u002Fhead>\n",[52,6224,6225],{"class":54,"line":434},[52,6226,6227],{},"    \u003Cbody>\n",[52,6229,6230],{"class":54,"line":445},[52,6231,6232],{},"        \u003Cdiv class=\"font-sans text-gray-900 antialiased\">\n",[52,6234,6235],{"class":54,"line":479},[52,6236,6237],{},"            \u003Cdiv id=\"app\">\n",[52,6239,6240],{"class":54,"line":508},[52,6241,6242],{},"                \u003Crouter-view\u002F>\n",[52,6244,6245],{"class":54,"line":538},[52,6246,6247],{},"            \u003C\u002Fdiv>\n",[52,6249,6250],{"class":54,"line":546},[52,6251,6252],{},"        \u003C\u002Fdiv>\n",[52,6254,6255],{"class":54,"line":552},[52,6256,6257],{},"    \u003C\u002Fbody>\n",[52,6259,6260],{"class":54,"line":558},[52,6261,6262],{},"    \u003C!-- Scripts -->\n",[52,6264,6265],{"class":54,"line":563},[52,6266,6267],{},"    \u003Cscript src=\"{{ asset('js\u002Fadmin\u002Findex.js') }}\" defer>\u003C\u002Fscript>\n",[52,6269,6270],{"class":54,"line":568},[52,6271,6272],{},"\u003C\u002Fhtml>\n",[13,6274,6275,6276,6279,6280,6283],{},"テンプレートは上記の様にして",[49,6277,6278],{},"\u003Cdiv id=\"app\">\u003Crouter-view\u002F>\u003C\u002Fdiv>","を設置して、vueのエントリーポイントと、vueのビルドファイルを読み込む様にします。実際はヘッダーなどを分けたほうがいいですが、今はとりあえずこんな感じでOKです。\n次に",[49,6281,6282],{},"'js\u002Fadmin\u002Findex.js","で読み込ませるjsファイルを作成していきます。",[1721,6285,6286],{"id":6286},"必要なライブラリをインストール",[13,6288,6289,6290,6293,6294,2388,6296,6299,6300,2374,6302,2388,6305,6308],{},"一昔前の",[49,6291,6292],{},"laravel\u002Fui","の時は",[49,6295,204],{},[49,6297,6298],{},"bootstrap","の設定がインストール時に自動設定されますが、今回の",[49,6301,6084],{},[49,6303,6304],{},"alpinejs",[49,6306,6307],{},"tailwindcss","が入っているので、vue一式を自分でインストールする必要があります。まずはVue・Vuex・Vue-Routerをインストールしましょう。",[1905,6310,6314],{"className":6311},[6312,6313],"alert","alert-danger","\nこの記事を作成した2021年3月現在、Vue3がリリースされておりバージョンを指定しないと、それぞれ最新版がインストールされる可能性があります。この記事はVue2を用いて解説しますのでバージョンを指定してインストールしています。\n",[42,6316,6319],{"className":6317,"code":6318,"language":451},[1727],"npm install vue@2 vue-loader@15 vue-template-compiler@2 --save-dev\nnpm install vuex@3 vue-router@3\n",[49,6320,6318],{"__ignoreMap":47},[1721,6322,6324],{"id":6323},"spa用のjsファイルを作成する","SPA用のJSファイルを作成する",[13,6326,6327,6328,6331],{},"それでは",[49,6329,6330],{},"resources\u002Fjs","配下にSPAのファイルを作成を行います。以下の様にファイルとディレクトリを作成してください。",[42,6333,6336],{"className":6334,"code":6335,"language":451},[1727],"js\n├── admin\n│   ├── index.js\n│   ├── router.js\n│   └── store.js\n└── vue\n    └── page\n        ├── Home.vue\n        └── Profile.vue\n",[49,6337,6335],{"__ignoreMap":47},[13,6339,6340],{},"store.jsとrouter.jsは以下の様にします。",[42,6342,6345],{"className":2395,"code":6343,"filename":6344,"language":1433,"meta":47,"style":47},"export default {\n    state:{},\n    getters: {},\n    mutations: {},\n    actions: {}\n}\n","store.js",[49,6346,6347,6355,6363,6372,6381,6390],{"__ignoreMap":47},[52,6348,6349,6351,6353],{"class":54,"line":55},[52,6350,356],{"class":359},[52,6352,360],{"class":359},[52,6354,2012],{"class":58},[52,6356,6357,6360],{"class":54,"line":83},[52,6358,6359],{"class":62},"    state",[52,6361,6362],{"class":58},":{},\n",[52,6364,6365,6368,6370],{"class":54,"line":115},[52,6366,6367],{"class":62},"    getters",[52,6369,372],{"class":58},[52,6371,3045],{"class":58},[52,6373,6374,6377,6379],{"class":54,"line":142},[52,6375,6376],{"class":62},"    mutations",[52,6378,372],{"class":58},[52,6380,3045],{"class":58},[52,6382,6383,6386,6388],{"class":54,"line":169},[52,6384,6385],{"class":62},"    actions",[52,6387,372],{"class":58},[52,6389,5931],{"class":58},[52,6391,6392],{"class":54,"line":302},[52,6393,535],{"class":58},[13,6395,6396],{},"storeはひとまず必要な型だけ準備します。",[42,6398,6401],{"className":2395,"code":6399,"filename":6400,"language":1433,"meta":47,"style":47},"import Home from '~js\u002Fvue\u002Fpage\u002FHome.vue';\nimport Profile from '~js\u002Fvue\u002Fpage\u002FProfile.vue';\n\nconst routes = [\n    { path: '\u002Fsystem', component: Home },\n    { path: '\u002Fsystem\u002Fprofile', component: Profile },\n]\n\nexport default routes;\n","router.js",[49,6402,6403,6421,6439,6443,6455,6482,6507,6512,6516],{"__ignoreMap":47},[52,6404,6405,6407,6410,6412,6414,6417,6419],{"class":54,"line":55},[52,6406,1847],{"class":359},[52,6408,6409],{"class":105}," Home ",[52,6411,1976],{"class":359},[52,6413,1979],{"class":58},[52,6415,6416],{"class":75},"~js\u002Fvue\u002Fpage\u002FHome.vue",[52,6418,375],{"class":58},[52,6420,1006],{"class":58},[52,6422,6423,6425,6428,6430,6432,6435,6437],{"class":54,"line":83},[52,6424,1847],{"class":359},[52,6426,6427],{"class":105}," Profile ",[52,6429,1976],{"class":359},[52,6431,1979],{"class":58},[52,6433,6434],{"class":75},"~js\u002Fvue\u002Fpage\u002FProfile.vue",[52,6436,375],{"class":58},[52,6438,1006],{"class":58},[52,6440,6441],{"class":54,"line":115},[52,6442,340],{"emptyLinePlaceholder":339},[52,6444,6445,6447,6450,6452],{"class":54,"line":142},[52,6446,2792],{"class":65},[52,6448,6449],{"class":105}," routes ",[52,6451,69],{"class":58},[52,6453,6454],{"class":105}," [\n",[52,6456,6457,6460,6463,6465,6467,6469,6471,6473,6476,6478,6480],{"class":54,"line":169},[52,6458,6459],{"class":58},"    {",[52,6461,6462],{"class":62}," path",[52,6464,372],{"class":58},[52,6466,1979],{"class":58},[52,6468,6110],{"class":75},[52,6470,375],{"class":58},[52,6472,407],{"class":58},[52,6474,6475],{"class":62}," component",[52,6477,372],{"class":58},[52,6479,6409],{"class":105},[52,6481,476],{"class":58},[52,6483,6484,6486,6488,6490,6492,6495,6497,6499,6501,6503,6505],{"class":54,"line":302},[52,6485,6459],{"class":58},[52,6487,6462],{"class":62},[52,6489,372],{"class":58},[52,6491,1979],{"class":58},[52,6493,6494],{"class":75},"\u002Fsystem\u002Fprofile",[52,6496,375],{"class":58},[52,6498,407],{"class":58},[52,6500,6475],{"class":62},[52,6502,372],{"class":58},[52,6504,6427],{"class":105},[52,6506,476],{"class":58},[52,6508,6509],{"class":54,"line":308},[52,6510,6511],{"class":105},"]\n",[52,6513,6514],{"class":54,"line":318},[52,6515,340],{"emptyLinePlaceholder":339},[52,6517,6518,6520,6522,6525],{"class":54,"line":328},[52,6519,356],{"class":359},[52,6521,360],{"class":359},[52,6523,6524],{"class":105}," routes",[52,6526,1006],{"class":58},[13,6528,6529,6530,6533],{},"router.jsでは指定のパスに対してどのコンポーネントを出すかを定義します。",[49,6531,6532],{},"~js","という記述は後で解説しますので、ひとまず記述してください。",[13,6535,6536],{},"router.jsで参照しているコンポーネントは以下の様にしておきます。",[42,6538,6541],{"className":202,"code":6539,"filename":6540,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv>\n        home\n        \u003Crouter-link to=\"\u002Fsystem\u002Fprofile\">profile\u003C\u002Frouter-link>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    name:'home'\n}\n\u003C\u002Fscript>\n","Home.vue",[49,6542,6543,6551,6559,6564,6593,6601,6609,6617,6625,6638,6642],{"__ignoreMap":47},[52,6544,6545,6547,6549],{"class":54,"line":55},[52,6546,59],{"class":58},[52,6548,213],{"class":62},[52,6550,80],{"class":58},[52,6552,6553,6555,6557],{"class":54,"line":83},[52,6554,1902],{"class":58},[52,6556,1905],{"class":62},[52,6558,80],{"class":58},[52,6560,6561],{"class":54,"line":115},[52,6562,6563],{"class":105},"        home\n",[52,6565,6566,6568,6571,6574,6576,6578,6580,6582,6584,6587,6589,6591],{"class":54,"line":142},[52,6567,1912],{"class":58},[52,6569,6570],{"class":62},"router-link",[52,6572,6573],{"class":65}," to",[52,6575,69],{"class":58},[52,6577,72],{"class":58},[52,6579,6494],{"class":75},[52,6581,72],{"class":58},[52,6583,102],{"class":58},[52,6585,6586],{"class":105},"profile",[52,6588,108],{"class":58},[52,6590,6570],{"class":62},[52,6592,80],{"class":58},[52,6594,6595,6597,6599],{"class":54,"line":169},[52,6596,1946],{"class":58},[52,6598,1905],{"class":62},[52,6600,80],{"class":58},[52,6602,6603,6605,6607],{"class":54,"line":302},[52,6604,108],{"class":58},[52,6606,213],{"class":62},[52,6608,80],{"class":58},[52,6610,6611,6613,6615],{"class":54,"line":308},[52,6612,59],{"class":58},[52,6614,348],{"class":62},[52,6616,80],{"class":58},[52,6618,6619,6621,6623],{"class":54,"line":318},[52,6620,356],{"class":359},[52,6622,360],{"class":359},[52,6624,2012],{"class":58},[52,6626,6627,6629,6631,6633,6636],{"class":54,"line":328},[52,6628,2017],{"class":62},[52,6630,372],{"class":58},[52,6632,375],{"class":58},[52,6634,6635],{"class":75},"home",[52,6637,5629],{"class":58},[52,6639,6640],{"class":54,"line":4},[52,6641,535],{"class":58},[52,6643,6644,6646,6648],{"class":54,"line":343},[52,6645,108],{"class":58},[52,6647,348],{"class":62},[52,6649,80],{"class":58},[42,6651,6654],{"className":202,"code":6652,"filename":6653,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv>\n        profile\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    name:'profile'\n}\n\u003C\u002Fscript>\n","Profile.vue",[49,6655,6656,6664,6672,6677,6685,6693,6701,6709,6721,6725],{"__ignoreMap":47},[52,6657,6658,6660,6662],{"class":54,"line":55},[52,6659,59],{"class":58},[52,6661,213],{"class":62},[52,6663,80],{"class":58},[52,6665,6666,6668,6670],{"class":54,"line":83},[52,6667,1902],{"class":58},[52,6669,1905],{"class":62},[52,6671,80],{"class":58},[52,6673,6674],{"class":54,"line":115},[52,6675,6676],{"class":105},"        profile\n",[52,6678,6679,6681,6683],{"class":54,"line":142},[52,6680,1946],{"class":58},[52,6682,1905],{"class":62},[52,6684,80],{"class":58},[52,6686,6687,6689,6691],{"class":54,"line":169},[52,6688,108],{"class":58},[52,6690,213],{"class":62},[52,6692,80],{"class":58},[52,6694,6695,6697,6699],{"class":54,"line":302},[52,6696,59],{"class":58},[52,6698,348],{"class":62},[52,6700,80],{"class":58},[52,6702,6703,6705,6707],{"class":54,"line":308},[52,6704,356],{"class":359},[52,6706,360],{"class":359},[52,6708,2012],{"class":58},[52,6710,6711,6713,6715,6717,6719],{"class":54,"line":318},[52,6712,2017],{"class":62},[52,6714,372],{"class":58},[52,6716,375],{"class":58},[52,6718,6586],{"class":75},[52,6720,5629],{"class":58},[52,6722,6723],{"class":54,"line":328},[52,6724,535],{"class":58},[52,6726,6727,6729,6731],{"class":54,"line":4},[52,6728,108],{"class":58},[52,6730,348],{"class":62},[52,6732,80],{"class":58},[13,6734,6735],{},"index.jsは以下の様に記述します。",[42,6737,6740],{"className":2395,"code":6738,"filename":6739,"language":1433,"meta":47,"style":47},"window.axios = require('axios');\nwindow.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';\n\nimport Vue from 'vue';\n\nimport Vuex from 'vuex';\nimport index from '.\u002Fstore';\nVue.use(Vuex);\nconst store = new Vuex.Store(index);\n\nimport VueRouter from 'vue-router'\nimport routes from '.\u002Frouter';\nVue.use(VueRouter)\nconst router =  new VueRouter({mode: 'history',routes})\n\nconst app = new Vue({\n    store,\n    router,\n}).$mount(\"#app\");\n","index.js",[49,6741,6742,6770,6814,6818,6835,6839,6857,6875,6889,6914,6918,6934,6951,6962,7003,7007,7025,7032,7039],{"__ignoreMap":47},[52,6743,6744,6747,6749,6752,6754,6757,6759,6761,6764,6766,6768],{"class":54,"line":55},[52,6745,6746],{"class":105},"window",[52,6748,956],{"class":58},[52,6750,6751],{"class":105},"axios ",[52,6753,69],{"class":58},[52,6755,6756],{"class":417}," require",[52,6758,931],{"class":105},[52,6760,375],{"class":58},[52,6762,6763],{"class":75},"axios",[52,6765,375],{"class":58},[52,6767,937],{"class":105},[52,6769,1006],{"class":58},[52,6771,6772,6774,6776,6778,6780,6783,6785,6788,6790,6793,6795,6798,6800,6803,6805,6807,6810,6812],{"class":54,"line":83},[52,6773,6746],{"class":105},[52,6775,956],{"class":58},[52,6777,6763],{"class":105},[52,6779,956],{"class":58},[52,6781,6782],{"class":105},"defaults",[52,6784,956],{"class":58},[52,6786,6787],{"class":105},"headers",[52,6789,956],{"class":58},[52,6791,6792],{"class":105},"common[",[52,6794,375],{"class":58},[52,6796,6797],{"class":75},"X-Requested-With",[52,6799,375],{"class":58},[52,6801,6802],{"class":105},"] ",[52,6804,69],{"class":58},[52,6806,1979],{"class":58},[52,6808,6809],{"class":75},"XMLHttpRequest",[52,6811,375],{"class":58},[52,6813,1006],{"class":58},[52,6815,6816],{"class":54,"line":115},[52,6817,340],{"emptyLinePlaceholder":339},[52,6819,6820,6822,6825,6827,6829,6831,6833],{"class":54,"line":142},[52,6821,1847],{"class":359},[52,6823,6824],{"class":105}," Vue ",[52,6826,1976],{"class":359},[52,6828,1979],{"class":58},[52,6830,204],{"class":75},[52,6832,375],{"class":58},[52,6834,1006],{"class":58},[52,6836,6837],{"class":54,"line":169},[52,6838,340],{"emptyLinePlaceholder":339},[52,6840,6841,6843,6846,6848,6850,6853,6855],{"class":54,"line":302},[52,6842,1847],{"class":359},[52,6844,6845],{"class":105}," Vuex ",[52,6847,1976],{"class":359},[52,6849,1979],{"class":58},[52,6851,6852],{"class":75},"vuex",[52,6854,375],{"class":58},[52,6856,1006],{"class":58},[52,6858,6859,6861,6864,6866,6868,6871,6873],{"class":54,"line":308},[52,6860,1847],{"class":359},[52,6862,6863],{"class":105}," index ",[52,6865,1976],{"class":359},[52,6867,1979],{"class":58},[52,6869,6870],{"class":75},".\u002Fstore",[52,6872,375],{"class":58},[52,6874,1006],{"class":58},[52,6876,6877,6879,6881,6884,6887],{"class":54,"line":318},[52,6878,2829],{"class":105},[52,6880,956],{"class":58},[52,6882,6883],{"class":417},"use",[52,6885,6886],{"class":105},"(Vuex)",[52,6888,1006],{"class":58},[52,6890,6891,6893,6896,6898,6901,6904,6906,6909,6912],{"class":54,"line":328},[52,6892,2792],{"class":65},[52,6894,6895],{"class":105}," store ",[52,6897,69],{"class":58},[52,6899,6900],{"class":58}," new",[52,6902,6903],{"class":105}," Vuex",[52,6905,956],{"class":58},[52,6907,6908],{"class":417},"Store",[52,6910,6911],{"class":105},"(index)",[52,6913,1006],{"class":58},[52,6915,6916],{"class":54,"line":4},[52,6917,340],{"emptyLinePlaceholder":339},[52,6919,6920,6922,6925,6927,6929,6932],{"class":54,"line":343},[52,6921,1847],{"class":359},[52,6923,6924],{"class":105}," VueRouter ",[52,6926,1976],{"class":359},[52,6928,1979],{"class":58},[52,6930,6931],{"class":75},"vue-router",[52,6933,5629],{"class":58},[52,6935,6936,6938,6940,6942,6944,6947,6949],{"class":54,"line":353},[52,6937,1847],{"class":359},[52,6939,6449],{"class":105},[52,6941,1976],{"class":359},[52,6943,1979],{"class":58},[52,6945,6946],{"class":75},".\u002Frouter",[52,6948,375],{"class":58},[52,6950,1006],{"class":58},[52,6952,6953,6955,6957,6959],{"class":54,"line":366},[52,6954,2829],{"class":105},[52,6956,956],{"class":58},[52,6958,6883],{"class":417},[52,6960,6961],{"class":105},"(VueRouter)\n",[52,6963,6964,6966,6969,6971,6974,6977,6979,6982,6985,6987,6989,6992,6994,6996,6999,7001],{"class":54,"line":386},[52,6965,2792],{"class":65},[52,6967,6968],{"class":105}," router ",[52,6970,69],{"class":58},[52,6972,6973],{"class":58},"  new",[52,6975,6976],{"class":417}," VueRouter",[52,6978,931],{"class":105},[52,6980,6981],{"class":58},"{",[52,6983,6984],{"class":62},"mode",[52,6986,372],{"class":58},[52,6988,1979],{"class":58},[52,6990,6991],{"class":75},"history",[52,6993,375],{"class":58},[52,6995,407],{"class":58},[52,6997,6998],{"class":105},"routes",[52,7000,1311],{"class":58},[52,7002,1014],{"class":105},[52,7004,7005],{"class":54,"line":414},[52,7006,340],{"emptyLinePlaceholder":339},[52,7008,7009,7011,7014,7016,7018,7021,7023],{"class":54,"line":426},[52,7010,2792],{"class":65},[52,7012,7013],{"class":105}," app ",[52,7015,69],{"class":58},[52,7017,6900],{"class":58},[52,7019,7020],{"class":417}," Vue",[52,7022,931],{"class":105},[52,7024,363],{"class":58},[52,7026,7027,7030],{"class":54,"line":434},[52,7028,7029],{"class":105},"    store",[52,7031,383],{"class":58},[52,7033,7034,7037],{"class":54,"line":445},[52,7035,7036],{"class":105},"    router",[52,7038,383],{"class":58},[52,7040,7041,7043,7045,7047,7050,7052,7054,7057,7059,7061],{"class":54,"line":479},[52,7042,1311],{"class":58},[52,7044,937],{"class":105},[52,7046,956],{"class":58},[52,7048,7049],{"class":417},"$mount",[52,7051,931],{"class":105},[52,7053,72],{"class":58},[52,7055,7056],{"class":75},"#app",[52,7058,72],{"class":58},[52,7060,937],{"class":105},[52,7062,1006],{"class":58},[13,7064,7065,7066,7069],{},"axiosはLaravelインストール時に入っているのでそのまま利用しています。このファイルではVuexとVue-routerの連携を行い、最終的に",[49,7067,7068],{},"\u003Cdiv id=\"app\">\u003C\u002Fdiv>","にレンダリングされる様にします。",[13,7071,7072,7073,7076],{},"上記のファイルを作成した後、",[49,7074,7075],{},"webpac.mix.js","を修正します。",[1721,7078,7079],{"id":7079},"mixファイルの作成",[13,7081,7082,7083,7086,7087,7090,7091,7094,7095,7098],{},"このようなVueのプロジェクトwebpackを使用しますがLaravelは簡単な記述で",[49,7084,7085],{},"resources","配下を簡単に",[49,7088,7089],{},"public\u002F","配下に出力してくれます。またvueやsassのコンパイル設定を",[49,7092,7093],{},"webpack.config.js","の様に書く必要がありません。どのファイルをコンパイル対象にするかなどは",[49,7096,7097],{},"webpack.mix.js","に記載します。以下の様に修正します。",[42,7100,7102],{"className":2395,"code":7101,"filename":7093,"language":1433,"meta":47,"style":47},"const mix = require('laravel-mix');\nconst path = require('path');\n\nmix.webpackConfig({\n    resolve: {\n      alias: {\n        '~js': path.resolve('.\u002Fresources\u002Fjs'),\n      }\n    }\n});\nmix.js('resources\u002Fjs\u002Fadmin\u002Findex.js', 'public\u002Fjs\u002Fadmin').vue();\n",[49,7103,7104,7128,7152,7156,7170,7179,7188,7219,7224,7228,7236],{"__ignoreMap":47},[52,7105,7106,7108,7111,7113,7115,7117,7119,7122,7124,7126],{"class":54,"line":55},[52,7107,2792],{"class":65},[52,7109,7110],{"class":105}," mix ",[52,7112,69],{"class":58},[52,7114,6756],{"class":417},[52,7116,931],{"class":105},[52,7118,375],{"class":58},[52,7120,7121],{"class":75},"laravel-mix",[52,7123,375],{"class":58},[52,7125,937],{"class":105},[52,7127,1006],{"class":58},[52,7129,7130,7132,7135,7137,7139,7141,7143,7146,7148,7150],{"class":54,"line":83},[52,7131,2792],{"class":65},[52,7133,7134],{"class":105}," path ",[52,7136,69],{"class":58},[52,7138,6756],{"class":417},[52,7140,931],{"class":105},[52,7142,375],{"class":58},[52,7144,7145],{"class":75},"path",[52,7147,375],{"class":58},[52,7149,937],{"class":105},[52,7151,1006],{"class":58},[52,7153,7154],{"class":54,"line":115},[52,7155,340],{"emptyLinePlaceholder":339},[52,7157,7158,7161,7163,7166,7168],{"class":54,"line":142},[52,7159,7160],{"class":105},"mix",[52,7162,956],{"class":58},[52,7164,7165],{"class":417},"webpackConfig",[52,7167,931],{"class":105},[52,7169,363],{"class":58},[52,7171,7172,7175,7177],{"class":54,"line":169},[52,7173,7174],{"class":62},"    resolve",[52,7176,372],{"class":58},[52,7178,2012],{"class":58},[52,7180,7181,7184,7186],{"class":54,"line":302},[52,7182,7183],{"class":62},"      alias",[52,7185,372],{"class":58},[52,7187,2012],{"class":58},[52,7189,7190,7193,7195,7197,7199,7201,7203,7206,7208,7210,7213,7215,7217],{"class":54,"line":308},[52,7191,7192],{"class":58},"        '",[52,7194,6532],{"class":62},[52,7196,375],{"class":58},[52,7198,372],{"class":58},[52,7200,6462],{"class":105},[52,7202,956],{"class":58},[52,7204,7205],{"class":417},"resolve",[52,7207,931],{"class":105},[52,7209,375],{"class":58},[52,7211,7212],{"class":75},".\u002Fresources\u002Fjs",[52,7214,375],{"class":58},[52,7216,937],{"class":105},[52,7218,383],{"class":58},[52,7220,7221],{"class":54,"line":318},[52,7222,7223],{"class":58},"      }\n",[52,7225,7226],{"class":54,"line":328},[52,7227,3753],{"class":58},[52,7229,7230,7232,7234],{"class":54,"line":4},[52,7231,1311],{"class":58},[52,7233,937],{"class":105},[52,7235,1006],{"class":58},[52,7237,7238,7240,7242,7244,7246,7248,7251,7253,7255,7257,7260,7262,7264,7266,7268,7270],{"class":54,"line":343},[52,7239,7160],{"class":105},[52,7241,956],{"class":58},[52,7243,1433],{"class":417},[52,7245,931],{"class":105},[52,7247,375],{"class":58},[52,7249,7250],{"class":75},"resources\u002Fjs\u002Fadmin\u002Findex.js",[52,7252,375],{"class":58},[52,7254,407],{"class":58},[52,7256,1979],{"class":58},[52,7258,7259],{"class":75},"public\u002Fjs\u002Fadmin",[52,7261,375],{"class":58},[52,7263,937],{"class":105},[52,7265,956],{"class":58},[52,7267,204],{"class":417},[52,7269,421],{"class":105},[52,7271,1006],{"class":58},[13,7273,7274,7277,7278,7280],{},[49,7275,7276],{},"mix.webpackConfig","はのように",[49,7279,7093],{},"に書く様な他の細かいwebpackの設定を定義でき、ここではエイリアスを定義しています。",[13,7282,7283,7286,7287,7289,7290,7292],{},[49,7284,7285],{},"'~js': path.resolve('.\u002Fresources\u002Fjs')","という記述は",[49,7288,6532],{},"というパスの記載があった場合は「",[49,7291,6330],{},"までの絶対ルート」であるとwebpackに支持しています。この様にエイリアスを定義することで相対パスによるファイルの参照がなくなります。router.jsで以下の様に定義していましたが、",[42,7294,7296],{"className":2395,"code":7295,"filename":6400,"language":1433,"meta":47,"style":47},"import Home from '~js\u002Fvue\u002Fpage\u002FHome.vue';\nimport Profile from '~js\u002Fvue\u002Fpage\u002FProfile.vue';\n",[49,7297,7298,7314],{"__ignoreMap":47},[52,7299,7300,7302,7304,7306,7308,7310,7312],{"class":54,"line":55},[52,7301,1847],{"class":359},[52,7303,6409],{"class":105},[52,7305,1976],{"class":359},[52,7307,1979],{"class":58},[52,7309,6416],{"class":75},[52,7311,375],{"class":58},[52,7313,1006],{"class":58},[52,7315,7316,7318,7320,7322,7324,7326,7328],{"class":54,"line":83},[52,7317,1847],{"class":359},[52,7319,6427],{"class":105},[52,7321,1976],{"class":359},[52,7323,1979],{"class":58},[52,7325,6434],{"class":75},[52,7327,375],{"class":58},[52,7329,1006],{"class":58},[13,7331,7332],{},"もしエイリアスが使えない場合は",[42,7334,7336],{"className":2395,"code":7335,"filename":6400,"language":1433,"meta":47,"style":47},"import Home from '..\u002Fvue\u002Fpage\u002FHome.vue';\nimport Profile from '..\u002Fvue\u002Fpage\u002FProfile.vue';\n",[49,7337,7338,7355],{"__ignoreMap":47},[52,7339,7340,7342,7344,7346,7348,7351,7353],{"class":54,"line":55},[52,7341,1847],{"class":359},[52,7343,6409],{"class":105},[52,7345,1976],{"class":359},[52,7347,1979],{"class":58},[52,7349,7350],{"class":75},"..\u002Fvue\u002Fpage\u002FHome.vue",[52,7352,375],{"class":58},[52,7354,1006],{"class":58},[52,7356,7357,7359,7361,7363,7365,7368,7370],{"class":54,"line":83},[52,7358,1847],{"class":359},[52,7360,6427],{"class":105},[52,7362,1976],{"class":359},[52,7364,1979],{"class":58},[52,7366,7367],{"class":75},"..\u002Fvue\u002Fpage\u002FProfile.vue",[52,7369,375],{"class":58},[52,7371,1006],{"class":58},[13,7373,7374,7375,7377],{},"このように相対パスになってしまい、もし構成を変えようとした時に相対関係の修正が必要となります。その対策としてエイリアスを定めておくと今後の管理がしやすいです。",[49,7376,7285],{},"はjsディレクトリを参照する様にしています。",[13,7379,7380,7383,7384,7386,7387,7390],{},[49,7381,7382],{},"mix.js('resources\u002Fjs\u002Fadmin\u002Findex.js', 'public\u002Fjs\u002Fadmin').vue();"," にて",[49,7385,6739],{},"をソースとして",[49,7388,7389],{},"'public\u002Fjs\u002Fadmin'","配下に出力し、vueコンパイルを行う様に定義してます。",[13,7392,7393,7394,7397,7398,7401],{},"問題なければ",[49,7395,7396],{},"npm run prod","をプロジェクト ルートでコマンドを叩いてコンパイルを行います。完了後に",[49,7399,7400],{},"public\u002Fjs\u002Fadmin\u002Findex.js","というものが出力されていることを確認してください。",[1721,7403,7404],{"id":7404},"反映の確認",[13,7406,7407,7408,7411,7412,7414,7415,7417],{},"jsファイルが出力されましたら",[49,7409,7410],{},"http:\u002F\u002Flocalhost:8005\u002Fsystem","にアクセスします。以下の様に表示され、",[49,7413,6586],{},"というリンクをクリックした際にURLが変わり、",[49,7416,6653],{},"に書かれた内容が表示されればSPAはできています。",[728,7419],{":src":7420,":center":1322},"'vue_laravel_app\u002Fhomevue.png'",[13,7422,7423,7425,7426,7429],{},[49,7424,6586],{},"というリンクをクリック後 or ",[49,7427,7428],{},"http:\u002F\u002Flocalhost:8005\u002Fsystem\u002Fprofile","にアクセスしますと以下の様になります。",[728,7431],{":src":7432,":center":1322},"'vue_laravel_app\u002Fprofilevue.png'",[13,7434,7435],{},"これでSPAが設定できたことを確認できました。",[17,7437,7439],{"id":7438},"次回は","次回は..",[13,7441,7442],{},"今回は環境構築とLaravel、Vue SPAのセットアップまでとなります。来週はweb apiを通じたSPAでの認証と簡単なプロフィールの更新機能を作成してみます。",[1413,7444,7445],{},"html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}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 pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}",{"title":47,"searchDepth":115,"depth":115,"links":7447},[7448,7456,7461,7462,7469],{"id":5226,"depth":83,"text":5226,"children":7449},[7450,7455],{"id":5232,"depth":115,"text":5232,"children":7451},[7452,7453,7454],{"id":5238,"depth":142,"text":5238},{"id":5272,"depth":142,"text":5272},{"id":5312,"depth":142,"text":5312},{"id":5326,"depth":115,"text":5326},{"id":5338,"depth":83,"text":5338,"children":7457},[7458,7459,7460],{"id":5452,"depth":115,"text":5453},{"id":5515,"depth":115,"text":5515},{"id":5603,"depth":115,"text":5604},{"id":6077,"depth":83,"text":6078},{"id":6097,"depth":83,"text":6098,"children":7463},[7464,7465,7466,7467,7468],{"id":6104,"depth":115,"text":6105},{"id":6286,"depth":115,"text":6286},{"id":6323,"depth":115,"text":6324},{"id":7079,"depth":115,"text":7079},{"id":7404,"depth":115,"text":7404},{"id":7438,"depth":83,"text":7439},[1423],"2022-03-02","アプリの解説とシリーズの概要",{},"\u002Fseries\u002Fvue-laravel-app-1",{"title":5164,"description":7472},"vue_laravel_app","Vue SPA x Laravelでつくる実務パチモンアプリ","series\u002Fvue-laravel-app-1",[6059,6117,1433,204],"vue_laravel_app\u002Fseries.png","QS_7_9yqTbYmh1Gt9XAVtEnkXBXd1wzlct80a3xdm_U",{"id":7483,"title":7484,"body":7485,"category":9175,"createdAt":9177,"description":9178,"extension":1426,"index":1427,"meta":9179,"navigation":339,"path":9180,"publish":339,"seo":9181,"series":1427,"seriesTitle":1427,"stem":9182,"tag":9183,"thumbnail":1427,"updatedAt":1427,"__hash__":9184},"articles\u002Farticles\u002Fjs-deep-copy.md","jsで配列内のオブジェクトの値が連動してしまう原因と対処法",{"type":10,"value":7486,"toc":9163},[7487,7494,7634,7647,7650,7658,7763,7770,7775,7778,7783,7786,7790,7797,7808,7810,7818,7821,8015,8035,8092,8095,8097,8100,8103,8112,8116,8127,8296,8299,8303,8313,8489,8496,8705,8708,8712,8722,8729,8919,8922,8926,8929,8984,8987,9157,9160],[13,7488,7489,7490,7493],{},"こんにちはjunです。vue.jsとかでアプリを作るととき、一覧ページや複数個のデータを出力する時はオブジェクトが内包された配列データを使用することが多いと思います。例としては以下のような「記事一覧」用の",[49,7491,7492],{},"posts","データです。",[42,7495,7497],{"className":1249,"code":7496,"language":1251,"meta":47,"style":47},"const posts = [\n    {id:1,title:\"記事タイトル１\",content:\"...\"},\n    {id:2,title:\"記事タイトル２\",content:\"...\"},\n    {id:3,title:\"記事タイトル３\",content:\"...\"},\n    \u002F\u002F ...\n]\n",[49,7498,7499,7510,7551,7588,7625,7630],{"__ignoreMap":47},[52,7500,7501,7503,7506,7508],{"class":54,"line":55},[52,7502,2792],{"class":65},[52,7504,7505],{"class":105}," posts ",[52,7507,69],{"class":58},[52,7509,6454],{"class":105},[52,7511,7512,7514,7517,7519,7521,7523,7526,7528,7530,7533,7535,7537,7540,7542,7544,7547,7549],{"class":54,"line":83},[52,7513,6459],{"class":58},[52,7515,7516],{"class":62},"id",[52,7518,372],{"class":58},[52,7520,31],{"class":4596},[52,7522,407],{"class":58},[52,7524,7525],{"class":62},"title",[52,7527,372],{"class":58},[52,7529,72],{"class":58},[52,7531,7532],{"class":75},"記事タイトル１",[52,7534,72],{"class":58},[52,7536,407],{"class":58},[52,7538,7539],{"class":62},"content",[52,7541,372],{"class":58},[52,7543,72],{"class":58},[52,7545,7546],{"class":75},"...",[52,7548,72],{"class":58},[52,7550,476],{"class":58},[52,7552,7553,7555,7557,7559,7561,7563,7565,7567,7569,7572,7574,7576,7578,7580,7582,7584,7586],{"class":54,"line":115},[52,7554,6459],{"class":58},[52,7556,7516],{"class":62},[52,7558,372],{"class":58},[52,7560,35],{"class":4596},[52,7562,407],{"class":58},[52,7564,7525],{"class":62},[52,7566,372],{"class":58},[52,7568,72],{"class":58},[52,7570,7571],{"class":75},"記事タイトル２",[52,7573,72],{"class":58},[52,7575,407],{"class":58},[52,7577,7539],{"class":62},[52,7579,372],{"class":58},[52,7581,72],{"class":58},[52,7583,7546],{"class":75},[52,7585,72],{"class":58},[52,7587,476],{"class":58},[52,7589,7590,7592,7594,7596,7598,7600,7602,7604,7606,7609,7611,7613,7615,7617,7619,7621,7623],{"class":54,"line":142},[52,7591,6459],{"class":58},[52,7593,7516],{"class":62},[52,7595,372],{"class":58},[52,7597,39],{"class":4596},[52,7599,407],{"class":58},[52,7601,7525],{"class":62},[52,7603,372],{"class":58},[52,7605,72],{"class":58},[52,7607,7608],{"class":75},"記事タイトル３",[52,7610,72],{"class":58},[52,7612,407],{"class":58},[52,7614,7539],{"class":62},[52,7616,372],{"class":58},[52,7618,72],{"class":58},[52,7620,7546],{"class":75},[52,7622,72],{"class":58},[52,7624,476],{"class":58},[52,7626,7627],{"class":54,"line":169},[52,7628,7629],{"class":410},"    \u002F\u002F ...\n",[52,7631,7632],{"class":54,"line":302},[52,7633,6511],{"class":105},[13,7635,7636,7637,7641,7642,7646],{},"今回の記事で解説する内容は上記のような配列を別の変数に格納した時、スプレッド構文を使用して配列を生成したにもかかわらず、オブジェクト内の値が連動してしまったときの対処と原因について解説します。「どんなデータの状況だったか」という実装背景から話すので、ささっと原因からは知りたい人は「",[1445,7638,7640],{"href":7639},"#%E5%8E%9F%E5%9B%A0","原因","」へ、解決方法だけ知りたい人は「",[1445,7643,7645],{"href":7644},"#%E5%AF%BE%E5%87%A6%E6%B3%95","対処法","」へ移動してください。",[17,7648,7649],{"id":7649},"実装背景",[13,7651,7652,7653,7657],{},"vue.jsで編集画面を実装していた時です。編集画面は「入力された新しい値」と「登録済みの値（DBにある値）」を持たせておき、一部でその差分を確認できるようにするという",[7654,7655,7656],"del",{},"面倒な","実装がありました。内容としては「1日の予定表」みたいなもので、以下のようなデータ構造です。",[42,7659,7661],{"className":1249,"code":7660,"language":1251,"meta":47,"style":47},"const DATA_FROM_DB = response.data;\n\nconsole.log(DATA_FROM_DB);\n\u002F**\n{\n    date:\"2021-11-01\", \n    memo:\"...\",\n    todo:   \u002F\u002F この日の予定を入れる。\n    [\n        {id:1,content:\"AAAA\"},\n        {id:2,content:\"BBBB\"},\n        {id:3,content:\"CCCC\"},\n        ...\n    ]\n}\n**\u002F\n\n",[49,7662,7663,7681,7685,7700,7705,7709,7714,7719,7724,7729,7734,7739,7744,7749,7754,7758],{"__ignoreMap":47},[52,7664,7665,7667,7670,7672,7675,7677,7679],{"class":54,"line":55},[52,7666,2792],{"class":65},[52,7668,7669],{"class":105}," DATA_FROM_DB ",[52,7671,69],{"class":58},[52,7673,7674],{"class":105}," response",[52,7676,956],{"class":58},[52,7678,3038],{"class":105},[52,7680,1006],{"class":58},[52,7682,7683],{"class":54,"line":83},[52,7684,340],{"emptyLinePlaceholder":339},[52,7686,7687,7690,7692,7695,7698],{"class":54,"line":115},[52,7688,7689],{"class":105},"console",[52,7691,956],{"class":58},[52,7693,7694],{"class":417},"log",[52,7696,7697],{"class":105},"(DATA_FROM_DB)",[52,7699,1006],{"class":58},[52,7701,7702],{"class":54,"line":142},[52,7703,7704],{"class":410},"\u002F**\n",[52,7706,7707],{"class":54,"line":169},[52,7708,363],{"class":410},[52,7710,7711],{"class":54,"line":302},[52,7712,7713],{"class":410},"    date:\"2021-11-01\", \n",[52,7715,7716],{"class":54,"line":308},[52,7717,7718],{"class":410},"    memo:\"...\",\n",[52,7720,7721],{"class":54,"line":318},[52,7722,7723],{"class":410},"    todo:   \u002F\u002F この日の予定を入れる。\n",[52,7725,7726],{"class":54,"line":328},[52,7727,7728],{"class":410},"    [\n",[52,7730,7731],{"class":54,"line":4},[52,7732,7733],{"class":410},"        {id:1,content:\"AAAA\"},\n",[52,7735,7736],{"class":54,"line":343},[52,7737,7738],{"class":410},"        {id:2,content:\"BBBB\"},\n",[52,7740,7741],{"class":54,"line":353},[52,7742,7743],{"class":410},"        {id:3,content:\"CCCC\"},\n",[52,7745,7746],{"class":54,"line":366},[52,7747,7748],{"class":410},"        ...\n",[52,7750,7751],{"class":54,"line":386},[52,7752,7753],{"class":410},"    ]\n",[52,7755,7756],{"class":54,"line":414},[52,7757,535],{"class":410},[52,7759,7760],{"class":54,"line":426},[52,7761,7762],{"class":410},"**\u002F\n",[13,7764,7765,7766,7769],{},"上記データの ",[49,7767,7768],{},"DATA_FROM_DB.todo"," の変更前のデータを確認できるようにする必要があります。実装のためには別の定数なりに格納しておく必要があります。私はもちろん「参照渡し」・「値渡し」の概念は知っていたので、",[13,7771,7772],{},[49,7773,7774],{},"const OLD_TODO_DATA = DATA_FROM_DB.todo;",[13,7776,7777],{},"なんてことせず、",[13,7779,7780],{},[49,7781,7782],{},"const OLD_TODO_DATA = [...DATA_FROM_DB.todo];",[13,7784,7785],{},"とスプレッド構文を使用して新しく配列を生成しました。これで大丈夫だろと思っていましたが。。",[1721,7787,7789],{"id":7788},"事件は起きた","事件は起きた。",[13,7791,7792,7793,7796],{},"新しいTODOと元のTODOを画面上に表示させて、TODO編集をテストしていた時です。新しくTODOを変更しているはずなに、古い ",[49,7794,7795],{},"OLD_TODO_DATA","から表示している内容も同じ変更した値に切り替わっていました。つまり値が連動していたのです。「WHY?」と声を出してしまいました。開発ツールで見ていても同じ値になっていることが確認できました。値が参照渡しされているとすぐに気づきましたが、「スプレッド構文を使用したのに...」と対処方法ずっと考えていました。",[1905,7798,7801,7802,7807],{"className":7799},[6312,7800],"alert-info","\nここでは値渡しと参照渡しの概念は解説しません。知らない方は",[1445,7803,7806],{"target":7804,"href":7805},"_blank","https:\u002F\u002Fwww.google.com\u002Fsearch?q=js+%E5%80%A4%E6%B8%A1%E3%81%97+%E5%8F%82%E7%85%A7%E6%B8%A1%E3%81%97&oq=js+%E5%80%A4%E6%B8%A1%E3%81%97+%E5%8F%82%E7%85%A7%E6%B8%A1%E3%81%97&aqs=chrome..69i57.290j0j7&sourceid=chrome&ie=UTF-8","「js 値渡し 参照渡し」","でググってください。\n",[17,7809,7640],{"id":7640},[13,7811,7812,7813,7817],{},"原因は内包されたオブジェクトが参照渡しされていたからなのです。スプレッド構文は使用しましたが、これはあくまで",[7814,7815,7816],"strong",{},"別の配列","を作っただけであり、中身のオブジェクトの参照は維持されて（コピー元を参照して）いたのです。",[13,7819,7820],{},"以下のような実験をコンソールでしてみます。",[42,7822,7824],{"className":1249,"code":7823,"filename":7689,"language":1251,"meta":47,"style":47},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const passbyval = origin;\n\n> const spred = [...origin];\n\n> origin === passbyval;\n\u002F\u002F true\n\n> origin === spred;\n\u002F\u002F false\n\n> origin[0] === spred[0];\n\u002F\u002F true\n\u002F\u002F WHY!?\n",[49,7825,7826,7889,7893,7909,7913,7934,7938,7952,7957,7961,7974,7979,7983,8006,8010],{"__ignoreMap":47},[52,7827,7828,7830,7833,7836,7838,7840,7842,7844,7846,7848,7850,7852,7854,7856,7859,7861,7864,7866,7868,7870,7872,7874,7876,7878,7881,7883,7885,7887],{"class":54,"line":55},[52,7829,102],{"class":58},[52,7831,7832],{"class":65}," const",[52,7834,7835],{"class":105}," origin ",[52,7837,69],{"class":58},[52,7839,394],{"class":105},[52,7841,6981],{"class":58},[52,7843,7516],{"class":62},[52,7845,372],{"class":58},[52,7847,31],{"class":4596},[52,7849,407],{"class":58},[52,7851,7539],{"class":62},[52,7853,372],{"class":58},[52,7855,72],{"class":58},[52,7857,7858],{"class":75},"1111",[52,7860,72],{"class":58},[52,7862,7863],{"class":58},"},{",[52,7865,7516],{"class":62},[52,7867,372],{"class":58},[52,7869,35],{"class":4596},[52,7871,407],{"class":58},[52,7873,7539],{"class":62},[52,7875,372],{"class":58},[52,7877,72],{"class":58},[52,7879,7880],{"class":75},"2222",[52,7882,72],{"class":58},[52,7884,1311],{"class":58},[52,7886,404],{"class":105},[52,7888,1006],{"class":58},[52,7890,7891],{"class":54,"line":83},[52,7892,340],{"emptyLinePlaceholder":339},[52,7894,7895,7897,7899,7902,7904,7907],{"class":54,"line":115},[52,7896,102],{"class":58},[52,7898,7832],{"class":65},[52,7900,7901],{"class":105}," passbyval ",[52,7903,69],{"class":58},[52,7905,7906],{"class":105}," origin",[52,7908,1006],{"class":58},[52,7910,7911],{"class":54,"line":142},[52,7912,340],{"emptyLinePlaceholder":339},[52,7914,7915,7917,7919,7922,7924,7927,7929,7932],{"class":54,"line":169},[52,7916,102],{"class":58},[52,7918,7832],{"class":65},[52,7920,7921],{"class":105}," spred ",[52,7923,69],{"class":58},[52,7925,7926],{"class":105}," [",[52,7928,7546],{"class":58},[52,7930,7931],{"class":105},"origin]",[52,7933,1006],{"class":58},[52,7935,7936],{"class":54,"line":302},[52,7937,340],{"emptyLinePlaceholder":339},[52,7939,7940,7942,7944,7947,7950],{"class":54,"line":308},[52,7941,102],{"class":58},[52,7943,7835],{"class":105},[52,7945,7946],{"class":58},"===",[52,7948,7949],{"class":105}," passbyval",[52,7951,1006],{"class":58},[52,7953,7954],{"class":54,"line":318},[52,7955,7956],{"class":410},"\u002F\u002F true\n",[52,7958,7959],{"class":54,"line":328},[52,7960,340],{"emptyLinePlaceholder":339},[52,7962,7963,7965,7967,7969,7972],{"class":54,"line":4},[52,7964,102],{"class":58},[52,7966,7835],{"class":105},[52,7968,7946],{"class":58},[52,7970,7971],{"class":105}," spred",[52,7973,1006],{"class":58},[52,7975,7976],{"class":54,"line":343},[52,7977,7978],{"class":410},"\u002F\u002F false\n",[52,7980,7981],{"class":54,"line":353},[52,7982,340],{"emptyLinePlaceholder":339},[52,7984,7985,7987,7990,7993,7995,7997,8000,8002,8004],{"class":54,"line":366},[52,7986,102],{"class":58},[52,7988,7989],{"class":105}," origin[",[52,7991,7992],{"class":4596},"0",[52,7994,6802],{"class":105},[52,7996,7946],{"class":58},[52,7998,7999],{"class":105}," spred[",[52,8001,7992],{"class":4596},[52,8003,404],{"class":105},[52,8005,1006],{"class":58},[52,8007,8008],{"class":54,"line":386},[52,8009,7956],{"class":410},[52,8011,8012],{"class":54,"line":414},[52,8013,8014],{"class":410},"\u002F\u002F WHY!?\n",[13,8016,8017,8018,8021,8022,8024,8025,2374,8028,8030,8031,8034],{},"上記が示すとおり、スプレッド構文を使用することで配列としては別物の",[49,8019,8020],{},"origin === copy"," は",[49,8023,1326],{},"となり、値渡しの",[49,8026,8027],{},"origin === passbyval ",[49,8029,1322],{},"となります。ただし同じindexのオブジェクトを比較すると、なんと同じになっています。値を変えてみると",[49,8032,8033],{},"spred","も変更されているのが分かります。",[42,8036,8038],{"className":1249,"code":8037,"filename":7689,"language":1251,"meta":47,"style":47},"> origin[0].content = \"changed!\";\n\n> spred[0];\n\u002F\u002F {id: 1, content: 'changed!'}\n\u002F\u002F contentが変更されている\n",[49,8039,8040,8066,8070,8082,8087],{"__ignoreMap":47},[52,8041,8042,8044,8046,8048,8050,8052,8055,8057,8059,8062,8064],{"class":54,"line":55},[52,8043,102],{"class":58},[52,8045,7989],{"class":105},[52,8047,7992],{"class":4596},[52,8049,404],{"class":105},[52,8051,956],{"class":58},[52,8053,8054],{"class":105},"content ",[52,8056,69],{"class":58},[52,8058,1502],{"class":58},[52,8060,8061],{"class":75},"changed!",[52,8063,72],{"class":58},[52,8065,1006],{"class":58},[52,8067,8068],{"class":54,"line":83},[52,8069,340],{"emptyLinePlaceholder":339},[52,8071,8072,8074,8076,8078,8080],{"class":54,"line":115},[52,8073,102],{"class":58},[52,8075,7999],{"class":105},[52,8077,7992],{"class":4596},[52,8079,404],{"class":105},[52,8081,1006],{"class":58},[52,8083,8084],{"class":54,"line":142},[52,8085,8086],{"class":410},"\u002F\u002F {id: 1, content: 'changed!'}\n",[52,8088,8089],{"class":54,"line":169},[52,8090,8091],{"class":410},"\u002F\u002F contentが変更されている\n",[13,8093,8094],{},"これが今回起きた原因です。つまり一応スプレッド構文を使用するのは配列の値をコピーするのでは確かに正しいのですが、今回のようなオブジェクトが内包されている場合は別の手法が必要です。",[17,8096,7645],{"id":7645},[13,8098,8099],{},"さて上記のように配列にオブジェクトが内包されている場合は、オブジェクトの参照が維持されたままになるのは確認できました。ではスプレッド構文以外にどうやって中身を値渡しできるでしょうか？",[13,8101,8102],{},"この時とられる方法としては「ディープコピー」があります。今回のように配列内のオブジェクトも値渡ししたいとき、つまり配列の中の深いとこまでマルッと別物としてコピーする処理をディープコピーと言います。",[1905,8104,8107,8108,8111],{"className":8105},[6312,8106],"alert-warning","\nvanilla ES6に",[49,8109,8110],{},"Array.prototype.deepcopy()","みたいなディープコピーを一発で行う関数はありません。以下の３つテクニックを使用します。\n",[1721,8113,8115],{"id":8114},"_1jsonstringifyを使う","1:JSON.stringifyを使う",[13,8117,8118,8119,8122,8123,8126],{},"手取り早いのは",[49,8120,8121],{},"JSON.stringify()","を使用してコピー元をJSONにして、すぐに",[49,8124,8125],{},"JSON.parse()","を使用して元に戻します。この際、デコードしたJSONは全く新しい値となるので参照を断ち切ることができます。",[42,8128,8130],{"className":1249,"code":8129,"filename":7689,"language":1251,"meta":47,"style":47},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const copyjson = JSON.prase(JSON.stringify(origin));\n\n> copyjson;\n\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n\n> origin === copyjson;\n\u002F\u002F false\n\n> origin[0] === copyjson[0]\n\u002F\u002F false\n\u002F\u002F よし！\n",[49,8131,8132,8190,8194,8226,8230,8239,8244,8248,8260,8264,8268,8287,8291],{"__ignoreMap":47},[52,8133,8134,8136,8138,8140,8142,8144,8146,8148,8150,8152,8154,8156,8158,8160,8162,8164,8166,8168,8170,8172,8174,8176,8178,8180,8182,8184,8186,8188],{"class":54,"line":55},[52,8135,102],{"class":58},[52,8137,7832],{"class":65},[52,8139,7835],{"class":105},[52,8141,69],{"class":58},[52,8143,394],{"class":105},[52,8145,6981],{"class":58},[52,8147,7516],{"class":62},[52,8149,372],{"class":58},[52,8151,31],{"class":4596},[52,8153,407],{"class":58},[52,8155,7539],{"class":62},[52,8157,372],{"class":58},[52,8159,72],{"class":58},[52,8161,7858],{"class":75},[52,8163,72],{"class":58},[52,8165,7863],{"class":58},[52,8167,7516],{"class":62},[52,8169,372],{"class":58},[52,8171,35],{"class":4596},[52,8173,407],{"class":58},[52,8175,7539],{"class":62},[52,8177,372],{"class":58},[52,8179,72],{"class":58},[52,8181,7880],{"class":75},[52,8183,72],{"class":58},[52,8185,1311],{"class":58},[52,8187,404],{"class":105},[52,8189,1006],{"class":58},[52,8191,8192],{"class":54,"line":83},[52,8193,340],{"emptyLinePlaceholder":339},[52,8195,8196,8198,8200,8203,8205,8208,8210,8213,8216,8218,8221,8224],{"class":54,"line":115},[52,8197,102],{"class":58},[52,8199,7832],{"class":65},[52,8201,8202],{"class":105}," copyjson ",[52,8204,69],{"class":58},[52,8206,8207],{"class":105}," JSON",[52,8209,956],{"class":58},[52,8211,8212],{"class":417},"prase",[52,8214,8215],{"class":105},"(JSON",[52,8217,956],{"class":58},[52,8219,8220],{"class":417},"stringify",[52,8222,8223],{"class":105},"(origin))",[52,8225,1006],{"class":58},[52,8227,8228],{"class":54,"line":142},[52,8229,340],{"emptyLinePlaceholder":339},[52,8231,8232,8234,8237],{"class":54,"line":169},[52,8233,102],{"class":58},[52,8235,8236],{"class":105}," copyjson",[52,8238,1006],{"class":58},[52,8240,8241],{"class":54,"line":302},[52,8242,8243],{"class":410},"\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n",[52,8245,8246],{"class":54,"line":308},[52,8247,340],{"emptyLinePlaceholder":339},[52,8249,8250,8252,8254,8256,8258],{"class":54,"line":318},[52,8251,102],{"class":58},[52,8253,7835],{"class":105},[52,8255,7946],{"class":58},[52,8257,8236],{"class":105},[52,8259,1006],{"class":58},[52,8261,8262],{"class":54,"line":328},[52,8263,7978],{"class":410},[52,8265,8266],{"class":54,"line":4},[52,8267,340],{"emptyLinePlaceholder":339},[52,8269,8270,8272,8274,8276,8278,8280,8283,8285],{"class":54,"line":343},[52,8271,102],{"class":58},[52,8273,7989],{"class":105},[52,8275,7992],{"class":4596},[52,8277,6802],{"class":105},[52,8279,7946],{"class":58},[52,8281,8282],{"class":105}," copyjson[",[52,8284,7992],{"class":4596},[52,8286,6511],{"class":105},[52,8288,8289],{"class":54,"line":353},[52,8290,7978],{"class":410},[52,8292,8293],{"class":54,"line":366},[52,8294,8295],{"class":410},"\u002F\u002F よし！\n",[13,8297,8298],{},"JSONエンコードしてデコードする必要はありますが、中身がなんであろうが関係なく展開できるのは良いところです。",[1721,8300,8302],{"id":8301},"_2スプレッドとmapを組み合わせる使用箇所が限定的なので微妙","2:スプレッドとmap()を組み合わせる（使用箇所が限定的なので微妙）",[13,8304,8305,8306,8312],{},"スプレッド構文はオブジェクトにも使用できます。しかし今回は配列内にいるのが厄介です。そんな時は ",[1445,8307,8310],{"href":8308,"rel":8309},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FArray\u002Fmap",[1449],[49,8311,1392],{},"を使用して各々のオブジェクトを展開して、新しい配列を生成します。",[42,8314,8316],{"className":1249,"code":8315,"filename":7689,"language":1251,"meta":47,"style":47},"> const origin =[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n\n> const copymap = origin.map(obj => {return {...obj}});\n\n> copymap;\n\u002F\u002F [{id:1,content:\"1111\"},{id:2,content:\"2222\"}]\n\n> origin === copymap;\n\u002F\u002F false\n\n> origin[0] === copymap[0]\n\u002F\u002F false\n\u002F\u002F よし！\n",[49,8317,8318,8376,8380,8421,8425,8434,8438,8442,8454,8458,8462,8481,8485],{"__ignoreMap":47},[52,8319,8320,8322,8324,8326,8328,8330,8332,8334,8336,8338,8340,8342,8344,8346,8348,8350,8352,8354,8356,8358,8360,8362,8364,8366,8368,8370,8372,8374],{"class":54,"line":55},[52,8321,102],{"class":58},[52,8323,7832],{"class":65},[52,8325,7835],{"class":105},[52,8327,69],{"class":58},[52,8329,394],{"class":105},[52,8331,6981],{"class":58},[52,8333,7516],{"class":62},[52,8335,372],{"class":58},[52,8337,31],{"class":4596},[52,8339,407],{"class":58},[52,8341,7539],{"class":62},[52,8343,372],{"class":58},[52,8345,72],{"class":58},[52,8347,7858],{"class":75},[52,8349,72],{"class":58},[52,8351,7863],{"class":58},[52,8353,7516],{"class":62},[52,8355,372],{"class":58},[52,8357,35],{"class":4596},[52,8359,407],{"class":58},[52,8361,7539],{"class":62},[52,8363,372],{"class":58},[52,8365,72],{"class":58},[52,8367,7880],{"class":75},[52,8369,72],{"class":58},[52,8371,1311],{"class":58},[52,8373,404],{"class":105},[52,8375,1006],{"class":58},[52,8377,8378],{"class":54,"line":83},[52,8379,340],{"emptyLinePlaceholder":339},[52,8381,8382,8384,8386,8389,8391,8393,8395,8397,8399,8402,8404,8407,8409,8412,8414,8417,8419],{"class":54,"line":115},[52,8383,102],{"class":58},[52,8385,7832],{"class":65},[52,8387,8388],{"class":105}," copymap ",[52,8390,69],{"class":58},[52,8392,7906],{"class":105},[52,8394,956],{"class":58},[52,8396,1030],{"class":417},[52,8398,931],{"class":105},[52,8400,8401],{"class":985},"obj",[52,8403,2282],{"class":65},[52,8405,8406],{"class":58}," {",[52,8408,2403],{"class":359},[52,8410,8411],{"class":58}," {...",[52,8413,8401],{"class":105},[52,8415,8416],{"class":58},"}}",[52,8418,937],{"class":105},[52,8420,1006],{"class":58},[52,8422,8423],{"class":54,"line":142},[52,8424,340],{"emptyLinePlaceholder":339},[52,8426,8427,8429,8432],{"class":54,"line":169},[52,8428,102],{"class":58},[52,8430,8431],{"class":105}," copymap",[52,8433,1006],{"class":58},[52,8435,8436],{"class":54,"line":302},[52,8437,8243],{"class":410},[52,8439,8440],{"class":54,"line":308},[52,8441,340],{"emptyLinePlaceholder":339},[52,8443,8444,8446,8448,8450,8452],{"class":54,"line":318},[52,8445,102],{"class":58},[52,8447,7835],{"class":105},[52,8449,7946],{"class":58},[52,8451,8431],{"class":105},[52,8453,1006],{"class":58},[52,8455,8456],{"class":54,"line":328},[52,8457,7978],{"class":410},[52,8459,8460],{"class":54,"line":4},[52,8461,340],{"emptyLinePlaceholder":339},[52,8463,8464,8466,8468,8470,8472,8474,8477,8479],{"class":54,"line":343},[52,8465,102],{"class":58},[52,8467,7989],{"class":105},[52,8469,7992],{"class":4596},[52,8471,6802],{"class":105},[52,8473,7946],{"class":58},[52,8475,8476],{"class":105}," copymap[",[52,8478,7992],{"class":4596},[52,8480,6511],{"class":105},[52,8482,8483],{"class":54,"line":353},[52,8484,7978],{"class":410},[52,8486,8487],{"class":54,"line":366},[52,8488,8295],{"class":410},[13,8490,8491,8492,8495],{},"JSONを使うよりスマートですが、配列内がオブジェクト・配列といったiterableなものでないと使えません。今使用した",[49,8493,8494],{},"origin","のような簡単な構成であればいいですが、途中で文字列があったりなど、中身が全てiterableである保証がない場合はエラーが起きる可能性があります。あと以下の様にオブジェクトの中にオブジェクトがあるネストした場合はディープコピーできません！！",[42,8497,8499],{"className":1249,"code":8498,"filename":7689,"language":1251,"meta":47,"style":47},"> const origin =[{id:1,content:{summery:\"detail1\",detail:\"detail1\"}},{id:2,content:{summery:\"detail2\",detail:\"detail2\"}},];\n\n> const copymap = origin.map(obj => {return {...obj}});\n\n> origin[0] === copymap[0]\n\u002F\u002F false\n\n> origin[0].content === copymap[0].content;\n\u002F\u002F true\n\u002F\u002F んっっ！？\n",[49,8500,8501,8598,8602,8638,8642,8660,8664,8668,8696,8700],{"__ignoreMap":47},[52,8502,8503,8505,8507,8509,8511,8513,8515,8517,8519,8521,8523,8525,8528,8531,8533,8535,8538,8540,8542,8545,8547,8549,8551,8553,8556,8558,8560,8562,8564,8566,8568,8570,8572,8574,8577,8579,8581,8583,8585,8587,8589,8591,8594,8596],{"class":54,"line":55},[52,8504,102],{"class":58},[52,8506,7832],{"class":65},[52,8508,7835],{"class":105},[52,8510,69],{"class":58},[52,8512,394],{"class":105},[52,8514,6981],{"class":58},[52,8516,7516],{"class":62},[52,8518,372],{"class":58},[52,8520,31],{"class":4596},[52,8522,407],{"class":58},[52,8524,7539],{"class":62},[52,8526,8527],{"class":58},":{",[52,8529,8530],{"class":62},"summery",[52,8532,372],{"class":58},[52,8534,72],{"class":58},[52,8536,8537],{"class":75},"detail1",[52,8539,72],{"class":58},[52,8541,407],{"class":58},[52,8543,8544],{"class":62},"detail",[52,8546,372],{"class":58},[52,8548,72],{"class":58},[52,8550,8537],{"class":75},[52,8552,72],{"class":58},[52,8554,8555],{"class":58},"}},{",[52,8557,7516],{"class":62},[52,8559,372],{"class":58},[52,8561,35],{"class":4596},[52,8563,407],{"class":58},[52,8565,7539],{"class":62},[52,8567,8527],{"class":58},[52,8569,8530],{"class":62},[52,8571,372],{"class":58},[52,8573,72],{"class":58},[52,8575,8576],{"class":75},"detail2",[52,8578,72],{"class":58},[52,8580,407],{"class":58},[52,8582,8544],{"class":62},[52,8584,372],{"class":58},[52,8586,72],{"class":58},[52,8588,8576],{"class":75},[52,8590,72],{"class":58},[52,8592,8593],{"class":58},"}},",[52,8595,404],{"class":105},[52,8597,1006],{"class":58},[52,8599,8600],{"class":54,"line":83},[52,8601,340],{"emptyLinePlaceholder":339},[52,8603,8604,8606,8608,8610,8612,8614,8616,8618,8620,8622,8624,8626,8628,8630,8632,8634,8636],{"class":54,"line":115},[52,8605,102],{"class":58},[52,8607,7832],{"class":65},[52,8609,8388],{"class":105},[52,8611,69],{"class":58},[52,8613,7906],{"class":105},[52,8615,956],{"class":58},[52,8617,1030],{"class":417},[52,8619,931],{"class":105},[52,8621,8401],{"class":985},[52,8623,2282],{"class":65},[52,8625,8406],{"class":58},[52,8627,2403],{"class":359},[52,8629,8411],{"class":58},[52,8631,8401],{"class":105},[52,8633,8416],{"class":58},[52,8635,937],{"class":105},[52,8637,1006],{"class":58},[52,8639,8640],{"class":54,"line":142},[52,8641,340],{"emptyLinePlaceholder":339},[52,8643,8644,8646,8648,8650,8652,8654,8656,8658],{"class":54,"line":169},[52,8645,102],{"class":58},[52,8647,7989],{"class":105},[52,8649,7992],{"class":4596},[52,8651,6802],{"class":105},[52,8653,7946],{"class":58},[52,8655,8476],{"class":105},[52,8657,7992],{"class":4596},[52,8659,6511],{"class":105},[52,8661,8662],{"class":54,"line":302},[52,8663,7978],{"class":410},[52,8665,8666],{"class":54,"line":308},[52,8667,340],{"emptyLinePlaceholder":339},[52,8669,8670,8672,8674,8676,8678,8680,8682,8684,8686,8688,8690,8692,8694],{"class":54,"line":318},[52,8671,102],{"class":58},[52,8673,7989],{"class":105},[52,8675,7992],{"class":4596},[52,8677,404],{"class":105},[52,8679,956],{"class":58},[52,8681,8054],{"class":105},[52,8683,7946],{"class":58},[52,8685,8476],{"class":105},[52,8687,7992],{"class":4596},[52,8689,404],{"class":105},[52,8691,956],{"class":58},[52,8693,7539],{"class":105},[52,8695,1006],{"class":58},[52,8697,8698],{"class":54,"line":328},[52,8699,7956],{"class":410},[52,8701,8702],{"class":54,"line":4},[52,8703,8704],{"class":410},"\u002F\u002F んっっ！？\n",[13,8706,8707],{},"なのでこのmapとスプレッドは使うのは結構微妙です。",[1721,8709,8711],{"id":8710},"_3lodashのclonedeepを使用する","3:lodashのcloneDeep()を使用する",[13,8713,8714,8715,8718,8719,8721],{},"テクニックではないのですがlodashなどのライブラリを用いると、",[49,8716,8717],{},"cloneDeep()","といったディープコピー を行うユーティリティー関数があります。面倒な場合はそれを使ってしまってもいいと思います。なんか方法１のJSONよりもlodashの",[49,8720,8717],{},"の方が早いみたいです。",[13,8723,8724],{},[1445,8725,8728],{"href":8726,"rel":8727},"https:\u002F\u002Fqiita.com\u002Fsuin\u002Fitems\u002F80e687dd1789b9d9d2fd",[1449],"参考：JavaScriptのディープコピー速さ比較 〜7つの手法\u002Fライブラリを比べてみた〜",[42,8730,8732],{"className":1249,"code":8731,"filename":7689,"language":1251,"meta":47,"style":47},"> const origin =[{id:1,content:{summery:\"detail1\",detail:\"detail1\"}},{id:2,content:{summery:\"detail2\",detail:\"detail2\"}},];\n\n> const copy_ =  _.cloneDeep(origin);\n\n> origin[0] === copy_[0]\n\u002F\u002F false\n\n> origin[0].content === copy_[0].content;\n\u002F\u002F false\n\u002F\u002F よし！\n",[49,8733,8734,8824,8828,8852,8856,8875,8879,8883,8911,8915],{"__ignoreMap":47},[52,8735,8736,8738,8740,8742,8744,8746,8748,8750,8752,8754,8756,8758,8760,8762,8764,8766,8768,8770,8772,8774,8776,8778,8780,8782,8784,8786,8788,8790,8792,8794,8796,8798,8800,8802,8804,8806,8808,8810,8812,8814,8816,8818,8820,8822],{"class":54,"line":55},[52,8737,102],{"class":58},[52,8739,7832],{"class":65},[52,8741,7835],{"class":105},[52,8743,69],{"class":58},[52,8745,394],{"class":105},[52,8747,6981],{"class":58},[52,8749,7516],{"class":62},[52,8751,372],{"class":58},[52,8753,31],{"class":4596},[52,8755,407],{"class":58},[52,8757,7539],{"class":62},[52,8759,8527],{"class":58},[52,8761,8530],{"class":62},[52,8763,372],{"class":58},[52,8765,72],{"class":58},[52,8767,8537],{"class":75},[52,8769,72],{"class":58},[52,8771,407],{"class":58},[52,8773,8544],{"class":62},[52,8775,372],{"class":58},[52,8777,72],{"class":58},[52,8779,8537],{"class":75},[52,8781,72],{"class":58},[52,8783,8555],{"class":58},[52,8785,7516],{"class":62},[52,8787,372],{"class":58},[52,8789,35],{"class":4596},[52,8791,407],{"class":58},[52,8793,7539],{"class":62},[52,8795,8527],{"class":58},[52,8797,8530],{"class":62},[52,8799,372],{"class":58},[52,8801,72],{"class":58},[52,8803,8576],{"class":75},[52,8805,72],{"class":58},[52,8807,407],{"class":58},[52,8809,8544],{"class":62},[52,8811,372],{"class":58},[52,8813,72],{"class":58},[52,8815,8576],{"class":75},[52,8817,72],{"class":58},[52,8819,8593],{"class":58},[52,8821,404],{"class":105},[52,8823,1006],{"class":58},[52,8825,8826],{"class":54,"line":83},[52,8827,340],{"emptyLinePlaceholder":339},[52,8829,8830,8832,8834,8837,8839,8842,8844,8847,8850],{"class":54,"line":115},[52,8831,102],{"class":58},[52,8833,7832],{"class":65},[52,8835,8836],{"class":105}," copy_ ",[52,8838,69],{"class":58},[52,8840,8841],{"class":105},"  _",[52,8843,956],{"class":58},[52,8845,8846],{"class":417},"cloneDeep",[52,8848,8849],{"class":105},"(origin)",[52,8851,1006],{"class":58},[52,8853,8854],{"class":54,"line":142},[52,8855,340],{"emptyLinePlaceholder":339},[52,8857,8858,8860,8862,8864,8866,8868,8871,8873],{"class":54,"line":169},[52,8859,102],{"class":58},[52,8861,7989],{"class":105},[52,8863,7992],{"class":4596},[52,8865,6802],{"class":105},[52,8867,7946],{"class":58},[52,8869,8870],{"class":105}," copy_[",[52,8872,7992],{"class":4596},[52,8874,6511],{"class":105},[52,8876,8877],{"class":54,"line":302},[52,8878,7978],{"class":410},[52,8880,8881],{"class":54,"line":308},[52,8882,340],{"emptyLinePlaceholder":339},[52,8884,8885,8887,8889,8891,8893,8895,8897,8899,8901,8903,8905,8907,8909],{"class":54,"line":318},[52,8886,102],{"class":58},[52,8888,7989],{"class":105},[52,8890,7992],{"class":4596},[52,8892,404],{"class":105},[52,8894,956],{"class":58},[52,8896,8054],{"class":105},[52,8898,7946],{"class":58},[52,8900,8870],{"class":105},[52,8902,7992],{"class":4596},[52,8904,404],{"class":105},[52,8906,956],{"class":58},[52,8908,7539],{"class":105},[52,8910,1006],{"class":58},[52,8912,8913],{"class":54,"line":328},[52,8914,7978],{"class":410},[52,8916,8917],{"class":54,"line":4},[52,8918,8295],{"class":410},[13,8920,8921],{},"ちなみに方法１のJSONもネストしたオブジェクトの参照は断ち切れます。",[17,8923,8925],{"id":8924},"ライブラリかjson変換を使うといい","ライブラリかJSON変換を使うといい",[13,8927,8928],{},"以上が配列内のオブジェクトの値が連動してしまう原因と対処法です。正確には配列内にオブジェクトを含む場合や、オブジェクト内にオブジェクトを含む値コピーする時は「ディープコピー 」を使いましょうというお話です。ネストしたオブジェクトは今回解説した様に、参照が根深く残っています。アプリによっては以下のような単純な構造でなく、",[42,8930,8932],{"className":1249,"code":8931,"language":1251,"meta":47,"style":47},"[{id:1,content:\"1111\"},{id:2,content:\"2222\"}];\n",[49,8933,8934],{"__ignoreMap":47},[52,8935,8936,8938,8940,8942,8944,8946,8948,8950,8952,8954,8956,8958,8960,8962,8964,8966,8968,8970,8972,8974,8976,8978,8980,8982],{"class":54,"line":55},[52,8937,394],{"class":105},[52,8939,6981],{"class":58},[52,8941,7516],{"class":62},[52,8943,372],{"class":58},[52,8945,31],{"class":4596},[52,8947,407],{"class":58},[52,8949,7539],{"class":62},[52,8951,372],{"class":58},[52,8953,72],{"class":58},[52,8955,7858],{"class":75},[52,8957,72],{"class":58},[52,8959,7863],{"class":58},[52,8961,7516],{"class":62},[52,8963,372],{"class":58},[52,8965,35],{"class":4596},[52,8967,407],{"class":58},[52,8969,7539],{"class":62},[52,8971,372],{"class":58},[52,8973,72],{"class":58},[52,8975,7880],{"class":75},[52,8977,72],{"class":58},[52,8979,1311],{"class":58},[52,8981,404],{"class":105},[52,8983,1006],{"class":58},[13,8985,8986],{},"以下のように内包する値も複雑で、さらにオブジェクトがネストしていることもあります。",[42,8988,8990],{"className":1249,"code":8989,"language":1251,"meta":47,"style":47},"const origin = {\n    title: \"...\", \u002F\u002F 途中にiterableでないものがある。\n    todo:[\n            {\n                id:1,\n                \u002F\u002F オブジェクトがネストしている\n                content:{\n                    summery:\"detail1\",detail:\"detail1\"\n                }\n            },\n            {\n                id:2,\n                content:{\n                    summery:\"detail2\",detail:\"detail2\"\n                }\n            }\n        ];\n    \u002F\u002F More unpredictable properties..\n}\n",[49,8991,8992,9002,9020,9029,9034,9045,9050,9057,9082,9087,9091,9095,9105,9111,9135,9139,9143,9148,9153],{"__ignoreMap":47},[52,8993,8994,8996,8998,9000],{"class":54,"line":55},[52,8995,2792],{"class":65},[52,8997,7835],{"class":105},[52,8999,69],{"class":58},[52,9001,2012],{"class":58},[52,9003,9004,9007,9009,9011,9013,9015,9017],{"class":54,"line":83},[52,9005,9006],{"class":62},"    title",[52,9008,372],{"class":58},[52,9010,1502],{"class":58},[52,9012,7546],{"class":75},[52,9014,72],{"class":58},[52,9016,407],{"class":58},[52,9018,9019],{"class":410}," \u002F\u002F 途中にiterableでないものがある。\n",[52,9021,9022,9025,9027],{"class":54,"line":115},[52,9023,9024],{"class":62},"    todo",[52,9026,372],{"class":58},[52,9028,442],{"class":105},[52,9030,9031],{"class":54,"line":142},[52,9032,9033],{"class":58},"            {\n",[52,9035,9036,9039,9041,9043],{"class":54,"line":169},[52,9037,9038],{"class":62},"                id",[52,9040,372],{"class":58},[52,9042,31],{"class":4596},[52,9044,383],{"class":58},[52,9046,9047],{"class":54,"line":302},[52,9048,9049],{"class":410},"                \u002F\u002F オブジェクトがネストしている\n",[52,9051,9052,9055],{"class":54,"line":308},[52,9053,9054],{"class":62},"                content",[52,9056,923],{"class":58},[52,9058,9059,9062,9064,9066,9068,9070,9072,9074,9076,9078,9080],{"class":54,"line":318},[52,9060,9061],{"class":62},"                    summery",[52,9063,372],{"class":58},[52,9065,72],{"class":58},[52,9067,8537],{"class":75},[52,9069,72],{"class":58},[52,9071,407],{"class":58},[52,9073,8544],{"class":62},[52,9075,372],{"class":58},[52,9077,72],{"class":58},[52,9079,8537],{"class":75},[52,9081,266],{"class":58},[52,9083,9084],{"class":54,"line":328},[52,9085,9086],{"class":58},"                }\n",[52,9088,9089],{"class":54,"line":4},[52,9090,4972],{"class":58},[52,9092,9093],{"class":54,"line":343},[52,9094,9033],{"class":58},[52,9096,9097,9099,9101,9103],{"class":54,"line":353},[52,9098,9038],{"class":62},[52,9100,372],{"class":58},[52,9102,35],{"class":4596},[52,9104,383],{"class":58},[52,9106,9107,9109],{"class":54,"line":366},[52,9108,9054],{"class":62},[52,9110,923],{"class":58},[52,9112,9113,9115,9117,9119,9121,9123,9125,9127,9129,9131,9133],{"class":54,"line":386},[52,9114,9061],{"class":62},[52,9116,372],{"class":58},[52,9118,72],{"class":58},[52,9120,8576],{"class":75},[52,9122,72],{"class":58},[52,9124,407],{"class":58},[52,9126,8544],{"class":62},[52,9128,372],{"class":58},[52,9130,72],{"class":58},[52,9132,8576],{"class":75},[52,9134,266],{"class":58},[52,9136,9137],{"class":54,"line":414},[52,9138,9086],{"class":58},[52,9140,9141],{"class":54,"line":426},[52,9142,2320],{"class":58},[52,9144,9145],{"class":54,"line":434},[52,9146,9147],{"class":105},"        ];\n",[52,9149,9150],{"class":54,"line":445},[52,9151,9152],{"class":410},"    \u002F\u002F More unpredictable properties..\n",[52,9154,9155],{"class":54,"line":479},[52,9156,535],{"class":58},[13,9158,9159],{},"上記のような状況を踏まえると、ディープコピー はJSONを用いるか大人しくライブラリを使用する方が賢明そうです。値が連動してしまう時はまず値渡し・参照渡しを疑い、その次はディープコピーがされているか（ネストしたオブジェクトがないか）を確かめてみましょう。",[1413,9161,9162],{},"html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}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 pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}",{"title":47,"searchDepth":115,"depth":115,"links":9164},[9165,9168,9169,9174],{"id":7649,"depth":83,"text":7649,"children":9166},[9167],{"id":7788,"depth":115,"text":7789},{"id":7640,"depth":83,"text":7640},{"id":7645,"depth":83,"text":7645,"children":9170},[9171,9172,9173],{"id":8114,"depth":115,"text":8115},{"id":8301,"depth":115,"text":8302},{"id":8710,"depth":115,"text":8711},{"id":8924,"depth":83,"text":8925},[9176],"ministack","2021-11-07","配列内のオブジェクトの値が連動するときの原因と対処法",{},"\u002Farticles\u002Fjs-deep-copy",{"title":7484,"description":9178},"articles\u002Fjs-deep-copy",[1433,204],"TVfFMZbaj-eg5y8hB-QhEPtPjdhOPFn6vmaY0JeSo0g",{"id":9186,"title":9187,"body":9188,"category":9722,"createdAt":9723,"description":9724,"extension":1426,"index":1427,"meta":9725,"navigation":339,"path":9726,"publish":339,"seo":9727,"series":1427,"seriesTitle":1427,"stem":9728,"tag":9729,"thumbnail":9731,"updatedAt":1427,"__hash__":9732},"articles\u002Farticles\u002Fbag-html-break-tag.md","white-space： pre;で要素内で生じる文章の隙間、インテンドの原因。",{"type":10,"value":9189,"toc":9720},[9190,9197,9201,9204,9381,9394,9406,9413,9537,9543,9546,9549,9711,9717],[13,9191,9192,9193,9196],{},"こんにちはjunです。ある日、vue.jsを使用して",[49,9194,9195],{},"textarea","の中の文章をリアルタイムにレンダーするような機能を実装しました。その時、改行文章に謎のインテンドが入り、困りました。こんな感じです。",[728,9198],{":src":9199,":width":9200,":center":1322},"'_mix\u002Fsch-2021-05-04 21.53.14.png'","'300px'",[13,9202,9203],{},"ソースは以下の感じ（かなり簡略化してます。）",[42,9205,9207],{"className":202,"code":9206,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">\n        {{test}}\n        \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n    \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    data(){\n        return{\n            test:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[49,9208,9209,9217,9225,9245,9250,9299,9307,9315,9323,9331,9339,9345,9351,9361,9365,9369,9373],{"__ignoreMap":47},[52,9210,9211,9213,9215],{"class":54,"line":55},[52,9212,59],{"class":58},[52,9214,213],{"class":62},[52,9216,80],{"class":58},[52,9218,9219,9221,9223],{"class":54,"line":83},[52,9220,59],{"class":58},[52,9222,1905],{"class":62},[52,9224,80],{"class":58},[52,9226,9227,9229,9231,9234,9236,9238,9241,9243],{"class":54,"line":115},[52,9228,1902],{"class":58},[52,9230,1905],{"class":62},[52,9232,9233],{"class":65}," style",[52,9235,69],{"class":58},[52,9237,72],{"class":58},[52,9239,9240],{"class":75},"white-space:pre;",[52,9242,72],{"class":58},[52,9244,80],{"class":58},[52,9246,9247],{"class":54,"line":142},[52,9248,9249],{"class":105},"        {{test}}\n",[52,9251,9252,9254,9256,9259,9261,9263,9266,9268,9271,9273,9275,9278,9280,9283,9285,9287,9290,9292,9295,9297],{"class":54,"line":169},[52,9253,1912],{"class":58},[52,9255,9195],{"class":62},[52,9257,9258],{"class":65}," v-model",[52,9260,69],{"class":58},[52,9262,72],{"class":58},[52,9264,9265],{"class":75},"test",[52,9267,72],{"class":58},[52,9269,9270],{"class":65},"cols",[52,9272,69],{"class":58},[52,9274,72],{"class":58},[52,9276,9277],{"class":75},"30",[52,9279,72],{"class":58},[52,9281,9282],{"class":65}," rows",[52,9284,69],{"class":58},[52,9286,72],{"class":58},[52,9288,9289],{"class":75},"10",[52,9291,72],{"class":58},[52,9293,9294],{"class":58},">\u003C\u002F",[52,9296,9195],{"class":62},[52,9298,80],{"class":58},[52,9300,9301,9303,9305],{"class":54,"line":302},[52,9302,1946],{"class":58},[52,9304,1905],{"class":62},[52,9306,80],{"class":58},[52,9308,9309,9311,9313],{"class":54,"line":308},[52,9310,108],{"class":58},[52,9312,1905],{"class":62},[52,9314,80],{"class":58},[52,9316,9317,9319,9321],{"class":54,"line":318},[52,9318,108],{"class":58},[52,9320,213],{"class":62},[52,9322,80],{"class":58},[52,9324,9325,9327,9329],{"class":54,"line":328},[52,9326,59],{"class":58},[52,9328,348],{"class":62},[52,9330,80],{"class":58},[52,9332,9333,9335,9337],{"class":54,"line":4},[52,9334,356],{"class":359},[52,9336,360],{"class":359},[52,9338,2012],{"class":58},[52,9340,9341,9343],{"class":54,"line":343},[52,9342,2033],{"class":62},[52,9344,2036],{"class":58},[52,9346,9347,9349],{"class":54,"line":353},[52,9348,2041],{"class":359},[52,9350,363],{"class":58},[52,9352,9353,9356,9358],{"class":54,"line":366},[52,9354,9355],{"class":62},"            test",[52,9357,372],{"class":58},[52,9359,9360],{"class":58},"''\n",[52,9362,9363],{"class":54,"line":386},[52,9364,2060],{"class":58},[52,9366,9367],{"class":54,"line":414},[52,9368,3753],{"class":58},[52,9370,9371],{"class":54,"line":426},[52,9372,535],{"class":58},[52,9374,9375,9377,9379],{"class":54,"line":434},[52,9376,108],{"class":58},[52,9378,348],{"class":62},[52,9380,80],{"class":58},[13,9382,9383,9384,9386,9387,9390,9391,9393],{},"とても簡単で",[49,9385,181],{},"を使用してその",[49,9388,9389],{},"data()","を表示してあるだけです。そしてCSSでは",[49,9392,9240],{},"を指定して、改行コードが存在したらそこで改行するようにします。",[1905,9395,9398,9399],{"className":9396},[6312,9397],"alert-success","\nCSS の white-space プロパティは、要素内のホワイトスペースをどのように扱うかを設定します。\n",[9400,9401,9402],"small",{},[1445,9403,9405],{"href":9404,"target":7804},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FCSS\u002Fwhite-space","mozilla.org",[13,9407,9408,9409,9412],{},"ただし上図のように謎のインテンドが最初の改行にあります。なぜ生じしてしまうのかを調べたところ、 ",[7814,9410,9411],{},"エディター上でのインテンド"," が原因でした。以下のようにファイルを直してみます。",[42,9414,9416],{"className":202,"code":9415,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">\n{{test}}\n        \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n    \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003C\u002Fscript>\n",[49,9417,9418,9426,9434,9452,9457,9499,9507,9515,9523,9527],{"__ignoreMap":47},[52,9419,9420,9422,9424],{"class":54,"line":55},[52,9421,59],{"class":58},[52,9423,213],{"class":62},[52,9425,80],{"class":58},[52,9427,9428,9430,9432],{"class":54,"line":83},[52,9429,59],{"class":58},[52,9431,1905],{"class":62},[52,9433,80],{"class":58},[52,9435,9436,9438,9440,9442,9444,9446,9448,9450],{"class":54,"line":115},[52,9437,1902],{"class":58},[52,9439,1905],{"class":62},[52,9441,9233],{"class":65},[52,9443,69],{"class":58},[52,9445,72],{"class":58},[52,9447,9240],{"class":75},[52,9449,72],{"class":58},[52,9451,80],{"class":58},[52,9453,9454],{"class":54,"line":142},[52,9455,9456],{"class":105},"{{test}}\n",[52,9458,9459,9461,9463,9465,9467,9469,9471,9473,9475,9477,9479,9481,9483,9485,9487,9489,9491,9493,9495,9497],{"class":54,"line":169},[52,9460,1912],{"class":58},[52,9462,9195],{"class":62},[52,9464,9258],{"class":65},[52,9466,69],{"class":58},[52,9468,72],{"class":58},[52,9470,9265],{"class":75},[52,9472,72],{"class":58},[52,9474,9270],{"class":65},[52,9476,69],{"class":58},[52,9478,72],{"class":58},[52,9480,9277],{"class":75},[52,9482,72],{"class":58},[52,9484,9282],{"class":65},[52,9486,69],{"class":58},[52,9488,72],{"class":58},[52,9490,9289],{"class":75},[52,9492,72],{"class":58},[52,9494,9294],{"class":58},[52,9496,9195],{"class":62},[52,9498,80],{"class":58},[52,9500,9501,9503,9505],{"class":54,"line":302},[52,9502,1946],{"class":58},[52,9504,1905],{"class":62},[52,9506,80],{"class":58},[52,9508,9509,9511,9513],{"class":54,"line":308},[52,9510,108],{"class":58},[52,9512,1905],{"class":62},[52,9514,80],{"class":58},[52,9516,9517,9519,9521],{"class":54,"line":318},[52,9518,108],{"class":58},[52,9520,213],{"class":62},[52,9522,80],{"class":58},[52,9524,9525],{"class":54,"line":328},[52,9526,340],{"emptyLinePlaceholder":339},[52,9528,9529,9531,9533,9535],{"class":54,"line":4},[52,9530,59],{"class":58},[52,9532,4603],{"class":105},[52,9534,348],{"class":62},[52,9536,80],{"class":58},[13,9538,9539,9542],{},[49,9540,9541],{},"{{text}}","の箇所を一番左につけることでなぜか、改行の際のインテンドがなくなりました。",[728,9544],{":src":9545,":width":9200,":center":1322},"'_mix\u002Fsch-2021-05-04 22.01.03.png'",[13,9547,9548],{},"またはこのようにタグを改行させず、一行内に書くことでも解決できます。",[42,9550,9552],{"className":202,"code":9551,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n\u003Cdiv>\n    \u003Cdiv style=\"white-space:pre;\">{{test}}\u003C\u002Fdiv>\n    \u003Ctextarea v-model=\"test\"cols=\"30\" rows=\"10\">\u003C\u002Ftextarea>\n\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    data(){\n        return{\n            test:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[49,9553,9554,9562,9570,9597,9639,9647,9655,9663,9671,9677,9683,9691,9695,9699,9703],{"__ignoreMap":47},[52,9555,9556,9558,9560],{"class":54,"line":55},[52,9557,59],{"class":58},[52,9559,213],{"class":62},[52,9561,80],{"class":58},[52,9563,9564,9566,9568],{"class":54,"line":83},[52,9565,59],{"class":58},[52,9567,1905],{"class":62},[52,9569,80],{"class":58},[52,9571,9572,9574,9576,9578,9580,9582,9584,9586,9588,9591,9593,9595],{"class":54,"line":115},[52,9573,1902],{"class":58},[52,9575,1905],{"class":62},[52,9577,9233],{"class":65},[52,9579,69],{"class":58},[52,9581,72],{"class":58},[52,9583,9240],{"class":75},[52,9585,72],{"class":58},[52,9587,102],{"class":58},[52,9589,9590],{"class":105},"{{test}}",[52,9592,108],{"class":58},[52,9594,1905],{"class":62},[52,9596,80],{"class":58},[52,9598,9599,9601,9603,9605,9607,9609,9611,9613,9615,9617,9619,9621,9623,9625,9627,9629,9631,9633,9635,9637],{"class":54,"line":142},[52,9600,1902],{"class":58},[52,9602,9195],{"class":62},[52,9604,9258],{"class":65},[52,9606,69],{"class":58},[52,9608,72],{"class":58},[52,9610,9265],{"class":75},[52,9612,72],{"class":58},[52,9614,9270],{"class":65},[52,9616,69],{"class":58},[52,9618,72],{"class":58},[52,9620,9277],{"class":75},[52,9622,72],{"class":58},[52,9624,9282],{"class":65},[52,9626,69],{"class":58},[52,9628,72],{"class":58},[52,9630,9289],{"class":75},[52,9632,72],{"class":58},[52,9634,9294],{"class":58},[52,9636,9195],{"class":62},[52,9638,80],{"class":58},[52,9640,9641,9643,9645],{"class":54,"line":169},[52,9642,108],{"class":58},[52,9644,1905],{"class":62},[52,9646,80],{"class":58},[52,9648,9649,9651,9653],{"class":54,"line":302},[52,9650,108],{"class":58},[52,9652,213],{"class":62},[52,9654,80],{"class":58},[52,9656,9657,9659,9661],{"class":54,"line":308},[52,9658,59],{"class":58},[52,9660,348],{"class":62},[52,9662,80],{"class":58},[52,9664,9665,9667,9669],{"class":54,"line":318},[52,9666,356],{"class":359},[52,9668,360],{"class":359},[52,9670,2012],{"class":58},[52,9672,9673,9675],{"class":54,"line":328},[52,9674,2033],{"class":62},[52,9676,2036],{"class":58},[52,9678,9679,9681],{"class":54,"line":4},[52,9680,2041],{"class":359},[52,9682,363],{"class":58},[52,9684,9685,9687,9689],{"class":54,"line":343},[52,9686,9355],{"class":62},[52,9688,372],{"class":58},[52,9690,9360],{"class":58},[52,9692,9693],{"class":54,"line":353},[52,9694,2060],{"class":58},[52,9696,9697],{"class":54,"line":366},[52,9698,3753],{"class":58},[52,9700,9701],{"class":54,"line":386},[52,9702,535],{"class":58},[52,9704,9705,9707,9709],{"class":54,"line":414},[52,9706,108],{"class":58},[52,9708,348],{"class":62},[52,9710,80],{"class":58},[13,9712,9713,9714,9716],{},"なぜ",[49,9715,9240],{},"で謎インテンドが生じてしまうのかわかりませんが、改行コードが入る箇所をエディターで整形する際は気をつけたほうがいいかもしれません。",[1413,9718,9719],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}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":47,"searchDepth":115,"depth":115,"links":9721},[],[9176],"2021-05-24","white-space： pre;で要素内で生じる、文章の隙間、インテンドの原因。",{},"\u002Farticles\u002Fbag-html-break-tag",{"title":9187,"description":9724},"articles\u002Fbag-html-break-tag",[46,9730,204],"css","_mix\u002Fsch-2021-05-04 21.53.14.png","Uglb2nJDSJTaiJVJS_4tGrhobJMBKtzio_BSkBLsen0",{"id":9734,"title":9735,"body":9736,"category":10151,"createdAt":10152,"description":9735,"extension":1426,"index":1427,"meta":10153,"navigation":339,"path":10154,"publish":339,"seo":10155,"series":1427,"seriesTitle":1427,"stem":10156,"tag":10157,"thumbnail":10158,"updatedAt":1427,"__hash__":10159},"articles\u002Farticles\u002Fbootstrap-vue-asset-save.md","bootstrap-vue,iconのバンドルを減らす。開発時に気をつけたいbootstrap-vueの使い方",{"type":10,"value":9737,"toc":10141},[9738,9741,9744,9747,9750,9778,9781,9784,9793,9838,9845,9852,9957,9964,9967,9977,10069,10072,10075,10082,10111,10118,10122,10125,10128,10135,10138],[13,9739,9740],{},"こんにちはjunです。Nuxt.js or Vue.js x Bootstrap-vue の構成を使って管理画面UIを作成する機会が多く、それらの融合性や使いやすさに虜になっています。しかしやけにビルドの時間がかかるなーと思っていたら、なんとバンドルサイズが1MBを超いたという事実に気付き、慌てて対処しました。（他のライブラリもあります）",[13,9742,9743],{},"今回はそのbootstrap-vueを使ったアプリのバンドルサイズを減らす方法として、開発時から気をつけたいことについて述べます。",[17,9745,9746],{"id":9746},"そのままいれるな",[13,9748,9749],{},"ドキュメントの最初の方にある通り、bootstrap-vueとboo-strap-iconを以下のようにいれるとかなりサイズを食います。",[42,9751,9753],{"className":1249,"code":9752,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport { BootstrapVue, IconsPlugin } from 'bootstrap-vue';\n\nVue.use(BootstrapVue);\nVue.use(IconsPlugin);\n",[49,9754,9755,9759,9764,9768,9773],{"__ignoreMap":47},[52,9756,9757],{"class":54,"line":55},[52,9758,1776],{},[52,9760,9761],{"class":54,"line":83},[52,9762,9763],{},"import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';\n",[52,9765,9766],{"class":54,"line":115},[52,9767,340],{"emptyLinePlaceholder":339},[52,9769,9770],{"class":54,"line":142},[52,9771,9772],{},"Vue.use(BootstrapVue);\n",[52,9774,9775],{"class":54,"line":169},[52,9776,9777],{},"Vue.use(IconsPlugin);\n",[13,9779,9780],{},"理由はnode_modulesのBootstrap-vueの全てを入れているためです。別に全てのbootstrapモジュールを使用しているならば問題ありませんが、基本的にそんな状況はないと思います。importでモジュールを読み込む時は原則、必要なものだけインポートして置くことがベストです。それを意識するだけでも自然とバンドルサイズが小さくなります。",[17,9782,9783],{"id":9783},"必要なものだけ指定する",[13,9785,9786,9787,9792],{},"やり方は",[1445,9788,9791],{"href":9789,"rel":9790},"https:\u002F\u002Fbootstrap-vue.org\u002Fdocs#vue-cli-3",[1449],"公式ドキュメント","にもありますが、必要なコンポーネントだけ使用する場合は以下のようにします。",[42,9794,9797],{"className":1249,"code":9795,"filename":9796,"language":1251,"meta":47,"style":47},"import {  \n    BButton,BSpinner,BTable,BAlert\n} from 'bootstrap-vue';\n\nVue.component('b-button',BButton);\nVue.component('b-spinner',BSpinner);\nVue.component('b-table',BTable);\nVue.component('b-alert',BAlert);\n","parent.js",[49,9798,9799,9804,9809,9814,9818,9823,9828,9833],{"__ignoreMap":47},[52,9800,9801],{"class":54,"line":55},[52,9802,9803],{},"import {  \n",[52,9805,9806],{"class":54,"line":83},[52,9807,9808],{},"    BButton,BSpinner,BTable,BAlert\n",[52,9810,9811],{"class":54,"line":115},[52,9812,9813],{},"} from 'bootstrap-vue';\n",[52,9815,9816],{"class":54,"line":142},[52,9817,340],{"emptyLinePlaceholder":339},[52,9819,9820],{"class":54,"line":169},[52,9821,9822],{},"Vue.component('b-button',BButton);\n",[52,9824,9825],{"class":54,"line":302},[52,9826,9827],{},"Vue.component('b-spinner',BSpinner);\n",[52,9829,9830],{"class":54,"line":308},[52,9831,9832],{},"Vue.component('b-table',BTable);\n",[52,9834,9835],{"class":54,"line":318},[52,9836,9837],{},"Vue.component('b-alert',BAlert);\n",[13,9839,9840,9841,9844],{},"上記はapp.jsのような元締めのファイルでグローバルコンポーネントとして登録する場合です。こうすれば配下のファイルで",[49,9842,9843],{},"\u003Cb-badge>\u003C\u002Fb-badge>","という風に使用できます。",[13,9846,9847,9848,9851],{},"グローバルでなく、局所的に単体のvueファイルで使用したい場合は",[49,9849,9850],{},"Vue.component()","でなく、そのvueファイルにいて以下のようにします。",[42,9853,9856],{"className":202,"code":9854,"filename":9855,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n  \u003CBButton variant=\"danger\">Clikc\u003C\u002FBButton>\n\u003C\u002Ftemplate>\n\nimport { BButton } from 'bootstrap-vue';\n\u003Cscript>\nexport default{\n  components:{\n    BButton\n  }\n}\n\u003C\u002Fscript>\n","child.vue",[49,9857,9858,9866,9896,9904,9908,9913,9921,9929,9936,9941,9945,9949],{"__ignoreMap":47},[52,9859,9860,9862,9864],{"class":54,"line":55},[52,9861,59],{"class":58},[52,9863,213],{"class":62},[52,9865,80],{"class":58},[52,9867,9868,9871,9874,9876,9878,9880,9883,9885,9887,9890,9892,9894],{"class":54,"line":83},[52,9869,9870],{"class":58},"  \u003C",[52,9872,9873],{"class":62},"BButton",[52,9875,3513],{"class":65},[52,9877,69],{"class":58},[52,9879,72],{"class":58},[52,9881,9882],{"class":75},"danger",[52,9884,72],{"class":58},[52,9886,102],{"class":58},[52,9888,9889],{"class":105},"Clikc",[52,9891,108],{"class":58},[52,9893,9873],{"class":62},[52,9895,80],{"class":58},[52,9897,9898,9900,9902],{"class":54,"line":115},[52,9899,108],{"class":58},[52,9901,213],{"class":62},[52,9903,80],{"class":58},[52,9905,9906],{"class":54,"line":142},[52,9907,340],{"emptyLinePlaceholder":339},[52,9909,9910],{"class":54,"line":169},[52,9911,9912],{"class":105},"import { BButton } from 'bootstrap-vue';\n",[52,9914,9915,9917,9919],{"class":54,"line":302},[52,9916,59],{"class":58},[52,9918,348],{"class":62},[52,9920,80],{"class":58},[52,9922,9923,9925,9927],{"class":54,"line":308},[52,9924,356],{"class":65},[52,9926,360],{"class":359},[52,9928,363],{"class":58},[52,9930,9931,9934],{"class":54,"line":318},[52,9932,9933],{"class":369},"  components",[52,9935,923],{"class":58},[52,9937,9938],{"class":54,"line":328},[52,9939,9940],{"class":105},"    BButton\n",[52,9942,9943],{"class":54,"line":4},[52,9944,1075],{"class":58},[52,9946,9947],{"class":54,"line":343},[52,9948,535],{"class":58},[52,9950,9951,9953,9955],{"class":54,"line":353},[52,9952,108],{"class":58},[52,9954,348],{"class":62},[52,9956,80],{"class":58},[13,9958,9959,9960,9963],{},"グローバルでやっていたものを",[49,9961,9962],{},"components","配下で入れてあげるだけです。",[1721,9965,9966],{"id":9966},"アイコンも同様",[13,9968,9969,9970,9973,9974,9976],{},"アイコンが豊富な故にサイズも大きいです。",[49,9971,9972],{},"Vue.use(IconsPlugin);","とすると全てのアイコンがインポートされるので、これも以下のように",[49,9975,9962],{},"で使用します。",[42,9978,9980],{"className":202,"code":9979,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n  \u003CBIconXCircleFill variant=\"danger\">\n\u003C\u002Ftemplate>\n\nimport { BIconXCircleFill } from 'bootstrap-vue';\n\u003Cscript>\nexport default{\n  components:{\n    BIconXCircleFill\n  }\n}\n\u003C\u002Fscript>\n",[49,9981,9982,9990,10009,10017,10021,10026,10034,10042,10048,10053,10057,10061],{"__ignoreMap":47},[52,9983,9984,9986,9988],{"class":54,"line":55},[52,9985,59],{"class":58},[52,9987,213],{"class":62},[52,9989,80],{"class":58},[52,9991,9992,9994,9997,9999,10001,10003,10005,10007],{"class":54,"line":83},[52,9993,9870],{"class":58},[52,9995,9996],{"class":62},"BIconXCircleFill",[52,9998,3513],{"class":65},[52,10000,69],{"class":58},[52,10002,72],{"class":58},[52,10004,9882],{"class":75},[52,10006,72],{"class":58},[52,10008,80],{"class":58},[52,10010,10011,10013,10015],{"class":54,"line":115},[52,10012,108],{"class":58},[52,10014,213],{"class":62},[52,10016,80],{"class":58},[52,10018,10019],{"class":54,"line":142},[52,10020,340],{"emptyLinePlaceholder":339},[52,10022,10023],{"class":54,"line":169},[52,10024,10025],{"class":105},"import { BIconXCircleFill } from 'bootstrap-vue';\n",[52,10027,10028,10030,10032],{"class":54,"line":302},[52,10029,59],{"class":58},[52,10031,348],{"class":62},[52,10033,80],{"class":58},[52,10035,10036,10038,10040],{"class":54,"line":308},[52,10037,356],{"class":65},[52,10039,360],{"class":359},[52,10041,363],{"class":58},[52,10043,10044,10046],{"class":54,"line":318},[52,10045,9933],{"class":369},[52,10047,923],{"class":58},[52,10049,10050],{"class":54,"line":328},[52,10051,10052],{"class":105},"    BIconXCircleFill\n",[52,10054,10055],{"class":54,"line":4},[52,10056,1075],{"class":58},[52,10058,10059],{"class":54,"line":343},[52,10060,535],{"class":58},[52,10062,10063,10065,10067],{"class":54,"line":353},[52,10064,108],{"class":58},[52,10066,348],{"class":62},[52,10068,80],{"class":58},[13,10070,10071],{},"アイコンはグローバルに登録するよりも、必要になったら都度入れとく方がいいです。",[17,10073,10074],{"id":10074},"適宜必要なモジュールを入れる",[13,10076,10077,10078,10081],{},"BadgeやButtonは上記のような",[49,10079,10080],{},"Vue.commponent","で十分ですが、ModalやCollapseは追加のプラグインなどが必要です。例えばModalは以下のモジュールをセットしておく必要があります。",[42,10083,10085],{"className":1249,"code":10084,"language":1251,"meta":47,"style":47},"import { BModal,VBModal,ModalPlugin } from 'bootstrap-vue';\n\nVue.use(ModalPlugin);\nVue.component('b-modal',BModal);\nVue.directive('b-modal', VBModal)\n",[49,10086,10087,10092,10096,10101,10106],{"__ignoreMap":47},[52,10088,10089],{"class":54,"line":55},[52,10090,10091],{},"import { BModal,VBModal,ModalPlugin } from 'bootstrap-vue';\n",[52,10093,10094],{"class":54,"line":83},[52,10095,340],{"emptyLinePlaceholder":339},[52,10097,10098],{"class":54,"line":115},[52,10099,10100],{},"Vue.use(ModalPlugin);\n",[52,10102,10103],{"class":54,"line":142},[52,10104,10105],{},"Vue.component('b-modal',BModal);\n",[52,10107,10108],{"class":54,"line":169},[52,10109,10110],{},"Vue.directive('b-modal', VBModal)\n",[13,10112,10113,10114,10117],{},"こうすることでModalのコンポーネントや",[49,10115,10116],{},"this.$bvModal.show('select-file-modal');","のようなディレクティブや動きを実装できます。",[1721,10119,10121],{"id":10120},"どこにかいてある","どこにかいてある？",[13,10123,10124],{},"それぞのコンポーネントのドキュメントの最後の方にある、Component referenceにあります。さらにいうとその下のImporting individual componentsに詳しく、依存関係が書いてあるのでその通りにインポートしてあげましょう。",[17,10126,10127],{"id":10127},"開発時初期から個別インポートを考える",[13,10129,10130,10131,10134],{},"もしこれに気づかず後から単体読み込みにしようと思ったら大変なことになります。 ",[7814,10132,10133],{},"必要なコンポーネントの洗い出しとそのチェックが必要になるからです。"," ファイル検索でなんとからならくもないですが、後からの修正はかなり大変です。",[13,10136,10137],{},"であれば最初から個別のインポートで行っていくほうが、必要になった時にエラーで教えてくれるので対処がしやすいです。端末の性能や通信速度が上がっているとはいえ、まだ1Mを超えるのは気が引けます。塵も積もれば山となる精神で不要なインポートは避けましょう。",[1413,10139,10140],{},"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 pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}",{"title":47,"searchDepth":115,"depth":115,"links":10142},[10143,10144,10147,10150],{"id":9746,"depth":83,"text":9746},{"id":9783,"depth":83,"text":9783,"children":10145},[10146],{"id":9966,"depth":115,"text":9966},{"id":10074,"depth":83,"text":10074,"children":10148},[10149],{"id":10120,"depth":115,"text":10121},{"id":10127,"depth":83,"text":10127},[9176],"2021-03-29",{},"\u002Farticles\u002Fbootstrap-vue-asset-save",{"title":9735,"description":9735},"articles\u002Fbootstrap-vue-asset-save",[9730,204],"_mix\u002Fsch-2021-03-29-22.48.45.png","eqyqBM0LwYz49ZyHXkO-fsX2wiHR3pqkEe-fvzvZ4Hg",{"id":10161,"title":10162,"body":10163,"category":11666,"createdAt":11667,"description":10162,"extension":1426,"index":1427,"meta":11668,"navigation":339,"path":11669,"publish":339,"seo":11670,"series":1427,"seriesTitle":1427,"stem":11671,"tag":11672,"thumbnail":11673,"updatedAt":1427,"__hash__":11674},"articles\u002Farticles\u002Fgoogle-map-vuejs.md","Google Maps APIとVue.js を使ってGoogle Map 上にルートを描画する",{"type":10,"value":10164,"toc":11653},[10165,10168,10172,10181,10190,10194,10197,10201,10210,10216,10220,10236,10551,10557,10560,10564,10567,10591,10594,10603,10614,10662,10665,10668,10675,10956,10964,10967,10975,10990,10996,10999,11005,11040,11043,11046,11224,11230,11233,11257,11260,11263,11266,11269,11276,11279,11398,11408,11411,11414,11417,11420,11424,11427,11430,11444,11451,11614,11631,11634,11637,11641,11644,11647,11650],[13,10166,10167],{},"こんにちはjunです。自主開発で地図上に描画する機能を実装するときに「Vueを用いてGoogle Map上にラインを描画できないかな？」と思いその方法を調べた結果、なんとか実装できました。今回の記事ではGoogle Map APIを用いてVue（またはVanilla js）で地図の表示とラインの描画機能を実装したいと思います。Google Map APIの取得の仕方とVue.jsのインストールなどはある程度省きます。",[17,10169,10171],{"id":10170},"google-map-apiを取得する","Google Map APIを取得する",[13,10173,10174,10175,10180],{},"詳細な取得方法は省略しますが、最低限必要なものだけ解説します。自前のGoogleアカウントを用いて、",[1445,10176,10179],{"href":10177,"rel":10178},"https:\u002F\u002Fcloud.google.com\u002Fmaps-platform?hl=ja",[1449],"Google Cloud Platform","でGoogle Map APIを取得します。",[13,10182,10183,10184,10189],{},"毎月$200分までのリクエストは無料なので開発環境には十分でしょう。そしてweb上にGoogleMapを表示するには",[1445,10185,10188],{"href":10186,"rel":10187},"https:\u002F\u002Fconsole.cloud.google.com\u002Fapis\u002Flibrary\u002Fmaps-backend.googleapis.com?",[1449],"Maps JavaScript API","が必要になります。",[728,10191],{":src":10192,":width":10193,":center":1322},"'_mix\u002Fsch-2021-03-07-17.15.12.png'","'500px'",[13,10195,10196],{},"このAPIを有効にしてAPIキーを手に入れます。まずAPI側のセットアップは以上です。",[17,10198,10200],{"id":10199},"vue側の準備","Vue側の準備",[13,10202,10203,10204,10209],{},"今回は",[1445,10205,10208],{"href":10206,"rel":10207},"https:\u002F\u002Fcli.vuejs.org\u002F",[1449],"Vue CLI","を用いて開発します。vue cliを用いて適当にプロジェクトを作成します。",[42,10211,10214],{"className":10212,"code":10213,"language":451},[1727],"$ vue create vue_map\n",[49,10215,10213],{"__ignoreMap":47},[1721,10217,10219],{"id":10218},"api-用のjsを読み込む","api 用のJSを読み込む",[13,10221,10222,10225,10226,2388,10228,10231,10232,10235],{},[49,10223,10224],{},"\u002Fsrc"," 配下にある",[49,10227,1769],{},[49,10229,10230],{},"\u002Fpublic","配下にある",[49,10233,10234],{},"index.html","に以下のコードを挿入します。",[42,10237,10240],{"className":44,"code":10238,"filename":10239,"language":46,"meta":47,"style":47},"\u003C!DOCTYPE html>\n\u003Chtml lang=\"\">\n  \u003Chead>\n    \u003Cmeta charset=\"utf-8\">\n    \u003Cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    \u003Cmeta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    \u003Clink rel=\"icon\" href=\"\u003C%= BASE_URL %>favicon.ico\">\n    \n　　\u003C!-- このスクリプトを挿入-->\n    \u003Cscript src=\"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs?key=YOUR_API_KEY&language=ja\">\u003C\u002Fscript>\n   \n　　 \u003Ctitle>\u003C%= htmlWebpackPlugin.options.title %>\u003C\u002Ftitle>\n  \u003C\u002Fhead>\n  \u003Cbody>\n    \u003Cnoscript>\n      \u003Cstrong>We're sorry but \u003C%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.\u003C\u002Fstrong>\n    \u003C\u002Fnoscript>\n    \u003Cdiv id=\"app\">\u003C\u002Fdiv>\n    \u003C!-- built files will be auto injected -->\n  \u003C\u002Fbody>\n\u003C\u002Fhtml>\n","public\u002Findex.html",[49,10241,10242,10255,10271,10280,10301,10333,10363,10396,10401,10406,10430,10435,10453,10462,10471,10480,10498,10506,10530,10535,10543],{"__ignoreMap":47},[52,10243,10244,10247,10250,10253],{"class":54,"line":55},[52,10245,10246],{"class":58},"\u003C!",[52,10248,10249],{"class":62},"DOCTYPE",[52,10251,10252],{"class":65}," html",[52,10254,80],{"class":58},[52,10256,10257,10259,10261,10264,10266,10269],{"class":54,"line":83},[52,10258,59],{"class":58},[52,10260,46],{"class":62},[52,10262,10263],{"class":65}," lang",[52,10265,69],{"class":58},[52,10267,10268],{"class":58},"\"\"",[52,10270,80],{"class":58},[52,10272,10273,10275,10278],{"class":54,"line":115},[52,10274,9870],{"class":58},[52,10276,10277],{"class":62},"head",[52,10279,80],{"class":58},[52,10281,10282,10284,10287,10290,10292,10294,10297,10299],{"class":54,"line":142},[52,10283,1902],{"class":58},[52,10285,10286],{"class":62},"meta",[52,10288,10289],{"class":65}," charset",[52,10291,69],{"class":58},[52,10293,72],{"class":58},[52,10295,10296],{"class":75},"utf-8",[52,10298,72],{"class":58},[52,10300,80],{"class":58},[52,10302,10303,10305,10307,10310,10312,10314,10317,10319,10322,10324,10326,10329,10331],{"class":54,"line":169},[52,10304,1902],{"class":58},[52,10306,10286],{"class":62},[52,10308,10309],{"class":65}," http-equiv",[52,10311,69],{"class":58},[52,10313,72],{"class":58},[52,10315,10316],{"class":75},"X-UA-Compatible",[52,10318,72],{"class":58},[52,10320,10321],{"class":65}," content",[52,10323,69],{"class":58},[52,10325,72],{"class":58},[52,10327,10328],{"class":75},"IE=edge",[52,10330,72],{"class":58},[52,10332,80],{"class":58},[52,10334,10335,10337,10339,10341,10343,10345,10348,10350,10352,10354,10356,10359,10361],{"class":54,"line":302},[52,10336,1902],{"class":58},[52,10338,10286],{"class":62},[52,10340,66],{"class":65},[52,10342,69],{"class":58},[52,10344,72],{"class":58},[52,10346,10347],{"class":75},"viewport",[52,10349,72],{"class":58},[52,10351,10321],{"class":65},[52,10353,69],{"class":58},[52,10355,72],{"class":58},[52,10357,10358],{"class":75},"width=device-width,initial-scale=1.0",[52,10360,72],{"class":58},[52,10362,80],{"class":58},[52,10364,10365,10367,10370,10373,10375,10377,10380,10382,10385,10387,10389,10392,10394],{"class":54,"line":308},[52,10366,1902],{"class":58},[52,10368,10369],{"class":62},"link",[52,10371,10372],{"class":65}," rel",[52,10374,69],{"class":58},[52,10376,72],{"class":58},[52,10378,10379],{"class":75},"icon",[52,10381,72],{"class":58},[52,10383,10384],{"class":65}," href",[52,10386,69],{"class":58},[52,10388,72],{"class":58},[52,10390,10391],{"class":75},"\u003C%= BASE_URL %>favicon.ico",[52,10393,72],{"class":58},[52,10395,80],{"class":58},[52,10397,10398],{"class":54,"line":318},[52,10399,10400],{"class":105},"    \n",[52,10402,10403],{"class":54,"line":328},[52,10404,10405],{"class":410},"　　\u003C!-- このスクリプトを挿入-->\n",[52,10407,10408,10410,10412,10415,10417,10419,10422,10424,10426,10428],{"class":54,"line":4},[52,10409,1902],{"class":58},[52,10411,348],{"class":62},[52,10413,10414],{"class":65}," src",[52,10416,69],{"class":58},[52,10418,72],{"class":58},[52,10420,10421],{"class":75},"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs?key=YOUR_API_KEY&language=ja",[52,10423,72],{"class":58},[52,10425,9294],{"class":58},[52,10427,348],{"class":62},[52,10429,80],{"class":58},[52,10431,10432],{"class":54,"line":343},[52,10433,10434],{"class":105},"   \n",[52,10436,10437,10440,10442,10444,10447,10449,10451],{"class":54,"line":353},[52,10438,10439],{"class":58},"　　 \u003C",[52,10441,7525],{"class":62},[52,10443,102],{"class":58},[52,10445,10446],{"class":105},"\u003C%= htmlWebpackPlugin.options.title %>",[52,10448,108],{"class":58},[52,10450,7525],{"class":62},[52,10452,80],{"class":58},[52,10454,10455,10458,10460],{"class":54,"line":366},[52,10456,10457],{"class":58},"  \u003C\u002F",[52,10459,10277],{"class":62},[52,10461,80],{"class":58},[52,10463,10464,10466,10469],{"class":54,"line":386},[52,10465,9870],{"class":58},[52,10467,10468],{"class":62},"body",[52,10470,80],{"class":58},[52,10472,10473,10475,10478],{"class":54,"line":414},[52,10474,1902],{"class":58},[52,10476,10477],{"class":62},"noscript",[52,10479,80],{"class":58},[52,10481,10482,10485,10487,10489,10492,10494,10496],{"class":54,"line":426},[52,10483,10484],{"class":58},"      \u003C",[52,10486,7814],{"class":62},[52,10488,102],{"class":58},[52,10490,10491],{"class":105},"We're sorry but \u003C%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.",[52,10493,108],{"class":58},[52,10495,7814],{"class":62},[52,10497,80],{"class":58},[52,10499,10500,10502,10504],{"class":54,"line":434},[52,10501,1946],{"class":58},[52,10503,10477],{"class":62},[52,10505,80],{"class":58},[52,10507,10508,10510,10512,10515,10517,10519,10522,10524,10526,10528],{"class":54,"line":445},[52,10509,1902],{"class":58},[52,10511,1905],{"class":62},[52,10513,10514],{"class":65}," id",[52,10516,69],{"class":58},[52,10518,72],{"class":58},[52,10520,10521],{"class":75},"app",[52,10523,72],{"class":58},[52,10525,9294],{"class":58},[52,10527,1905],{"class":62},[52,10529,80],{"class":58},[52,10531,10532],{"class":54,"line":479},[52,10533,10534],{"class":410},"    \u003C!-- built files will be auto injected -->\n",[52,10536,10537,10539,10541],{"class":54,"line":508},[52,10538,10457],{"class":58},[52,10540,10468],{"class":62},[52,10542,80],{"class":58},[52,10544,10545,10547,10549],{"class":54,"line":538},[52,10546,108],{"class":58},[52,10548,46],{"class":62},[52,10550,80],{"class":58},[13,10552,10553,10556],{},[49,10554,10555],{},"http:\u002F\u002Fmaps.google.com\u002Fmaps\u002Fapi\u002Fjs","からAPIのソースを手に入れます。できたらnpmあたりでローカルに予めインストールしたいなと思ったのですが、node.js専用だったりとひとまず開発したかったので、今回は外部ファイルとします。このときVue.jsより早く読み込まれるようにしましょう。",[13,10558,10559],{},"スクリプトのurlにはAPIキーを含めます。公開環境で使用する場合は必ずAPIキーが自サイトのみで使用される条件を設定しておきましょう。でないと第三者に好き勝手にキーを使われて、請求だけはあなたのクレジットカードにきます。",[1721,10561,10563],{"id":10562},"プラグインとしてvueに登録しておく","プラグインとしてVueに登録しておく",[13,10565,10566],{},"上記のソースを読み込めばwindow.googleを見ると、今回使用するAPIを操作できるクラスなりメソッドがあります。",[42,10568,10570],{"className":1249,"code":10569,"language":1251,"meta":47,"style":47},"console.lgo(window.google);\n\u002F**\n*{maps: {…}}\n*\u002F\n",[49,10571,10572,10577,10581,10586],{"__ignoreMap":47},[52,10573,10574],{"class":54,"line":55},[52,10575,10576],{},"console.lgo(window.google);\n",[52,10578,10579],{"class":54,"line":83},[52,10580,7704],{},[52,10582,10583],{"class":54,"line":115},[52,10584,10585],{},"*{maps: {…}}\n",[52,10587,10588],{"class":54,"line":142},[52,10589,10590],{},"*\u002F\n",[13,10592,10593],{},"例えば地図を特定のDOMにマウントするときは以下のように呼びます。",[42,10595,10597],{"className":1249,"code":10596,"language":1251,"meta":47,"style":47},"window.google.maps.Map(document.getElementById('map'),{option});\n",[49,10598,10599],{"__ignoreMap":47},[52,10600,10601],{"class":54,"line":55},[52,10602,10596],{},[13,10604,10605,10606,10609,10610,10613],{},"毎回、",[49,10607,10608],{},"window.google.maps","とやるのは面倒なので",[49,10611,10612],{},"this.$gm","と呼び出せるようにプラグイン化しておきます。",[42,10615,10617],{"className":1249,"code":10616,"filename":1764,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport App from '.\u002FApp.vue'\n\n\u002F\u002Fこれ\nVue.prototype.$gm = window.google.maps;\n\nVue.config.productionTip = false\nnew Vue({\n  render: h => h(App),\n}).$mount('#app')\n",[49,10618,10619,10623,10628,10632,10637,10642,10646,10650,10654,10658],{"__ignoreMap":47},[52,10620,10621],{"class":54,"line":55},[52,10622,1776],{},[52,10624,10625],{"class":54,"line":83},[52,10626,10627],{},"import App from '.\u002FApp.vue'\n",[52,10629,10630],{"class":54,"line":115},[52,10631,340],{"emptyLinePlaceholder":339},[52,10633,10634],{"class":54,"line":142},[52,10635,10636],{},"\u002F\u002Fこれ\n",[52,10638,10639],{"class":54,"line":169},[52,10640,10641],{},"Vue.prototype.$gm = window.google.maps;\n",[52,10643,10644],{"class":54,"line":302},[52,10645,340],{"emptyLinePlaceholder":339},[52,10647,10648],{"class":54,"line":308},[52,10649,1819],{},[52,10651,10652],{"class":54,"line":318},[52,10653,1828],{},[52,10655,10656],{"class":54,"line":328},[52,10657,1833],{},[52,10659,10660],{"class":54,"line":4},[52,10661,1838],{},[13,10663,10664],{},"これで前準備が完了しました。",[17,10666,10667],{"id":10667},"とりあえず地図をマウントする",[13,10669,10670,10671,10674],{},"準備が整ったのでvueを用いてGoogle Mapをマウントしましょう。インストール直後にある",[49,10672,10673],{},"App.vue","を以下のように書きます。",[42,10676,10678],{"className":202,"code":10677,"filename":1883,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n  \u003Cdiv id=\"app\" class=\"mt-4\">\n      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: 'App',\n  data(){\n    return{\n      map:undefined,\n    }\n  },\n  mounted(){\n   const map = new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n      zoom: 10,\n    });\n　　this.map = map;\n  }\n}\n\u003C\u002Fscript>\n",[49,10679,10680,10688,10718,10740,10748,10756,10760,10768,10776,10792,10799,10805,10813,10817,10822,10829,10874,10907,10919,10927,10940,10944,10948],{"__ignoreMap":47},[52,10681,10682,10684,10686],{"class":54,"line":55},[52,10683,59],{"class":58},[52,10685,213],{"class":62},[52,10687,80],{"class":58},[52,10689,10690,10692,10694,10696,10698,10700,10702,10704,10707,10709,10711,10714,10716],{"class":54,"line":83},[52,10691,9870],{"class":58},[52,10693,1905],{"class":62},[52,10695,10514],{"class":65},[52,10697,69],{"class":58},[52,10699,72],{"class":58},[52,10701,10521],{"class":75},[52,10703,72],{"class":58},[52,10705,10706],{"class":65}," class",[52,10708,69],{"class":58},[52,10710,72],{"class":58},[52,10712,10713],{"class":75},"mt-4",[52,10715,72],{"class":58},[52,10717,80],{"class":58},[52,10719,10720,10722,10724,10726,10728,10730,10732,10734,10736,10738],{"class":54,"line":115},[52,10721,10484],{"class":58},[52,10723,1905],{"class":62},[52,10725,10514],{"class":65},[52,10727,69],{"class":58},[52,10729,72],{"class":58},[52,10731,1030],{"class":75},[52,10733,72],{"class":58},[52,10735,9294],{"class":58},[52,10737,1905],{"class":62},[52,10739,80],{"class":58},[52,10741,10742,10744,10746],{"class":54,"line":142},[52,10743,10457],{"class":58},[52,10745,1905],{"class":62},[52,10747,80],{"class":58},[52,10749,10750,10752,10754],{"class":54,"line":169},[52,10751,108],{"class":58},[52,10753,213],{"class":62},[52,10755,80],{"class":58},[52,10757,10758],{"class":54,"line":302},[52,10759,340],{"emptyLinePlaceholder":339},[52,10761,10762,10764,10766],{"class":54,"line":308},[52,10763,59],{"class":58},[52,10765,348],{"class":62},[52,10767,80],{"class":58},[52,10769,10770,10772,10774],{"class":54,"line":318},[52,10771,356],{"class":359},[52,10773,360],{"class":359},[52,10775,2012],{"class":58},[52,10777,10778,10781,10783,10785,10788,10790],{"class":54,"line":328},[52,10779,10780],{"class":62},"  name",[52,10782,372],{"class":58},[52,10784,1979],{"class":58},[52,10786,10787],{"class":75},"App",[52,10789,375],{"class":58},[52,10791,383],{"class":58},[52,10793,10794,10797],{"class":54,"line":4},[52,10795,10796],{"class":62},"  data",[52,10798,2036],{"class":58},[52,10800,10801,10803],{"class":54,"line":343},[52,10802,3828],{"class":359},[52,10804,363],{"class":58},[52,10806,10807,10810],{"class":54,"line":353},[52,10808,10809],{"class":62},"      map",[52,10811,10812],{"class":58},":undefined,\n",[52,10814,10815],{"class":54,"line":366},[52,10816,3753],{"class":58},[52,10818,10819],{"class":54,"line":386},[52,10820,10821],{"class":58},"  },\n",[52,10823,10824,10827],{"class":54,"line":414},[52,10825,10826],{"class":62},"  mounted",[52,10828,2036],{"class":58},[52,10830,10831,10834,10837,10839,10841,10843,10846,10848,10851,10853,10856,10858,10861,10863,10865,10867,10869,10871],{"class":54,"line":426},[52,10832,10833],{"class":65},"   const",[52,10835,10836],{"class":105}," map",[52,10838,950],{"class":58},[52,10840,6900],{"class":58},[52,10842,2285],{"class":58},[52,10844,10845],{"class":105},"$gm",[52,10847,956],{"class":58},[52,10849,10850],{"class":417},"Map",[52,10852,931],{"class":62},[52,10854,10855],{"class":105},"document",[52,10857,956],{"class":58},[52,10859,10860],{"class":417},"getElementById",[52,10862,931],{"class":62},[52,10864,375],{"class":58},[52,10866,1030],{"class":75},[52,10868,375],{"class":58},[52,10870,937],{"class":62},[52,10872,10873],{"class":58},",{\n",[52,10875,10876,10879,10881,10883,10886,10888,10891,10893,10896,10898,10901,10904],{"class":54,"line":434},[52,10877,10878],{"class":62},"      center",[52,10880,372],{"class":58},[52,10882,8406],{"class":58},[52,10884,10885],{"class":62}," lat",[52,10887,372],{"class":58},[52,10889,10890],{"class":4596}," 34.855273888888888",[52,10892,407],{"class":58},[52,10894,10895],{"class":62}," lng",[52,10897,372],{"class":58},[52,10899,10900],{"class":4596}," 135.30649",[52,10902,10903],{"class":58}," },",[52,10905,10906],{"class":410}," \u002F\u002F自由な緯度・経度を入力\n",[52,10908,10909,10912,10914,10917],{"class":54,"line":445},[52,10910,10911],{"class":62},"      zoom",[52,10913,372],{"class":58},[52,10915,10916],{"class":4596}," 10",[52,10918,383],{"class":58},[52,10920,10921,10923,10925],{"class":54,"line":479},[52,10922,5094],{"class":58},[52,10924,937],{"class":62},[52,10926,1006],{"class":58},[52,10928,10929,10932,10934,10936,10938],{"class":54,"line":508},[52,10930,10931],{"class":58},"　　this.",[52,10933,1030],{"class":105},[52,10935,950],{"class":58},[52,10937,10836],{"class":105},[52,10939,1006],{"class":58},[52,10941,10942],{"class":54,"line":538},[52,10943,1075],{"class":58},[52,10945,10946],{"class":54,"line":546},[52,10947,535],{"class":58},[52,10949,10950,10952,10954],{"class":54,"line":552},[52,10951,108],{"class":58},[52,10953,348],{"class":62},[52,10955,80],{"class":58},[13,10957,10958,10963],{},[1445,10959,10962],{"href":10960,"rel":10961},"https:\u002F\u002Fdevelopers.google.com\u002Fmaps\u002Fdocumentation\u002Fjavascript\u002Freference\u002Fmap?hl=ja",[1449],"Mapsクラス","のレファランスの通り、第一引数にマウント対象のDOMを入れ、第二引数にはオプションを入れます。DOMが必要なのでmounted()で初期処理を行います。",[13,10965,10966],{},"オプションには",[1854,10968,10969,10972],{},[1699,10970,10971],{},"center：初期表示の地図の中央座標",[1699,10973,10974],{},"zoom：拡大の縮尺（10ぐらいがちょうどいい）",[13,10976,10977,10978,10981,10982,10985,10986,10989],{},"を入れておきましょう。",[49,10979,10980],{},"lat","は緯度、",[49,10983,10984],{},"lng","は経度を示しています。このインスタンスは後で使い回すので",[49,10987,10988],{},"this.map = map"," としてインスタンスを入れておきましょう。ひとまずこの処理を実装してブラウザで見てみましょう。",[42,10991,10994],{"className":10992,"code":10993,"language":451},[1727],"$ npm run serve\n",[49,10995,10993],{"__ignoreMap":47},[728,10997],{":src":10998,":width":731},"'_mix\u002Fsch-2021-03-07-17.39.26-768x352.png'",[13,11000,11001,11004],{},[49,11002,11003],{},"localhost","をみたとき、このようになっていれば問題ありません。ストリートビューや前面表示がない方がいい人はオプションを以下のようにしておきます。",[42,11006,11008],{"className":1249,"code":11007,"filename":1764,"language":1251,"meta":47,"style":47},"new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 },\n      zoom: 10,\n      streetViewControl:false, \u002F\u002F ストリートビュー非表示\n      fullscreenControl:false  \u002F\u002F フルスクリーン非表示\n});\n",[49,11009,11010,11015,11020,11025,11030,11035],{"__ignoreMap":47},[52,11011,11012],{"class":54,"line":55},[52,11013,11014],{},"new this.$gm.Map(document.getElementById('map'),{\n",[52,11016,11017],{"class":54,"line":83},[52,11018,11019],{},"      center: { lat: 34.855273888888888, lng: 135.30649 },\n",[52,11021,11022],{"class":54,"line":115},[52,11023,11024],{},"      zoom: 10,\n",[52,11026,11027],{"class":54,"line":142},[52,11028,11029],{},"      streetViewControl:false, \u002F\u002F ストリートビュー非表示\n",[52,11031,11032],{"class":54,"line":169},[52,11033,11034],{},"      fullscreenControl:false  \u002F\u002F フルスクリーン非表示\n",[52,11036,11037],{"class":54,"line":302},[52,11038,11039],{},"});\n",[17,11041,11042],{"id":11042},"地図にクリックイベントを追加",[13,11044,11045],{},"Google Mapの地図にはクリックやドラッグなどのイベントリスナーを追加できます。特定の位置やマーカーをクリックしたら何やかんやするというのができます。まずは簡単にクリックした地図位置の緯度・経度を取得してみましょう。以下のようにします。",[42,11047,11049],{"className":1249,"code":11048,"filename":1764,"language":1251,"meta":47,"style":47},"\u003Ctemplate>\n  \u003Cdiv id=\"app\" class=\"mt-4\">\n      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n      {{position}}\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n\nexport default {\n  name: 'App',\n  data(){\n      return{\n        map:undefined,\n        position:undefined\n      }\n  },\n  methods:{\n   clickOnMap(mapEvent){\n    console.log(mapEvent.latLng.toString())\n    this.position = mapEvent.latLng.toString();\n   }\n  },\n  mounted(){\n   const map = new this.$gm.Map(document.getElementById('map'),{\n      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n      zoom: 10,\n    });\n\n    \u002F\u002Fリスナーの登録\n    map.addListener('click',(mapsMouseEvent)=>{\n      return this.clickOnMap(mapsMouseEvent);\n    });\n\n　　this.map = map;\n  }\n}\n",[49,11050,11051,11056,11061,11066,11071,11076,11081,11085,11090,11094,11099,11104,11109,11114,11119,11124,11128,11132,11137,11142,11147,11152,11156,11160,11165,11170,11175,11179,11184,11188,11193,11198,11203,11207,11211,11216,11220],{"__ignoreMap":47},[52,11052,11053],{"class":54,"line":55},[52,11054,11055],{},"\u003Ctemplate>\n",[52,11057,11058],{"class":54,"line":83},[52,11059,11060],{},"  \u003Cdiv id=\"app\" class=\"mt-4\">\n",[52,11062,11063],{"class":54,"line":115},[52,11064,11065],{},"      \u003Cdiv id=\"map\">\u003C\u002Fdiv>\n",[52,11067,11068],{"class":54,"line":142},[52,11069,11070],{},"      {{position}}\n",[52,11072,11073],{"class":54,"line":169},[52,11074,11075],{},"  \u003C\u002Fdiv>\n",[52,11077,11078],{"class":54,"line":302},[52,11079,11080],{},"\u003C\u002Ftemplate>\n",[52,11082,11083],{"class":54,"line":308},[52,11084,340],{"emptyLinePlaceholder":339},[52,11086,11087],{"class":54,"line":318},[52,11088,11089],{},"\u003Cscript>\n",[52,11091,11092],{"class":54,"line":328},[52,11093,340],{"emptyLinePlaceholder":339},[52,11095,11096],{"class":54,"line":4},[52,11097,11098],{},"export default {\n",[52,11100,11101],{"class":54,"line":343},[52,11102,11103],{},"  name: 'App',\n",[52,11105,11106],{"class":54,"line":353},[52,11107,11108],{},"  data(){\n",[52,11110,11111],{"class":54,"line":366},[52,11112,11113],{},"      return{\n",[52,11115,11116],{"class":54,"line":386},[52,11117,11118],{},"        map:undefined,\n",[52,11120,11121],{"class":54,"line":414},[52,11122,11123],{},"        position:undefined\n",[52,11125,11126],{"class":54,"line":426},[52,11127,7223],{},[52,11129,11130],{"class":54,"line":434},[52,11131,10821],{},[52,11133,11134],{"class":54,"line":445},[52,11135,11136],{},"  methods:{\n",[52,11138,11139],{"class":54,"line":479},[52,11140,11141],{},"   clickOnMap(mapEvent){\n",[52,11143,11144],{"class":54,"line":508},[52,11145,11146],{},"    console.log(mapEvent.latLng.toString())\n",[52,11148,11149],{"class":54,"line":538},[52,11150,11151],{},"    this.position = mapEvent.latLng.toString();\n",[52,11153,11154],{"class":54,"line":546},[52,11155,549],{},[52,11157,11158],{"class":54,"line":552},[52,11159,10821],{},[52,11161,11162],{"class":54,"line":558},[52,11163,11164],{},"  mounted(){\n",[52,11166,11167],{"class":54,"line":563},[52,11168,11169],{},"   const map = new this.$gm.Map(document.getElementById('map'),{\n",[52,11171,11172],{"class":54,"line":568},[52,11173,11174],{},"      center: { lat: 34.855273888888888, lng: 135.30649 }, \u002F\u002F自由な緯度・経度を入力\n",[52,11176,11177],{"class":54,"line":1105},[52,11178,11024],{},[52,11180,11181],{"class":54,"line":1134},[52,11182,11183],{},"    });\n",[52,11185,11186],{"class":54,"line":1163},[52,11187,340],{"emptyLinePlaceholder":339},[52,11189,11190],{"class":54,"line":1192},[52,11191,11192],{},"    \u002F\u002Fリスナーの登録\n",[52,11194,11195],{"class":54,"line":1199},[52,11196,11197],{},"    map.addListener('click',(mapsMouseEvent)=>{\n",[52,11199,11200],{"class":54,"line":1204},[52,11201,11202],{},"      return this.clickOnMap(mapsMouseEvent);\n",[52,11204,11205],{"class":54,"line":1209},[52,11206,11183],{},[52,11208,11209],{"class":54,"line":1214},[52,11210,340],{"emptyLinePlaceholder":339},[52,11212,11213],{"class":54,"line":1219},[52,11214,11215],{},"　　this.map = map;\n",[52,11217,11218],{"class":54,"line":2302},[52,11219,1075],{},[52,11221,11222],{"class":54,"line":2308},[52,11223,535],{},[13,11225,11226,11229],{},[49,11227,11228],{},"map.addListener('click',(mapsMouseEvent)=>{...})","とDOMにイベントを追加する時と似ていますね。第二引数に実行するコールバックを入れます。ちなみにコールバックの引数には自動的に地図上の座標なり他の情報が入っています。",[13,11231,11232],{},"このイベントリスナーには以下のメソッドが実行されるようになっており、クリック位置の経度、緯度を取得します。",[42,11234,11236],{"className":1249,"code":11235,"filename":1764,"language":1251,"meta":47,"style":47},"clickOnMap(mapEvent){\n        console.log(mapEvent.latLng.toString())\n        this.position = mapEvent.latLng.toString();\n},\n",[49,11237,11238,11243,11248,11253],{"__ignoreMap":47},[52,11239,11240],{"class":54,"line":55},[52,11241,11242],{},"clickOnMap(mapEvent){\n",[52,11244,11245],{"class":54,"line":83},[52,11246,11247],{},"        console.log(mapEvent.latLng.toString())\n",[52,11249,11250],{"class":54,"line":115},[52,11251,11252],{},"        this.position = mapEvent.latLng.toString();\n",[52,11254,11255],{"class":54,"line":142},[52,11256,476],{},[13,11258,11259],{},"クリックすると以下のようになります。（真ん中の赤いのは気にしないでください。）",[728,11261],{":src":11262,":width":731},"'_mix\u002Fsch-2021-03-07-18.02.03-768x326.png'",[13,11264,11265],{},"左下に座標が表示されました。ひとまずこれで地図に対するイベントリスナーの登録と情報の取得については理解できたと思います。",[17,11267,11268],{"id":11268},"ラインの描画",[13,11270,11271,11272,11275],{},"それでは今度はクリックした際にラインを描画できるようにします。ラインを描画するためには",[49,11273,11274],{},"google.maps.Polyline","クラスのインスタンスを作成し、先ほどのMapインスタンスにセットすることで描画ができます。",[13,11277,11278],{},"上記の通り地図上の情報を取得できたように、今度は緯度経度の情報を元に地図に何かセットします。まずはMapの初期表示と同時にラインを描画しましょう。",[42,11280,11282],{"className":1249,"code":11281,"filename":1764,"language":1251,"meta":47,"style":47},"...  \nmounted(){\n  const map = new this.$gm.Map(document.getElementById('map'),{\n    center: { lat: 34.855273888888888, lng: 135.30649 },\n    zoom: 10,\n  });\n  map.addListener('click',(mapsMouseEvent)=>{\n    return this.clickOnMap(mapsMouseEvent);\n  });\n  const LINE = new this.$gm.Polyline({\n      path:[\n        { lat: 34.855273888888888, lng: 135.30649 },\n        { lat: 34.854465, lng: 135.8 },\n      ],\n      geodesic: true,\n      strokeColor: \"#FF0000\",\n      strokeOpacity: 1.0,\n      strokeWeight: 2,\n  })\n  LINE.setMap(map);\n  this.map = map;\n} \n...\n",[49,11283,11284,11289,11294,11299,11304,11309,11314,11319,11324,11328,11333,11338,11343,11348,11353,11358,11363,11368,11373,11378,11383,11388,11393],{"__ignoreMap":47},[52,11285,11286],{"class":54,"line":55},[52,11287,11288],{},"...  \n",[52,11290,11291],{"class":54,"line":83},[52,11292,11293],{},"mounted(){\n",[52,11295,11296],{"class":54,"line":115},[52,11297,11298],{},"  const map = new this.$gm.Map(document.getElementById('map'),{\n",[52,11300,11301],{"class":54,"line":142},[52,11302,11303],{},"    center: { lat: 34.855273888888888, lng: 135.30649 },\n",[52,11305,11306],{"class":54,"line":169},[52,11307,11308],{},"    zoom: 10,\n",[52,11310,11311],{"class":54,"line":302},[52,11312,11313],{},"  });\n",[52,11315,11316],{"class":54,"line":308},[52,11317,11318],{},"  map.addListener('click',(mapsMouseEvent)=>{\n",[52,11320,11321],{"class":54,"line":318},[52,11322,11323],{},"    return this.clickOnMap(mapsMouseEvent);\n",[52,11325,11326],{"class":54,"line":328},[52,11327,11313],{},[52,11329,11330],{"class":54,"line":4},[52,11331,11332],{},"  const LINE = new this.$gm.Polyline({\n",[52,11334,11335],{"class":54,"line":343},[52,11336,11337],{},"      path:[\n",[52,11339,11340],{"class":54,"line":353},[52,11341,11342],{},"        { lat: 34.855273888888888, lng: 135.30649 },\n",[52,11344,11345],{"class":54,"line":366},[52,11346,11347],{},"        { lat: 34.854465, lng: 135.8 },\n",[52,11349,11350],{"class":54,"line":386},[52,11351,11352],{},"      ],\n",[52,11354,11355],{"class":54,"line":414},[52,11356,11357],{},"      geodesic: true,\n",[52,11359,11360],{"class":54,"line":426},[52,11361,11362],{},"      strokeColor: \"#FF0000\",\n",[52,11364,11365],{"class":54,"line":434},[52,11366,11367],{},"      strokeOpacity: 1.0,\n",[52,11369,11370],{"class":54,"line":445},[52,11371,11372],{},"      strokeWeight: 2,\n",[52,11374,11375],{"class":54,"line":479},[52,11376,11377],{},"  })\n",[52,11379,11380],{"class":54,"line":508},[52,11381,11382],{},"  LINE.setMap(map);\n",[52,11384,11385],{"class":54,"line":538},[52,11386,11387],{},"  this.map = map;\n",[52,11389,11390],{"class":54,"line":546},[52,11391,11392],{},"} \n",[52,11394,11395],{"class":54,"line":552},[52,11396,11397],{},"...\n",[13,11399,11400,11403,11404,11407],{},[49,11401,11402],{},"this.$gm.Polyline","でラインインスタンスを作成し、オプションをオブジェクト形式で指定すればラインの色、パス（２点以上の座標）、太さなどを指定できます。最後に",[49,11405,11406],{},"LINE.setMap(map)","で地図にはめると、以下のように描画されます。",[728,11409],{":src":11410,":width":731},"'_mix\u002Fsch-2021-03-10-21.17.39-768x346.png'",[13,11412,11413],{},"地図に赤線が表示されました。今は２点の適当な座標間ですが細かくパスを設定すれば以下のようにも描画できます。",[728,11415],{":src":11416,":width":9200,":center":1322},"'_mix\u002Fsch-2021-03-10-21.19.41.png'",[13,11418,11419],{},"この座標情報は友人のGPSから引っ張ってきたもので、詳細な座標情報が配列であったのでこれほど細かく描画されます。",[17,11421,11423],{"id":11422},"クリックした任意の地点でラインを描画していく","クリックした任意の地点でラインを描画していく。",[13,11425,11426],{},"初期表示でラインを描画することができたので、次はユーザーが任意の地点をクリックしたらその地点に向かってラインが描画されるようにしましょう。",[13,11428,11429],{},"先ほどクリックイベントから座標情報をしたのを覚えていますか？それを応用します。",[1696,11431,11432,11435,11438,11441],{},[1699,11433,11434],{},"クリック位置から緯度・経度を取得",[1699,11436,11437],{},"Google Map用の座標インスタンスに変換",[1699,11439,11440],{},"ラインインスタンスにその座標（パス）を追加する。",[1699,11442,11443],{},"クリックされたら繰り返す。",[13,11445,11446,11447,11450],{},"クリックイベントに付与した",[49,11448,11449],{},"drawLine","メソッドこんな感じです。",[42,11452,11454],{"className":1249,"code":11453,"filename":1764,"language":1251,"meta":47,"style":47},"data(){\n  return{\n    map:undefined,\n    bounds:undefined,\n    path:[],\n    line:undefined\n  }\n},\nmethods:{\n  drawLine(mapEvent){\n    let latLng = mapEvent.latLng;\n\n    \u002F\u002F １点目をクリック\n    if(this.line === undefined){\n      const newLine = new this.$gm.Polyline({\n        path:[latLng],\n        geodesic: true,\n        strokeColor: \"#FF0000\",\n        strokeOpacity: 1.0,\n        strokeWeight: 2,\n      })\n      newLine.setMap(this.map);\n      this.path.push(latLng);\n      this.line = newLine;\n      return;\n    }\n\n    \u002F\u002F ２点目以降\n    this.path.push(latLng);\n    this.line.setPath([...this.path]);\n    return;\n  },\n},\n",[49,11455,11456,11461,11466,11471,11476,11481,11486,11490,11494,11499,11504,11509,11513,11518,11523,11528,11533,11538,11543,11548,11553,11558,11563,11568,11573,11578,11582,11586,11591,11596,11601,11606,11610],{"__ignoreMap":47},[52,11457,11458],{"class":54,"line":55},[52,11459,11460],{},"data(){\n",[52,11462,11463],{"class":54,"line":83},[52,11464,11465],{},"  return{\n",[52,11467,11468],{"class":54,"line":115},[52,11469,11470],{},"    map:undefined,\n",[52,11472,11473],{"class":54,"line":142},[52,11474,11475],{},"    bounds:undefined,\n",[52,11477,11478],{"class":54,"line":169},[52,11479,11480],{},"    path:[],\n",[52,11482,11483],{"class":54,"line":302},[52,11484,11485],{},"    line:undefined\n",[52,11487,11488],{"class":54,"line":308},[52,11489,1075],{},[52,11491,11492],{"class":54,"line":318},[52,11493,476],{},[52,11495,11496],{"class":54,"line":328},[52,11497,11498],{},"methods:{\n",[52,11500,11501],{"class":54,"line":4},[52,11502,11503],{},"  drawLine(mapEvent){\n",[52,11505,11506],{"class":54,"line":343},[52,11507,11508],{},"    let latLng = mapEvent.latLng;\n",[52,11510,11511],{"class":54,"line":353},[52,11512,340],{"emptyLinePlaceholder":339},[52,11514,11515],{"class":54,"line":366},[52,11516,11517],{},"    \u002F\u002F １点目をクリック\n",[52,11519,11520],{"class":54,"line":386},[52,11521,11522],{},"    if(this.line === undefined){\n",[52,11524,11525],{"class":54,"line":414},[52,11526,11527],{},"      const newLine = new this.$gm.Polyline({\n",[52,11529,11530],{"class":54,"line":426},[52,11531,11532],{},"        path:[latLng],\n",[52,11534,11535],{"class":54,"line":434},[52,11536,11537],{},"        geodesic: true,\n",[52,11539,11540],{"class":54,"line":445},[52,11541,11542],{},"        strokeColor: \"#FF0000\",\n",[52,11544,11545],{"class":54,"line":479},[52,11546,11547],{},"        strokeOpacity: 1.0,\n",[52,11549,11550],{"class":54,"line":508},[52,11551,11552],{},"        strokeWeight: 2,\n",[52,11554,11555],{"class":54,"line":538},[52,11556,11557],{},"      })\n",[52,11559,11560],{"class":54,"line":546},[52,11561,11562],{},"      newLine.setMap(this.map);\n",[52,11564,11565],{"class":54,"line":552},[52,11566,11567],{},"      this.path.push(latLng);\n",[52,11569,11570],{"class":54,"line":558},[52,11571,11572],{},"      this.line = newLine;\n",[52,11574,11575],{"class":54,"line":563},[52,11576,11577],{},"      return;\n",[52,11579,11580],{"class":54,"line":568},[52,11581,3753],{},[52,11583,11584],{"class":54,"line":1105},[52,11585,340],{"emptyLinePlaceholder":339},[52,11587,11588],{"class":54,"line":1134},[52,11589,11590],{},"    \u002F\u002F ２点目以降\n",[52,11592,11593],{"class":54,"line":1163},[52,11594,11595],{},"    this.path.push(latLng);\n",[52,11597,11598],{"class":54,"line":1192},[52,11599,11600],{},"    this.line.setPath([...this.path]);\n",[52,11602,11603],{"class":54,"line":1199},[52,11604,11605],{},"    return;\n",[52,11607,11608],{"class":54,"line":1204},[52,11609,10821],{},[52,11611,11612],{"class":54,"line":1209},[52,11613,476],{},[13,11615,11616,11617,11619,11620,11622,11623,11626,11627,11630],{},"１点目の時はインスタンスを作成し",[49,11618,9389],{},"に格納します。そしてクリックごとに",[49,11621,7145],{},"に挿入していき、",[49,11624,11625],{},"this.line.setPath([...this.path])","で更新したパスの配列を展開、インスタンスのパスも更新します。するとクリックするたびにその地点に向かって線画描画されます。静止画ですが",[7814,11628,11629],{},"VUE","という文字を一筆でかいてみました笑",[728,11632],{":src":11633,":width":731},"'_mix\u002Fscp-2021-03-10-21.42.12-768x408.png'",[13,11635,11636],{},"末尾のパスを消して再セットすればやり直し機能ができますし、特定のパスの座標を変更すれば途中の変更もできます。今回は面倒なのでやりませんでした。パスのインスタンスを複数管理できれば、複数ライン・レイヤーなど高度なライン描画を実現できます。詳細な実装をしたらまた記事を書いてみます。",[17,11638,11640],{"id":11639},"vueじゃなくてもよくね","Vueじゃなくてもよくね？",[13,11642,11643],{},"はい。その通りです。ほとんどがGoogle map javascript apiから提供されたオブジェクトをいじっているだけです。なのでVanilla.jsな環境でも普通に描画機能は実装できます。今回はvue.jsを利用して自主開発していたのでvue.jsを使っただけです。",[17,11645,11646],{"id":11646},"いろいろ試してみる",[13,11648,11649],{},"Google Map APIには他にもマーカ・カスタムデザインマーカを入れたり、DOM要素を地図に入れ込むなんてこともできるそうです。これらの描画情報をJSONに格納して、DBに入れておけば地図共有アプリなんかもできそうですね。いろいろやってみます。閲覧ありがとうございました。",[1413,11651,11652],{},"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 pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":47,"searchDepth":115,"depth":115,"links":11654},[11655,11656,11660,11661,11662,11663,11664,11665],{"id":10170,"depth":83,"text":10171},{"id":10199,"depth":83,"text":10200,"children":11657},[11658,11659],{"id":10218,"depth":115,"text":10219},{"id":10562,"depth":115,"text":10563},{"id":10667,"depth":83,"text":10667},{"id":11042,"depth":83,"text":11042},{"id":11268,"depth":83,"text":11268},{"id":11422,"depth":83,"text":11423},{"id":11639,"depth":83,"text":11640},{"id":11646,"depth":83,"text":11646},[1423],"2021-03-10",{},"\u002Farticles\u002Fgoogle-map-vuejs",{"title":10162,"description":10162},"articles\u002Fgoogle-map-vuejs",[1433,204],"_mix\u002Fscp-2021-03-10-21.42.12-768x408.png","oZOhHuAchOiO9qVocS-_1TA4WK0zOIDu_l3spKlDDsE",{"id":11676,"title":11677,"body":11678,"category":14982,"createdAt":14983,"description":14984,"extension":1426,"index":115,"meta":14985,"navigation":339,"path":14986,"publish":339,"seo":14987,"series":14988,"seriesTitle":14989,"stem":14990,"tag":14991,"thumbnail":14993,"updatedAt":1427,"__hash__":14994},"series\u002Fseries\u002Fconcrete5vue-3.md","Concrete5にVueCLIを使ってUIを構築する。3【編集画面と一覧画面】",{"type":10,"value":11679,"toc":14959},[11680,11688,11691,11695,11702,11705,11709,11712,11718,11725,11792,11803,11810,11817,11821,11824,12186,12190,12194,12201,12277,12286,12293,12296,12299,12329,12336,12453,12459,12701,12704,12711,12725,12728,12735,12738,12741,12744,12841,12844,12847,12853,13017,13024,13027,13030,13033,13036,13039,13042,13045,13048,14334,14337,14348,14351,14354,14357,14361,14366,14498,14502,14505,14511,14538,14541,14797,14803,14806,14809,14812,14815,14818,14821,14824,14827,14830,14833,14836,14839,14842,14845,14848,14945,14948,14951,14953,14956],[13,11681,11682,11683,11687],{},"こんにちはjunです。",[1445,11684,11686],{"href":11685},"\u002Fseries\u002Fconcrete5vue-2","Concrete5にVueCLIを使ってUIを構築する 2","の記事の続きを書いていきます。前回の記事ではフォームの作成・登録まで行いました。この記事では登録したデータの編集とファイルマネージャーのvueコンポーネント化を行っていきます。",[13,11689,11690],{},"編集画面は追加画面とコンポーネントを共有し、データベースからAjaxでデータを取得してコンポーネントに代入をします。そして登録したデータの操作が行える一覧画面を作成します。",[17,11692,11694],{"id":11693},"編集画面のレンダーとajax設定","編集画面のレンダーとAjax設定",[13,11696,11697,11698,11701],{},"まずは編集画面から作成していきます。編集は追加と違ってデータベースからデータを取得して、初期値として当てはめる必要があります。PHPであれば",[49,11699,11700],{},"value=\"\u003C?php echo $data?>\"","みたいに挿入することで簡単に実現できますが、vueを使うとなれば一捻り必要です。",[13,11703,11704],{},"jsでフロントを構築する場合、基本的にDBのデータはAjaxを用いて再度サーバーにデータを要求します。concrete5でもAjaxとそのエントリーを実装することができます。まずエントリーの設定からやってみましょう。",[1721,11706,11708],{"id":11707},"ajaxエントリーrest-apiの作成","Ajaxエントリー(REST API)の作成",[13,11710,11711],{},"今回はシングルページのコントローラーを用いてAjax用のエントリーを実装します。Ajaxでデータを取得する際は基本的に取得用のURLを作成して、そのURLに対してAjaxを飛ばしてJSONデータをレスポンスとして受け取るのが定石です。",[42,11713,11716],{"className":11714,"code":11715,"language":451},[1727],"vuetest\n├── controller.php \u002F\u002Fこれはパッケージのcontroller\n├── controllers\n│   └── single_page\n│       └── dashboard\n│           └── vuetest.php\n└── single_pages\n    └── dashboard\n        └── vuetest\n            ├── add.php   \u002F\u002F追加画面シングルページ\n            ├── edit.php  \u002F\u002F編集画面シングルページ\n            └── view.php\n",[49,11717,11715],{"__ignoreMap":47},[13,11719,11720,11721,11724],{},"では ",[49,11722,11723],{},"vuetest\u002Fcontrollers\u002Fsingle_page\u002Fdashboard\u002Fvuetest.php"," に以下のように記述します。",[42,11726,11729],{"className":6114,"code":11727,"filename":11728,"language":6117,"meta":47,"style":47},"public function edit($id=null){\n    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n\n    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album WHERE ID = ?',array($id));\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }\n\n    $this->render('\u002Fdashboard\u002Fvuetest\u002Fedit');\n}\n","vuetest.php",[49,11730,11731,11736,11741,11745,11750,11755,11760,11765,11770,11775,11779,11783,11788],{"__ignoreMap":47},[52,11732,11733],{"class":54,"line":55},[52,11734,11735],{},"public function edit($id=null){\n",[52,11737,11738],{"class":54,"line":83},[52,11739,11740],{},"    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n",[52,11742,11743],{"class":54,"line":115},[52,11744,340],{"emptyLinePlaceholder":339},[52,11746,11747],{"class":54,"line":142},[52,11748,11749],{},"    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n",[52,11751,11752],{"class":54,"line":169},[52,11753,11754],{},"        $db = Database::connection();\n",[52,11756,11757],{"class":54,"line":302},[52,11758,11759],{},"        $db->Execute(\"START TRANSACTION\");\n",[52,11761,11762],{"class":54,"line":308},[52,11763,11764],{},"        $result = $db->fetchAll('SELECT * FROM album WHERE ID = ?',array($id));\n",[52,11766,11767],{"class":54,"line":318},[52,11768,11769],{},"        $db->Execute(\"COMMIT\");\n",[52,11771,11772],{"class":54,"line":328},[52,11773,11774],{},"        return Core::make('helper\u002Fajax')->sendResult($result);\n",[52,11776,11777],{"class":54,"line":4},[52,11778,3753],{},[52,11780,11781],{"class":54,"line":343},[52,11782,340],{"emptyLinePlaceholder":339},[52,11784,11785],{"class":54,"line":353},[52,11786,11787],{},"    $this->render('\u002Fdashboard\u002Fvuetest\u002Fedit');\n",[52,11789,11790],{"class":54,"line":366},[52,11791,535],{},[13,11793,11794,11795,11798,11799,11802],{},"まずは編集画面を ",[49,11796,11797],{},"\u002Fdashboard\u002Fvuetest\u002Fedit"," というURLで表示できるようにします。このメソッドではパラメータがあるので ",[49,11800,11801],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F2"," のようなURLを送信できます。数字の部分はアルバムのDBでのIDとします。（アルバムID）",[13,11804,11805,11806,11809],{},"つまり",[49,11807,11808],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F"," にアルバムIDを加えて送信することで、指定したIDのデータを表示できるようにします。そしてリクエストがXMLHttpRequestつまり、AjaxであればデータJSONで返し、そうでなければ404を返すようにします。",[13,11811,11812,11813,11816],{},"リクエストの種別を限定することで、ブラウザなどでAjax専用の ",[49,11814,11815],{},"\u002Fdashboard\u002Fvuetest\u002FloadData"," というURLを叩いても404しか表示されません。",[1905,11818,11820],{"className":11819},[6312,7800],"\nこのようなAPIを作成するときは、データを差し出してもいいユーザーなのかをチェックする必要があります。しかし今回のような管理画面配下のページ（dashboard）でルーティングする場合は特に気にする必要はありません。\n",[13,11822,11823],{},"\u002Fdashboard\u002F* 配下はリクエストからログインユーザーであるかをチェックしており、ログインユーザーでないリクエストの場合、ログインページのHTMLが返されます。実際にcurlで上記のURLを打ってみると",[42,11825,11827],{"className":44,"code":11826,"language":46,"meta":47,"style":47},"\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Clink rel=\"stylesheet\" type=\"text\u002Fcss\" href=\"\u002Fconcrete\u002Fthemes\u002Fconcrete\u002Fmain.css\" \u002F>\n    \n\u003Ctitle>ログイン :: c5test\u003C\u002Ftitle>\n\n\u003Cmeta http-equiv=\"content-type\" content=\"text\u002Fhtml; charset=UTF-8\"\u002F>\n\u003Cmeta name=\"generator\" content=\"concrete5 - 8.5.4\"\u002F>\n\u003Clink rel=\"canonical\" href=\"http:\u002F\u002Flocalhost:8888\u002Flogin\">\n\u003Cscript type=\"text\u002Fjavascript\">\n    var CCM_DISPATCHER_FILENAME = \"\u002Findex.php\";\n    var CCM_CID = 174;\n    var CCM_EDIT_MODE = false;\n    var CCM_ARRANGE_MODE = false;\n    var CCM_IMAGE_PATH = \"\u002Fconcrete\u002Fimages\";\n    var CCM_TOOLS_PATH = \"\u002Findex.php\u002Ftools\u002Frequired\";\n    var CCM_APPLICATION_URL = \"http:\u002F\u002Flocalhost:8888\";\n    var CCM_REL = \"\";\n    var CCM_ACTIVE_LOCALE = \"ja_JP\";\n\u003C\u002Fscript>\n",[49,11828,11829,11839,11847,11855,11898,11902,11919,11923,11953,11983,12013,12032,12051,12065,12079,12092,12110,12128,12146,12160,12178],{"__ignoreMap":47},[52,11830,11831,11833,11835,11837],{"class":54,"line":55},[52,11832,10246],{"class":58},[52,11834,10249],{"class":62},[52,11836,10252],{"class":65},[52,11838,80],{"class":58},[52,11840,11841,11843,11845],{"class":54,"line":83},[52,11842,59],{"class":58},[52,11844,46],{"class":62},[52,11846,80],{"class":58},[52,11848,11849,11851,11853],{"class":54,"line":115},[52,11850,59],{"class":58},[52,11852,10277],{"class":62},[52,11854,80],{"class":58},[52,11856,11857,11859,11861,11863,11865,11867,11870,11872,11875,11877,11879,11882,11884,11886,11888,11890,11893,11895],{"class":54,"line":142},[52,11858,1902],{"class":58},[52,11860,10369],{"class":62},[52,11862,10372],{"class":65},[52,11864,69],{"class":58},[52,11866,72],{"class":58},[52,11868,11869],{"class":75},"stylesheet",[52,11871,72],{"class":58},[52,11873,11874],{"class":65}," type",[52,11876,69],{"class":58},[52,11878,72],{"class":58},[52,11880,11881],{"class":75},"text\u002Fcss",[52,11883,72],{"class":58},[52,11885,10384],{"class":65},[52,11887,69],{"class":58},[52,11889,72],{"class":58},[52,11891,11892],{"class":75},"\u002Fconcrete\u002Fthemes\u002Fconcrete\u002Fmain.css",[52,11894,72],{"class":58},[52,11896,11897],{"class":58}," \u002F>\n",[52,11899,11900],{"class":54,"line":169},[52,11901,10400],{"class":105},[52,11903,11904,11906,11908,11910,11913,11915,11917],{"class":54,"line":302},[52,11905,59],{"class":58},[52,11907,7525],{"class":62},[52,11909,102],{"class":58},[52,11911,11912],{"class":105},"ログイン :: c5test",[52,11914,108],{"class":58},[52,11916,7525],{"class":62},[52,11918,80],{"class":58},[52,11920,11921],{"class":54,"line":308},[52,11922,340],{"emptyLinePlaceholder":339},[52,11924,11925,11927,11929,11931,11933,11935,11938,11940,11942,11944,11946,11949,11951],{"class":54,"line":318},[52,11926,59],{"class":58},[52,11928,10286],{"class":62},[52,11930,10309],{"class":65},[52,11932,69],{"class":58},[52,11934,72],{"class":58},[52,11936,11937],{"class":75},"content-type",[52,11939,72],{"class":58},[52,11941,10321],{"class":65},[52,11943,69],{"class":58},[52,11945,72],{"class":58},[52,11947,11948],{"class":75},"text\u002Fhtml; charset=UTF-8",[52,11950,72],{"class":58},[52,11952,1941],{"class":58},[52,11954,11955,11957,11959,11961,11963,11965,11968,11970,11972,11974,11976,11979,11981],{"class":54,"line":328},[52,11956,59],{"class":58},[52,11958,10286],{"class":62},[52,11960,66],{"class":65},[52,11962,69],{"class":58},[52,11964,72],{"class":58},[52,11966,11967],{"class":75},"generator",[52,11969,72],{"class":58},[52,11971,10321],{"class":65},[52,11973,69],{"class":58},[52,11975,72],{"class":58},[52,11977,11978],{"class":75},"concrete5 - 8.5.4",[52,11980,72],{"class":58},[52,11982,1941],{"class":58},[52,11984,11985,11987,11989,11991,11993,11995,11998,12000,12002,12004,12006,12009,12011],{"class":54,"line":4},[52,11986,59],{"class":58},[52,11988,10369],{"class":62},[52,11990,10372],{"class":65},[52,11992,69],{"class":58},[52,11994,72],{"class":58},[52,11996,11997],{"class":75},"canonical",[52,11999,72],{"class":58},[52,12001,10384],{"class":65},[52,12003,69],{"class":58},[52,12005,72],{"class":58},[52,12007,12008],{"class":75},"http:\u002F\u002Flocalhost:8888\u002Flogin",[52,12010,72],{"class":58},[52,12012,80],{"class":58},[52,12014,12015,12017,12019,12021,12023,12025,12028,12030],{"class":54,"line":343},[52,12016,59],{"class":58},[52,12018,348],{"class":62},[52,12020,11874],{"class":65},[52,12022,69],{"class":58},[52,12024,72],{"class":58},[52,12026,12027],{"class":75},"text\u002Fjavascript",[52,12029,72],{"class":58},[52,12031,80],{"class":58},[52,12033,12034,12037,12040,12042,12044,12047,12049],{"class":54,"line":353},[52,12035,12036],{"class":65},"    var",[52,12038,12039],{"class":105}," CCM_DISPATCHER_FILENAME ",[52,12041,69],{"class":58},[52,12043,1502],{"class":58},[52,12045,12046],{"class":75},"\u002Findex.php",[52,12048,72],{"class":58},[52,12050,1006],{"class":58},[52,12052,12053,12055,12058,12060,12063],{"class":54,"line":366},[52,12054,12036],{"class":65},[52,12056,12057],{"class":105}," CCM_CID ",[52,12059,69],{"class":58},[52,12061,12062],{"class":4596}," 174",[52,12064,1006],{"class":58},[52,12066,12067,12069,12072,12074,12077],{"class":54,"line":386},[52,12068,12036],{"class":65},[52,12070,12071],{"class":105}," CCM_EDIT_MODE ",[52,12073,69],{"class":58},[52,12075,12076],{"class":2160}," false",[52,12078,1006],{"class":58},[52,12080,12081,12083,12086,12088,12090],{"class":54,"line":414},[52,12082,12036],{"class":65},[52,12084,12085],{"class":105}," CCM_ARRANGE_MODE ",[52,12087,69],{"class":58},[52,12089,12076],{"class":2160},[52,12091,1006],{"class":58},[52,12093,12094,12096,12099,12101,12103,12106,12108],{"class":54,"line":426},[52,12095,12036],{"class":65},[52,12097,12098],{"class":105}," CCM_IMAGE_PATH ",[52,12100,69],{"class":58},[52,12102,1502],{"class":58},[52,12104,12105],{"class":75},"\u002Fconcrete\u002Fimages",[52,12107,72],{"class":58},[52,12109,1006],{"class":58},[52,12111,12112,12114,12117,12119,12121,12124,12126],{"class":54,"line":434},[52,12113,12036],{"class":65},[52,12115,12116],{"class":105}," CCM_TOOLS_PATH ",[52,12118,69],{"class":58},[52,12120,1502],{"class":58},[52,12122,12123],{"class":75},"\u002Findex.php\u002Ftools\u002Frequired",[52,12125,72],{"class":58},[52,12127,1006],{"class":58},[52,12129,12130,12132,12135,12137,12139,12142,12144],{"class":54,"line":445},[52,12131,12036],{"class":65},[52,12133,12134],{"class":105}," CCM_APPLICATION_URL ",[52,12136,69],{"class":58},[52,12138,1502],{"class":58},[52,12140,12141],{"class":75},"http:\u002F\u002Flocalhost:8888",[52,12143,72],{"class":58},[52,12145,1006],{"class":58},[52,12147,12148,12150,12153,12155,12158],{"class":54,"line":479},[52,12149,12036],{"class":65},[52,12151,12152],{"class":105}," CCM_REL ",[52,12154,69],{"class":58},[52,12156,12157],{"class":58}," \"\"",[52,12159,1006],{"class":58},[52,12161,12162,12164,12167,12169,12171,12174,12176],{"class":54,"line":508},[52,12163,12036],{"class":65},[52,12165,12166],{"class":105}," CCM_ACTIVE_LOCALE ",[52,12168,69],{"class":58},[52,12170,1502],{"class":58},[52,12172,12173],{"class":75},"ja_JP",[52,12175,72],{"class":58},[52,12177,1006],{"class":58},[52,12179,12180,12182,12184],{"class":54,"line":538},[52,12181,108],{"class":58},[52,12183,348],{"class":62},[52,12185,80],{"class":58},[1905,12187,12189],{"className":12188},[6312,6313],"\n内部の生データが外部からアクセスされるのは非常にまずいのでdashbord配下にルーティングを置き、さらにリクエストの種類をXHRだけにしましょう。\n",[1721,12191,12193],{"id":12192},"コンポーネントにajaxアクセスを実装","コンポーネントにAjaxアクセスを実装",[13,12195,12196,12197,12200],{},"URLとデータの取得処理は書いたので、vue側でそこにAjaxを飛ばすようにします。前回作成した",[49,12198,12199],{},"form.vue"," にAjaxの処理を書きます。",[42,12202,12204],{"className":202,"code":12203,"filename":12199,"language":204,"meta":47,"style":47},"created(){\n    if(this.isEdit){\n        $.ajax({\n            url:location.href,\n            type:'GET',\n            success: (data)=> {\n                let result = JSON.parse(data)[0]; \u002F\u002F returns array\n                this.title = result.title;\n            },\n            error: (xhr, textStatus, errorThrown)=>{\n                console.error('Error! ' + textStatus + ' ' + errorThrown);\n            }\n        })\n    }\n}\n",[49,12205,12206,12211,12216,12221,12226,12231,12236,12241,12246,12250,12255,12260,12264,12269,12273],{"__ignoreMap":47},[52,12207,12208],{"class":54,"line":55},[52,12209,12210],{"class":105},"created(){\n",[52,12212,12213],{"class":54,"line":83},[52,12214,12215],{"class":105},"    if(this.isEdit){\n",[52,12217,12218],{"class":54,"line":115},[52,12219,12220],{"class":105},"        $.ajax({\n",[52,12222,12223],{"class":54,"line":142},[52,12224,12225],{"class":105},"            url:location.href,\n",[52,12227,12228],{"class":54,"line":169},[52,12229,12230],{"class":105},"            type:'GET',\n",[52,12232,12233],{"class":54,"line":302},[52,12234,12235],{"class":105},"            success: (data)=> {\n",[52,12237,12238],{"class":54,"line":308},[52,12239,12240],{"class":105},"                let result = JSON.parse(data)[0]; \u002F\u002F returns array\n",[52,12242,12243],{"class":54,"line":318},[52,12244,12245],{"class":105},"                this.title = result.title;\n",[52,12247,12248],{"class":54,"line":328},[52,12249,4972],{"class":105},[52,12251,12252],{"class":54,"line":4},[52,12253,12254],{"class":105},"            error: (xhr, textStatus, errorThrown)=>{\n",[52,12256,12257],{"class":54,"line":343},[52,12258,12259],{"class":105},"                console.error('Error! ' + textStatus + ' ' + errorThrown);\n",[52,12261,12262],{"class":54,"line":353},[52,12263,2320],{"class":105},[52,12265,12266],{"class":54,"line":366},[52,12267,12268],{"class":105},"        })\n",[52,12270,12271],{"class":54,"line":386},[52,12272,3753],{"class":105},[52,12274,12275],{"class":54,"line":414},[52,12276,535],{"class":105},[13,12278,12279,12281,12282,12285],{},[49,12280,12199],{},"は編集と新規追加を併用しているので、",[49,12283,12284],{},"isEdit","というプロパティでAjaxを飛ばすかを制御しています。現在のURLに対してAjaxを飛ばすと、先ほどのコードで書かれているようにIDに紐づいたアルバム情報をDBから取ってきてくれます。",[13,12287,12288,12289,12292],{},"データはJSONで戻ってくるので　",[49,12290,12291],{},"JSON.prase","を用いてJSで用いられるようにします。もし仮にAjaxが失敗した場合\b（400、500系のエラー）、コンソールでエラーが吐かれるようになっています。",[1721,12294,12295],{"id":12295},"編集用コンポーネントのレンダリング設定",[13,12297,12298],{},"シングルページそのものはエントリーポイントだけ。",[42,12300,12303],{"className":6114,"code":12301,"filename":12302,"language":6117,"meta":47,"style":47},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"edit\">\u003C\u002Fdiv>\n","edit.php",[49,12304,12305,12310,12315,12320,12324],{"__ignoreMap":47},[52,12306,12307],{"class":54,"line":55},[52,12308,12309],{},"\u003C?php\n",[52,12311,12312],{"class":54,"line":83},[52,12313,12314],{},"defined('C5_EXECUTE') or die('Access Denied.');\n",[52,12316,12317],{"class":54,"line":115},[52,12318,12319],{},"?>\n",[52,12321,12322],{"class":54,"line":142},[52,12323,340],{"emptyLinePlaceholder":339},[52,12325,12326],{"class":54,"line":169},[52,12327,12328],{},"\u003Cdiv id=\"edit\">\u003C\u002Fdiv>\n",[13,12330,12331,12332,12335],{},"そしてvue側のeditコンポーネントはpropsを変えるだけで",[49,12333,12334],{},"add.vue","とほぼ同じ",[42,12337,12340],{"className":202,"code":12338,"filename":12339,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003CAlbumForm :isEdit=\"true\"\u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport AlbumForm from '.\u002Fcomponents\u002Fform';\nexport default {\n    name:'add',\n    components:{AlbumForm}\n}\n\u003C\u002Fscript>\n","edit.vue",[49,12341,12342,12350,12370,12378,12382,12390,12408,12416,12431,12441,12445],{"__ignoreMap":47},[52,12343,12344,12346,12348],{"class":54,"line":55},[52,12345,59],{"class":58},[52,12347,213],{"class":62},[52,12349,80],{"class":58},[52,12351,12352,12354,12357,12360,12362,12364,12366,12368],{"class":54,"line":83},[52,12353,1902],{"class":58},[52,12355,12356],{"class":62},"AlbumForm",[52,12358,12359],{"class":65}," :isEdit",[52,12361,69],{"class":58},[52,12363,72],{"class":58},[52,12365,1322],{"class":75},[52,12367,72],{"class":58},[52,12369,1941],{"class":58},[52,12371,12372,12374,12376],{"class":54,"line":115},[52,12373,108],{"class":58},[52,12375,213],{"class":62},[52,12377,80],{"class":58},[52,12379,12380],{"class":54,"line":142},[52,12381,340],{"emptyLinePlaceholder":339},[52,12383,12384,12386,12388],{"class":54,"line":169},[52,12385,59],{"class":58},[52,12387,348],{"class":62},[52,12389,80],{"class":58},[52,12391,12392,12394,12397,12399,12401,12404,12406],{"class":54,"line":302},[52,12393,1847],{"class":359},[52,12395,12396],{"class":105}," AlbumForm ",[52,12398,1976],{"class":359},[52,12400,1979],{"class":58},[52,12402,12403],{"class":75},".\u002Fcomponents\u002Fform",[52,12405,375],{"class":58},[52,12407,1006],{"class":58},[52,12409,12410,12412,12414],{"class":54,"line":308},[52,12411,356],{"class":359},[52,12413,360],{"class":359},[52,12415,2012],{"class":58},[52,12417,12418,12420,12422,12424,12427,12429],{"class":54,"line":318},[52,12419,2017],{"class":62},[52,12421,372],{"class":58},[52,12423,375],{"class":58},[52,12425,12426],{"class":75},"add",[52,12428,375],{"class":58},[52,12430,383],{"class":58},[52,12432,12433,12435,12437,12439],{"class":54,"line":328},[52,12434,3738],{"class":62},[52,12436,8527],{"class":58},[52,12438,12356],{"class":105},[52,12440,535],{"class":58},[52,12442,12443],{"class":54,"line":4},[52,12444,535],{"class":58},[52,12446,12447,12449,12451],{"class":54,"line":343},[52,12448,108],{"class":58},[52,12450,348],{"class":62},[52,12452,80],{"class":58},[13,12454,12455,12456,12458],{},"最後にレンダー用の",[49,12457,1769],{},"を以下のようにしておきます。",[42,12460,12462],{"className":1249,"code":12461,"filename":1769,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport Add from '.\u002Fadd.vue'\nimport Edit from '.\u002Fedit.vue'\n\n\nVue.config.productionTip = false\n\nfunction renderIfidExits(id,vueRoot){\n  if(document.getElementById(id) !== null){\n    return new Vue({\n      render: h => h(vueRoot),\n    }).$mount('#'+id)\n  }\n}\n\nrenderIfidExits('add',Add);\nrenderIfidExits('edit',Edit);\n",[49,12463,12464,12478,12494,12510,12514,12518,12537,12541,12560,12589,12601,12623,12649,12653,12657,12661,12681],{"__ignoreMap":47},[52,12465,12466,12468,12470,12472,12474,12476],{"class":54,"line":55},[52,12467,1847],{"class":359},[52,12469,6824],{"class":105},[52,12471,1976],{"class":359},[52,12473,1979],{"class":58},[52,12475,204],{"class":75},[52,12477,5629],{"class":58},[52,12479,12480,12482,12485,12487,12489,12492],{"class":54,"line":83},[52,12481,1847],{"class":359},[52,12483,12484],{"class":105}," Add ",[52,12486,1976],{"class":359},[52,12488,1979],{"class":58},[52,12490,12491],{"class":75},".\u002Fadd.vue",[52,12493,5629],{"class":58},[52,12495,12496,12498,12501,12503,12505,12508],{"class":54,"line":115},[52,12497,1847],{"class":359},[52,12499,12500],{"class":105}," Edit ",[52,12502,1976],{"class":359},[52,12504,1979],{"class":58},[52,12506,12507],{"class":75},".\u002Fedit.vue",[52,12509,5629],{"class":58},[52,12511,12512],{"class":54,"line":142},[52,12513,340],{"emptyLinePlaceholder":339},[52,12515,12516],{"class":54,"line":169},[52,12517,340],{"emptyLinePlaceholder":339},[52,12519,12520,12522,12524,12527,12529,12532,12534],{"class":54,"line":302},[52,12521,2829],{"class":105},[52,12523,956],{"class":58},[52,12525,12526],{"class":105},"config",[52,12528,956],{"class":58},[52,12530,12531],{"class":105},"productionTip ",[52,12533,69],{"class":58},[52,12535,12536],{"class":2160}," false\n",[52,12538,12539],{"class":54,"line":308},[52,12540,340],{"emptyLinePlaceholder":339},[52,12542,12543,12546,12549,12551,12553,12555,12558],{"class":54,"line":318},[52,12544,12545],{"class":65},"function",[52,12547,12548],{"class":417}," renderIfidExits",[52,12550,931],{"class":58},[52,12552,7516],{"class":985},[52,12554,407],{"class":58},[52,12556,12557],{"class":985},"vueRoot",[52,12559,2085],{"class":58},[52,12561,12562,12565,12567,12569,12571,12573,12575,12577,12579,12582,12585,12587],{"class":54,"line":328},[52,12563,12564],{"class":359},"  if",[52,12566,931],{"class":62},[52,12568,10855],{"class":105},[52,12570,956],{"class":58},[52,12572,10860],{"class":417},[52,12574,931],{"class":62},[52,12576,7516],{"class":105},[52,12578,4600],{"class":62},[52,12580,12581],{"class":58},"!==",[52,12583,12584],{"class":58}," null",[52,12586,937],{"class":62},[52,12588,363],{"class":58},[52,12590,12591,12593,12595,12597,12599],{"class":54,"line":4},[52,12592,3828],{"class":359},[52,12594,6900],{"class":58},[52,12596,7020],{"class":417},[52,12598,931],{"class":62},[52,12600,363],{"class":58},[52,12602,12603,12606,12608,12611,12613,12615,12617,12619,12621],{"class":54,"line":343},[52,12604,12605],{"class":417},"      render",[52,12607,372],{"class":58},[52,12609,12610],{"class":985}," h",[52,12612,2282],{"class":65},[52,12614,12610],{"class":417},[52,12616,931],{"class":62},[52,12618,12557],{"class":105},[52,12620,937],{"class":62},[52,12622,383],{"class":58},[52,12624,12625,12627,12629,12631,12633,12635,12637,12640,12642,12645,12647],{"class":54,"line":353},[52,12626,5094],{"class":58},[52,12628,937],{"class":62},[52,12630,956],{"class":58},[52,12632,7049],{"class":417},[52,12634,931],{"class":62},[52,12636,375],{"class":58},[52,12638,12639],{"class":75},"#",[52,12641,375],{"class":58},[52,12643,12644],{"class":58},"+",[52,12646,7516],{"class":105},[52,12648,1014],{"class":62},[52,12650,12651],{"class":54,"line":366},[52,12652,1075],{"class":58},[52,12654,12655],{"class":54,"line":386},[52,12656,535],{"class":58},[52,12658,12659],{"class":54,"line":414},[52,12660,340],{"emptyLinePlaceholder":339},[52,12662,12663,12666,12668,12670,12672,12674,12676,12679],{"class":54,"line":426},[52,12664,12665],{"class":417},"renderIfidExits",[52,12667,931],{"class":105},[52,12669,375],{"class":58},[52,12671,12426],{"class":75},[52,12673,375],{"class":58},[52,12675,407],{"class":58},[52,12677,12678],{"class":105},"Add)",[52,12680,1006],{"class":58},[52,12682,12683,12685,12687,12689,12692,12694,12696,12699],{"class":54,"line":434},[52,12684,12665],{"class":417},[52,12686,931],{"class":105},[52,12688,375],{"class":58},[52,12690,12691],{"class":75},"edit",[52,12693,375],{"class":58},[52,12695,407],{"class":58},[52,12697,12698],{"class":105},"Edit)",[52,12700,1006],{"class":58},[13,12702,12703],{},"前回はAddコンポーネントだけでしたが、今回はEditもあります。さらにこのmain.jsで全てのコンポーネントのレンダーを制御しているので、エントリーポイント のIDが存在すればそこにコンポーネントをレンダリングする。という方法を取っています。",[13,12705,12706,12707,12710],{},"本当はコンポーネントごとにレンダー用のjs（",[49,12708,12709],{},"add.js,edit.js","みたいな）を作成するのですが、面倒だったのでこうしました。",[13,12712,12713,12714,12717,12718,12721,12722,12724],{},"そしてform.vueで編集の場合（",[49,12715,12716],{},"isEdit = true","）に",[49,12719,12720],{},"created()","でAjaxを飛ばしてデータを取得し、",[49,12723,9389],{},"に代入するようします。",[17,12726,12727],{"id":12727},"実際にレンダーしてみる",[13,12729,12730,12731,12734],{},"ビルドをして ",[49,12732,12733],{},"\u002Fdashboard\u002Fvuetest\u002Fedit\u002F{id}"," へアクセスします。IDがあっていればそのデータを取ってきてくれます。",[728,12736],{":src":12737,":width":731},"'_mix\u002Fsch-2020-10-04-1.14.27-768x527.png'",[728,12739],{":src":12740,":width":731},"'_mix\u002Fajax-768x764.png'",[13,12742,12743],{},"きちんと画面には前回入力した追加内容が表示されています。開発者ツールでNetworkでAjaxを確認してみましょう。Request Header を確認すると確かに、現在のURLにアクセスしておりさらにXMLHttpRequestで送信されています。Resonseをみてみると",[42,12745,12747],{"className":1470,"code":12746,"language":1472,"meta":47,"style":47},"[\n    {\n        \"id\":\"1\",\n        \"title\":\"\\u30c6\\u30b9\\u30c8\",\n        \"created\":\"2020-08-27 00:28:38\",\n        \"modified\":\"2020-08-27 00:28:38\"\n    }\n]\n",[49,12748,12749,12753,12758,12777,12796,12816,12833,12837],{"__ignoreMap":47},[52,12750,12751],{"class":54,"line":55},[52,12752,442],{"class":58},[52,12754,12755],{"class":54,"line":83},[52,12756,12757],{"class":58},"    {\n",[52,12759,12760,12763,12765,12767,12769,12771,12773,12775],{"class":54,"line":115},[52,12761,12762],{"class":58},"        \"",[52,12764,7516],{"class":65},[52,12766,72],{"class":58},[52,12768,372],{"class":58},[52,12770,72],{"class":58},[52,12772,31],{"class":75},[52,12774,72],{"class":58},[52,12776,383],{"class":58},[52,12778,12779,12781,12783,12785,12787,12789,12792,12794],{"class":54,"line":142},[52,12780,12762],{"class":58},[52,12782,7525],{"class":65},[52,12784,72],{"class":58},[52,12786,372],{"class":58},[52,12788,72],{"class":58},[52,12790,12791],{"class":105},"\\u30c6\\u30b9\\u30c8",[52,12793,72],{"class":58},[52,12795,383],{"class":58},[52,12797,12798,12800,12803,12805,12807,12809,12812,12814],{"class":54,"line":169},[52,12799,12762],{"class":58},[52,12801,12802],{"class":65},"created",[52,12804,72],{"class":58},[52,12806,372],{"class":58},[52,12808,72],{"class":58},[52,12810,12811],{"class":75},"2020-08-27 00:28:38",[52,12813,72],{"class":58},[52,12815,383],{"class":58},[52,12817,12818,12820,12823,12825,12827,12829,12831],{"class":54,"line":302},[52,12819,12762],{"class":58},[52,12821,12822],{"class":65},"modified",[52,12824,72],{"class":58},[52,12826,372],{"class":58},[52,12828,72],{"class":58},[52,12830,12811],{"class":75},[52,12832,266],{"class":58},[52,12834,12835],{"class":54,"line":308},[52,12836,3753],{"class":58},[52,12838,12839],{"class":54,"line":318},[52,12840,6511],{"class":58},[13,12842,12843],{},"このようにデータベースから取ってきた内容がJSONとして渡されているのが確認できます。ちなみに日本語はエンコードされているので、js側でJSON praseを使うことで元の文章に戻すことができます。",[17,12845,12846],{"id":12846},"内容を更新する",[13,12848,12849,12850,12852],{},"編集画面を表示した際の初期表示はできるようになったので、次は内容が書き換えてDBの内容を変更できるようにしましょう。しかし触るのはバックエンドの部分だけです。",[49,12851,11723],{},"を以下のように変更します。",[42,12854,12856],{"className":6114,"code":12855,"filename":11728,"language":6117,"meta":47,"style":47},"pupublic function edit($id=null){\n\n    \u002F\u002F パラメータがない場合は一覧画面へリダイレクト\n    if($id==null) return Redirect::to('\u002Fdashboard\u002Fvuetest\u002F')->send();\n\n    \u002F\u002F Ajax エンドポイント\n    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }\n\n    \u002F\u002Fpost処理(ここを追記)\n    if(Request::isPost() == true){\n        $title = $this->post('title');\n\n        if(empty($title)==false){\n            $db = Database::connection();\n            $db->executeQuery(\"START TRANSACTION\");\n            $db->executeQuery(\n                'UPDATE album SET `title`=?, `modified`=now() WHERE `ID`=?',\n                array($title,$id)\n            );\n            $db->executeQuery(\"COMMIT\");\n            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n        }else{\n            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n        }\n\n    }else{\n        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n    }\n}\n",[49,12857,12858,12863,12867,12872,12876,12880,12885,12889,12893,12897,12902,12906,12910,12914,12918,12923,12928,12933,12937,12942,12947,12952,12957,12962,12967,12972,12977,12982,12987,12991,12995,12999,13004,13009,13013],{"__ignoreMap":47},[52,12859,12860],{"class":54,"line":55},[52,12861,12862],{},"pupublic function edit($id=null){\n",[52,12864,12865],{"class":54,"line":83},[52,12866,340],{"emptyLinePlaceholder":339},[52,12868,12869],{"class":54,"line":115},[52,12870,12871],{},"    \u002F\u002F パラメータがない場合は一覧画面へリダイレクト\n",[52,12873,12874],{"class":54,"line":142},[52,12875,11740],{},[52,12877,12878],{"class":54,"line":169},[52,12879,340],{"emptyLinePlaceholder":339},[52,12881,12882],{"class":54,"line":302},[52,12883,12884],{},"    \u002F\u002F Ajax エンドポイント\n",[52,12886,12887],{"class":54,"line":308},[52,12888,11749],{},[52,12890,12891],{"class":54,"line":318},[52,12892,11754],{},[52,12894,12895],{"class":54,"line":328},[52,12896,11759],{},[52,12898,12899],{"class":54,"line":4},[52,12900,12901],{},"        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n",[52,12903,12904],{"class":54,"line":343},[52,12905,11769],{},[52,12907,12908],{"class":54,"line":353},[52,12909,11774],{},[52,12911,12912],{"class":54,"line":366},[52,12913,3753],{},[52,12915,12916],{"class":54,"line":386},[52,12917,340],{"emptyLinePlaceholder":339},[52,12919,12920],{"class":54,"line":414},[52,12921,12922],{},"    \u002F\u002Fpost処理(ここを追記)\n",[52,12924,12925],{"class":54,"line":426},[52,12926,12927],{},"    if(Request::isPost() == true){\n",[52,12929,12930],{"class":54,"line":434},[52,12931,12932],{},"        $title = $this->post('title');\n",[52,12934,12935],{"class":54,"line":445},[52,12936,340],{"emptyLinePlaceholder":339},[52,12938,12939],{"class":54,"line":479},[52,12940,12941],{},"        if(empty($title)==false){\n",[52,12943,12944],{"class":54,"line":508},[52,12945,12946],{},"            $db = Database::connection();\n",[52,12948,12949],{"class":54,"line":538},[52,12950,12951],{},"            $db->executeQuery(\"START TRANSACTION\");\n",[52,12953,12954],{"class":54,"line":546},[52,12955,12956],{},"            $db->executeQuery(\n",[52,12958,12959],{"class":54,"line":552},[52,12960,12961],{},"                'UPDATE album SET `title`=?, `modified`=now() WHERE `ID`=?',\n",[52,12963,12964],{"class":54,"line":558},[52,12965,12966],{},"                array($title,$id)\n",[52,12968,12969],{"class":54,"line":563},[52,12970,12971],{},"            );\n",[52,12973,12974],{"class":54,"line":568},[52,12975,12976],{},"            $db->executeQuery(\"COMMIT\");\n",[52,12978,12979],{"class":54,"line":1105},[52,12980,12981],{},"            Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n",[52,12983,12984],{"class":54,"line":1134},[52,12985,12986],{},"        }else{\n",[52,12988,12989],{"class":54,"line":1163},[52,12990,12981],{},[52,12992,12993],{"class":54,"line":1192},[52,12994,2060],{},[52,12996,12997],{"class":54,"line":1199},[52,12998,340],{"emptyLinePlaceholder":339},[52,13000,13001],{"class":54,"line":1204},[52,13002,13003],{},"    }else{\n",[52,13005,13006],{"class":54,"line":1209},[52,13007,13008],{},"        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n",[52,13010,13011],{"class":54,"line":1214},[52,13012,3753],{},[52,13014,13015],{"class":54,"line":1219},[52,13016,535],{},[13,13018,13019,13020,13023],{},"新規作成の際に使用される",[49,13021,13022],{},"pupublic function edit"," を一部変更したぐらいです。postがある場合、その値のバリデーションをして変更するIDを元に更新用のSQLを走らせるだけです。",[1721,13025,13026],{"id":13026},"実際に変更してみる",[728,13028],{":src":13029,":width":731},"'_mix\u002Fsch-2020-10-04-13.37.28-768x396.png'",[728,13031],{":src":13032,":width":731},"'_mix\u002Fsch-2020-10-04-13.38.13.png'",[13,13034,13035],{},"無事、タイトルと編集時間が更新されました。これでCRUDの「Update」が完成しました。",[17,13037,13038],{"id":13038},"一覧画面を作成する",[13,13040,13041],{},"追加・編集の画面は完成しました。次は全ての登録データを一覧で見れる画面を作成していきます。\u002Fdashboard\u002Fvuetest\u002F にアクセスした際に一覧が表示されるようにします。",[1721,13043,13044],{"id":13044},"一覧用コンポーネントの作成",[13,13046,13047],{},"一覧コンポーネントをindex.vueとしておきます。一覧画面では以下のような構成にしています。",[42,13049,13052],{"className":202,"code":13050,"filename":13051,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム一覧\u003C\u002Fh3>\n        \u003Chr>\n\n        \u003Ctable class=\"p-package-index table table-hover\">\n            \u003Cthead>\n                \u003Ctr>\n                    \u003Cth class=\"c-dol-title\">タイトル\u003C\u002Fth>\n                    \u003Cth class=\"c-dol-publish-date\">作成日\u003C\u002Fth>\n                    \u003Cth class=\"c-dol-operation\">操作\u003C\u002Fth>\n                \u003C\u002Ftr>\n            \u003C\u002Fthead>\n            \u003Ctbody>\n                \u003Ctr v-for=\"val in list\" :key=\"val.id\" tabindex=\"0\">\n                    \u003Ctd style=\"vertical-align:middle;\">{{val.title}}\u003C\u002Ftd>\n                    \u003Ctd style=\"vertical-align:middle;\">{{val.created}}\u003C\u002Ftd>\n                    \u003Ctd style=\"vertical-align:middle;\">\n                        \u003Ca :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\" type=\"button\" class=\"btn btn-success btn-sm\" style=\"margin-right:10px;\">編集\u003C\u002Fa>\n                        \u003Cbutton type=\"button\" class=\"btn btn-danger btn-sm\" v-on:click=\"cofirmDelete(val)\">削除\u003C\u002Fbutton>\n                    \u003C\u002Ftd>\n                \u003C\u002Ftr>\n            \u003C\u002Ftbody>\n        \u003C\u002Ftable>\n\n        \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n            \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                \u003Ca href=\"\u002Fdashboard\u002Fvuetest\u002Fadd\" class=\"pull-right btn btn-primary\">\n                    新規追加\n                \u003C\u002Fa>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'index',\n    data(){\n        return {\n            list:[],\n            isProcessing:false\n        }\n    },\n    methods:{\n        cofirmDelete(obj){\n            let result = window.confirm('アルバム：「'+obj.title+'」を本当に削除しますか？この操作は取り消せません。');\n            if(result) return this.deleteAlubm(obj.id);\n        },\n        deleteAlubm(id){\n            if(this.isProcessing==false){\n                this.isProcessing = true;\n\n                $.ajax({\n                    url:'\u002Fdashboard\u002Fvuetest\u002FdeleteData\u002F',\n                    type:'POST',\n                    data:{target:id},\n                    success: ()=> {\n                        let targetIndex = this.list.findIndex((ele)=>{\n                            return ele.ID == id;\n                        });\n                        this.list.splice(targetIndex,1);\n                        this.isProcessing = false;\n                    },\n                    error: (xhr, textStatus, errorThrown)=>{\n                        console.log('Error! ' + textStatus + ' ' + errorThrown);\n                    }\n                })\n            }\n        },\n    },\n    created(){\n        $.ajax({\n            url:'\u002Fdashboard\u002Fvuetest\u002FloadData',\n            type:'GET',\n            success: (data)=> {\n                this.list = JSON.parse(data); \u002F\u002F returns array\n            },\n            error: (xhr, textStatus, errorThrown)=>{\n                console.error('Error! ' + textStatus + ' ' + errorThrown);\n            }\n        })\n    }\n}\n\u003C\u002Fscript>\n","index.vue",[49,13053,13054,13062,13081,13098,13107,13111,13131,13141,13151,13180,13208,13236,13245,13254,13263,13305,13334,13361,13379,13441,13491,13500,13508,13516,13525,13529,13548,13567,13597,13602,13610,13618,13626,13634,13642,13646,13654,13662,13677,13683,13689,13700,13710,13714,13718,13724,13735,13782,13813,13817,13828,13848,13861,13865,13879,13895,13910,13925,13938,13970,13989,13998,14023,14036,14041,14070,14107,14113,14121,14126,14131,14136,14144,14158,14173,14190,14208,14235,14240,14266,14302,14307,14315,14320,14325],{"__ignoreMap":47},[52,13055,13056,13058,13060],{"class":54,"line":55},[52,13057,59],{"class":58},[52,13059,213],{"class":62},[52,13061,80],{"class":58},[52,13063,13064,13066,13068,13070,13072,13074,13077,13079],{"class":54,"line":83},[52,13065,1902],{"class":58},[52,13067,1905],{"class":62},[52,13069,10706],{"class":65},[52,13071,69],{"class":58},[52,13073,72],{"class":58},[52,13075,13076],{"class":75},"ccm-dashboard-content-inner",[52,13078,72],{"class":58},[52,13080,80],{"class":58},[52,13082,13083,13085,13087,13089,13092,13094,13096],{"class":54,"line":115},[52,13084,1912],{"class":58},[52,13086,1721],{"class":62},[52,13088,102],{"class":58},[52,13090,13091],{"class":105},"アルバム一覧",[52,13093,108],{"class":58},[52,13095,1721],{"class":62},[52,13097,80],{"class":58},[52,13099,13100,13102,13105],{"class":54,"line":142},[52,13101,1912],{"class":58},[52,13103,13104],{"class":62},"hr",[52,13106,80],{"class":58},[52,13108,13109],{"class":54,"line":169},[52,13110,340],{"emptyLinePlaceholder":339},[52,13112,13113,13115,13118,13120,13122,13124,13127,13129],{"class":54,"line":302},[52,13114,1912],{"class":58},[52,13116,13117],{"class":62},"table",[52,13119,10706],{"class":65},[52,13121,69],{"class":58},[52,13123,72],{"class":58},[52,13125,13126],{"class":75},"p-package-index table table-hover",[52,13128,72],{"class":58},[52,13130,80],{"class":58},[52,13132,13133,13136,13139],{"class":54,"line":308},[52,13134,13135],{"class":58},"            \u003C",[52,13137,13138],{"class":62},"thead",[52,13140,80],{"class":58},[52,13142,13143,13146,13149],{"class":54,"line":318},[52,13144,13145],{"class":58},"                \u003C",[52,13147,13148],{"class":62},"tr",[52,13150,80],{"class":58},[52,13152,13153,13156,13159,13161,13163,13165,13168,13170,13172,13174,13176,13178],{"class":54,"line":328},[52,13154,13155],{"class":58},"                    \u003C",[52,13157,13158],{"class":62},"th",[52,13160,10706],{"class":65},[52,13162,69],{"class":58},[52,13164,72],{"class":58},[52,13166,13167],{"class":75},"c-dol-title",[52,13169,72],{"class":58},[52,13171,102],{"class":58},[52,13173,5285],{"class":105},[52,13175,108],{"class":58},[52,13177,13158],{"class":62},[52,13179,80],{"class":58},[52,13181,13182,13184,13186,13188,13190,13192,13195,13197,13199,13202,13204,13206],{"class":54,"line":4},[52,13183,13155],{"class":58},[52,13185,13158],{"class":62},[52,13187,10706],{"class":65},[52,13189,69],{"class":58},[52,13191,72],{"class":58},[52,13193,13194],{"class":75},"c-dol-publish-date",[52,13196,72],{"class":58},[52,13198,102],{"class":58},[52,13200,13201],{"class":105},"作成日",[52,13203,108],{"class":58},[52,13205,13158],{"class":62},[52,13207,80],{"class":58},[52,13209,13210,13212,13214,13216,13218,13220,13223,13225,13227,13230,13232,13234],{"class":54,"line":343},[52,13211,13155],{"class":58},[52,13213,13158],{"class":62},[52,13215,10706],{"class":65},[52,13217,69],{"class":58},[52,13219,72],{"class":58},[52,13221,13222],{"class":75},"c-dol-operation",[52,13224,72],{"class":58},[52,13226,102],{"class":58},[52,13228,13229],{"class":105},"操作",[52,13231,108],{"class":58},[52,13233,13158],{"class":62},[52,13235,80],{"class":58},[52,13237,13238,13241,13243],{"class":54,"line":353},[52,13239,13240],{"class":58},"                \u003C\u002F",[52,13242,13148],{"class":62},[52,13244,80],{"class":58},[52,13246,13247,13250,13252],{"class":54,"line":366},[52,13248,13249],{"class":58},"            \u003C\u002F",[52,13251,13138],{"class":62},[52,13253,80],{"class":58},[52,13255,13256,13258,13261],{"class":54,"line":386},[52,13257,13135],{"class":58},[52,13259,13260],{"class":62},"tbody",[52,13262,80],{"class":58},[52,13264,13265,13267,13269,13271,13273,13275,13278,13280,13283,13285,13287,13290,13292,13295,13297,13299,13301,13303],{"class":54,"line":414},[52,13266,13145],{"class":58},[52,13268,13148],{"class":62},[52,13270,256],{"class":65},[52,13272,69],{"class":58},[52,13274,72],{"class":58},[52,13276,13277],{"class":75},"val in list",[52,13279,72],{"class":58},[52,13281,13282],{"class":65}," :key",[52,13284,69],{"class":58},[52,13286,72],{"class":58},[52,13288,13289],{"class":75},"val.id",[52,13291,72],{"class":58},[52,13293,13294],{"class":65}," tabindex",[52,13296,69],{"class":58},[52,13298,72],{"class":58},[52,13300,7992],{"class":75},[52,13302,72],{"class":58},[52,13304,80],{"class":58},[52,13306,13307,13309,13312,13314,13316,13318,13321,13323,13325,13328,13330,13332],{"class":54,"line":426},[52,13308,13155],{"class":58},[52,13310,13311],{"class":62},"td",[52,13313,9233],{"class":65},[52,13315,69],{"class":58},[52,13317,72],{"class":58},[52,13319,13320],{"class":75},"vertical-align:middle;",[52,13322,72],{"class":58},[52,13324,102],{"class":58},[52,13326,13327],{"class":105},"{{val.title}}",[52,13329,108],{"class":58},[52,13331,13311],{"class":62},[52,13333,80],{"class":58},[52,13335,13336,13338,13340,13342,13344,13346,13348,13350,13352,13355,13357,13359],{"class":54,"line":434},[52,13337,13155],{"class":58},[52,13339,13311],{"class":62},[52,13341,9233],{"class":65},[52,13343,69],{"class":58},[52,13345,72],{"class":58},[52,13347,13320],{"class":75},[52,13349,72],{"class":58},[52,13351,102],{"class":58},[52,13353,13354],{"class":105},"{{val.created}}",[52,13356,108],{"class":58},[52,13358,13311],{"class":62},[52,13360,80],{"class":58},[52,13362,13363,13365,13367,13369,13371,13373,13375,13377],{"class":54,"line":445},[52,13364,13155],{"class":58},[52,13366,13311],{"class":62},[52,13368,9233],{"class":65},[52,13370,69],{"class":58},[52,13372,72],{"class":58},[52,13374,13320],{"class":75},[52,13376,72],{"class":58},[52,13378,80],{"class":58},[52,13380,13381,13384,13386,13389,13391,13393,13396,13398,13400,13402,13404,13406,13408,13410,13412,13414,13417,13419,13421,13423,13425,13428,13430,13432,13435,13437,13439],{"class":54,"line":479},[52,13382,13383],{"class":58},"                        \u003C",[52,13385,1445],{"class":62},[52,13387,13388],{"class":65}," :href",[52,13390,69],{"class":58},[52,13392,72],{"class":58},[52,13394,13395],{"class":75},"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id",[52,13397,72],{"class":58},[52,13399,11874],{"class":65},[52,13401,69],{"class":58},[52,13403,72],{"class":58},[52,13405,3510],{"class":75},[52,13407,72],{"class":58},[52,13409,10706],{"class":65},[52,13411,69],{"class":58},[52,13413,72],{"class":58},[52,13415,13416],{"class":75},"btn btn-success btn-sm",[52,13418,72],{"class":58},[52,13420,9233],{"class":65},[52,13422,69],{"class":58},[52,13424,72],{"class":58},[52,13426,13427],{"class":75},"margin-right:10px;",[52,13429,72],{"class":58},[52,13431,102],{"class":58},[52,13433,13434],{"class":105},"編集",[52,13436,108],{"class":58},[52,13438,1445],{"class":62},[52,13440,80],{"class":58},[52,13442,13443,13445,13447,13449,13451,13453,13455,13457,13459,13461,13463,13466,13468,13471,13473,13475,13478,13480,13482,13485,13487,13489],{"class":54,"line":508},[52,13444,13383],{"class":58},[52,13446,3510],{"class":62},[52,13448,11874],{"class":65},[52,13450,69],{"class":58},[52,13452,72],{"class":58},[52,13454,3510],{"class":75},[52,13456,72],{"class":58},[52,13458,10706],{"class":65},[52,13460,69],{"class":58},[52,13462,72],{"class":58},[52,13464,13465],{"class":75},"btn btn-danger btn-sm",[52,13467,72],{"class":58},[52,13469,13470],{"class":65}," v-on:click",[52,13472,69],{"class":58},[52,13474,72],{"class":58},[52,13476,13477],{"class":75},"cofirmDelete(val)",[52,13479,72],{"class":58},[52,13481,102],{"class":58},[52,13483,13484],{"class":105},"削除",[52,13486,108],{"class":58},[52,13488,3510],{"class":62},[52,13490,80],{"class":58},[52,13492,13493,13496,13498],{"class":54,"line":538},[52,13494,13495],{"class":58},"                    \u003C\u002F",[52,13497,13311],{"class":62},[52,13499,80],{"class":58},[52,13501,13502,13504,13506],{"class":54,"line":546},[52,13503,13240],{"class":58},[52,13505,13148],{"class":62},[52,13507,80],{"class":58},[52,13509,13510,13512,13514],{"class":54,"line":552},[52,13511,13249],{"class":58},[52,13513,13260],{"class":62},[52,13515,80],{"class":58},[52,13517,13518,13521,13523],{"class":54,"line":558},[52,13519,13520],{"class":58},"        \u003C\u002F",[52,13522,13117],{"class":62},[52,13524,80],{"class":58},[52,13526,13527],{"class":54,"line":563},[52,13528,340],{"emptyLinePlaceholder":339},[52,13530,13531,13533,13535,13537,13539,13541,13544,13546],{"class":54,"line":568},[52,13532,1912],{"class":58},[52,13534,1905],{"class":62},[52,13536,10706],{"class":65},[52,13538,69],{"class":58},[52,13540,72],{"class":58},[52,13542,13543],{"class":75},"ccm-dashboard-form-actions-wrapper",[52,13545,72],{"class":58},[52,13547,80],{"class":58},[52,13549,13550,13552,13554,13556,13558,13560,13563,13565],{"class":54,"line":1105},[52,13551,13135],{"class":58},[52,13553,1905],{"class":62},[52,13555,10706],{"class":65},[52,13557,69],{"class":58},[52,13559,72],{"class":58},[52,13561,13562],{"class":75},"ccm-dashboard-form-actions",[52,13564,72],{"class":58},[52,13566,80],{"class":58},[52,13568,13569,13571,13573,13575,13577,13579,13582,13584,13586,13588,13590,13593,13595],{"class":54,"line":1134},[52,13570,13145],{"class":58},[52,13572,1445],{"class":62},[52,13574,10384],{"class":65},[52,13576,69],{"class":58},[52,13578,72],{"class":58},[52,13580,13581],{"class":75},"\u002Fdashboard\u002Fvuetest\u002Fadd",[52,13583,72],{"class":58},[52,13585,10706],{"class":65},[52,13587,69],{"class":58},[52,13589,72],{"class":58},[52,13591,13592],{"class":75},"pull-right btn btn-primary",[52,13594,72],{"class":58},[52,13596,80],{"class":58},[52,13598,13599],{"class":54,"line":1163},[52,13600,13601],{"class":105},"                    新規追加\n",[52,13603,13604,13606,13608],{"class":54,"line":1192},[52,13605,13240],{"class":58},[52,13607,1445],{"class":62},[52,13609,80],{"class":58},[52,13611,13612,13614,13616],{"class":54,"line":1199},[52,13613,13249],{"class":58},[52,13615,1905],{"class":62},[52,13617,80],{"class":58},[52,13619,13620,13622,13624],{"class":54,"line":1204},[52,13621,13520],{"class":58},[52,13623,1905],{"class":62},[52,13625,80],{"class":58},[52,13627,13628,13630,13632],{"class":54,"line":1209},[52,13629,1946],{"class":58},[52,13631,1905],{"class":62},[52,13633,80],{"class":58},[52,13635,13636,13638,13640],{"class":54,"line":1214},[52,13637,108],{"class":58},[52,13639,213],{"class":62},[52,13641,80],{"class":58},[52,13643,13644],{"class":54,"line":1219},[52,13645,340],{"emptyLinePlaceholder":339},[52,13647,13648,13650,13652],{"class":54,"line":2302},[52,13649,59],{"class":58},[52,13651,348],{"class":62},[52,13653,80],{"class":58},[52,13655,13656,13658,13660],{"class":54,"line":2308},[52,13657,356],{"class":359},[52,13659,360],{"class":359},[52,13661,2012],{"class":58},[52,13663,13664,13666,13668,13670,13673,13675],{"class":54,"line":2317},[52,13665,2017],{"class":62},[52,13667,372],{"class":58},[52,13669,375],{"class":58},[52,13671,13672],{"class":75},"index",[52,13674,375],{"class":58},[52,13676,383],{"class":58},[52,13678,13679,13681],{"class":54,"line":2323},[52,13680,2033],{"class":62},[52,13682,2036],{"class":58},[52,13684,13685,13687],{"class":54,"line":2328},[52,13686,2041],{"class":359},[52,13688,2012],{"class":58},[52,13690,13691,13694,13696,13698],{"class":54,"line":2333},[52,13692,13693],{"class":62},"            list",[52,13695,372],{"class":58},[52,13697,2053],{"class":62},[52,13699,383],{"class":58},[52,13701,13702,13705,13707],{"class":54,"line":2338},[52,13703,13704],{"class":62},"            isProcessing",[52,13706,372],{"class":58},[52,13708,13709],{"class":2160},"false\n",[52,13711,13712],{"class":54,"line":3141},[52,13713,2060],{"class":58},[52,13715,13716],{"class":54,"line":3158},[52,13717,2065],{"class":58},[52,13719,13720,13722],{"class":54,"line":3169},[52,13721,2070],{"class":62},[52,13723,923],{"class":58},[52,13725,13726,13729,13731,13733],{"class":54,"line":3188},[52,13727,13728],{"class":62},"        cofirmDelete",[52,13730,931],{"class":58},[52,13732,8401],{"class":985},[52,13734,2085],{"class":58},[52,13736,13737,13739,13742,13744,13747,13749,13752,13754,13756,13759,13761,13763,13765,13767,13769,13771,13773,13776,13778,13780],{"class":54,"line":3199},[52,13738,2129],{"class":65},[52,13740,13741],{"class":105}," result",[52,13743,950],{"class":58},[52,13745,13746],{"class":105}," window",[52,13748,956],{"class":58},[52,13750,13751],{"class":417},"confirm",[52,13753,931],{"class":62},[52,13755,375],{"class":58},[52,13757,13758],{"class":75},"アルバム：「",[52,13760,375],{"class":58},[52,13762,12644],{"class":58},[52,13764,8401],{"class":105},[52,13766,956],{"class":58},[52,13768,7525],{"class":105},[52,13770,12644],{"class":58},[52,13772,375],{"class":58},[52,13774,13775],{"class":75},"」を本当に削除しますか？この操作は取り消せません。",[52,13777,375],{"class":58},[52,13779,937],{"class":62},[52,13781,1006],{"class":58},[52,13783,13784,13787,13789,13792,13794,13796,13798,13801,13803,13805,13807,13809,13811],{"class":54,"line":3214},[52,13785,13786],{"class":359},"            if",[52,13788,931],{"class":62},[52,13790,13791],{"class":105},"result",[52,13793,4600],{"class":62},[52,13795,2403],{"class":359},[52,13797,2285],{"class":58},[52,13799,13800],{"class":417},"deleteAlubm",[52,13802,931],{"class":62},[52,13804,8401],{"class":105},[52,13806,956],{"class":58},[52,13808,7516],{"class":105},[52,13810,937],{"class":62},[52,13812,1006],{"class":58},[52,13814,13815],{"class":54,"line":3221},[52,13816,2106],{"class":58},[52,13818,13819,13822,13824,13826],{"class":54,"line":3230},[52,13820,13821],{"class":62},"        deleteAlubm",[52,13823,931],{"class":58},[52,13825,7516],{"class":985},[52,13827,2085],{"class":58},[52,13829,13830,13832,13834,13836,13839,13842,13844,13846],{"class":54,"line":3241},[52,13831,13786],{"class":359},[52,13833,931],{"class":62},[52,13835,1370],{"class":58},[52,13837,13838],{"class":105},"isProcessing",[52,13840,13841],{"class":58},"==",[52,13843,1326],{"class":2160},[52,13845,937],{"class":62},[52,13847,363],{"class":58},[52,13849,13850,13853,13855,13857,13859],{"class":54,"line":3256},[52,13851,13852],{"class":58},"                this.",[52,13854,13838],{"class":105},[52,13856,950],{"class":58},[52,13858,2264],{"class":2160},[52,13860,1006],{"class":58},[52,13862,13863],{"class":54,"line":3267},[52,13864,340],{"emptyLinePlaceholder":339},[52,13866,13867,13870,13872,13875,13877],{"class":54,"line":3290},[52,13868,13869],{"class":105},"                $",[52,13871,956],{"class":58},[52,13873,13874],{"class":417},"ajax",[52,13876,931],{"class":62},[52,13878,363],{"class":58},[52,13880,13881,13884,13886,13888,13891,13893],{"class":54,"line":3295},[52,13882,13883],{"class":62},"                    url",[52,13885,372],{"class":58},[52,13887,375],{"class":58},[52,13889,13890],{"class":75},"\u002Fdashboard\u002Fvuetest\u002FdeleteData\u002F",[52,13892,375],{"class":58},[52,13894,383],{"class":58},[52,13896,13897,13900,13902,13904,13906,13908],{"class":54,"line":3300},[52,13898,13899],{"class":62},"                    type",[52,13901,372],{"class":58},[52,13903,375],{"class":58},[52,13905,2250],{"class":75},[52,13907,375],{"class":58},[52,13909,383],{"class":58},[52,13911,13912,13915,13917,13919,13921,13923],{"class":54,"line":3307},[52,13913,13914],{"class":62},"                    data",[52,13916,8527],{"class":58},[52,13918,968],{"class":62},[52,13920,372],{"class":58},[52,13922,7516],{"class":105},[52,13924,476],{"class":58},[52,13926,13927,13930,13932,13934,13936],{"class":54,"line":3312},[52,13928,13929],{"class":417},"                    success",[52,13931,372],{"class":58},[52,13933,3068],{"class":58},[52,13935,989],{"class":65},[52,13937,2012],{"class":58},[52,13939,13940,13943,13946,13948,13950,13953,13955,13958,13960,13962,13964,13966,13968],{"class":54,"line":3317},[52,13941,13942],{"class":65},"                        let",[52,13944,13945],{"class":105}," targetIndex",[52,13947,950],{"class":58},[52,13949,2285],{"class":58},[52,13951,13952],{"class":105},"list",[52,13954,956],{"class":58},[52,13956,13957],{"class":417},"findIndex",[52,13959,931],{"class":62},[52,13961,931],{"class":58},[52,13963,986],{"class":985},[52,13965,937],{"class":58},[52,13967,989],{"class":65},[52,13969,363],{"class":58},[52,13971,13972,13975,13977,13979,13982,13985,13987],{"class":54,"line":3322},[52,13973,13974],{"class":359},"                            return",[52,13976,999],{"class":105},[52,13978,956],{"class":58},[52,13980,13981],{"class":105},"ID",[52,13983,13984],{"class":58}," ==",[52,13986,10514],{"class":105},[52,13988,1006],{"class":58},[52,13990,13991,13994,13996],{"class":54,"line":3327},[52,13992,13993],{"class":58},"                        }",[52,13995,937],{"class":62},[52,13997,1006],{"class":58},[52,13999,14000,14003,14005,14007,14010,14012,14015,14017,14019,14021],{"class":54,"line":3332},[52,14001,14002],{"class":58},"                        this.",[52,14004,13952],{"class":105},[52,14006,956],{"class":58},[52,14008,14009],{"class":417},"splice",[52,14011,931],{"class":62},[52,14013,14014],{"class":105},"targetIndex",[52,14016,407],{"class":58},[52,14018,31],{"class":4596},[52,14020,937],{"class":62},[52,14022,1006],{"class":58},[52,14024,14026,14028,14030,14032,14034],{"class":54,"line":14025},63,[52,14027,14002],{"class":58},[52,14029,13838],{"class":105},[52,14031,950],{"class":58},[52,14033,12076],{"class":2160},[52,14035,1006],{"class":58},[52,14037,14039],{"class":54,"line":14038},64,[52,14040,2299],{"class":58},[52,14042,14044,14047,14049,14051,14054,14056,14059,14061,14064,14066,14068],{"class":54,"line":14043},65,[52,14045,14046],{"class":417},"                    error",[52,14048,372],{"class":58},[52,14050,2980],{"class":58},[52,14052,14053],{"class":985},"xhr",[52,14055,407],{"class":58},[52,14057,14058],{"class":985}," textStatus",[52,14060,407],{"class":58},[52,14062,14063],{"class":985}," errorThrown",[52,14065,937],{"class":58},[52,14067,989],{"class":65},[52,14069,363],{"class":58},[52,14071,14073,14076,14078,14080,14082,14084,14087,14089,14091,14093,14095,14097,14099,14101,14103,14105],{"class":54,"line":14072},66,[52,14074,14075],{"class":105},"                        console",[52,14077,956],{"class":58},[52,14079,7694],{"class":417},[52,14081,931],{"class":62},[52,14083,375],{"class":58},[52,14085,14086],{"class":75},"Error! ",[52,14088,375],{"class":58},[52,14090,4584],{"class":58},[52,14092,14058],{"class":105},[52,14094,4584],{"class":58},[52,14096,1979],{"class":58},[52,14098,1979],{"class":58},[52,14100,4584],{"class":58},[52,14102,14063],{"class":105},[52,14104,937],{"class":62},[52,14106,1006],{"class":58},[52,14108,14110],{"class":54,"line":14109},67,[52,14111,14112],{"class":58},"                    }\n",[52,14114,14116,14119],{"class":54,"line":14115},68,[52,14117,14118],{"class":58},"                }",[52,14120,1014],{"class":62},[52,14122,14124],{"class":54,"line":14123},69,[52,14125,2320],{"class":58},[52,14127,14129],{"class":54,"line":14128},70,[52,14130,2106],{"class":58},[52,14132,14134],{"class":54,"line":14133},71,[52,14135,2065],{"class":58},[52,14137,14139,14142],{"class":54,"line":14138},72,[52,14140,14141],{"class":62},"    created",[52,14143,2036],{"class":58},[52,14145,14147,14150,14152,14154,14156],{"class":54,"line":14146},73,[52,14148,14149],{"class":105},"        $",[52,14151,956],{"class":58},[52,14153,13874],{"class":417},[52,14155,931],{"class":62},[52,14157,363],{"class":58},[52,14159,14161,14163,14165,14167,14169,14171],{"class":54,"line":14160},74,[52,14162,2533],{"class":62},[52,14164,372],{"class":58},[52,14166,375],{"class":58},[52,14168,11815],{"class":75},[52,14170,375],{"class":58},[52,14172,383],{"class":58},[52,14174,14176,14179,14181,14183,14186,14188],{"class":54,"line":14175},75,[52,14177,14178],{"class":62},"            type",[52,14180,372],{"class":58},[52,14182,375],{"class":58},[52,14184,14185],{"class":75},"GET",[52,14187,375],{"class":58},[52,14189,383],{"class":58},[52,14191,14193,14196,14198,14200,14202,14204,14206],{"class":54,"line":14192},76,[52,14194,14195],{"class":417},"            success",[52,14197,372],{"class":58},[52,14199,2980],{"class":58},[52,14201,3038],{"class":985},[52,14203,937],{"class":58},[52,14205,989],{"class":65},[52,14207,2012],{"class":58},[52,14209,14211,14213,14215,14217,14219,14221,14224,14226,14228,14230,14232],{"class":54,"line":14210},77,[52,14212,13852],{"class":58},[52,14214,13952],{"class":105},[52,14216,950],{"class":58},[52,14218,8207],{"class":105},[52,14220,956],{"class":58},[52,14222,14223],{"class":417},"parse",[52,14225,931],{"class":62},[52,14227,3038],{"class":105},[52,14229,937],{"class":62},[52,14231,2764],{"class":58},[52,14233,14234],{"class":410}," \u002F\u002F returns array\n",[52,14236,14238],{"class":54,"line":14237},78,[52,14239,4972],{"class":58},[52,14241,14243,14246,14248,14250,14252,14254,14256,14258,14260,14262,14264],{"class":54,"line":14242},79,[52,14244,14245],{"class":417},"            error",[52,14247,372],{"class":58},[52,14249,2980],{"class":58},[52,14251,14053],{"class":985},[52,14253,407],{"class":58},[52,14255,14058],{"class":985},[52,14257,407],{"class":58},[52,14259,14063],{"class":985},[52,14261,937],{"class":58},[52,14263,989],{"class":65},[52,14265,363],{"class":58},[52,14267,14269,14272,14274,14276,14278,14280,14282,14284,14286,14288,14290,14292,14294,14296,14298,14300],{"class":54,"line":14268},80,[52,14270,14271],{"class":105},"                console",[52,14273,956],{"class":58},[52,14275,2095],{"class":417},[52,14277,931],{"class":62},[52,14279,375],{"class":58},[52,14281,14086],{"class":75},[52,14283,375],{"class":58},[52,14285,4584],{"class":58},[52,14287,14058],{"class":105},[52,14289,4584],{"class":58},[52,14291,1979],{"class":58},[52,14293,1979],{"class":58},[52,14295,4584],{"class":58},[52,14297,14063],{"class":105},[52,14299,937],{"class":62},[52,14301,1006],{"class":58},[52,14303,14305],{"class":54,"line":14304},81,[52,14306,2320],{"class":58},[52,14308,14310,14313],{"class":54,"line":14309},82,[52,14311,14312],{"class":58},"        }",[52,14314,1014],{"class":62},[52,14316,14318],{"class":54,"line":14317},83,[52,14319,3753],{"class":58},[52,14321,14323],{"class":54,"line":14322},84,[52,14324,535],{"class":58},[52,14326,14328,14330,14332],{"class":54,"line":14327},85,[52,14329,108],{"class":58},[52,14331,348],{"class":62},[52,14333,80],{"class":58},[13,14335,14336],{},"レンダリングされる際は以下のような処理で一覧画面が表示されます。",[1696,14338,14339,14342,14345],{},[1699,14340,14341],{},"createdでDB上の情報を取ってくるAjaxをエンドポイントに飛ばす。",[1699,14343,14344],{},"取得したデータをdata()のlistに挿入。",[1699,14346,14347],{},"v-forでlist分 の行を表示する。",[13,14349,14350],{},"これをレンダーすると以下のようになります。",[728,14352],{":src":14353,":width":731},"'_mix\u002Fsch-2020-10-04-14.40.28-768x285.png'",[13,14355,14356],{},"右側の「操作」で、「編集」でそのアルバムデータの編集画面へ移動、「削除」ではそのデータを削除するAjaxを飛ばします。また、「新規追加」では新規追加画面へ移動します。この画面があれば一通りのデータ操作がブラウザ画面からできるようになります。",[1721,14358,14360],{"id":14359},"ロード用削除用エンドポイントを作成","ロード用・削除用エンドポイントを作成",[13,14362,14363,14365],{},[49,14364,11723],{}," コントローラーでは一覧データ・対象のIDを削除するAjaxエンドポイントを作成します。",[42,14367,14369],{"className":6114,"code":14368,"filename":11728,"language":6117,"meta":47,"style":47},"public function view() {\n    $this->render('\u002Fdashboard\u002Fvuetest\u002Fview');\n}\n\n\u002F\u002F ロード用のエンドポイント\npublic function loadData() {\n    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $result = $db->fetchAll('SELECT * FROM album ORDER BY ID DESC');\n        $db->Execute(\"COMMIT\");\n        return Core::make('helper\u002Fajax')->sendResult($result);\n    }else{\n        $this->replace('\u002Fpage_not_found');\n    }\n}\n\n\u002F\u002F 削除エンドポイント\npublic function deleteData(){\n    $targetID=$this->post('target');\n    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && !is_null($targetID)){\n        $db = Database::connection();\n        $db->Execute(\"START TRANSACTION\");\n        $db->executeQuery('DELETE FROM album WHERE `ID`=?',array($targetID));\n        $db->Execute(\"COMMIT\");\n    }else{\n        $this->replace('\u002Fpage_not_found');\n    }\n}\n",[49,14370,14371,14376,14381,14385,14389,14394,14399,14404,14408,14412,14416,14420,14424,14428,14433,14437,14441,14445,14450,14455,14460,14465,14469,14473,14478,14482,14486,14490,14494],{"__ignoreMap":47},[52,14372,14373],{"class":54,"line":55},[52,14374,14375],{},"public function view() {\n",[52,14377,14378],{"class":54,"line":83},[52,14379,14380],{},"    $this->render('\u002Fdashboard\u002Fvuetest\u002Fview');\n",[52,14382,14383],{"class":54,"line":115},[52,14384,535],{},[52,14386,14387],{"class":54,"line":142},[52,14388,340],{"emptyLinePlaceholder":339},[52,14390,14391],{"class":54,"line":169},[52,14392,14393],{},"\u002F\u002F ロード用のエンドポイント\n",[52,14395,14396],{"class":54,"line":302},[52,14397,14398],{},"public function loadData() {\n",[52,14400,14401],{"class":54,"line":308},[52,14402,14403],{},"    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){\n",[52,14405,14406],{"class":54,"line":318},[52,14407,11754],{},[52,14409,14410],{"class":54,"line":328},[52,14411,11759],{},[52,14413,14414],{"class":54,"line":4},[52,14415,12901],{},[52,14417,14418],{"class":54,"line":343},[52,14419,11769],{},[52,14421,14422],{"class":54,"line":353},[52,14423,11774],{},[52,14425,14426],{"class":54,"line":366},[52,14427,13003],{},[52,14429,14430],{"class":54,"line":386},[52,14431,14432],{},"        $this->replace('\u002Fpage_not_found');\n",[52,14434,14435],{"class":54,"line":414},[52,14436,3753],{},[52,14438,14439],{"class":54,"line":426},[52,14440,535],{},[52,14442,14443],{"class":54,"line":434},[52,14444,340],{"emptyLinePlaceholder":339},[52,14446,14447],{"class":54,"line":445},[52,14448,14449],{},"\u002F\u002F 削除エンドポイント\n",[52,14451,14452],{"class":54,"line":479},[52,14453,14454],{},"public function deleteData(){\n",[52,14456,14457],{"class":54,"line":508},[52,14458,14459],{},"    $targetID=$this->post('target');\n",[52,14461,14462],{"class":54,"line":538},[52,14463,14464],{},"    if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && !is_null($targetID)){\n",[52,14466,14467],{"class":54,"line":546},[52,14468,11754],{},[52,14470,14471],{"class":54,"line":552},[52,14472,11759],{},[52,14474,14475],{"class":54,"line":558},[52,14476,14477],{},"        $db->executeQuery('DELETE FROM album WHERE `ID`=?',array($targetID));\n",[52,14479,14480],{"class":54,"line":563},[52,14481,11769],{},[52,14483,14484],{"class":54,"line":568},[52,14485,13003],{},[52,14487,14488],{"class":54,"line":1105},[52,14489,14432],{},[52,14491,14492],{"class":54,"line":1134},[52,14493,3753],{},[52,14495,14496],{"class":54,"line":1163},[52,14497,535],{},[1721,14499,14501],{"id":14500},"エントリーポイント-を作成","エントリーポイント を作成",[13,14503,14504],{},"上記のコンポーネントをレンダリングするために編集・追加の時のように、一覧用ページにレンダーできるように設定をします。",[13,14506,14507,14510],{},[49,14508,14509],{},"packages\u002Fvuetest\u002Fsingle_pages\u002Fdashboard\u002Fvuetest\u002Fview.php"," に以下のようにエントリーポイントを記述します。",[42,14512,14515],{"className":6114,"code":14513,"filename":14514,"language":6117,"meta":47,"style":47},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"index\">\u003C\u002Fdiv>\n","view.php",[49,14516,14517,14521,14525,14529,14533],{"__ignoreMap":47},[52,14518,14519],{"class":54,"line":55},[52,14520,12309],{},[52,14522,14523],{"class":54,"line":83},[52,14524,12314],{},[52,14526,14527],{"class":54,"line":115},[52,14528,12319],{},[52,14530,14531],{"class":54,"line":142},[52,14532,340],{"emptyLinePlaceholder":339},[52,14534,14535],{"class":54,"line":169},[52,14536,14537],{},"\u003Cdiv id=\"index\">\u003C\u002Fdiv>\n",[13,14539,14540],{},"そしてmain.jsでは",[42,14542,14544],{"className":1249,"code":14543,"filename":1769,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport Index from '.\u002Findex.vue'\nimport Add from '.\u002Fadd.vue'\nimport Edit from '.\u002Fedit.vue'\n\n\nVue.config.productionTip = false\n\nfunction renderIfidExits(id,vueRoot){\n  if(document.getElementById(id) !== null){\n    return new Vue({\n      render: h => h(vueRoot),\n    }).$mount('#'+id)\n  }\n}\n\nrenderIfidExits('index',Index);\nrenderIfidExits('add',Add);\nrenderIfidExits('edit',Edit);\n",[49,14545,14546,14560,14576,14590,14604,14608,14612,14628,14632,14648,14674,14686,14706,14730,14734,14738,14742,14761,14779],{"__ignoreMap":47},[52,14547,14548,14550,14552,14554,14556,14558],{"class":54,"line":55},[52,14549,1847],{"class":359},[52,14551,6824],{"class":105},[52,14553,1976],{"class":359},[52,14555,1979],{"class":58},[52,14557,204],{"class":75},[52,14559,5629],{"class":58},[52,14561,14562,14564,14567,14569,14571,14574],{"class":54,"line":83},[52,14563,1847],{"class":359},[52,14565,14566],{"class":105}," Index ",[52,14568,1976],{"class":359},[52,14570,1979],{"class":58},[52,14572,14573],{"class":75},".\u002Findex.vue",[52,14575,5629],{"class":58},[52,14577,14578,14580,14582,14584,14586,14588],{"class":54,"line":115},[52,14579,1847],{"class":359},[52,14581,12484],{"class":105},[52,14583,1976],{"class":359},[52,14585,1979],{"class":58},[52,14587,12491],{"class":75},[52,14589,5629],{"class":58},[52,14591,14592,14594,14596,14598,14600,14602],{"class":54,"line":142},[52,14593,1847],{"class":359},[52,14595,12500],{"class":105},[52,14597,1976],{"class":359},[52,14599,1979],{"class":58},[52,14601,12507],{"class":75},[52,14603,5629],{"class":58},[52,14605,14606],{"class":54,"line":169},[52,14607,340],{"emptyLinePlaceholder":339},[52,14609,14610],{"class":54,"line":302},[52,14611,340],{"emptyLinePlaceholder":339},[52,14613,14614,14616,14618,14620,14622,14624,14626],{"class":54,"line":308},[52,14615,2829],{"class":105},[52,14617,956],{"class":58},[52,14619,12526],{"class":105},[52,14621,956],{"class":58},[52,14623,12531],{"class":105},[52,14625,69],{"class":58},[52,14627,12536],{"class":2160},[52,14629,14630],{"class":54,"line":318},[52,14631,340],{"emptyLinePlaceholder":339},[52,14633,14634,14636,14638,14640,14642,14644,14646],{"class":54,"line":328},[52,14635,12545],{"class":65},[52,14637,12548],{"class":417},[52,14639,931],{"class":58},[52,14641,7516],{"class":985},[52,14643,407],{"class":58},[52,14645,12557],{"class":985},[52,14647,2085],{"class":58},[52,14649,14650,14652,14654,14656,14658,14660,14662,14664,14666,14668,14670,14672],{"class":54,"line":4},[52,14651,12564],{"class":359},[52,14653,931],{"class":62},[52,14655,10855],{"class":105},[52,14657,956],{"class":58},[52,14659,10860],{"class":417},[52,14661,931],{"class":62},[52,14663,7516],{"class":105},[52,14665,4600],{"class":62},[52,14667,12581],{"class":58},[52,14669,12584],{"class":58},[52,14671,937],{"class":62},[52,14673,363],{"class":58},[52,14675,14676,14678,14680,14682,14684],{"class":54,"line":343},[52,14677,3828],{"class":359},[52,14679,6900],{"class":58},[52,14681,7020],{"class":417},[52,14683,931],{"class":62},[52,14685,363],{"class":58},[52,14687,14688,14690,14692,14694,14696,14698,14700,14702,14704],{"class":54,"line":353},[52,14689,12605],{"class":417},[52,14691,372],{"class":58},[52,14693,12610],{"class":985},[52,14695,2282],{"class":65},[52,14697,12610],{"class":417},[52,14699,931],{"class":62},[52,14701,12557],{"class":105},[52,14703,937],{"class":62},[52,14705,383],{"class":58},[52,14707,14708,14710,14712,14714,14716,14718,14720,14722,14724,14726,14728],{"class":54,"line":366},[52,14709,5094],{"class":58},[52,14711,937],{"class":62},[52,14713,956],{"class":58},[52,14715,7049],{"class":417},[52,14717,931],{"class":62},[52,14719,375],{"class":58},[52,14721,12639],{"class":75},[52,14723,375],{"class":58},[52,14725,12644],{"class":58},[52,14727,7516],{"class":105},[52,14729,1014],{"class":62},[52,14731,14732],{"class":54,"line":386},[52,14733,1075],{"class":58},[52,14735,14736],{"class":54,"line":414},[52,14737,535],{"class":58},[52,14739,14740],{"class":54,"line":426},[52,14741,340],{"emptyLinePlaceholder":339},[52,14743,14744,14746,14748,14750,14752,14754,14756,14759],{"class":54,"line":434},[52,14745,12665],{"class":417},[52,14747,931],{"class":105},[52,14749,375],{"class":58},[52,14751,13672],{"class":75},[52,14753,375],{"class":58},[52,14755,407],{"class":58},[52,14757,14758],{"class":105},"Index)",[52,14760,1006],{"class":58},[52,14762,14763,14765,14767,14769,14771,14773,14775,14777],{"class":54,"line":445},[52,14764,12665],{"class":417},[52,14766,931],{"class":105},[52,14768,375],{"class":58},[52,14770,12426],{"class":75},[52,14772,375],{"class":58},[52,14774,407],{"class":58},[52,14776,12678],{"class":105},[52,14778,1006],{"class":58},[52,14780,14781,14783,14785,14787,14789,14791,14793,14795],{"class":54,"line":479},[52,14782,12665],{"class":417},[52,14784,931],{"class":105},[52,14786,375],{"class":58},[52,14788,12691],{"class":75},[52,14790,375],{"class":58},[52,14792,407],{"class":58},[52,14794,12698],{"class":105},[52,14796,1006],{"class":58},[13,14798,14799,14802],{},[49,14800,14801],{},"id='index'","があれば一覧のコンポーネントが出力されるようにしました。",[17,14804,14805],{"id":14805},"実際に操作してみる",[1721,14807,14808],{"id":14808},"新しくデータを入れてみる",[728,14810],{":src":14811,":width":731},"'_mix\u002Fsch-2020-10-04-14.40.28-768x285-2.png'",[13,14813,14814],{},"右下の「新規追加」は \u002Fdashboard\u002Fvuetest\u002Fadd へリンクしています。そのためクリックすると追加画面が現れて、追加ができます。新規に「テスト２」としておきましょう。",[728,14816],{":src":14817,":width":731},"'_mix\u002Fsch-2020-10-04-15.11.23-768x216.png'",[13,14819,14820],{},"それで「登録」を押すとデータ挿入処理と共に一覧へリダイレクトされます。すると、",[728,14822],{":src":14823,":width":731},"'_mix\u002Fsch-2020-10-04-15.12.17-768x313.png'",[13,14825,14826],{},"きちんと一覧に反映されました。",[17,14828,14829],{"id":14829},"削除してみる",[13,14831,14832],{},"では削除を押すと、確認ダイアログがでてOKであれば削除APIが走って実行されます。",[728,14834],{":src":14835,":width":10193,":center":1322},"'_mix\u002Fsch-2020-10-04-15.13.59-768x251.png'",[728,14837],{":src":14838,":width":731},"'_mix\u002Fsch-2020-10-04-15.22.02.png'",[13,14840,14841],{},"「変更テスト（id 1）」がDB上から削除されまた、一覧からも消えました。",[1721,14843,14844],{"id":14844},"編集してみる",[13,14846,14847],{},"緑色の「編集」は編集画面のURLへリンクしています。vueでは以下のようにv-for内で動的に作成できるようにしています。",[42,14849,14851],{"className":202,"code":14850,"language":204,"meta":13051,"style":47},"\u003Ctr v-for=\"val in list\" :key=\"val.id\" tabindex=\"0\">\n...\n    \u003Ctd style=\"vertical-align:middle;\">\n        ...\n        \u003Ca target=\"_blank\" :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\">編集\u003C\u002Fa>\n        ...\n    \u003C\u002Ftd>\n...\n\u003C\u002Ftr>\n",[49,14852,14853,14906,14910,14915,14919,14924,14928,14933,14937],{"__ignoreMap":47},[52,14854,14855,14857,14859,14861,14863,14865,14868,14871,14874,14876,14878,14881,14883,14885,14888,14890,14892,14894,14896,14898,14900,14902,14904],{"class":54,"line":55},[52,14856,59],{"class":58},[52,14858,13148],{"class":62},[52,14860,256],{"class":359},[52,14862,69],{"class":58},[52,14864,72],{"class":58},[52,14866,14867],{"class":105},"val ",[52,14869,14870],{"class":58},"in",[52,14872,14873],{"class":105}," list",[52,14875,72],{"class":58},[52,14877,4691],{"class":58},[52,14879,14880],{"class":65},"key",[52,14882,69],{"class":58},[52,14884,72],{"class":58},[52,14886,14887],{"class":105},"val",[52,14889,956],{"class":58},[52,14891,7516],{"class":105},[52,14893,72],{"class":58},[52,14895,13294],{"class":65},[52,14897,69],{"class":58},[52,14899,72],{"class":58},[52,14901,7992],{"class":75},[52,14903,72],{"class":58},[52,14905,80],{"class":58},[52,14907,14908],{"class":54,"line":83},[52,14909,11397],{"class":105},[52,14911,14912],{"class":54,"line":115},[52,14913,14914],{"class":105},"    \u003Ctd style=\"vertical-align:middle;\">\n",[52,14916,14917],{"class":54,"line":142},[52,14918,7748],{"class":105},[52,14920,14921],{"class":54,"line":169},[52,14922,14923],{"class":105},"        \u003Ca target=\"_blank\" :href=\"'\u002Fdashboard\u002Fvuetest\u002Fedit\u002F'+val.id\">編集\u003C\u002Fa>\n",[52,14925,14926],{"class":54,"line":302},[52,14927,7748],{"class":105},[52,14929,14930],{"class":54,"line":308},[52,14931,14932],{"class":105},"    \u003C\u002Ftd>\n",[52,14934,14935],{"class":54,"line":318},[52,14936,11397],{"class":105},[52,14938,14939,14941,14943],{"class":54,"line":328},[52,14940,108],{"class":58},[52,14942,13148],{"class":62},[52,14944,80],{"class":58},[13,14946,14947],{},"実際にリンクしてみると、選択したデータの編集画面が表示されました。",[728,14949],{":src":14950,":width":10193,":center":1322},"'_mix\u002Fsch-2020-10-04-15.29.21-768x342.png'",[17,14952,7439],{"id":7438},[13,14954,14955],{},"今回の記事では編集画面と一覧画面が完成しました。これで「作成」「読み取り」「更新」「削除」の実装ができました。次の記事では「タイトル」だけでなく「画像データ」「リッチテキスト」といったデータを使えるようにします。",[1413,14957,14958],{},"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 pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":47,"searchDepth":115,"depth":115,"links":14960},[14961,14966,14967,14970,14975,14978,14981],{"id":11693,"depth":83,"text":11694,"children":14962},[14963,14964,14965],{"id":11707,"depth":115,"text":11708},{"id":12192,"depth":115,"text":12193},{"id":12295,"depth":115,"text":12295},{"id":12727,"depth":83,"text":12727},{"id":12846,"depth":83,"text":12846,"children":14968},[14969],{"id":13026,"depth":115,"text":13026},{"id":13038,"depth":83,"text":13038,"children":14971},[14972,14973,14974],{"id":13044,"depth":115,"text":13044},{"id":14359,"depth":115,"text":14360},{"id":14500,"depth":115,"text":14501},{"id":14805,"depth":83,"text":14805,"children":14976},[14977],{"id":14808,"depth":115,"text":14808},{"id":14829,"depth":83,"text":14829,"children":14979},[14980],{"id":14844,"depth":115,"text":14844},{"id":7438,"depth":83,"text":7439},[1423],"2020-10-04","oncrete5にVueCLIを使ってUIを構築する。編集画面と一覧画面。",{},"\u002Fseries\u002Fconcrete5vue-3",{"title":11677,"description":14984},"concrete5vue","Concrete5にVueCLIを使ってUIを構築する。","series\u002Fconcrete5vue-3",[14992,1433,204],"concrete5","_mix\u002Fvuewithconcrete.png","b60sq7M9Lg8p5F-WfOF_VM7wNdrKWtYXHxXbLU-P1O4",{"id":14996,"title":14997,"body":14998,"category":17450,"createdAt":17451,"description":17452,"extension":1426,"index":83,"meta":17453,"navigation":339,"path":11685,"publish":339,"seo":17454,"series":14988,"seriesTitle":14989,"stem":17455,"tag":17456,"thumbnail":14993,"updatedAt":1427,"__hash__":17457},"series\u002Fseries\u002Fconcrete5vue-2.md","Concrete5にVueCLIを使ってUIを構築する。2【コンポーネント作成・データ登録編】",{"type":10,"value":14999,"toc":17429},[15000,15006,15009,15012,15015,15018,15032,15036,15039,15042,15046,15049,15260,15263,15267,15271,15274,15279,15285,15366,15369,15392,15399,15402,15424,15431,15433,15436,15442,15445,15448,15706,15709,15821,15830,15937,15943,15946,15958,15961,15964,15967,15971,15984,16394,16397,16400,17018,17033,17054,17057,17060,17065,17069,17075,17081,17091,17097,17103,17106,17109,17314,17327,17345,17349,17352,17371,17379,17382,17385,17388,17394,17397,17400,17403,17406,17409,17412,17423,17426],[13,15001,11682,15002,15005],{},[1445,15003,15004],{"href":11685},"Concrete5にVueCLIを使ってUIを構築する。1【環境構築編】","の記事の続きを書いていきます。",[13,15007,15008],{},"今回の記事では",[13,15010,15011],{},"どんなフォームを作成するのか。\nテキストインプットを用いたフォームの簡易実装\nデータの保存のバックエンド実装\nを行いたいと思います。ファイルマネージャー、リッチテキストエディタをvueでレンダリングする方法は追加・編集・一覧化が終わった後に書きたいと思います。まずは簡単なフォーム（テキスト）とデータの保存をvueとともに実装していきましょう。",[17,15013,15014],{"id":15014},"最終的に作成するフォーム",[13,15016,15017],{},"「アルバム管理」たるものを作成しようと思います。インスタグラム的な物で、機能は以下の通りです。",[1854,15019,15020,15023,15026,15029],{},[1699,15021,15022],{},"1つのアルバムに複数枚の画像を自由に登録できる。数は基本的に無制限、最低１枚",[1699,15024,15025],{},"画像と一緒にその画像に関する情報をリッチテキストエディタで編集できる。",[1699,15027,15028],{},"画像は順番の並び替え、追加、削除が可能。",[1699,15030,15031],{},"ページ内ではブロックを通じてアルバムの写真を出力できる。",[1721,15033,15035],{"id":15034},"ワイヤーフレーム超簡素","ワイヤーフレーム（超簡素）",[728,15037],{":src":15038,":width":731},"'_mix\u002Fvueconcrete2-1.jpeg'",[728,15040],{":src":15041,":width":731},"'_mix\u002Fslide-2.jpeg'",[17,15043,15045],{"id":15044},"db構造","DB構造",[13,15047,15048],{},"db.xmlを用いて以下のようなテーブルを作成しておきます。",[42,15050,15055],{"className":15051,"code":15052,"filename":15053,"language":15054,"meta":47,"style":47},"language-xml shiki shiki-themes material-theme-ocean","\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003Cschema\n  xmlns=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5\"\n  xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n  xsi:schemaLocation=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5 http:\u002F\u002Fconcrete5.github.io\u002Fdoctrine-xml\u002Fdoctrine-xml-0.5.xsd\">\n\n\u003Ctable name=\"album\">\n    \u003Cfield name=\"id\" type=\"integer\">\n        \u003Cautoincrement\u002F>\n        \u003Ckey\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"title\" type=\"string\" size=\"255\"\u002F>\n    \u003Cfield name=\"created\" type=\"datetime\">\n      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"modified\" type=\"timestamp\">\n      \u003Cdeftimestamp\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n\u003C\u002Ftable>\n\n\u003Ctable name=\"albumPics\">\n    \u003Cfield name=\"id\" type=\"integer\">\n        \u003Cautoincrement\u002F>\n        \u003Ckey\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"albumID\" type=\"integer\">\n        \u003Cunsigned\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"fID\" type=\"integer\">\n        \u003Cunsigned\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"html\" type=\"text\" size=\"65535\"\u002F>\n    \u003Cfield name=\"created\" type=\"datetime\">\n      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n    \u003Cfield name=\"modified\" type=\"timestamp\">\n      \u003Cdeftimestamp\u002F>\n      \u003Cnotnull\u002F>\n    \u003C\u002Ffield>\n\u003C\u002Ftable>\n\n\u003C\u002Fschema>\n","db.xml","xml",[49,15056,15057,15062,15067,15072,15077,15082,15086,15091,15096,15101,15106,15111,15116,15121,15126,15131,15135,15140,15145,15149,15153,15158,15162,15167,15171,15175,15179,15183,15188,15193,15197,15202,15206,15210,15215,15219,15223,15227,15231,15235,15239,15243,15247,15251,15255],{"__ignoreMap":47},[52,15058,15059],{"class":54,"line":55},[52,15060,15061],{},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",[52,15063,15064],{"class":54,"line":83},[52,15065,15066],{},"\u003Cschema\n",[52,15068,15069],{"class":54,"line":115},[52,15070,15071],{},"  xmlns=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5\"\n",[52,15073,15074],{"class":54,"line":142},[52,15075,15076],{},"  xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n",[52,15078,15079],{"class":54,"line":169},[52,15080,15081],{},"  xsi:schemaLocation=\"http:\u002F\u002Fwww.concrete5.org\u002Fdoctrine-xml\u002F0.5 http:\u002F\u002Fconcrete5.github.io\u002Fdoctrine-xml\u002Fdoctrine-xml-0.5.xsd\">\n",[52,15083,15084],{"class":54,"line":302},[52,15085,340],{"emptyLinePlaceholder":339},[52,15087,15088],{"class":54,"line":308},[52,15089,15090],{},"\u003Ctable name=\"album\">\n",[52,15092,15093],{"class":54,"line":318},[52,15094,15095],{},"    \u003Cfield name=\"id\" type=\"integer\">\n",[52,15097,15098],{"class":54,"line":328},[52,15099,15100],{},"        \u003Cautoincrement\u002F>\n",[52,15102,15103],{"class":54,"line":4},[52,15104,15105],{},"        \u003Ckey\u002F>\n",[52,15107,15108],{"class":54,"line":343},[52,15109,15110],{},"    \u003C\u002Ffield>\n",[52,15112,15113],{"class":54,"line":353},[52,15114,15115],{},"    \u003Cfield name=\"title\" type=\"string\" size=\"255\"\u002F>\n",[52,15117,15118],{"class":54,"line":366},[52,15119,15120],{},"    \u003Cfield name=\"created\" type=\"datetime\">\n",[52,15122,15123],{"class":54,"line":386},[52,15124,15125],{},"      \u003Cdefault value=\"1000-01-01 00:00:00\"\u002F>\n",[52,15127,15128],{"class":54,"line":414},[52,15129,15130],{},"      \u003Cnotnull\u002F>\n",[52,15132,15133],{"class":54,"line":426},[52,15134,15110],{},[52,15136,15137],{"class":54,"line":434},[52,15138,15139],{},"    \u003Cfield name=\"modified\" type=\"timestamp\">\n",[52,15141,15142],{"class":54,"line":445},[52,15143,15144],{},"      \u003Cdeftimestamp\u002F>\n",[52,15146,15147],{"class":54,"line":479},[52,15148,15130],{},[52,15150,15151],{"class":54,"line":508},[52,15152,15110],{},[52,15154,15155],{"class":54,"line":538},[52,15156,15157],{},"\u003C\u002Ftable>\n",[52,15159,15160],{"class":54,"line":546},[52,15161,340],{"emptyLinePlaceholder":339},[52,15163,15164],{"class":54,"line":552},[52,15165,15166],{},"\u003Ctable name=\"albumPics\">\n",[52,15168,15169],{"class":54,"line":558},[52,15170,15095],{},[52,15172,15173],{"class":54,"line":563},[52,15174,15100],{},[52,15176,15177],{"class":54,"line":568},[52,15178,15105],{},[52,15180,15181],{"class":54,"line":1105},[52,15182,15110],{},[52,15184,15185],{"class":54,"line":1134},[52,15186,15187],{},"    \u003Cfield name=\"albumID\" type=\"integer\">\n",[52,15189,15190],{"class":54,"line":1163},[52,15191,15192],{},"        \u003Cunsigned\u002F>\n",[52,15194,15195],{"class":54,"line":1192},[52,15196,15110],{},[52,15198,15199],{"class":54,"line":1199},[52,15200,15201],{},"    \u003Cfield name=\"fID\" type=\"integer\">\n",[52,15203,15204],{"class":54,"line":1204},[52,15205,15192],{},[52,15207,15208],{"class":54,"line":1209},[52,15209,15110],{},[52,15211,15212],{"class":54,"line":1214},[52,15213,15214],{},"    \u003Cfield name=\"html\" type=\"text\" size=\"65535\"\u002F>\n",[52,15216,15217],{"class":54,"line":1219},[52,15218,15120],{},[52,15220,15221],{"class":54,"line":2302},[52,15222,15125],{},[52,15224,15225],{"class":54,"line":2308},[52,15226,15130],{},[52,15228,15229],{"class":54,"line":2317},[52,15230,15110],{},[52,15232,15233],{"class":54,"line":2323},[52,15234,15139],{},[52,15236,15237],{"class":54,"line":2328},[52,15238,15144],{},[52,15240,15241],{"class":54,"line":2333},[52,15242,15130],{},[52,15244,15245],{"class":54,"line":2338},[52,15246,15110],{},[52,15248,15249],{"class":54,"line":3141},[52,15250,15157],{},[52,15252,15253],{"class":54,"line":3158},[52,15254,340],{"emptyLinePlaceholder":339},[52,15256,15257],{"class":54,"line":3169},[52,15258,15259],{},"\u003C\u002Fschema>\n",[13,15261,15262],{},"1アルバムに対して不定数の画像が登録されるので上記の様なDBになっています。",[17,15264,15266],{"id":15265},"パッケージのビューphpとvueのsrc構成","パッケージのビューPHPとvueのSrc構成",[1721,15268,15270],{"id":15269},"パッケージ側phpの下準備","パッケージ側（PHP）の下準備",[13,15272,15273],{},"それではアルバムののフォームを作っていきましょう。前回インストールした「vuetest」にてフォーム用のシングルページを作成します。",[42,15275,15277],{"className":15276,"code":11715,"language":451},[1727],[49,15278,11715],{"__ignoreMap":47},[13,15280,15281,15282,15284],{},"そしてシングルページのコントローラーである",[49,15283,11728],{},"で以下の様に入力",[42,15286,15288],{"className":6114,"code":15287,"filename":11728,"language":6117,"meta":47,"style":47},"class Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n   \u002F\u002Fvuetest のシングルページでvueのjsファイルを読み込む様にする。\n　　public function on_start() {\n        $this->requireAsset('package-vue-production');\n    }\n\n    public function view() {\n    }\n\n    \u002F\u002F \u002Fdashboard\u002Fvuetest\u002F に \u002Fadd というURLを追加できる\n    public function add(){\n        $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n    }\n}\n",[49,15289,15290,15295,15299,15304,15308,15313,15318,15323,15327,15331,15336,15340,15344,15349,15354,15358,15362],{"__ignoreMap":47},[52,15291,15292],{"class":54,"line":55},[52,15293,15294],{},"class Vuetest extends DashboardPageController\n",[52,15296,15297],{"class":54,"line":83},[52,15298,363],{},[52,15300,15301],{"class":54,"line":115},[52,15302,15303],{},"    public $packageHandle = 'vuetest';\n",[52,15305,15306],{"class":54,"line":142},[52,15307,340],{"emptyLinePlaceholder":339},[52,15309,15310],{"class":54,"line":169},[52,15311,15312],{},"   \u002F\u002Fvuetest のシングルページでvueのjsファイルを読み込む様にする。\n",[52,15314,15315],{"class":54,"line":302},[52,15316,15317],{},"　　public function on_start() {\n",[52,15319,15320],{"class":54,"line":308},[52,15321,15322],{},"        $this->requireAsset('package-vue-production');\n",[52,15324,15325],{"class":54,"line":318},[52,15326,3753],{},[52,15328,15329],{"class":54,"line":328},[52,15330,340],{"emptyLinePlaceholder":339},[52,15332,15333],{"class":54,"line":4},[52,15334,15335],{},"    public function view() {\n",[52,15337,15338],{"class":54,"line":343},[52,15339,3753],{},[52,15341,15342],{"class":54,"line":353},[52,15343,340],{"emptyLinePlaceholder":339},[52,15345,15346],{"class":54,"line":366},[52,15347,15348],{},"    \u002F\u002F \u002Fdashboard\u002Fvuetest\u002F に \u002Fadd というURLを追加できる\n",[52,15350,15351],{"class":54,"line":386},[52,15352,15353],{},"    public function add(){\n",[52,15355,15356],{"class":54,"line":414},[52,15357,13008],{},[52,15359,15360],{"class":54,"line":426},[52,15361,3753],{},[52,15363,15364],{"class":54,"line":434},[52,15365,535],{},[13,15367,15368],{},"すると\u002Fdashboard\u002Fvuetest\u002Fadd というURLを叩くとadd.phpが表示されます。",[42,15370,15373],{"className":6114,"code":15371,"filename":15372,"language":6117,"meta":47,"style":47},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\u003Cp>add用のページだよ\u003C\u002Fp>\n","add.php",[49,15374,15375,15379,15383,15387],{"__ignoreMap":47},[52,15376,15377],{"class":54,"line":55},[52,15378,12309],{},[52,15380,15381],{"class":54,"line":83},[52,15382,12314],{},[52,15384,15385],{"class":54,"line":115},[52,15386,12319],{},[52,15388,15389],{"class":54,"line":142},[52,15390,15391],{},"\u003Cp>add用のページだよ\u003C\u002Fp>\n",[13,15393,15394,15395],{},"↓\n",[728,15396],{":src":15397,":width":15398,":center":1322},"'_mix\u002Fscsh-2020-08-26-21.34.56-768x436.png'","'600px'",[13,15400,15401],{},"ページの表示が確認できたら、add.phpに以下の様に変更しておきます。",[42,15403,15405],{"className":6114,"code":15404,"filename":15372,"language":6117,"meta":47,"style":47},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\u003Cdiv id=\"add\">\u003C\u002Fdiv>\n",[49,15406,15407,15411,15415,15419],{"__ignoreMap":47},[52,15408,15409],{"class":54,"line":55},[52,15410,12309],{},[52,15412,15413],{"class":54,"line":83},[52,15414,12314],{},[52,15416,15417],{"class":54,"line":115},[52,15418,12319],{},[52,15420,15421],{"class":54,"line":142},[52,15422,15423],{},"\u003Cdiv id=\"add\">\u003C\u002Fdiv>\n",[13,15425,15426,15427,15430],{},"この",[49,15428,15429],{},"\u003Cdiv id=”app>\u003C\u002Fdiv>","としたところがvueコンポーネントを流し込むエントリーになります。フォームのビューファイルであるadd.phpはこれだけでおしまいです。",[17,15432,10199],{"id":10199},[13,15434,15435],{},"ではvue側も作っていきましょう。src配下は以下の様に構成します。",[42,15437,15440],{"className":15438,"code":15439,"language":451},[1727],"├── src\n   ├── add.vue\n   ├── components\n   │   └── form.vue\n   ├── edit.vue\n   ├── index.vue\n   └── main.js\n",[49,15441,15439],{"__ignoreMap":47},[13,15443,15444],{},"index.vue、add.vue、edit.vueそれぞれが一覧・追加・編集ページのUIを構築します。しかしedit.vueとadd.vueは入力項目が同じで、初期値があるかないかの違いだけです。そのため共通のコンポーネントform.vueを作成します。",[13,15446,15447],{},"form.vueはひとまず以下の様に設定しておきます。",[42,15449,15451],{"className":202,"code":15450,"filename":12199,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Cp>vueレンダリングテスト\u003C\u002Fp>\n        \n        \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n            \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                \u003Cbutton class=\"pull-left btn btn-primary\">\n                    一覧へ戻る\n                \u003C\u002Fbutton>\n                \u003Ca href=\"#\" class=\"pull-right btn btn-primary\">\n                    登録\n                \u003C\u002Fa>\n            \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit']\n}\n\u003C\u002Fscript>\n",[49,15452,15453,15461,15479,15496,15501,15519,15537,15556,15561,15569,15597,15602,15610,15618,15626,15634,15642,15646,15654,15662,15677,15694,15698],{"__ignoreMap":47},[52,15454,15455,15457,15459],{"class":54,"line":55},[52,15456,59],{"class":58},[52,15458,213],{"class":62},[52,15460,80],{"class":58},[52,15462,15463,15465,15467,15469,15471,15473,15475,15477],{"class":54,"line":83},[52,15464,1902],{"class":58},[52,15466,1905],{"class":62},[52,15468,10706],{"class":65},[52,15470,69],{"class":58},[52,15472,72],{"class":58},[52,15474,13076],{"class":75},[52,15476,72],{"class":58},[52,15478,80],{"class":58},[52,15480,15481,15483,15485,15487,15490,15492,15494],{"class":54,"line":115},[52,15482,1912],{"class":58},[52,15484,13],{"class":62},[52,15486,102],{"class":58},[52,15488,15489],{"class":105},"vueレンダリングテスト",[52,15491,108],{"class":58},[52,15493,13],{"class":62},[52,15495,80],{"class":58},[52,15497,15498],{"class":54,"line":142},[52,15499,15500],{"class":105},"        \n",[52,15502,15503,15505,15507,15509,15511,15513,15515,15517],{"class":54,"line":169},[52,15504,1912],{"class":58},[52,15506,1905],{"class":62},[52,15508,10706],{"class":65},[52,15510,69],{"class":58},[52,15512,72],{"class":58},[52,15514,13543],{"class":75},[52,15516,72],{"class":58},[52,15518,80],{"class":58},[52,15520,15521,15523,15525,15527,15529,15531,15533,15535],{"class":54,"line":302},[52,15522,13135],{"class":58},[52,15524,1905],{"class":62},[52,15526,10706],{"class":65},[52,15528,69],{"class":58},[52,15530,72],{"class":58},[52,15532,13562],{"class":75},[52,15534,72],{"class":58},[52,15536,80],{"class":58},[52,15538,15539,15541,15543,15545,15547,15549,15552,15554],{"class":54,"line":308},[52,15540,13145],{"class":58},[52,15542,3510],{"class":62},[52,15544,10706],{"class":65},[52,15546,69],{"class":58},[52,15548,72],{"class":58},[52,15550,15551],{"class":75},"pull-left btn btn-primary",[52,15553,72],{"class":58},[52,15555,80],{"class":58},[52,15557,15558],{"class":54,"line":318},[52,15559,15560],{"class":105},"                    一覧へ戻る\n",[52,15562,15563,15565,15567],{"class":54,"line":328},[52,15564,13240],{"class":58},[52,15566,3510],{"class":62},[52,15568,80],{"class":58},[52,15570,15571,15573,15575,15577,15579,15581,15583,15585,15587,15589,15591,15593,15595],{"class":54,"line":4},[52,15572,13145],{"class":58},[52,15574,1445],{"class":62},[52,15576,10384],{"class":65},[52,15578,69],{"class":58},[52,15580,72],{"class":58},[52,15582,12639],{"class":75},[52,15584,72],{"class":58},[52,15586,10706],{"class":65},[52,15588,69],{"class":58},[52,15590,72],{"class":58},[52,15592,13592],{"class":75},[52,15594,72],{"class":58},[52,15596,80],{"class":58},[52,15598,15599],{"class":54,"line":343},[52,15600,15601],{"class":105},"                    登録\n",[52,15603,15604,15606,15608],{"class":54,"line":353},[52,15605,13240],{"class":58},[52,15607,1445],{"class":62},[52,15609,80],{"class":58},[52,15611,15612,15614,15616],{"class":54,"line":366},[52,15613,13249],{"class":58},[52,15615,1905],{"class":62},[52,15617,80],{"class":58},[52,15619,15620,15622,15624],{"class":54,"line":386},[52,15621,13520],{"class":58},[52,15623,1905],{"class":62},[52,15625,80],{"class":58},[52,15627,15628,15630,15632],{"class":54,"line":414},[52,15629,1946],{"class":58},[52,15631,1905],{"class":62},[52,15633,80],{"class":58},[52,15635,15636,15638,15640],{"class":54,"line":426},[52,15637,108],{"class":58},[52,15639,213],{"class":62},[52,15641,80],{"class":58},[52,15643,15644],{"class":54,"line":434},[52,15645,340],{"emptyLinePlaceholder":339},[52,15647,15648,15650,15652],{"class":54,"line":445},[52,15649,59],{"class":58},[52,15651,348],{"class":62},[52,15653,80],{"class":58},[52,15655,15656,15658,15660],{"class":54,"line":479},[52,15657,356],{"class":359},[52,15659,360],{"class":359},[52,15661,2012],{"class":58},[52,15663,15664,15666,15668,15670,15673,15675],{"class":54,"line":508},[52,15665,2017],{"class":62},[52,15667,372],{"class":58},[52,15669,375],{"class":58},[52,15671,15672],{"class":75},"albumForm",[52,15674,375],{"class":58},[52,15676,383],{"class":58},[52,15678,15679,15682,15684,15686,15688,15690,15692],{"class":54,"line":538},[52,15680,15681],{"class":62},"    props",[52,15683,372],{"class":58},[52,15685,394],{"class":105},[52,15687,375],{"class":58},[52,15689,12284],{"class":75},[52,15691,375],{"class":58},[52,15693,6511],{"class":105},[52,15695,15696],{"class":54,"line":546},[52,15697,535],{"class":58},[52,15699,15700,15702,15704],{"class":54,"line":552},[52,15701,108],{"class":58},[52,15703,348],{"class":62},[52,15705,80],{"class":58},[13,15707,15708],{},"そしてadd.vueでこのform.vueを読み込んで",[42,15710,15713],{"className":202,"code":15711,"filename":15712,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003CAlbumForm :isEdit=\"false\"\u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport AlbumForm from '.\u002Fcomponents\u002Fform';\nexport default {\n    name:'add',\n    components:{AlbumForm}\n}\n\u003C\u002Fscript>\n","app.vue",[49,15714,15715,15723,15741,15749,15753,15761,15777,15785,15799,15809,15813],{"__ignoreMap":47},[52,15716,15717,15719,15721],{"class":54,"line":55},[52,15718,59],{"class":58},[52,15720,213],{"class":62},[52,15722,80],{"class":58},[52,15724,15725,15727,15729,15731,15733,15735,15737,15739],{"class":54,"line":83},[52,15726,1902],{"class":58},[52,15728,12356],{"class":62},[52,15730,12359],{"class":65},[52,15732,69],{"class":58},[52,15734,72],{"class":58},[52,15736,1326],{"class":75},[52,15738,72],{"class":58},[52,15740,1941],{"class":58},[52,15742,15743,15745,15747],{"class":54,"line":115},[52,15744,108],{"class":58},[52,15746,213],{"class":62},[52,15748,80],{"class":58},[52,15750,15751],{"class":54,"line":142},[52,15752,340],{"emptyLinePlaceholder":339},[52,15754,15755,15757,15759],{"class":54,"line":169},[52,15756,59],{"class":58},[52,15758,348],{"class":62},[52,15760,80],{"class":58},[52,15762,15763,15765,15767,15769,15771,15773,15775],{"class":54,"line":302},[52,15764,1847],{"class":359},[52,15766,12396],{"class":105},[52,15768,1976],{"class":359},[52,15770,1979],{"class":58},[52,15772,12403],{"class":75},[52,15774,375],{"class":58},[52,15776,1006],{"class":58},[52,15778,15779,15781,15783],{"class":54,"line":308},[52,15780,356],{"class":359},[52,15782,360],{"class":359},[52,15784,2012],{"class":58},[52,15786,15787,15789,15791,15793,15795,15797],{"class":54,"line":318},[52,15788,2017],{"class":62},[52,15790,372],{"class":58},[52,15792,375],{"class":58},[52,15794,12426],{"class":75},[52,15796,375],{"class":58},[52,15798,383],{"class":58},[52,15800,15801,15803,15805,15807],{"class":54,"line":328},[52,15802,3738],{"class":62},[52,15804,8527],{"class":58},[52,15806,12356],{"class":105},[52,15808,535],{"class":58},[52,15810,15811],{"class":54,"line":4},[52,15812,535],{"class":58},[52,15814,15815,15817,15819],{"class":54,"line":343},[52,15816,108],{"class":58},[52,15818,348],{"class":62},[52,15820,80],{"class":58},[13,15822,15823,15825,15826,15829],{},[49,15824,1769],{},"にて",[49,15827,15828],{},"id=\"app\"","の要素にマウントする様にします。",[42,15831,15833],{"className":1249,"code":15832,"filename":1769,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport Add from '.\u002Fadd.vue'\n\nVue.config.productionTip = false\n\nnew Vue({\n  render: h => h(Add),\n}).$mount('#add')\n",[49,15834,15835,15849,15863,15867,15883,15887,15898,15916],{"__ignoreMap":47},[52,15836,15837,15839,15841,15843,15845,15847],{"class":54,"line":55},[52,15838,1847],{"class":359},[52,15840,6824],{"class":105},[52,15842,1976],{"class":359},[52,15844,1979],{"class":58},[52,15846,204],{"class":75},[52,15848,5629],{"class":58},[52,15850,15851,15853,15855,15857,15859,15861],{"class":54,"line":83},[52,15852,1847],{"class":359},[52,15854,12484],{"class":105},[52,15856,1976],{"class":359},[52,15858,1979],{"class":58},[52,15860,12491],{"class":75},[52,15862,5629],{"class":58},[52,15864,15865],{"class":54,"line":115},[52,15866,340],{"emptyLinePlaceholder":339},[52,15868,15869,15871,15873,15875,15877,15879,15881],{"class":54,"line":142},[52,15870,2829],{"class":105},[52,15872,956],{"class":58},[52,15874,12526],{"class":105},[52,15876,956],{"class":58},[52,15878,12531],{"class":105},[52,15880,69],{"class":58},[52,15882,12536],{"class":2160},[52,15884,15885],{"class":54,"line":169},[52,15886,340],{"emptyLinePlaceholder":339},[52,15888,15889,15892,15894,15896],{"class":54,"line":302},[52,15890,15891],{"class":58},"new",[52,15893,7020],{"class":417},[52,15895,931],{"class":105},[52,15897,363],{"class":58},[52,15899,15900,15903,15905,15907,15909,15911,15914],{"class":54,"line":308},[52,15901,15902],{"class":417},"  render",[52,15904,372],{"class":58},[52,15906,12610],{"class":985},[52,15908,2282],{"class":65},[52,15910,12610],{"class":417},[52,15912,15913],{"class":105},"(Add)",[52,15915,383],{"class":58},[52,15917,15918,15920,15922,15924,15926,15928,15930,15933,15935],{"class":54,"line":318},[52,15919,1311],{"class":58},[52,15921,937],{"class":105},[52,15923,956],{"class":58},[52,15925,7049],{"class":417},[52,15927,931],{"class":105},[52,15929,375],{"class":58},[52,15931,15932],{"class":75},"#add",[52,15934,375],{"class":58},[52,15936,1014],{"class":105},[13,15938,15939,15940,15942],{},"こうしてビルドをしてみましょう。そして",[49,15941,13581],{},"へ移動してみると",[728,15944],{":src":15945,":width":731},"'_mix\u002Fsch-2020-08-26-22.48.54-768x529.png'",[13,15947,15948,15949,15951,15952,15954,15955,15957],{},"しっかりと",[49,15950,15828],{},"に",[49,15953,12199],{},"がレンダリングされました。ではこの",[49,15956,12199],{},"にガシガシとフォームUIを作っていきましょう！",[17,15959,15960],{"id":15960},"まずはタイトルを入力するだけのものを作成",[13,15962,15963],{},"最終的なフォームにはリッチテキストエディタとファイルセレクターなど、concrete5で用いられているフォームをvueで実装したいと思います。しかし、その２つはなかなか曲者で今回の記事で説明すると長くなるので次回に話します。",[13,15965,15966],{},"まずはvueとPHP(concrete5)でどう連携させてDBにデータを挿入するかの全体的な流れについて説明するとともに、タイトル部分（プレーンテキスト）を追加できる様にしていきましょう。",[1721,15968,15970],{"id":15969},"postでバックに値を送る","POSTでバックに値を送る",[13,15972,15973,15974,722,15977,15980,15981,15983],{},"vueで構築したUIで入力された値はどうやってバックに渡すか？簡単です。フォームを作る時の様に",[49,15975,15976],{},"input",[49,15978,15979],{},"\u003Cform method=\"post\">\u003C\u002Fform>","で囲んであげて、送信用のsubmitボタンを作るだけです。今回のパッケージではPOSTの値をAjaxとかで送るのでなく、普通にsubmitでサーバーに送信する様にしました。以下の様に",[49,15982,12199],{},"を変えます。",[42,15985,15987],{"className":202,"code":15986,"filename":12199,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム新規追加\u003C\u002Fh3>\n        \u003Chr>\n        \u003Cform method=\"post\">\n            \u003Clabel for=\"title\" class=\"control-label\">アルバムタイトル\u003C\u002Flabel>\n            \u003Cinput type=\"text\" name=\"title\" class=\"form-control ccm-input-text\" v-model=\"title\">\n\n            \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n                \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                    \u003Cbutton class=\"pull-left btn btn-primary\">\n                        一覧へ戻る\n                    \u003C\u002Fbutton>\n                    \u003Cinput value=\"登録\" type=\"submit\" class=\"pull-right btn btn-primary\">\n                \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n        \u003C\u002Fform>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit'],\n    data(){\n        return{\n            title:''\n        }\n    }\n}\n\u003C\u002Fscript>\n",[49,15988,15989,15997,16015,16032,16040,16061,16101,16150,16154,16172,16190,16208,16213,16221,16261,16269,16277,16285,16293,16301,16305,16313,16321,16335,16353,16359,16365,16374,16378,16382,16386],{"__ignoreMap":47},[52,15990,15991,15993,15995],{"class":54,"line":55},[52,15992,59],{"class":58},[52,15994,213],{"class":62},[52,15996,80],{"class":58},[52,15998,15999,16001,16003,16005,16007,16009,16011,16013],{"class":54,"line":83},[52,16000,1902],{"class":58},[52,16002,1905],{"class":62},[52,16004,10706],{"class":65},[52,16006,69],{"class":58},[52,16008,72],{"class":58},[52,16010,13076],{"class":75},[52,16012,72],{"class":58},[52,16014,80],{"class":58},[52,16016,16017,16019,16021,16023,16026,16028,16030],{"class":54,"line":115},[52,16018,1912],{"class":58},[52,16020,1721],{"class":62},[52,16022,102],{"class":58},[52,16024,16025],{"class":105},"アルバム新規追加",[52,16027,108],{"class":58},[52,16029,1721],{"class":62},[52,16031,80],{"class":58},[52,16033,16034,16036,16038],{"class":54,"line":142},[52,16035,1912],{"class":58},[52,16037,13104],{"class":62},[52,16039,80],{"class":58},[52,16041,16042,16044,16047,16050,16052,16054,16057,16059],{"class":54,"line":169},[52,16043,1912],{"class":58},[52,16045,16046],{"class":62},"form",[52,16048,16049],{"class":65}," method",[52,16051,69],{"class":58},[52,16053,72],{"class":58},[52,16055,16056],{"class":75},"post",[52,16058,72],{"class":58},[52,16060,80],{"class":58},[52,16062,16063,16065,16068,16071,16073,16075,16077,16079,16081,16083,16085,16088,16090,16092,16095,16097,16099],{"class":54,"line":302},[52,16064,13135],{"class":58},[52,16066,16067],{"class":62},"label",[52,16069,16070],{"class":65}," for",[52,16072,69],{"class":58},[52,16074,72],{"class":58},[52,16076,7525],{"class":75},[52,16078,72],{"class":58},[52,16080,10706],{"class":65},[52,16082,69],{"class":58},[52,16084,72],{"class":58},[52,16086,16087],{"class":75},"control-label",[52,16089,72],{"class":58},[52,16091,102],{"class":58},[52,16093,16094],{"class":105},"アルバムタイトル",[52,16096,108],{"class":58},[52,16098,16067],{"class":62},[52,16100,80],{"class":58},[52,16102,16103,16105,16107,16109,16111,16113,16115,16117,16119,16121,16123,16125,16127,16129,16131,16133,16136,16138,16140,16142,16144,16146,16148],{"class":54,"line":308},[52,16104,13135],{"class":58},[52,16106,15976],{"class":62},[52,16108,11874],{"class":65},[52,16110,69],{"class":58},[52,16112,72],{"class":58},[52,16114,451],{"class":75},[52,16116,72],{"class":58},[52,16118,66],{"class":65},[52,16120,69],{"class":58},[52,16122,72],{"class":58},[52,16124,7525],{"class":75},[52,16126,72],{"class":58},[52,16128,10706],{"class":65},[52,16130,69],{"class":58},[52,16132,72],{"class":58},[52,16134,16135],{"class":75},"form-control ccm-input-text",[52,16137,72],{"class":58},[52,16139,9258],{"class":65},[52,16141,69],{"class":58},[52,16143,72],{"class":58},[52,16145,7525],{"class":75},[52,16147,72],{"class":58},[52,16149,80],{"class":58},[52,16151,16152],{"class":54,"line":318},[52,16153,340],{"emptyLinePlaceholder":339},[52,16155,16156,16158,16160,16162,16164,16166,16168,16170],{"class":54,"line":328},[52,16157,13135],{"class":58},[52,16159,1905],{"class":62},[52,16161,10706],{"class":65},[52,16163,69],{"class":58},[52,16165,72],{"class":58},[52,16167,13543],{"class":75},[52,16169,72],{"class":58},[52,16171,80],{"class":58},[52,16173,16174,16176,16178,16180,16182,16184,16186,16188],{"class":54,"line":4},[52,16175,13145],{"class":58},[52,16177,1905],{"class":62},[52,16179,10706],{"class":65},[52,16181,69],{"class":58},[52,16183,72],{"class":58},[52,16185,13562],{"class":75},[52,16187,72],{"class":58},[52,16189,80],{"class":58},[52,16191,16192,16194,16196,16198,16200,16202,16204,16206],{"class":54,"line":343},[52,16193,13155],{"class":58},[52,16195,3510],{"class":62},[52,16197,10706],{"class":65},[52,16199,69],{"class":58},[52,16201,72],{"class":58},[52,16203,15551],{"class":75},[52,16205,72],{"class":58},[52,16207,80],{"class":58},[52,16209,16210],{"class":54,"line":353},[52,16211,16212],{"class":105},"                        一覧へ戻る\n",[52,16214,16215,16217,16219],{"class":54,"line":366},[52,16216,13495],{"class":58},[52,16218,3510],{"class":62},[52,16220,80],{"class":58},[52,16222,16223,16225,16227,16229,16231,16233,16236,16238,16240,16242,16244,16247,16249,16251,16253,16255,16257,16259],{"class":54,"line":386},[52,16224,13155],{"class":58},[52,16226,15976],{"class":62},[52,16228,91],{"class":65},[52,16230,69],{"class":58},[52,16232,72],{"class":58},[52,16234,16235],{"class":75},"登録",[52,16237,72],{"class":58},[52,16239,11874],{"class":65},[52,16241,69],{"class":58},[52,16243,72],{"class":58},[52,16245,16246],{"class":75},"submit",[52,16248,72],{"class":58},[52,16250,10706],{"class":65},[52,16252,69],{"class":58},[52,16254,72],{"class":58},[52,16256,13592],{"class":75},[52,16258,72],{"class":58},[52,16260,80],{"class":58},[52,16262,16263,16265,16267],{"class":54,"line":414},[52,16264,13240],{"class":58},[52,16266,1905],{"class":62},[52,16268,80],{"class":58},[52,16270,16271,16273,16275],{"class":54,"line":426},[52,16272,13249],{"class":58},[52,16274,1905],{"class":62},[52,16276,80],{"class":58},[52,16278,16279,16281,16283],{"class":54,"line":434},[52,16280,13520],{"class":58},[52,16282,16046],{"class":62},[52,16284,80],{"class":58},[52,16286,16287,16289,16291],{"class":54,"line":445},[52,16288,1946],{"class":58},[52,16290,1905],{"class":62},[52,16292,80],{"class":58},[52,16294,16295,16297,16299],{"class":54,"line":479},[52,16296,108],{"class":58},[52,16298,213],{"class":62},[52,16300,80],{"class":58},[52,16302,16303],{"class":54,"line":508},[52,16304,340],{"emptyLinePlaceholder":339},[52,16306,16307,16309,16311],{"class":54,"line":538},[52,16308,59],{"class":58},[52,16310,348],{"class":62},[52,16312,80],{"class":58},[52,16314,16315,16317,16319],{"class":54,"line":546},[52,16316,356],{"class":359},[52,16318,360],{"class":359},[52,16320,2012],{"class":58},[52,16322,16323,16325,16327,16329,16331,16333],{"class":54,"line":552},[52,16324,2017],{"class":62},[52,16326,372],{"class":58},[52,16328,375],{"class":58},[52,16330,15672],{"class":75},[52,16332,375],{"class":58},[52,16334,383],{"class":58},[52,16336,16337,16339,16341,16343,16345,16347,16349,16351],{"class":54,"line":558},[52,16338,15681],{"class":62},[52,16340,372],{"class":58},[52,16342,394],{"class":105},[52,16344,375],{"class":58},[52,16346,12284],{"class":75},[52,16348,375],{"class":58},[52,16350,404],{"class":105},[52,16352,383],{"class":58},[52,16354,16355,16357],{"class":54,"line":563},[52,16356,2033],{"class":62},[52,16358,2036],{"class":58},[52,16360,16361,16363],{"class":54,"line":568},[52,16362,2041],{"class":359},[52,16364,363],{"class":58},[52,16366,16367,16370,16372],{"class":54,"line":1105},[52,16368,16369],{"class":62},"            title",[52,16371,372],{"class":58},[52,16373,9360],{"class":58},[52,16375,16376],{"class":54,"line":1134},[52,16377,2060],{"class":58},[52,16379,16380],{"class":54,"line":1163},[52,16381,3753],{"class":58},[52,16383,16384],{"class":54,"line":1192},[52,16385,535],{"class":58},[52,16387,16388,16390,16392],{"class":54,"line":1199},[52,16389,108],{"class":58},[52,16391,348],{"class":62},[52,16393,80],{"class":58},[1721,16395,16396],{"id":16396},"フロントバリデーションを実装",[13,16398,16399],{},"フォームから入力された値をバリデーションチェックします。しかし今回はせっかくvueを使っているのでフロントでバリデーションをしてあげましょう。例えばtitleが空でないかをチェックする場合以下の様にします。",[42,16401,16403],{"className":202,"code":16402,"filename":12199,"language":204,"meta":47,"style":47},"\u003Ctemplate>\n    \u003Cdiv class=\"ccm-dashboard-content-inner\">\n        \u003Ch3>アルバム新規追加\u003C\u002Fh3>\n        \u003Chr>\n        \u003Cform method=\"post\" @submit=\"checkForm\">\n            \u003Clabel for=\"title\" class=\"control-label\">アルバムタイトル\u003C\u002Flabel>\n            \u003Cinput type=\"text\" name=\"title\" class=\"form-control ccm-input-text\" v-model=\"title\">\n            \u003Cp class=\"text-danger\" v-if=\"errTitle.length>0\">{{errTitle}}\u003C\u002Fp>\n\n            \u003Cdiv class=\"ccm-dashboard-form-actions-wrapper\">\n                \u003Cdiv class=\"ccm-dashboard-form-actions\">\n                    \u003Cbutton class=\"pull-left btn btn-primary\">\n                        一覧へ戻る\n                    \u003C\u002Fbutton>\n                    \u003Cinput value=\"登録\" type=\"submit\" class=\"pull-right btn btn-primary\">\n                \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n        \u003C\u002Fform>\n    \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\u003Cscript>\nexport default {\n    name:'albumForm',\n    props:['isEdit'],\n    data(){\n        return{\n            title:'',\n            errTitle:''\n        }\n    },\n    methods:{\n        checkForm($event){\n            if(this.title.length >0){\n                return true;\n            }else{\n                $event.preventDefault();\n                ConcreteAlert.error({\n                    title:'入力項目に誤りがあります。',\n                    message:'アルバムタイトルが入力されていません。',\n                    delay:5000\n                })\n                this.errTitle = \"タイトルを入力してください。\"\n            }\n        }\n    }\n}\n\u003C\u002Fscript>\n",[49,16404,16405,16413,16431,16447,16455,16485,16521,16569,16609,16613,16631,16649,16667,16671,16679,16717,16725,16733,16741,16749,16757,16765,16773,16787,16805,16811,16817,16827,16836,16840,16844,16850,16861,16884,16893,16903,16917,16930,16946,16962,16972,16978,16994,16998,17002,17006,17010],{"__ignoreMap":47},[52,16406,16407,16409,16411],{"class":54,"line":55},[52,16408,59],{"class":58},[52,16410,213],{"class":62},[52,16412,80],{"class":58},[52,16414,16415,16417,16419,16421,16423,16425,16427,16429],{"class":54,"line":83},[52,16416,1902],{"class":58},[52,16418,1905],{"class":62},[52,16420,10706],{"class":65},[52,16422,69],{"class":58},[52,16424,72],{"class":58},[52,16426,13076],{"class":75},[52,16428,72],{"class":58},[52,16430,80],{"class":58},[52,16432,16433,16435,16437,16439,16441,16443,16445],{"class":54,"line":115},[52,16434,1912],{"class":58},[52,16436,1721],{"class":62},[52,16438,102],{"class":58},[52,16440,16025],{"class":105},[52,16442,108],{"class":58},[52,16444,1721],{"class":62},[52,16446,80],{"class":58},[52,16448,16449,16451,16453],{"class":54,"line":142},[52,16450,1912],{"class":58},[52,16452,13104],{"class":62},[52,16454,80],{"class":58},[52,16456,16457,16459,16461,16463,16465,16467,16469,16471,16474,16476,16478,16481,16483],{"class":54,"line":169},[52,16458,1912],{"class":58},[52,16460,16046],{"class":62},[52,16462,16049],{"class":65},[52,16464,69],{"class":58},[52,16466,72],{"class":58},[52,16468,16056],{"class":75},[52,16470,72],{"class":58},[52,16472,16473],{"class":65}," @submit",[52,16475,69],{"class":58},[52,16477,72],{"class":58},[52,16479,16480],{"class":75},"checkForm",[52,16482,72],{"class":58},[52,16484,80],{"class":58},[52,16486,16487,16489,16491,16493,16495,16497,16499,16501,16503,16505,16507,16509,16511,16513,16515,16517,16519],{"class":54,"line":302},[52,16488,13135],{"class":58},[52,16490,16067],{"class":62},[52,16492,16070],{"class":65},[52,16494,69],{"class":58},[52,16496,72],{"class":58},[52,16498,7525],{"class":75},[52,16500,72],{"class":58},[52,16502,10706],{"class":65},[52,16504,69],{"class":58},[52,16506,72],{"class":58},[52,16508,16087],{"class":75},[52,16510,72],{"class":58},[52,16512,102],{"class":58},[52,16514,16094],{"class":105},[52,16516,108],{"class":58},[52,16518,16067],{"class":62},[52,16520,80],{"class":58},[52,16522,16523,16525,16527,16529,16531,16533,16535,16537,16539,16541,16543,16545,16547,16549,16551,16553,16555,16557,16559,16561,16563,16565,16567],{"class":54,"line":308},[52,16524,13135],{"class":58},[52,16526,15976],{"class":62},[52,16528,11874],{"class":65},[52,16530,69],{"class":58},[52,16532,72],{"class":58},[52,16534,451],{"class":75},[52,16536,72],{"class":58},[52,16538,66],{"class":65},[52,16540,69],{"class":58},[52,16542,72],{"class":58},[52,16544,7525],{"class":75},[52,16546,72],{"class":58},[52,16548,10706],{"class":65},[52,16550,69],{"class":58},[52,16552,72],{"class":58},[52,16554,16135],{"class":75},[52,16556,72],{"class":58},[52,16558,9258],{"class":65},[52,16560,69],{"class":58},[52,16562,72],{"class":58},[52,16564,7525],{"class":75},[52,16566,72],{"class":58},[52,16568,80],{"class":58},[52,16570,16571,16573,16575,16577,16579,16581,16584,16586,16589,16591,16593,16596,16598,16600,16603,16605,16607],{"class":54,"line":318},[52,16572,13135],{"class":58},[52,16574,13],{"class":62},[52,16576,10706],{"class":65},[52,16578,69],{"class":58},[52,16580,72],{"class":58},[52,16582,16583],{"class":75},"text-danger",[52,16585,72],{"class":58},[52,16587,16588],{"class":65}," v-if",[52,16590,69],{"class":58},[52,16592,72],{"class":58},[52,16594,16595],{"class":75},"errTitle.length>0",[52,16597,72],{"class":58},[52,16599,102],{"class":58},[52,16601,16602],{"class":105},"{{errTitle}}",[52,16604,108],{"class":58},[52,16606,13],{"class":62},[52,16608,80],{"class":58},[52,16610,16611],{"class":54,"line":328},[52,16612,340],{"emptyLinePlaceholder":339},[52,16614,16615,16617,16619,16621,16623,16625,16627,16629],{"class":54,"line":4},[52,16616,13135],{"class":58},[52,16618,1905],{"class":62},[52,16620,10706],{"class":65},[52,16622,69],{"class":58},[52,16624,72],{"class":58},[52,16626,13543],{"class":75},[52,16628,72],{"class":58},[52,16630,80],{"class":58},[52,16632,16633,16635,16637,16639,16641,16643,16645,16647],{"class":54,"line":343},[52,16634,13145],{"class":58},[52,16636,1905],{"class":62},[52,16638,10706],{"class":65},[52,16640,69],{"class":58},[52,16642,72],{"class":58},[52,16644,13562],{"class":75},[52,16646,72],{"class":58},[52,16648,80],{"class":58},[52,16650,16651,16653,16655,16657,16659,16661,16663,16665],{"class":54,"line":353},[52,16652,13155],{"class":58},[52,16654,3510],{"class":62},[52,16656,10706],{"class":65},[52,16658,69],{"class":58},[52,16660,72],{"class":58},[52,16662,15551],{"class":75},[52,16664,72],{"class":58},[52,16666,80],{"class":58},[52,16668,16669],{"class":54,"line":366},[52,16670,16212],{"class":105},[52,16672,16673,16675,16677],{"class":54,"line":386},[52,16674,13495],{"class":58},[52,16676,3510],{"class":62},[52,16678,80],{"class":58},[52,16680,16681,16683,16685,16687,16689,16691,16693,16695,16697,16699,16701,16703,16705,16707,16709,16711,16713,16715],{"class":54,"line":414},[52,16682,13155],{"class":58},[52,16684,15976],{"class":62},[52,16686,91],{"class":65},[52,16688,69],{"class":58},[52,16690,72],{"class":58},[52,16692,16235],{"class":75},[52,16694,72],{"class":58},[52,16696,11874],{"class":65},[52,16698,69],{"class":58},[52,16700,72],{"class":58},[52,16702,16246],{"class":75},[52,16704,72],{"class":58},[52,16706,10706],{"class":65},[52,16708,69],{"class":58},[52,16710,72],{"class":58},[52,16712,13592],{"class":75},[52,16714,72],{"class":58},[52,16716,80],{"class":58},[52,16718,16719,16721,16723],{"class":54,"line":426},[52,16720,13240],{"class":58},[52,16722,1905],{"class":62},[52,16724,80],{"class":58},[52,16726,16727,16729,16731],{"class":54,"line":434},[52,16728,13249],{"class":58},[52,16730,1905],{"class":62},[52,16732,80],{"class":58},[52,16734,16735,16737,16739],{"class":54,"line":445},[52,16736,13520],{"class":58},[52,16738,16046],{"class":62},[52,16740,80],{"class":58},[52,16742,16743,16745,16747],{"class":54,"line":479},[52,16744,1946],{"class":58},[52,16746,1905],{"class":62},[52,16748,80],{"class":58},[52,16750,16751,16753,16755],{"class":54,"line":508},[52,16752,108],{"class":58},[52,16754,213],{"class":62},[52,16756,80],{"class":58},[52,16758,16759,16761,16763],{"class":54,"line":538},[52,16760,59],{"class":58},[52,16762,348],{"class":62},[52,16764,80],{"class":58},[52,16766,16767,16769,16771],{"class":54,"line":546},[52,16768,356],{"class":359},[52,16770,360],{"class":359},[52,16772,2012],{"class":58},[52,16774,16775,16777,16779,16781,16783,16785],{"class":54,"line":552},[52,16776,2017],{"class":62},[52,16778,372],{"class":58},[52,16780,375],{"class":58},[52,16782,15672],{"class":75},[52,16784,375],{"class":58},[52,16786,383],{"class":58},[52,16788,16789,16791,16793,16795,16797,16799,16801,16803],{"class":54,"line":558},[52,16790,15681],{"class":62},[52,16792,372],{"class":58},[52,16794,394],{"class":105},[52,16796,375],{"class":58},[52,16798,12284],{"class":75},[52,16800,375],{"class":58},[52,16802,404],{"class":105},[52,16804,383],{"class":58},[52,16806,16807,16809],{"class":54,"line":563},[52,16808,2033],{"class":62},[52,16810,2036],{"class":58},[52,16812,16813,16815],{"class":54,"line":568},[52,16814,2041],{"class":359},[52,16816,363],{"class":58},[52,16818,16819,16821,16823,16825],{"class":54,"line":1105},[52,16820,16369],{"class":62},[52,16822,372],{"class":58},[52,16824,3657],{"class":58},[52,16826,383],{"class":58},[52,16828,16829,16832,16834],{"class":54,"line":1134},[52,16830,16831],{"class":62},"            errTitle",[52,16833,372],{"class":58},[52,16835,9360],{"class":58},[52,16837,16838],{"class":54,"line":1163},[52,16839,2060],{"class":58},[52,16841,16842],{"class":54,"line":1192},[52,16843,2065],{"class":58},[52,16845,16846,16848],{"class":54,"line":1199},[52,16847,2070],{"class":62},[52,16849,923],{"class":58},[52,16851,16852,16855,16857,16859],{"class":54,"line":1204},[52,16853,16854],{"class":62},"        checkForm",[52,16856,931],{"class":58},[52,16858,934],{"class":985},[52,16860,2085],{"class":58},[52,16862,16863,16865,16867,16869,16871,16873,16876,16878,16880,16882],{"class":54,"line":1209},[52,16864,13786],{"class":359},[52,16866,931],{"class":62},[52,16868,1370],{"class":58},[52,16870,7525],{"class":105},[52,16872,956],{"class":58},[52,16874,16875],{"class":105},"length",[52,16877,4674],{"class":58},[52,16879,7992],{"class":4596},[52,16881,937],{"class":62},[52,16883,363],{"class":58},[52,16885,16886,16889,16891],{"class":54,"line":1214},[52,16887,16888],{"class":359},"                return",[52,16890,2264],{"class":2160},[52,16892,1006],{"class":58},[52,16894,16895,16898,16901],{"class":54,"line":1219},[52,16896,16897],{"class":58},"            }",[52,16899,16900],{"class":359},"else",[52,16902,363],{"class":58},[52,16904,16905,16908,16910,16913,16915],{"class":54,"line":2302},[52,16906,16907],{"class":105},"                $event",[52,16909,956],{"class":58},[52,16911,16912],{"class":417},"preventDefault",[52,16914,421],{"class":62},[52,16916,1006],{"class":58},[52,16918,16919,16922,16924,16926,16928],{"class":54,"line":2308},[52,16920,16921],{"class":105},"                ConcreteAlert",[52,16923,956],{"class":58},[52,16925,2095],{"class":417},[52,16927,931],{"class":62},[52,16929,363],{"class":58},[52,16931,16932,16935,16937,16939,16942,16944],{"class":54,"line":2317},[52,16933,16934],{"class":62},"                    title",[52,16936,372],{"class":58},[52,16938,375],{"class":58},[52,16940,16941],{"class":75},"入力項目に誤りがあります。",[52,16943,375],{"class":58},[52,16945,383],{"class":58},[52,16947,16948,16951,16953,16955,16958,16960],{"class":54,"line":2323},[52,16949,16950],{"class":62},"                    message",[52,16952,372],{"class":58},[52,16954,375],{"class":58},[52,16956,16957],{"class":75},"アルバムタイトルが入力されていません。",[52,16959,375],{"class":58},[52,16961,383],{"class":58},[52,16963,16964,16967,16969],{"class":54,"line":2328},[52,16965,16966],{"class":62},"                    delay",[52,16968,372],{"class":58},[52,16970,16971],{"class":4596},"5000\n",[52,16973,16974,16976],{"class":54,"line":2333},[52,16975,14118],{"class":58},[52,16977,1014],{"class":62},[52,16979,16980,16982,16985,16987,16989,16992],{"class":54,"line":2338},[52,16981,13852],{"class":58},[52,16983,16984],{"class":105},"errTitle",[52,16986,950],{"class":58},[52,16988,1502],{"class":58},[52,16990,16991],{"class":75},"タイトルを入力してください。",[52,16993,266],{"class":58},[52,16995,16996],{"class":54,"line":3141},[52,16997,2320],{"class":58},[52,16999,17000],{"class":54,"line":3158},[52,17001,2060],{"class":58},[52,17003,17004],{"class":54,"line":3169},[52,17005,3753],{"class":58},[52,17007,17008],{"class":54,"line":3188},[52,17009,535],{"class":58},[52,17011,17012,17014,17016],{"class":54,"line":3199},[52,17013,108],{"class":58},[52,17015,348],{"class":62},[52,17017,80],{"class":58},[13,17019,17020,17022,17023,17026,17027,17029,17030,17032],{},[49,17021,16046],{},"の箇所に",[49,17024,17025],{},"@submit=\"checkForm\"","というイベントを作成。これはこのformがsubmitされた際に",[49,17028,16480],{},"というメソッドを発火させるという意味です。そして",[49,17031,16480],{},"ではtitleの値が空かどうかを判断しています。",[13,17034,17035,17036,17039,17040,17042,17043,17046,17047,17050,17051,17053],{},"もし空でない場合は",[49,17037,17038],{},"return true","となって",[49,17041,16246],{},"が通って、サーバーへ値が送信されます。からの場合は",[49,17044,17045],{},"$event.preventDefault();","が実行されてsubmitされません。そして",[49,17048,17049],{},"ConcreteAlert.error","という8.4系から使用できるconcrete5のフラッシュメッセージのjsを出しています。（",[49,17052,17049],{},"は特に何も読み込まないでも使える）",[13,17055,17056],{},"空で「登録」を押すと以下の様になります。",[728,17058],{":src":17059,":width":731},"'_mix\u002Fsch-2020-08-27-0.07.18-768x531.png'",[13,17061,17062,17064],{},[49,17063,17045],{},"によってサーバーにデータは送信されず、ユーザーに対してエラーを表示できました。",[4424,17066,17068],{"id":17067},"eslintがある時のchips","ESLintがある時のchips",[13,17070,17071,17074],{},[49,17072,17073],{},"ConcreteAlert"," はconcrete5が用意してくれた便利なフラッシュメッセージです。しかし、ESLint付きのvueCLI内で使用ようとすると、ビルド時にこの様に怒られます。",[42,17076,17079],{"className":17077,"code":17078,"language":451},[1727],"ERROR  Failed to compile with 1 errors                                                                                                       23:50:16\n\n error  in .\u002Fsrc\u002Fcomponents\u002Fform.vue\n\nModule Error (from .\u002Fnode_modules\u002Feslint-loader\u002Findex.js):\n\n\u002FApplications\u002FMAMP\u002Fhtdocs\u002Fc5test\u002Fpackages\u002Fvuetest\u002Fjs\u002Fpackageui\u002Fsrc\u002Fcomponents\u002Fform.vue\n  40:17  error  'ConcreteAlert' is not defined  no-undef\n\n✖ 1 problem (1 error, 0 warnings)\n",[49,17080,17078],{"__ignoreMap":47},[13,17082,17083,17084,17086,17087,17090],{},"そうです。vueプロジェクト内には",[49,17085,17073],{}," を定義したjsファイルがない、というかconcreteが用意したjsを読み込めないのでこの様に怒られます。これだとビルドできないので",[49,17088,17089],{},"package.json","のeslintの設定に以下の記述をします。",[42,17092,17095],{"className":17093,"code":17094,"language":451},[1727]," \"eslintConfig\": {\n　　\"globals\":{\n      \"ConcreteAlert\": true,\n    }\n },\n",[49,17096,17094],{"__ignoreMap":47},[13,17098,17099,17100,17102],{},"こうするとESLintは「ConcreteAlertってのはグローバルな奴なんだな〜。」と認識してくれて、実際にvueプロジェクト外にある",[49,17101,17073],{},"に対して怒らなくなります。",[17,17104,17105],{"id":17105},"バックエンド実装",[13,17107,17108],{},"vueを用いてまずはアルバムのタイトルだけを入力できるフォームを作りました。そしてこのタイトルをDBに挿入するまで行います。と言ってもシングルページコントローラーを以下の様に記述します。",[42,17110,17112],{"className":6114,"code":17111,"filename":11728,"language":6117,"meta":47,"style":47},"\u003C?php\nnamespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\nuse Concrete\\Core\\Routing\\Redirect;\nuse Concrete\\Core\\Http\\Request;\n\n\nuse Core;\nuse Database;\n\nclass Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n    public function on_start()\n    {\n        $this->requireAsset('package-vue-production');\n    }\n\n    public function view() {\n    }\n\n    public function add(){\n        if(Request::isPost() == true){\n            $title = $this->post('title');\n\n            if(empty($title)==false){\n                $db = Database::connection();\n                $db->executeQuery(\"START TRANSACTION\");\n                $db->executeQuery(\n                    'INSERT album SET `title`=?, `created`=now(), `modified`=now()',\n                    array($title)\n                );\n                $db->executeQuery(\"COMMIT\");\n                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n            }else{\n                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n            }\n\n        }else{\n            $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n        }\n    }\n}\n",[49,17113,17114,17118,17123,17127,17132,17137,17142,17146,17150,17155,17160,17164,17168,17172,17176,17180,17185,17189,17193,17197,17201,17205,17209,17213,17217,17222,17227,17231,17236,17241,17246,17251,17256,17261,17266,17271,17276,17281,17285,17289,17293,17297,17302,17306,17310],{"__ignoreMap":47},[52,17115,17116],{"class":54,"line":55},[52,17117,12309],{},[52,17119,17120],{"class":54,"line":83},[52,17121,17122],{},"namespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\n",[52,17124,17125],{"class":54,"line":115},[52,17126,12314],{},[52,17128,17129],{"class":54,"line":142},[52,17130,17131],{},"use \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\n",[52,17133,17134],{"class":54,"line":169},[52,17135,17136],{},"use Concrete\\Core\\Routing\\Redirect;\n",[52,17138,17139],{"class":54,"line":302},[52,17140,17141],{},"use Concrete\\Core\\Http\\Request;\n",[52,17143,17144],{"class":54,"line":308},[52,17145,340],{"emptyLinePlaceholder":339},[52,17147,17148],{"class":54,"line":318},[52,17149,340],{"emptyLinePlaceholder":339},[52,17151,17152],{"class":54,"line":328},[52,17153,17154],{},"use Core;\n",[52,17156,17157],{"class":54,"line":4},[52,17158,17159],{},"use Database;\n",[52,17161,17162],{"class":54,"line":343},[52,17163,340],{"emptyLinePlaceholder":339},[52,17165,17166],{"class":54,"line":353},[52,17167,15294],{},[52,17169,17170],{"class":54,"line":366},[52,17171,363],{},[52,17173,17174],{"class":54,"line":386},[52,17175,15303],{},[52,17177,17178],{"class":54,"line":414},[52,17179,340],{"emptyLinePlaceholder":339},[52,17181,17182],{"class":54,"line":426},[52,17183,17184],{},"    public function on_start()\n",[52,17186,17187],{"class":54,"line":434},[52,17188,12757],{},[52,17190,17191],{"class":54,"line":445},[52,17192,15322],{},[52,17194,17195],{"class":54,"line":479},[52,17196,3753],{},[52,17198,17199],{"class":54,"line":508},[52,17200,340],{"emptyLinePlaceholder":339},[52,17202,17203],{"class":54,"line":538},[52,17204,15335],{},[52,17206,17207],{"class":54,"line":546},[52,17208,3753],{},[52,17210,17211],{"class":54,"line":552},[52,17212,340],{"emptyLinePlaceholder":339},[52,17214,17215],{"class":54,"line":558},[52,17216,15353],{},[52,17218,17219],{"class":54,"line":563},[52,17220,17221],{},"        if(Request::isPost() == true){\n",[52,17223,17224],{"class":54,"line":568},[52,17225,17226],{},"            $title = $this->post('title');\n",[52,17228,17229],{"class":54,"line":1105},[52,17230,340],{"emptyLinePlaceholder":339},[52,17232,17233],{"class":54,"line":1134},[52,17234,17235],{},"            if(empty($title)==false){\n",[52,17237,17238],{"class":54,"line":1163},[52,17239,17240],{},"                $db = Database::connection();\n",[52,17242,17243],{"class":54,"line":1192},[52,17244,17245],{},"                $db->executeQuery(\"START TRANSACTION\");\n",[52,17247,17248],{"class":54,"line":1199},[52,17249,17250],{},"                $db->executeQuery(\n",[52,17252,17253],{"class":54,"line":1204},[52,17254,17255],{},"                    'INSERT album SET `title`=?, `created`=now(), `modified`=now()',\n",[52,17257,17258],{"class":54,"line":1209},[52,17259,17260],{},"                    array($title)\n",[52,17262,17263],{"class":54,"line":1214},[52,17264,17265],{},"                );\n",[52,17267,17268],{"class":54,"line":1219},[52,17269,17270],{},"                $db->executeQuery(\"COMMIT\");\n",[52,17272,17273],{"class":54,"line":2302},[52,17274,17275],{},"                Redirect::to('\u002Fdashboard\u002Fvuetest')->send();\n",[52,17277,17278],{"class":54,"line":2308},[52,17279,17280],{},"            }else{\n",[52,17282,17283],{"class":54,"line":2317},[52,17284,17275],{},[52,17286,17287],{"class":54,"line":2323},[52,17288,2320],{},[52,17290,17291],{"class":54,"line":2328},[52,17292,340],{"emptyLinePlaceholder":339},[52,17294,17295],{"class":54,"line":2333},[52,17296,12986],{},[52,17298,17299],{"class":54,"line":2338},[52,17300,17301],{},"            $this->render('\u002Fdashboard\u002Fvuetest\u002Fadd');\n",[52,17303,17304],{"class":54,"line":3141},[52,17305,2060],{},[52,17307,17308],{"class":54,"line":3158},[52,17309,3753],{},[52,17311,17312],{"class":54,"line":3169},[52,17313,535],{},[13,17315,17316,17318,17319,17322,17323,17326],{},[49,17317,13581],{}," でpostを送ると",[49,17320,17321],{},"add()","にて処理が行われます。",[49,17324,17325],{},"Request::isPost()","というメソッドを用いてリクエストがpostかどうかをチェックします。postであれば値をDBへ挿入するスクリプトを実行し、そうでなければ新規追加の画面を表示します。",[13,17328,17329,17332,17333,17336,17337,17340,17341,17344],{},[49,17330,17331],{},"DashboardPageController","配下では",[49,17334,17335],{},"$this->post('name')"," というメソッドで対応するname属性のinputの値を取得することができます！先ほどのフォームではタイトルの値を",[49,17338,17339],{},"name=\"title\"","としていたので",[49,17342,17343],{},"$title = $this->post('title');","で取得します",[1721,17346,17348],{"id":17347},"chips-必ずバックエンドでもバリデーションを実装する","chips 必ずバックエンドでもバリデーションを実装する",[13,17350,17351],{},"よくみると下記の様にタイトルの値を検査しています。",[42,17353,17355],{"className":6114,"code":17354,"filename":11728,"language":6117,"meta":47,"style":47},"if(empty($title)==false){\n ...\n}\n",[49,17356,17357,17362,17367],{"__ignoreMap":47},[52,17358,17359],{"class":54,"line":55},[52,17360,17361],{},"if(empty($title)==false){\n",[52,17363,17364],{"class":54,"line":83},[52,17365,17366],{}," ...\n",[52,17368,17369],{"class":54,"line":115},[52,17370,535],{},[1905,17372,17374,17375],{"className":17373},[6312,6313],"\n「フロントエンド でタイトルの値をバリデーションしたから別にやらなくても良くない？」というのは厳禁です。postで来た値は必ずバックエンドで同様にバリデーションをかけます。",[17376,17377,17378],"b",{},"なぜならブラウザのconsoleでフロントでの値は偽造することもでき、フロントエンドのバリデーションを不正にスルーできるからです。",[13,17380,17381],{},"vueで行っているバリデーションはあくまでユーザー補助、UX的な物でありセキュリティの観点からは言えばガバガバです。エンドユーザーが偽造ができないバックエンドであれば確実にバリデーションをすることができます。",[13,17383,17384],{},"dashbord配下は基本的にサイト管理者が触る物なので、不正な値を入れようとする人はいないと思いますが、フロントからpostされた値は基本的に信用しないスタイルを貫いた方が無難です。",[17,17386,17387],{"id":17387},"データを入れてみる",[13,17389,17390,17391,17393],{},"では早速使ってみましょう。",[49,17392,13581],{}," にアクセスするとタイトル入力フォームが出てきました。仮に「テスト」と入力。そして「登録」を押します。",[728,17395],{":src":17396,":width":731},"'_mix\u002Fsch-2020-08-27-0.48.59-768x203.png'",[13,17398,17399],{},"一覧のページにリダイレクトされました。ちゃんと挿入されたか、phpmyadminでみてみましょう。",[728,17401],{":src":17402,":width":10193,":center":1322},"'_mix\u002Fsch-2020-08-27-0.51.36-768x340.png'",[13,17404,17405],{},"いましたね。titleが「テスト」となっているので、正しくデータが入力されました。",[17,17407,17408],{"id":7438},"次回は…",[13,17410,17411],{},"以上がvueとバックエンド部分の一通りの実装でした。",[1854,17413,17414,17417,17420],{},[1699,17415,17416],{},"シングルページにvueのエントリーポイントを作る",[1699,17418,17419],{},"エントリポイントにレンダリングされる様にコンポーネントを設定",[1699,17421,17422],{},"jsをシングルページに読み込む",[13,17424,17425],{},"¥以上を意識すればconcrete5のシングルページに自由にvueを用いてUIを構築できます。あとはvueの使い方とバックエンドの設計を頑張るだけです。そして次回は編集画面と一覧画面の作成をしていきます。",[1413,17427,17428],{},"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 pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":47,"searchDepth":115,"depth":115,"links":17430},[17431,17434,17435,17438,17439,17445,17448,17449],{"id":15014,"depth":83,"text":15014,"children":17432},[17433],{"id":15034,"depth":115,"text":15035},{"id":15044,"depth":83,"text":15045},{"id":15265,"depth":83,"text":15266,"children":17436},[17437],{"id":15269,"depth":115,"text":15270},{"id":10199,"depth":83,"text":10199},{"id":15960,"depth":83,"text":15960,"children":17440},[17441,17442],{"id":15969,"depth":115,"text":15970},{"id":16396,"depth":115,"text":16396,"children":17443},[17444],{"id":17067,"depth":142,"text":17068},{"id":17105,"depth":83,"text":17105,"children":17446},[17447],{"id":17347,"depth":115,"text":17348},{"id":17387,"depth":83,"text":17387},{"id":7438,"depth":83,"text":17408},[1423],"2020-08-27","oncrete5にVueCLIを使ってUIを構築する。データの登録。",{},{"title":14997,"description":17452},"series\u002Fconcrete5vue-2",[14992,1433,204],"s28kXBmZtYl1vPtmgjcP0QiTjdZEL9Zwpvzi-377-0o",{"id":17459,"title":15004,"body":17460,"category":18117,"createdAt":18118,"description":14989,"extension":1426,"index":55,"meta":18119,"navigation":339,"path":18120,"publish":339,"seo":18121,"series":14988,"seriesTitle":14989,"stem":18122,"tag":18123,"thumbnail":14993,"updatedAt":1427,"__hash__":18124},"series\u002Fseries\u002Fconcrete5vue-1.md",{"type":10,"value":17461,"toc":18104},[17462,17465,17468,17472,17475,17537,17540,17543,17546,17549,17560,17563,17567,17570,17573,17576,17579,17582,17588,17591,17594,17600,17603,17609,17615,17637,17640,17643,17646,17649,17652,17665,17771,17777,17787,17794,17950,17965,17976,17982,18044,18050,18053,18056,18060,18086,18089,18095,18098,18101],[13,17463,17464],{},"こんにちはjunです。今回はconcrete5というCMSでVueを使ったパッケージのUIを作成していこうと思います。今回の記事ではコンポーネントを作成する前の、concrete5にvueプロジェクトを作成してCMSに結びつける環境構築まで行います。",[13,17466,17467],{},"またConcrete5とそのカスタマイズ方法についてある程度熟知している人向け、基準としてはカスタムパッケージを作成したことがある人向けの記事となります。対象とするConcrete5のバージョンは8.4以降となります。",[17,17469,17471],{"id":17470},"なぜvue","なぜVue？",[13,17473,17474],{},"なぜVueを使うのか。それはPHPとjqueryによるUI構築が非常に面倒になったからです。Concrete5にはフォーム（テキストエリアとかCMSからのファイル選択フォーム）をPHPで出力してくれる以下の様なヘルパーが存在します。",[42,17476,17478],{"className":6114,"code":17477,"language":6117,"meta":47,"style":47},"\u002F\u002F ヘルパーを読み込む\n$form = Core::make('helper\u002Fform');\n\n\u002F\u002Fテキストinput\necho $form->text($name, $default_value);\n\n\u002F\u002Fテキストエリア\necho $form-> textarea($name, $default_value);\n\n\u002F\u002F ファイルマネージャーヘルパー\n$file_selector = Core::make('helper\u002Fconcrete\u002Ffile_manager');\necho $file_selector->file('label', 'name_attr', 'Select Photo', $default_fileObj);\n",[49,17479,17480,17485,17490,17494,17499,17504,17508,17513,17518,17522,17527,17532],{"__ignoreMap":47},[52,17481,17482],{"class":54,"line":55},[52,17483,17484],{},"\u002F\u002F ヘルパーを読み込む\n",[52,17486,17487],{"class":54,"line":83},[52,17488,17489],{},"$form = Core::make('helper\u002Fform');\n",[52,17491,17492],{"class":54,"line":115},[52,17493,340],{"emptyLinePlaceholder":339},[52,17495,17496],{"class":54,"line":142},[52,17497,17498],{},"\u002F\u002Fテキストinput\n",[52,17500,17501],{"class":54,"line":169},[52,17502,17503],{},"echo $form->text($name, $default_value);\n",[52,17505,17506],{"class":54,"line":302},[52,17507,340],{"emptyLinePlaceholder":339},[52,17509,17510],{"class":54,"line":308},[52,17511,17512],{},"\u002F\u002Fテキストエリア\n",[52,17514,17515],{"class":54,"line":318},[52,17516,17517],{},"echo $form-> textarea($name, $default_value);\n",[52,17519,17520],{"class":54,"line":328},[52,17521,340],{"emptyLinePlaceholder":339},[52,17523,17524],{"class":54,"line":4},[52,17525,17526],{},"\u002F\u002F ファイルマネージャーヘルパー\n",[52,17528,17529],{"class":54,"line":343},[52,17530,17531],{},"$file_selector = Core::make('helper\u002Fconcrete\u002Ffile_manager');\n",[52,17533,17534],{"class":54,"line":353},[52,17535,17536],{},"echo $file_selector->file('label', 'name_attr', 'Select Photo', $default_fileObj);\n",[13,17538,17539],{},"上記のコードをページ上で実行すれば以下の様にフォームが現れます。",[728,17541],{":src":17542,":width":731},"'_mix\u002Fformhelpertest-768x272.png'",[13,17544,17545],{},"上から順番にテキストインプット、テキストエリア、そしてconcrete５純正のファイルマネージャーが出現します。name属性が与えられ、postを通じてデータを送ることができます。",[13,17547,17548],{},"簡単なブロックやパッケージUIであれば問題ないのですが、",[1854,17550,17551,17554,17557],{},[1699,17552,17553],{},"フロント側のバリデーションを実装する",[1699,17555,17556],{},"決まったフォームを複数生成する",[1699,17558,17559],{},"フォーム同士が入力値で依存させる場合（入力値でフォームのパターンが変わる）",[13,17561,17562],{},"上記の際にPHPとjqueryだけでは非常に苦労して工数もかかります。",[1721,17564,17566],{"id":17565},"vueを使えばリッチなuiが作成可能","Vueを使えばリッチなUIが作成可能",[13,17568,17569],{},"今流行りのリッチなUI、フォームはほとんどがVue、React、Backbone,jsなどHTMLテンプレート、jsによる状態管理を行うことで簡単に実装できます。工数を抑えつつも、これらのライブラリを用いることでリッチなUIを作成することもできます。",[13,17571,17572],{},"今回の記事ではVue CLIを用いて作成したUIをconcrete5のパッケージ上で表示させ、入力内容の追加・更新・削除まで行える様に実装していきます。原理がわかれば意外と簡単です。",[17,17574,17575],{"id":17575},"パッケージの制作準備",[1721,17577,17578],{"id":17578},"パッケージの専用のディレクトリを作成",[13,17580,17581],{},"それではVueで構築したUIを持つパッケージを作成していきましょう。pckageディレクトリ配下にvuetestというカスタムパッケージディレクトリを作ります。またディレクトリ構成は以下の通りにします。",[42,17583,17586],{"className":17584,"code":17585,"language":451},[1727],"documentroot $ cd .\u002Fpackage\npackage $ mkdir vuetest && touch ...\npackage $ tree vuetest\n.\u002F\n└── vuetest\n    ├── controller.php\n    ├── controllers\n    │   └── single_page\n    │       └── dashboard\n    │           └── vuetest.php\n    ├── db.xml\n    ├── icon.png\n    ├── js\n    │\n    └── single_pages\n        └── dashboard\n            └── vuetest\n                └── view.php\n",[49,17587,17585],{"__ignoreMap":47},[1721,17589,17590],{"id":17590},"vueプロジェクトを作成",[13,17592,17593],{},"パッケージに必要なコントローラーやUIを表示するダッシュボード上のシングルページとそのコントローラーも用意します。そしてjsディレクトリを作成してその中にvue cliを用いてプロジェクトを作成します。",[42,17595,17598],{"className":17596,"code":17597,"language":451},[1727],"package $ cd vuetest\u002Fjs\njs $ vue create packageui\n\nVue CLI v4.4.6\n? Please pick a preset: default (babel, eslint) #default\n\nVue CLI v4.4.6\n✨  Creating project in documentroot\u002Fvuetest\u002Fjs\u002Fpackageui.\n🗃  Initializing git repository...\n⚙️  Installing CLI plugins. This might take a while... \n\n🎉  Successfully created project packageui.\n\njs $ cd packageui && tree -L 1\n.\n├── README.md\n├── babel.config.js\n├── node_modules\n├── package-lock.json\n├── package.json\n├── public\n",[49,17599,17597],{"__ignoreMap":47},[13,17601,17602],{},"無事にvueのプロジェクトが作成されました。concrete5との都合によりvue.config.jsファイルを作成してwebpackの設定をいじります。",[42,17604,17607],{"className":17605,"code":17606,"language":451},[1727],"packageui $ touch vue.config.js\n",[49,17608,17606],{"__ignoreMap":47},[42,17610,17613],{"className":17611,"code":17612,"language":451},[1727],"module.exports = {\n    configureWebpack: {\n      output: {\n        filename: '[name].js',\n        chunkFilename: '[name].js'\n      }\n    },\n  }\n",[49,17614,17612],{"__ignoreMap":47},[13,17616,17617,17618,407,17621,17624,17625,17628,17629,17632,17633,17636],{},"これは ",[49,17619,17620],{},"npm run build",[49,17622,17623],{},"npm run build --mode development","で",[49,17626,17627],{},".vue","ファイルを",[49,17630,17631],{},".js","ファイルにコンパイルして",[49,17634,17635],{},"\u002Fdist","配下に配置される時に名前がいつも同じになる様に設定します。",[13,17638,17639],{},"buildをするとビルドされたファイルの名前にはハッシュされた英数字がつくのですが、これがビルドの度にころころ変わります。Concrete5でjsファイルをロードする場合は設定した名前が一致しないと読み込めませんので、ビルドの際に設定を変えなくて済む様に上記の設定をします。",[4424,17641,17642],{"id":17642},"もし複数のパッケージで共通のvueファイルを用いる場合",[13,17644,17645],{},"今回は vuetestというパッケージとそのディレクトリ配下に専用のvueプロジェクトを作成しますす。しかし複数のパッケージでvueファイルを使用したい場合、applicationディレクトリにjsディレクトリを作成し、vueプロジェクトを作成してください。",[1721,17647,17648],{"id":17648},"コンパイルしたjsファイルをconcrete5と結びつける",[13,17650,17651],{},"vue cliでビルドするとdist配下にコンパイルされたjsファイルが生成されます。そのファイルとレンダー先のconcrete5上のページ（シングルページ）で読み込める様に、このjsファイルをCMSが読み込める様に設定します。",[13,17653,17654,17655,17657,17658,17660,17661,17664],{},"まずとりあえず以下の",[49,17656,1769],{},"をビルドしてみます。レンダリング先に ",[49,17659,15828],{}," という要素があれば",[49,17662,17663],{},"Appコンポーネント","がレンダーされます。",[42,17666,17668],{"className":1249,"code":17667,"filename":1764,"language":1251,"meta":47,"style":47},"import Vue from 'vue'\nimport App from '.\u002FApp.vue'\n\nVue.config.productionTip = false\n\nnew Vue({\n  render: h => h(App),\n}).$mount('#app')\n",[49,17669,17670,17684,17700,17704,17720,17724,17734,17751],{"__ignoreMap":47},[52,17671,17672,17674,17676,17678,17680,17682],{"class":54,"line":55},[52,17673,1847],{"class":359},[52,17675,6824],{"class":105},[52,17677,1976],{"class":359},[52,17679,1979],{"class":58},[52,17681,204],{"class":75},[52,17683,5629],{"class":58},[52,17685,17686,17688,17691,17693,17695,17698],{"class":54,"line":83},[52,17687,1847],{"class":359},[52,17689,17690],{"class":105}," App ",[52,17692,1976],{"class":359},[52,17694,1979],{"class":58},[52,17696,17697],{"class":75},".\u002FApp.vue",[52,17699,5629],{"class":58},[52,17701,17702],{"class":54,"line":115},[52,17703,340],{"emptyLinePlaceholder":339},[52,17705,17706,17708,17710,17712,17714,17716,17718],{"class":54,"line":142},[52,17707,2829],{"class":105},[52,17709,956],{"class":58},[52,17711,12526],{"class":105},[52,17713,956],{"class":58},[52,17715,12531],{"class":105},[52,17717,69],{"class":58},[52,17719,12536],{"class":2160},[52,17721,17722],{"class":54,"line":169},[52,17723,340],{"emptyLinePlaceholder":339},[52,17725,17726,17728,17730,17732],{"class":54,"line":302},[52,17727,15891],{"class":58},[52,17729,7020],{"class":417},[52,17731,931],{"class":105},[52,17733,363],{"class":58},[52,17735,17736,17738,17740,17742,17744,17746,17749],{"class":54,"line":308},[52,17737,15902],{"class":417},[52,17739,372],{"class":58},[52,17741,12610],{"class":985},[52,17743,2282],{"class":65},[52,17745,12610],{"class":417},[52,17747,17748],{"class":105},"(App)",[52,17750,383],{"class":58},[52,17752,17753,17755,17757,17759,17761,17763,17765,17767,17769],{"class":54,"line":318},[52,17754,1311],{"class":58},[52,17756,937],{"class":105},[52,17758,956],{"class":58},[52,17760,7049],{"class":417},[52,17762,931],{"class":105},[52,17764,375],{"class":58},[52,17766,7056],{"class":75},[52,17768,375],{"class":58},[52,17770,1014],{"class":105},[42,17772,17775],{"className":17773,"code":17774,"language":451},[1727],"packageui ＄ npm run build\n.\n├── README.md\n├── babel.config.js\n├── dist\n│   ├── app.js\n│   ├── app.js.map\n│   ├── chunk-vendors.js\n│   ├── chunk-vendors.js.map\n│   ├── css\n│   ├── favicon.ico\n│   ├── img\n│   └── index.html\n├\n",[49,17776,17774],{"__ignoreMap":47},[13,17778,17779,17780,2388,17783,17786],{},"ビルド成功。いらないものもありますが、",[49,17781,17782],{},"app.js",[49,17784,17785],{},"chunk-vendors.js","が読み込まれる様にすればOKです。",[13,17788,17789,17790,17793],{},"パッケージ専用のjsファイルで作成する場合はパッケージのインストールコントローラ（",[49,17791,17792],{},"package\u002Fvuetest\u002Fcontroller.php","）に以下の様な記述をします。",[42,17795,17798],{"className":6114,"code":17796,"filename":17797,"language":6117,"meta":47,"style":47},"\u003C?php\nnamespace Concrete\\Package\\Vuetest;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Asset\\AssetList;\nuse \\Concrete\\Core\\Asset\\Asset;\n\nclass Controller extends \\Concrete\\Core\\Package\\Package {\n    protected $pkgHandle = 'vuetest';\n    protected $appVersionRequired = '5.7.4';\n    protected $pkgVersion = '1.0.0';\n\n    public function on_start()\n    {\n        $al = AssetList::getInstance();\n        $al->register(\n            'javascript', 'package-vue-build', 'js\u002Fpackageui\u002Fdist\u002Fapp.js',\n            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n            $this->pkgHandle\n        );\n        \n        $al->register(\n            'javascript', 'package-vue-chunk', 'js\u002Fpackageui\u002Fdist\u002Fchunk-vendors.js',\n            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n            $this->pkgHandle\n        );\n        \n        $al->registerGroup('package-vue-production', array(\n            array('javascript', 'package-vue-build'),\n            array('javascript', 'package-vue-chunk'),\n        )); \n    }\n...\n}\n","controller.php",[49,17799,17800,17804,17809,17813,17818,17823,17827,17832,17837,17842,17847,17851,17855,17859,17864,17869,17874,17879,17884,17889,17893,17897,17902,17906,17910,17914,17918,17923,17928,17933,17938,17942,17946],{"__ignoreMap":47},[52,17801,17802],{"class":54,"line":55},[52,17803,12309],{},[52,17805,17806],{"class":54,"line":83},[52,17807,17808],{},"namespace Concrete\\Package\\Vuetest;\n",[52,17810,17811],{"class":54,"line":115},[52,17812,12314],{},[52,17814,17815],{"class":54,"line":142},[52,17816,17817],{},"use \\Concrete\\Core\\Asset\\AssetList;\n",[52,17819,17820],{"class":54,"line":169},[52,17821,17822],{},"use \\Concrete\\Core\\Asset\\Asset;\n",[52,17824,17825],{"class":54,"line":302},[52,17826,340],{"emptyLinePlaceholder":339},[52,17828,17829],{"class":54,"line":308},[52,17830,17831],{},"class Controller extends \\Concrete\\Core\\Package\\Package {\n",[52,17833,17834],{"class":54,"line":318},[52,17835,17836],{},"    protected $pkgHandle = 'vuetest';\n",[52,17838,17839],{"class":54,"line":328},[52,17840,17841],{},"    protected $appVersionRequired = '5.7.4';\n",[52,17843,17844],{"class":54,"line":4},[52,17845,17846],{},"    protected $pkgVersion = '1.0.0';\n",[52,17848,17849],{"class":54,"line":343},[52,17850,340],{"emptyLinePlaceholder":339},[52,17852,17853],{"class":54,"line":353},[52,17854,17184],{},[52,17856,17857],{"class":54,"line":366},[52,17858,12757],{},[52,17860,17861],{"class":54,"line":386},[52,17862,17863],{},"        $al = AssetList::getInstance();\n",[52,17865,17866],{"class":54,"line":414},[52,17867,17868],{},"        $al->register(\n",[52,17870,17871],{"class":54,"line":426},[52,17872,17873],{},"            'javascript', 'package-vue-build', 'js\u002Fpackageui\u002Fdist\u002Fapp.js',\n",[52,17875,17876],{"class":54,"line":434},[52,17877,17878],{},"            array('version' => '1.0.0', 'position' => Asset::ASSET_POSITION_FOOTER, 'combine' => true),\n",[52,17880,17881],{"class":54,"line":445},[52,17882,17883],{},"            $this->pkgHandle\n",[52,17885,17886],{"class":54,"line":479},[52,17887,17888],{},"        );\n",[52,17890,17891],{"class":54,"line":508},[52,17892,15500],{},[52,17894,17895],{"class":54,"line":538},[52,17896,17868],{},[52,17898,17899],{"class":54,"line":546},[52,17900,17901],{},"            'javascript', 'package-vue-chunk', 'js\u002Fpackageui\u002Fdist\u002Fchunk-vendors.js',\n",[52,17903,17904],{"class":54,"line":552},[52,17905,17878],{},[52,17907,17908],{"class":54,"line":558},[52,17909,17883],{},[52,17911,17912],{"class":54,"line":563},[52,17913,17888],{},[52,17915,17916],{"class":54,"line":568},[52,17917,15500],{},[52,17919,17920],{"class":54,"line":1105},[52,17921,17922],{},"        $al->registerGroup('package-vue-production', array(\n",[52,17924,17925],{"class":54,"line":1134},[52,17926,17927],{},"            array('javascript', 'package-vue-build'),\n",[52,17929,17930],{"class":54,"line":1163},[52,17931,17932],{},"            array('javascript', 'package-vue-chunk'),\n",[52,17934,17935],{"class":54,"line":1192},[52,17936,17937],{},"        )); \n",[52,17939,17940],{"class":54,"line":1199},[52,17941,3753],{},[52,17943,17944],{"class":54,"line":1204},[52,17945,11397],{},[52,17947,17948],{"class":54,"line":1209},[52,17949,535],{},[13,17951,17952,17953,17956,17957,17960,17961,17964],{},"vuetestパッケージのコントローラーで",[49,17954,17955],{},"$al->register","を用いて、パスで指定したjsファイルを登録します。２つあるのでを",[49,17958,17959],{},"$al->registerGroup","用いてのp",[49,17962,17963],{},"ackage-vue-production","名前で２つのjsファイルを読み込む様にグルーピングします。",[13,17966,17967,17968,17971,17972,17975],{},"concrete5ではこの様なjs\u002Fcssのアセット登録システムがあり、登録をすれば適当にアセットが読み込むことができる様になります。",[7814,17969,17970],{},"パッケージのコントローラーでは登録をした"," ので、次はjsファイルが必要な",[7814,17973,17974],{},"ページのコントローラーで呼び出し"," を行います。",[13,17977,17978,17981],{},[49,17979,17980],{},"vuetest\u002Fsingle_pages\u002Fdashboard\u002Fvuetest\u002Fview.php"," に以下の様に記述します。",[42,17983,17985],{"className":6114,"code":17984,"language":6117,"meta":47,"style":47},"\u003C?php\nnamespace Concrete\\Package\\Vuetest\\Controller\\SinglePage\\Dashboard;\ndefined('C5_EXECUTE') or die('Access Denied.');\nuse \\Concrete\\Core\\Page\\Controller\\DashboardPageController;\n\nclass Vuetest extends DashboardPageController\n{\n    public $packageHandle = 'vuetest';\n\n    public function view() {\n        $this->requireAsset('package-vue-production');\n        $this->set('success', 'My success message');\n    }\n}\n",[49,17986,17987,17991,17995,17999,18003,18007,18011,18015,18019,18023,18027,18031,18036,18040],{"__ignoreMap":47},[52,17988,17989],{"class":54,"line":55},[52,17990,12309],{},[52,17992,17993],{"class":54,"line":83},[52,17994,17122],{},[52,17996,17997],{"class":54,"line":115},[52,17998,12314],{},[52,18000,18001],{"class":54,"line":142},[52,18002,17131],{},[52,18004,18005],{"class":54,"line":169},[52,18006,340],{"emptyLinePlaceholder":339},[52,18008,18009],{"class":54,"line":302},[52,18010,15294],{},[52,18012,18013],{"class":54,"line":308},[52,18014,363],{},[52,18016,18017],{"class":54,"line":318},[52,18018,15303],{},[52,18020,18021],{"class":54,"line":328},[52,18022,340],{"emptyLinePlaceholder":339},[52,18024,18025],{"class":54,"line":4},[52,18026,15335],{},[52,18028,18029],{"class":54,"line":343},[52,18030,15322],{},[52,18032,18033],{"class":54,"line":353},[52,18034,18035],{},"        $this->set('success', 'My success message');\n",[52,18037,18038],{"class":54,"line":366},[52,18039,3753],{},[52,18041,18042],{"class":54,"line":386},[52,18043,535],{},[13,18045,15426,18046,18049],{},[49,18047,18048],{},"$this->requireAsset('package-vue-production');","で「先ほど登録したjsアセットをこのページで読み込め！」と命令しています。設定した後、実際に該当ページで探してみましょう。",[728,18051],{":src":18052,":width":731},"'_mix\u002Fsc-2020-08-01-19.52.09-768x133.png'",[13,18054,18055],{},"いました。\u002Fpackages\u002Fvuetest\u002Fjs\u002Fdist\u002F** と指定したパスにて読み込まれています。それではid=\"app\"を持つ適当なdivを作成して再度みてみましょう。",[13,18057,18058,7383],{},[49,18059,17980],{},[42,18061,18063],{"className":6114,"code":18062,"filename":14514,"language":6117,"meta":47,"style":47},"\u003C?php\ndefined('C5_EXECUTE') or die('Access Denied.');\n?>\n\n\u003Cdiv id=\"app\">\u003C\u002Fdiv>\n",[49,18064,18065,18069,18073,18077,18081],{"__ignoreMap":47},[52,18066,18067],{"class":54,"line":55},[52,18068,12309],{},[52,18070,18071],{"class":54,"line":83},[52,18072,12314],{},[52,18074,18075],{"class":54,"line":115},[52,18076,12319],{},[52,18078,18079],{"class":54,"line":142},[52,18080,340],{"emptyLinePlaceholder":339},[52,18082,18083],{"class":54,"line":169},[52,18084,18085],{},"\u003Cdiv id=\"app\">\u003C\u002Fdiv>\n",[728,18087],{":src":18088,":width":10193,":center":1322},"'_mix\u002Fsh-2020-08-01-19.56.01-768x812.png'",[13,18090,18091,18092,18094],{},"パスの関係上レイアウトが崩れ、画像が読み込めていませんがvue側で記述した内容が無事にレンダリングされています。これでvueとconcrete5のセッティングは完了です。vueプロジェクトでコンポーネントを作成しながら、適切な",[49,18093,7516],{},"を用いてページ上にレンダーします。",[17,18096,18097],{"id":18097},"次はフォームコンポーネントの作成",[13,18099,18100],{},"以上がconcrete5のパッケージ上にvueプロジェクトを作成して、concrete5に結びつける方法でした。これでvueを使え、レンダーされる環境は整ったので次は情報を登録するための登録フォームと編集画面の作成を行っていきます。",[1413,18102,18103],{},"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 pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}",{"title":47,"searchDepth":115,"depth":115,"links":18105},[18106,18109,18116],{"id":17470,"depth":83,"text":17471,"children":18107},[18108],{"id":17565,"depth":115,"text":17566},{"id":17575,"depth":83,"text":17575,"children":18110},[18111,18112,18115],{"id":17578,"depth":115,"text":17578},{"id":17590,"depth":115,"text":17590,"children":18113},[18114],{"id":17642,"depth":142,"text":17642},{"id":17648,"depth":115,"text":17648},{"id":18097,"depth":83,"text":18097},[1423],"2020-08-25",{},"\u002Fseries\u002Fconcrete5vue-1",{"title":15004,"description":14989},"series\u002Fconcrete5vue-1",[14992,1433,204],"SFdt3_VrU2GVgYjfNjC32zyOKCtr79IKO3992JqFQJo",1780987133094]