[{"data":1,"prerenderedAt":1157},["ShallowReactive",2],{"post-document:\u002Ffrontend\u002Fvue\u002F2026\u002F07\u002F30\u002Fvue_intro1\u002F":3},{"id":4,"title":5,"body":6,"categories":959,"date":962,"description":963,"extension":964,"image":965,"key_concepts":966,"last_modified_at":965,"legacyPath":970,"meta":971,"navigation":98,"part":965,"path":1141,"published":98,"robots":965,"seo":1142,"series":965,"stem":1143,"strengths":1144,"summary":1147,"tags":1148,"tradeoffs":1153,"__hash__":1156},"posts\u002Fposts\u002FFrontend\u002FVue\u002F2026-07-30-vue_intro1.md","01. Vue.js 입문: 핵심 구조와 렌더링",{"type":7,"value":8,"toc":941},"minimark",[9,14,23,34,37,123,126,129,132,135,251,255,260,267,311,315,325,400,416,420,423,429,436,559,570,574,577,580,583,589,596,603,728,732,735,741,744,770,774,783,787,790,804,807,833,836,839,843,846,881,884,887,897,903,907,935,938],[10,11,13],"h2",{"id":12},"vuejs란","Vue.js란?",[15,16,17,18,22],"p",{},"Vue.js는 사용자 인터페이스를 만들기 위한 JavaScript 프레임워크다. 핵심은 ",[19,20,21],"strong",{},"상태를 직접 DOM에 맞춰 관리하는 대신, 상태와 화면의 관계를 선언하는 것","이다.",[24,25,31],"pre",{"className":26,"code":28,"language":29,"meta":30},[27],"language-text","사용자 행동\n  ↓\n상태 변경\n  ↓\nVue의 반응성 시스템\n  ↓\n필요한 화면 갱신\n","text","",[32,33,28],"code",{"__ignoreMap":30},[15,35,36],{},"순수 JavaScript에서는 변경할 요소를 찾고 값을 직접 바꾼다.",[24,38,42],{"className":39,"code":40,"language":41,"meta":30,"style":30},"language-js shiki shiki-themes github-light github-dark","const countElement = document.querySelector('#count')\nlet count = 0\n\ncount += 1\ncountElement.textContent = count\n","js",[32,43,44,78,93,100,112],{"__ignoreMap":30},[45,46,49,53,57,60,64,68,71,75],"span",{"class":47,"line":48},"line",1,[45,50,52],{"class":51},"szBVR","const",[45,54,56],{"class":55},"sj4cs"," countElement",[45,58,59],{"class":51}," =",[45,61,63],{"class":62},"sVt8B"," document.",[45,65,67],{"class":66},"sScJk","querySelector",[45,69,70],{"class":62},"(",[45,72,74],{"class":73},"sZZnC","'#count'",[45,76,77],{"class":62},")\n",[45,79,81,84,87,90],{"class":47,"line":80},2,[45,82,83],{"class":51},"let",[45,85,86],{"class":62}," count ",[45,88,89],{"class":51},"=",[45,91,92],{"class":55}," 0\n",[45,94,96],{"class":47,"line":95},3,[45,97,99],{"emptyLinePlaceholder":98},true,"\n",[45,101,103,106,109],{"class":47,"line":102},4,[45,104,105],{"class":62},"count ",[45,107,108],{"class":51},"+=",[45,110,111],{"class":55}," 1\n",[45,113,115,118,120],{"class":47,"line":114},5,[45,116,117],{"class":62},"countElement.textContent ",[45,119,89],{"class":51},[45,121,122],{"class":62}," count\n",[15,124,125],{},"만약 프로젝트에서 관리할 요소가 많아진다면, 일일히 다 관리하는 것은 분명히 무리일것이다.",[15,127,128],{},"다행히도 Vue는 이러한 변경 요소를 자동으로 처리해준다.",[15,130,131],{},"개발자는 DOM 변경 순서보다 데이터 흐름과 사용자 동작에 집중할 수 있다.",[15,133,134],{},"Vue에서는 상태를 바꾸면 템플릿이 그 상태를 따라 갱신된다.",[24,136,140],{"className":137,"code":138,"language":139,"meta":30,"style":30},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"count++\">{{ count }}\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n","vue",[32,141,142,157,171,175,194,203,208,218,242],{"__ignoreMap":30},[45,143,144,147,151,154],{"class":47,"line":48},[45,145,146],{"class":62},"\u003C",[45,148,150],{"class":149},"s9eBZ","script",[45,152,153],{"class":66}," setup",[45,155,156],{"class":62},">\n",[45,158,159,162,165,168],{"class":47,"line":80},[45,160,161],{"class":51},"import",[45,163,164],{"class":62}," { ref } ",[45,166,167],{"class":51},"from",[45,169,170],{"class":73}," 'vue'\n",[45,172,173],{"class":47,"line":95},[45,174,99],{"emptyLinePlaceholder":98},[45,176,177,179,182,184,187,189,192],{"class":47,"line":102},[45,178,52],{"class":51},[45,180,181],{"class":55}," count",[45,183,59],{"class":51},[45,185,186],{"class":66}," ref",[45,188,70],{"class":62},[45,190,191],{"class":55},"0",[45,193,77],{"class":62},[45,195,196,199,201],{"class":47,"line":114},[45,197,198],{"class":62},"\u003C\u002F",[45,200,150],{"class":149},[45,202,156],{"class":62},[45,204,206],{"class":47,"line":205},6,[45,207,99],{"emptyLinePlaceholder":98},[45,209,211,213,216],{"class":47,"line":210},7,[45,212,146],{"class":62},[45,214,215],{"class":149},"template",[45,217,156],{"class":62},[45,219,221,224,227,230,232,235,238,240],{"class":47,"line":220},8,[45,222,223],{"class":62},"  \u003C",[45,225,226],{"class":149},"button",[45,228,229],{"class":66}," @click",[45,231,89],{"class":62},[45,233,234],{"class":73},"\"count++\"",[45,236,237],{"class":62},">{{ count }}\u003C\u002F",[45,239,226],{"class":149},[45,241,156],{"class":62},[45,243,245,247,249],{"class":47,"line":244},9,[45,246,198],{"class":62},[45,248,215],{"class":149},[45,250,156],{"class":62},[10,252,254],{"id":253},"vue의-네-가지-핵심","Vue의 네 가지 핵심",[256,257,259],"h3",{"id":258},"_1-선언적-렌더링","1. 선언적 렌더링",[15,261,262,263,266],{},"템플릿에는 상태가 화면에 ",[19,264,265],{},"어떻게 보일지"," 작성한다. 상태가 바뀌면 Vue가 화면을 다시 계산한다.",[268,269,270,283],"table",{},[271,272,273],"thead",{},[274,275,276,280],"tr",{},[277,278,279],"th",{},"명령형 DOM 조작",[277,281,282],{},"Vue의 선언적 렌더링",[284,285,286,295,303],"tbody",{},[274,287,288,292],{},[289,290,291],"td",{},"변경할 요소를 직접 찾는다.",[289,293,294],{},"상태와 템플릿의 관계를 작성한다.",[274,296,297,300],{},[289,298,299],{},"DOM 수정 시점을 직접 관리한다.",[289,301,302],{},"Vue가 상태 변경을 추적한다.",[274,304,305,308],{},[289,306,307],{},"화면이 커질수록 변경 코드가 흩어지기 쉽다.",[289,309,310],{},"화면 로직을 컴포넌트 안에 모을 수 있다.",[256,312,314],{"id":313},"_2-반응성","2. 반응성",[15,316,317,320,321,324],{},[32,318,319],{},"ref()","와 ",[32,322,323],{},"reactive()","로 만든 상태는 변경을 추적할 수 있다. Vue는 렌더링에 사용된 상태가 바뀌면 관련 부분을 자동으로 갱신한다.",[24,326,328],{"className":39,"code":327,"language":41,"meta":30,"style":30},"import { reactive, ref } from 'vue'\n\nconst count = ref(0)\nconst user = reactive({\n  name: 'Lee',\n  loggedIn: false\n})\n",[32,329,330,341,345,361,376,387,395],{"__ignoreMap":30},[45,331,332,334,337,339],{"class":47,"line":48},[45,333,161],{"class":51},[45,335,336],{"class":62}," { reactive, ref } ",[45,338,167],{"class":51},[45,340,170],{"class":73},[45,342,343],{"class":47,"line":80},[45,344,99],{"emptyLinePlaceholder":98},[45,346,347,349,351,353,355,357,359],{"class":47,"line":95},[45,348,52],{"class":51},[45,350,181],{"class":55},[45,352,59],{"class":51},[45,354,186],{"class":66},[45,356,70],{"class":62},[45,358,191],{"class":55},[45,360,77],{"class":62},[45,362,363,365,368,370,373],{"class":47,"line":102},[45,364,52],{"class":51},[45,366,367],{"class":55}," user",[45,369,59],{"class":51},[45,371,372],{"class":66}," reactive",[45,374,375],{"class":62},"({\n",[45,377,378,381,384],{"class":47,"line":114},[45,379,380],{"class":62},"  name: ",[45,382,383],{"class":73},"'Lee'",[45,385,386],{"class":62},",\n",[45,388,389,392],{"class":47,"line":205},[45,390,391],{"class":62},"  loggedIn: ",[45,393,394],{"class":55},"false\n",[45,396,397],{"class":47,"line":210},[45,398,399],{"class":62},"})\n",[401,402,403,410],"ul",{},[404,405,406,409],"li",{},[32,407,408],{},"ref",": 하나의 값이나 교체할 객체를 다룰 때 기본적으로 사용한다. (실무에서는 일단 ref를 고정으로 두고 쓴다한다.)",[404,411,412,415],{},[32,413,414],{},"reactive",": 관련된 여러 값을 객체로 묶어 다룰 때 사용할 수 있다.",[256,417,419],{"id":418},"_3-컴포넌트","3. 컴포넌트",[15,421,422],{},"Vue는 화면을 독립적이고 재사용 가능한 컴포넌트로 나눈다.",[24,424,427],{"className":425,"code":426,"language":29,"meta":30},[27],"App\n├── AppHeader\n├── ProductList\n│   └── ProductCard\n└── AppFooter\n",[32,428,426],{"__ignoreMap":30},[15,430,431,432,435],{},"각 컴포넌트는 보통 하나의 ",[32,433,434],{},".vue"," 파일에 템플릿, 로직, 스타일을 함께 담는다. 이를 SFC(Single-File Component)라고 한다.",[24,437,439],{"className":137,"code":438,"language":139,"meta":30,"style":30},"\u003Cscript setup>\nconst message = 'Vue 시작!'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Ch1>{{ message }}\u003C\u002Fh1>\n\u003C\u002Ftemplate>\n\n\u003Cstyle scoped>\nh1 {\n  color: #42b883;\n}\n\u003C\u002Fstyle>\n",[32,440,441,451,463,471,475,483,497,505,509,521,529,544,550],{"__ignoreMap":30},[45,442,443,445,447,449],{"class":47,"line":48},[45,444,146],{"class":62},[45,446,150],{"class":149},[45,448,153],{"class":66},[45,450,156],{"class":62},[45,452,453,455,458,460],{"class":47,"line":80},[45,454,52],{"class":51},[45,456,457],{"class":55}," message",[45,459,59],{"class":51},[45,461,462],{"class":73}," 'Vue 시작!'\n",[45,464,465,467,469],{"class":47,"line":95},[45,466,198],{"class":62},[45,468,150],{"class":149},[45,470,156],{"class":62},[45,472,473],{"class":47,"line":102},[45,474,99],{"emptyLinePlaceholder":98},[45,476,477,479,481],{"class":47,"line":114},[45,478,146],{"class":62},[45,480,215],{"class":149},[45,482,156],{"class":62},[45,484,485,487,490,493,495],{"class":47,"line":205},[45,486,223],{"class":62},[45,488,489],{"class":149},"h1",[45,491,492],{"class":62},">{{ message }}\u003C\u002F",[45,494,489],{"class":149},[45,496,156],{"class":62},[45,498,499,501,503],{"class":47,"line":210},[45,500,198],{"class":62},[45,502,215],{"class":149},[45,504,156],{"class":62},[45,506,507],{"class":47,"line":220},[45,508,99],{"emptyLinePlaceholder":98},[45,510,511,513,516,519],{"class":47,"line":244},[45,512,146],{"class":62},[45,514,515],{"class":149},"style",[45,517,518],{"class":66}," scoped",[45,520,156],{"class":62},[45,522,524,526],{"class":47,"line":523},10,[45,525,489],{"class":149},[45,527,528],{"class":62}," {\n",[45,530,532,535,538,541],{"class":47,"line":531},11,[45,533,534],{"class":55},"  color",[45,536,537],{"class":62},": ",[45,539,540],{"class":55},"#42b883",[45,542,543],{"class":62},";\n",[45,545,547],{"class":47,"line":546},12,[45,548,549],{"class":62},"}\n",[45,551,553,555,557],{"class":47,"line":552},13,[45,554,198],{"class":62},[45,556,515],{"class":149},[45,558,156],{"class":62},[15,560,561,562,565,566,569],{},"컴포넌트 사이에서는 보통 부모가 ",[32,563,564],{},"props","로 데이터를 내려주고, 자식이 ",[32,567,568],{},"emit","으로 이벤트를 알린다.",[256,571,573],{"id":572},"_4-렌더링과-virtual-dom","4. 렌더링과 Virtual DOM",[15,575,576],{},"HTML은 문서이고, DOM(Document Object Model)은 브라우저가 HTML을 메모리에 객체 트리로 표현한 결과다.",[15,578,579],{},"JavaScript와 Vue는 이 DOM을 통해 화면을 변경한다.",[15,581,582],{},"Vue의 기본 렌더링 흐름은 다음과 같다.",[24,584,587],{"className":585,"code":586,"language":29,"meta":30},[27],"템플릿 + 상태\n  ↓\nVirtual DOM 생성\n  ↓\n이전 결과와 새 결과 비교\n  ↓\n필요한 실제 DOM 반영\n",[32,588,586],{"__ignoreMap":30},[15,590,591,592,595],{},"Vue가 관리하는 DOM을 ",[32,593,594],{},"querySelector()","로 자주 직접 수정하면 상태와 화면이 서로 달라질 수 있다.",[15,597,598,599,602],{},"DOM 접근이 꼭 필요하면 템플릿 ref와 ",[32,600,601],{},"onMounted()","를 사용한다.",[24,604,606],{"className":137,"code":605,"language":139,"meta":30,"style":30},"\u003Cscript setup>\nimport { onMounted, ref } from 'vue'\n\nconst inputElement = ref(null)\n\nonMounted(() => {\n  inputElement.value?.focus()\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput ref=\"inputElement\" \u002F>\n\u003C\u002Ftemplate>\n",[32,607,608,618,629,633,651,655,668,679,683,691,695,703,720],{"__ignoreMap":30},[45,609,610,612,614,616],{"class":47,"line":48},[45,611,146],{"class":62},[45,613,150],{"class":149},[45,615,153],{"class":66},[45,617,156],{"class":62},[45,619,620,622,625,627],{"class":47,"line":80},[45,621,161],{"class":51},[45,623,624],{"class":62}," { onMounted, ref } ",[45,626,167],{"class":51},[45,628,170],{"class":73},[45,630,631],{"class":47,"line":95},[45,632,99],{"emptyLinePlaceholder":98},[45,634,635,637,640,642,644,646,649],{"class":47,"line":102},[45,636,52],{"class":51},[45,638,639],{"class":55}," inputElement",[45,641,59],{"class":51},[45,643,186],{"class":66},[45,645,70],{"class":62},[45,647,648],{"class":55},"null",[45,650,77],{"class":62},[45,652,653],{"class":47,"line":114},[45,654,99],{"emptyLinePlaceholder":98},[45,656,657,660,663,666],{"class":47,"line":205},[45,658,659],{"class":66},"onMounted",[45,661,662],{"class":62},"(() ",[45,664,665],{"class":51},"=>",[45,667,528],{"class":62},[45,669,670,673,676],{"class":47,"line":210},[45,671,672],{"class":62},"  inputElement.value?.",[45,674,675],{"class":66},"focus",[45,677,678],{"class":62},"()\n",[45,680,681],{"class":47,"line":220},[45,682,399],{"class":62},[45,684,685,687,689],{"class":47,"line":244},[45,686,198],{"class":62},[45,688,150],{"class":149},[45,690,156],{"class":62},[45,692,693],{"class":47,"line":523},[45,694,99],{"emptyLinePlaceholder":98},[45,696,697,699,701],{"class":47,"line":531},[45,698,146],{"class":62},[45,700,215],{"class":149},[45,702,156],{"class":62},[45,704,705,707,710,712,714,717],{"class":47,"line":546},[45,706,223],{"class":62},[45,708,709],{"class":149},"input",[45,711,186],{"class":66},[45,713,89],{"class":62},[45,715,716],{"class":73},"\"inputElement\"",[45,718,719],{"class":62}," \u002F>\n",[45,721,722,724,726],{"class":47,"line":552},[45,723,198],{"class":62},[45,725,215],{"class":149},[45,727,156],{"class":62},[10,729,731],{"id":730},"vue와-spa","Vue와 SPA",[15,733,734],{},"SPA(Single Page Application)는 최초에 애플리케이션을 불러온 뒤, 이동할 때 페이지 전체를 다시 받기보다 필요한 화면과 데이터를 바꾸는 방식이다.",[24,736,739],{"className":737,"code":738,"language":29,"meta":30},[27],"브라우저\n├── Vue Router: URL과 화면 연결\n├── Pinia: 여러 화면이 공유하는 상태\n└── fetch\u002FAxios: API 통신\n",[32,740,738],{"__ignoreMap":30},[256,742,743],{"id":743},"장점",[401,745,746,754,762],{},[404,747,748,749],{},"페이지 전환이 자연스럽고 애플리케이션 같은 사용자 경험을 만들기 좋다.\n",[401,750,751],{},[404,752,753],{},"사용자에게 압도적인 UX 경험 전달해줌",[404,755,756,757],{},"프론트엔드 화면과 백엔드 API의 역할을 분리하기 쉽다.\n",[401,758,759],{},[404,760,761],{},"MVVM 모델을 생각해보자!",[404,763,764,765],{},"이미 받은 CSS와 JavaScript를 재사용하며 필요한 데이터만 요청할 수 있다.\n",[401,766,767],{},[404,768,769],{},"데이터 전송량을 아낄 수 있는 장점이 있다.",[771,772,773],"h4",{"id":773},"참고자료",[15,775,776],{},[777,778,782],"a",{"href":779,"rel":780},"https:\u002F\u002Flearn.microsoft.com\u002Fko-kr\u002Fdotnet\u002Farchitecture\u002Fmaui\u002Fmvvm",[781],"nofollow",".NET MAUI MVVM 아키텍처 공식 문서",[256,784,786],{"id":785},"고려할-점","고려할 점",[15,788,789],{},"다만 아시다시피 모든 기술 Trade-off 가 존재합니다.. 장점만 있는 것은 아니다.",[401,791,792,795,798,801],{},[404,793,794],{},"첫 화면에 필요한 JavaScript가 크면 초기 로딩이 느려질 수 있다.",[404,796,797],{},"새로고침해도 같은 URL이 열리도록 서버의 fallback 설정이 필요하다.",[404,799,800],{},"CSR만 사용하면 검색 엔진과 링크 미리보기를 위한 별도 전략이 필요할 수 있다.",[404,802,803],{},"상태가 많아지면 지역 상태와 전역 상태의 경계를 정해야 한다.",[15,805,806],{},"다행히도 이런 문제를 해결할 방법들이 존재한다.",[401,808,809,817,825],{},[404,810,811,812],{},"코드 분할(Code Splitting):",[401,813,814],{},[404,815,816],{},"애플리케이션 코드를 여러 파일로 나누고, 필요한 시점에 필요한 코드만 불러오는 방식. 초기 로딩 속도를 줄이는 데 사용",[404,818,819,820],{},"SSR(Server-Side Rendering):",[401,821,822],{},[404,823,824],{},"서버에서 HTML을 먼저 완성해 브라우저에 전달하는 방식. 초기 화면 표시가 빠르고 SEO에 유리.",[404,826,827,828],{},"SSG(Static Site Generation):",[401,829,830],{},[404,831,832],{},"빌드 시점에 HTML 파일을 미리 생성해 두고 사용자에게 제공하는 방식. 속도가 빠르고 서버 부담이 적다.",[15,834,835],{},"아무튼!",[15,837,838],{},"모든 Vue 프로젝트가 SPA일 필요는 없으므로 서비스의 요구 사항에 맞춰 선택한다.",[10,840,842],{"id":841},"학습-순서","학습 순서",[15,844,845],{},"추천 순서는 아래와 같다",[847,848,849,852,855,864,875,878],"ol",{},[404,850,851],{},"JavaScript의 객체, 배열, 함수, 모듈, 비동기 문법 (이거는 꼭 해야하는 걸까..)",[404,853,854],{},"템플릿 문법과 디렉티브 (이거는 무적권 해야한다.)",[404,856,857,859,860,863],{},[32,858,408],{},", ",[32,861,862],{},"computed",", 이벤트 처리",[404,865,866,867,859,869,859,871,874],{},"컴포넌트와 ",[32,868,564],{},[32,870,568],{},[32,872,873],{},"slot"," (꽤나 중요하다.)",[404,876,877],{},"Vue Router와 API 통신",[404,879,880],{},"여러 화면이 공유하는 상태가 생길 때 Pinia",[10,882,883],{"id":883},"정리",[256,885,886],{"id":886},"요약",[888,889,890],"blockquote",{},[15,891,892,893,896],{},"상태를 바꾸면 Vue가 그 상태를 사용하는 화면을 갱신한다. ",[894,895],"br",{},"\n그 위에 컴포넌트, 라우팅, 상태 관리, API 통신을 필요한 만큼 조합하면 된다.",[15,898,899],{},[900,901,902],"del",{},"마치 뷔페 와서 먹고 싶은거 담는다고 생각하고 공부하자",[10,904,906],{"id":905},"참고-자료","참고 자료",[401,908,909,916,923,930],{},[404,910,911],{},[777,912,915],{"href":913,"rel":914},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fintroduction.html",[781],"Vue 공식 문서: Introduction",[404,917,918],{},[777,919,922],{"href":920,"rel":921},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Frendering-mechanism.html",[781],"Vue 공식 문서: Rendering Mechanism",[404,924,925],{},[777,926,929],{"href":927,"rel":928},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fscaling-up\u002Fstate-management.html",[781],"Vue 공식 문서: State Management",[404,931,932],{},[777,933,782],{"href":779,"rel":934},[781],[936,937],"hr",{},[515,939,940],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":30,"searchDepth":80,"depth":80,"links":942},[943,944,950,954,955,958],{"id":12,"depth":80,"text":13},{"id":253,"depth":80,"text":254,"children":945},[946,947,948,949],{"id":258,"depth":95,"text":259},{"id":313,"depth":95,"text":314},{"id":418,"depth":95,"text":419},{"id":572,"depth":95,"text":573},{"id":730,"depth":80,"text":731,"children":951},[952,953],{"id":743,"depth":95,"text":743},{"id":785,"depth":95,"text":786},{"id":841,"depth":80,"text":842},{"id":883,"depth":80,"text":883,"children":956},[957],{"id":886,"depth":95,"text":886},{"id":905,"depth":80,"text":906},[960,961],"Frontend","Vue","2026-07-30 20:00:00 +0900","Vue의 선언적 렌더링, 반응성, 컴포넌트 구조와 SPA 동작 방식을 한 번에 정리.","md",null,[967,968,969],"Vue는 상태와 템플릿의 관계를 선언하면 화면 갱신을 처리.","컴포넌트는 화면과 로직을 독립적이고 재사용 가능한 단위로 나눔.","SPA는 페이지 전체 대신 필요한 화면과 데이터만 갱신.","\u002Ffrontend\u002Fvue\u002F2026\u002F07\u002F30\u002Fvue_intro1\u002F",{"layout":972,"excerpt_separator":973,"excerpt":974},"post","\u003C!--more-->",{"type":7,"value":975},[976,978,982,987,989,1041,1043,1045,1047,1049,1139],[10,977,13],{"id":12},[15,979,17,980,22],{},[19,981,21],{},[24,983,985],{"className":984,"code":28,"language":29,"meta":30},[27],[32,986,28],{"__ignoreMap":30},[15,988,36],{},[24,990,991],{"className":39,"code":40,"language":41,"meta":30,"style":30},[32,992,993,1011,1021,1025,1033],{"__ignoreMap":30},[45,994,995,997,999,1001,1003,1005,1007,1009],{"class":47,"line":48},[45,996,52],{"class":51},[45,998,56],{"class":55},[45,1000,59],{"class":51},[45,1002,63],{"class":62},[45,1004,67],{"class":66},[45,1006,70],{"class":62},[45,1008,74],{"class":73},[45,1010,77],{"class":62},[45,1012,1013,1015,1017,1019],{"class":47,"line":80},[45,1014,83],{"class":51},[45,1016,86],{"class":62},[45,1018,89],{"class":51},[45,1020,92],{"class":55},[45,1022,1023],{"class":47,"line":95},[45,1024,99],{"emptyLinePlaceholder":98},[45,1026,1027,1029,1031],{"class":47,"line":102},[45,1028,105],{"class":62},[45,1030,108],{"class":51},[45,1032,111],{"class":55},[45,1034,1035,1037,1039],{"class":47,"line":114},[45,1036,117],{"class":62},[45,1038,89],{"class":51},[45,1040,122],{"class":62},[15,1042,125],{},[15,1044,128],{},[15,1046,131],{},[15,1048,134],{},[24,1050,1051],{"className":137,"code":138,"language":139,"meta":30,"style":30},[32,1052,1053,1063,1073,1077,1093,1101,1105,1113,1131],{"__ignoreMap":30},[45,1054,1055,1057,1059,1061],{"class":47,"line":48},[45,1056,146],{"class":62},[45,1058,150],{"class":149},[45,1060,153],{"class":66},[45,1062,156],{"class":62},[45,1064,1065,1067,1069,1071],{"class":47,"line":80},[45,1066,161],{"class":51},[45,1068,164],{"class":62},[45,1070,167],{"class":51},[45,1072,170],{"class":73},[45,1074,1075],{"class":47,"line":95},[45,1076,99],{"emptyLinePlaceholder":98},[45,1078,1079,1081,1083,1085,1087,1089,1091],{"class":47,"line":102},[45,1080,52],{"class":51},[45,1082,181],{"class":55},[45,1084,59],{"class":51},[45,1086,186],{"class":66},[45,1088,70],{"class":62},[45,1090,191],{"class":55},[45,1092,77],{"class":62},[45,1094,1095,1097,1099],{"class":47,"line":114},[45,1096,198],{"class":62},[45,1098,150],{"class":149},[45,1100,156],{"class":62},[45,1102,1103],{"class":47,"line":205},[45,1104,99],{"emptyLinePlaceholder":98},[45,1106,1107,1109,1111],{"class":47,"line":210},[45,1108,146],{"class":62},[45,1110,215],{"class":149},[45,1112,156],{"class":62},[45,1114,1115,1117,1119,1121,1123,1125,1127,1129],{"class":47,"line":220},[45,1116,223],{"class":62},[45,1118,226],{"class":149},[45,1120,229],{"class":66},[45,1122,89],{"class":62},[45,1124,234],{"class":73},[45,1126,237],{"class":62},[45,1128,226],{"class":149},[45,1130,156],{"class":62},[45,1132,1133,1135,1137],{"class":47,"line":244},[45,1134,198],{"class":62},[45,1136,215],{"class":149},[45,1138,156],{"class":62},[515,1140,940],{},"\u002Fposts\u002Ffrontend\u002Fvue\u002F2026-07-30-vue_intro1",{"title":5,"description":963},"posts\u002FFrontend\u002FVue\u002F2026-07-30-vue_intro1",[1145,1146],"작은 기능부터 점진적으로 도입하기 쉬움.","반응성과 컴포넌트 모델로 UI 상태를 체계적으로 관리할 수 있음.","Vue가 상태 변화를 화면에 반영하는 원리와 컴포넌트 기반 UI, SPA의 장단점을 정리.",[960,1149,1150,1151,1152],"Vue.js","SPA","Rendering","Virtual DOM",[1154,1155],"규모가 커지면 라우팅과 전역 상태의 기준을 따로 정해야 함.","CSR 중심 SPA는 초기 로딩과 SEO 전략을 함께 고려해야 함.","41yzCZaFDqo_Ke29VCBZ5VuVu7pmHcWVUu7ODbmU1iY",1788744789659]