<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Jae Front-end Study</title>
    <link>https://jae-study.tistory.com/</link>
    <description>Studying to become a front-end developer</description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 07:30:21 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>JAEEE</managingEditor>
    <image>
      <title>Jae Front-end Study</title>
      <url>https://tistory1.daumcdn.net/tistory/5394606/attach/34cd9c2c8ebd41acadc256c619d01976</url>
      <link>https://jae-study.tistory.com</link>
    </image>
    <item>
      <title>맥 jupyter notebook 설치하기</title>
      <link>https://jae-study.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;맥 터미널에서 아래 명령어 실행하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. python3 --version&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬이 설치되어 있지 않다면 파이썬부터 설치해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬을 설치하면 pip3도 함께 설치된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. pip3 --version&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. pip3 install --upgrade pip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. pip install jupyter&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 jupyter notebook 실행하면 아래와 같은 화면이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXeWqC/btsMDgO7Xww/XLrgpF85Zd9nuA0rjkzXx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXeWqC/btsMDgO7Xww/XLrgpF85Zd9nuA0rjkzXx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXeWqC/btsMDgO7Xww/XLrgpF85Zd9nuA0rjkzXx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXeWqC%2FbtsMDgO7Xww%2FXLrgpF85Zd9nuA0rjkzXx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1008&quot; height=&quot;308&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;View - Open JupyterLab를 클릭하면 JupyterLab을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JupyterLab&lt;/b&gt;는 Jupyter Notebook의 업그레이드 버전으로, 더 강력한 기능과 개선된 UI를 제공하는 웹 기반 인터페이스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 노트북, 터미널, 텍스트 편집을 한 화면에서 동시에 다룰 수 있는 IDE(통합 개발 환경)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python, Markdown, HTML, JavaScript 등 편집이 가능하고, 다양한 확장 기능(플러그인, 다크 모드, Vim 등)이 추가가 가능하다.&lt;/p&gt;</description>
      <category>기타 개념</category>
      <category>Jupyter Notebook</category>
      <category>jupyter notebook 설치하기</category>
      <category>맥 jupyter notebook</category>
      <category>맥 jupyter notebook 설치</category>
      <category>맥 jupyter notebook 설치하기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/151</guid>
      <comments>https://jae-study.tistory.com/151#entry151comment</comments>
      <pubDate>Thu, 6 Mar 2025 16:51:10 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] Serise(시리즈) 값 수정, 추가, 삭제</title>
      <link>https://jae-study.tistory.com/150</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;값 수정하기&lt;/h3&gt;
&lt;pre id=&quot;code_1740469280602&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pandas import *

data = [1000, 2000, 3000]
index = [&quot;메로나&quot;, &quot;구구콘&quot;, &quot;하겐다즈&quot;]
s = Series(data=data, index=index)

print(s)

# 값 수정
s.iloc[0] = 0
s.loc['구구콘'] = 0
s['하겐다즈'] = 0

print(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSG9qe/btsMxkp8Jrw/AAb1wrJ1E8bSPbLhPQ98r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSG9qe/btsMxkp8Jrw/AAb1wrJ1E8bSPbLhPQ98r0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSG9qe/btsMxkp8Jrw/AAb1wrJ1E8bSPbLhPQ98r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSG9qe%2FbtsMxkp8Jrw%2FAAb1wrJ1E8bSPbLhPQ98r0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;252&quot; height=&quot;358&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;값 삭제하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;drop 메서드는 원본 데이터가 변경되는 것을 방지하기 때문에 시리즈 원본 데이터를 제거하지 않고, 새로운 시리즈 객체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;따라서 변수에 다시 바인딩해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740469587555&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 값 삭제
s = s.drop('메로나')
s = s.drop(['구구콘', '하겐다즈']) # 여러 개 삭제

print(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T0K9K/btsMuwsugWm/Kg3GOP69zKDDb7w6dQEhwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T0K9K/btsMuwsugWm/Kg3GOP69zKDDb7w6dQEhwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T0K9K/btsMuwsugWm/Kg3GOP69zKDDb7w6dQEhwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT0K9K%2FbtsMuwsugWm%2FKg3GOP69zKDDb7w6dQEhwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;410&quot; height=&quot;50&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;50&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;값 추가하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loc[]나 concat() 방법을 가장 많이 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1740469728879&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 값 추가
s['new1'] = 1
s.at[&quot;new2&quot;] = 2
s.loc[&quot;new3&quot;] = 3
s = concat([s, Series([4], index=[&quot;new4&quot;])])

print(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwXegf/btsMvcfYGVt/7cooe63fzmvP0jLeaUoYr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwXegf/btsMvcfYGVt/7cooe63fzmvP0jLeaUoYr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwXegf/btsMvcfYGVt/7cooe63fzmvP0jLeaUoYr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwXegf%2FbtsMvcfYGVt%2F7cooe63fzmvP0jLeaUoYr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;212&quot; height=&quot;222&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Python3</category>
      <category>iloc</category>
      <category>loc</category>
      <category>Python</category>
      <category>Series</category>
      <category>시리즈</category>
      <category>시리즈 값 삭제</category>
      <category>시리즈 값 수정</category>
      <category>시리즈 값 추가</category>
      <category>파이썬</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/150</guid>
      <comments>https://jae-study.tistory.com/150#entry150comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:51:13 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] Serise(시리즈) 값 선택하기 - Indexing(인덱싱), Slicing(슬라이싱)</title>
      <link>https://jae-study.tistory.com/149</link>
      <description>&lt;h3 data-end=&quot;123&quot; data-start=&quot;95&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;iloc (정수 위치 기반 인덱싱)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정수 기반으로 데이터를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리스트처럼 0부터 시작하는 정수 인덱스를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;슬라이싱(:)을 활용하여 여러 개의 값을 선택할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;loc (라벨 기반 인덱싱)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인덱스(라벨) 값을 기준으로 데이터를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;숫자가 아닌 문자열 등 사용자 지정 인덱스를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;범위를 지정할 때 끝값까지 포함한다. (iloc와 차이점)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인덱싱(indexing)과 슬라이싱(slicing)의 차이&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;pandas.Series나 pandas.DataFrame에서 데이터를 선택하는 방법은 크게 두 가지가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인덱싱: 하나의 값 또는 여러 개의 개별 값을 선택&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;슬라이싱: 연속된 범위의 값을 선택&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1739770225537&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pandas as pd

data = [100, 200, 300]
index = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;]
s = pd.Series(data, index)

print(s.iloc[0]) # 100
print(s.iloc[1]) # 200
print(s.iloc[2]) # 300
print(s.iloc[3]) # IndexError

print(s.iloc[-1]) # 300
print(s.iloc[-2]) # 200
print(s.iloc[-3]) # 200
print(s.iloc[-4]) # IndexError

print(s.loc[&quot;월&quot;]) # 100
print(s.loc[&quot;화&quot;]) # 200
print(s.loc[&quot;수&quot;]) # 300

# 인덱싱 (개별 값)
print(s.iloc[[0, 2]]) # 월 100 수 300
print(s.loc[[&quot;월&quot;, &quot;수&quot;]]) # 월 100 수 300

# 슬라이싱 (범위)
print(s.iloc[0:2]) # 월 100 화 200
print(s.loc[&quot;월&quot;:&quot;화&quot;]) # 월 100 화 200&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python3</category>
      <category>iloc</category>
      <category>loc</category>
      <category>Python</category>
      <category>Series</category>
      <category>시리즈</category>
      <category>시리즈 슬라이싱</category>
      <category>시리즈 인덱싱</category>
      <category>파이썬</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/149</guid>
      <comments>https://jae-study.tistory.com/149#entry149comment</comments>
      <pubDate>Mon, 17 Feb 2025 14:40:14 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] Serise(시리즈) 생성</title>
      <link>https://jae-study.tistory.com/148</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Series&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;pandas.Series는 1차원 배열 형태의 데이터 구조고, 인덱스(index)와 값(value)으로 구성된 자료형이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스와 값으로 구성된다. 기본적으로 0부터 시작하는 정수형 인덱스가 자동 할당되지만, 직접 지정할 수도 있다.&lt;/li&gt;
&lt;li&gt;동일한 데이터 타입을 가진다. NumPy 배열(numpy.ndarray)과 유사하지만, 인덱스를 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;딕셔너리와 비슷한 구조이다. 키(key) = 인덱스, 값(value) = 데이터 라고 생각하면 이해하기 쉽다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 시리즈 생성 방법&lt;/p&gt;
&lt;pre id=&quot;code_1739768713210&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import pandas as pd

data = ['가', '나', '다', '라'] # type = list
s = pd.Series(data) # type = pandas.core.series.Series

print(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;144&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eliR63/btsMlpls86d/KEUGllkDIC1Vp7PCBtEXD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eliR63/btsMlpls86d/KEUGllkDIC1Vp7PCBtEXD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eliR63/btsMlpls86d/KEUGllkDIC1Vp7PCBtEXD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeliR63%2FbtsMlpls86d%2FKEUGllkDIC1Vp7PCBtEXD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;144&quot; height=&quot;190&quot; data-origin-width=&quot;144&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 생성되는 정수형 인덱스가 아닌 별도로 지정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1739768799164&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pandas import Series

data = [100, 200, 300]
index = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;]
s = Series(data, index)

print(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;174&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp2fVf/btsMk1SJVhf/21Gkl0Uk2RRyHTScWnqvE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp2fVf/btsMk1SJVhf/21Gkl0Uk2RRyHTScWnqvE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp2fVf/btsMk1SJVhf/21Gkl0Uk2RRyHTScWnqvE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp2fVf%2FbtsMk1SJVhf%2F21Gkl0Uk2RRyHTScWnqvE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;174&quot; height=&quot;138&quot; data-origin-width=&quot;174&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 별도의 변수명으로 지정해도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1739768922847&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pandas import Series

name = [&quot;메로나&quot;, &quot;누가바&quot;, &quot;빠삐코&quot;] # data = name
price = [500, 800, 200] # index = price
menu = Series(name, price)

print(menu)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZjNIA/btsMlhHPd9l/woKEfKHIDCaO8zRVSvJxxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZjNIA/btsMlhHPd9l/woKEfKHIDCaO8zRVSvJxxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZjNIA/btsMlhHPd9l/woKEfKHIDCaO8zRVSvJxxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZjNIA%2FbtsMlhHPd9l%2FwoKEfKHIDCaO8zRVSvJxxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;220&quot; height=&quot;142&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Python3</category>
      <category>Python</category>
      <category>Series</category>
      <category>시리즈</category>
      <category>파이썬</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/148</guid>
      <comments>https://jae-study.tistory.com/148#entry148comment</comments>
      <pubDate>Mon, 17 Feb 2025 14:17:28 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] NumPy(넘파이) 연산</title>
      <link>https://jae-study.tistory.com/147</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;브로드캐스트 (Broadcasting)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;파이썬에서 브로드캐스트는 주로 NumPy 배열에서 사용되는 개념으로, 다양한 크기의 배열들 간에 연산을 가능하게 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;크기가 다른 배열끼리 연산할 때, 작은 배열이 큰 배열의 크기게 맞게 자동으로 확장되어 연산이 이루어지도록 도와준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;즉, 작은 배열이 큰 배열에 맞게 확장되거나 &quot;브로드캐스트&quot; 되어 연산을 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;기본 연산&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739431838700&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np

a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
c = np.array([1, 2, 3, 4, 5]) # a와 c를 연산하면 ValueError가 발생

print(a + b) # [11 22 33]
print(a - b) # [9 18 27]
print(a * b) # [10 40 90]
print(a / b) # [10. 10. 10.]
print(a % b) # [0 0 0]
print(a + 5) # [15, 25, 35]&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1739431861871&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data1 = np.array([1, 2, 3]) # 1D 배열
data2 = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
]) # 2D 배열

print(data1[0]) # 1
print(data2[0]) # [10 20 30]

print(data2[0, 2]) # 30
print(data2[0][2]) # 30

print(data1[1] * 10) # 20
print(data2[1] * 10) # [400 500 600]

print(data1 + data2) # [[11 22 33] [41 52 63] [71 82 93]]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;조건문&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739432881097&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = np.array([10, 20, 30, 40, 50])
cond1 = arr &amp;gt; 10
cond2 = arr &amp;lt; 40

print(arr &amp;gt; 20) # [False False  True  True  True]

print(cond1) # [False  True  True  True  True]
print(cond2) # [ True  True  True False False]

print(arr[cond1 &amp;amp; cond2]) # [20 30]
print(arr[cond1 &amp;amp; cond2] / 10) # [2. 3.]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;함수와 메서드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;axis=0:&amp;nbsp;열 방향(세로) 계산&lt;/li&gt;
&lt;li&gt;axis=1:&amp;nbsp;행 방향(가로) 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1739433274032&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = np.array([10, 20, 30, 40, 50])

print(&quot;합계:&quot;, arr.sum())  # 150
print(&quot;최솟값:&quot;, arr.min())  # 10
print(&quot;최댓값:&quot;, arr.max())  # 50
print(&quot;평균:&quot;, arr.mean())  # 30.0
print(&quot;표준편차:&quot;, arr.std())  # 14.142135623730951
print(&quot;분산:&quot;, arr.var())  # 200.0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1739433298524&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr_2d = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(&quot;전체 합계:&quot;, arr_2d.sum())  # 45

print(&quot;열 방향 합계:&quot;, arr_2d.sum(axis=0))  # [12 15 18]
print(&quot;행 방향 합계:&quot;, arr_2d.sum(axis=1))  # [ 6 15 24]

print(&quot;열 방향 최댓값:&quot;, arr_2d.max(axis=0))  # [7 8 9]
print(&quot;행 방향 최댓값:&quot;, arr_2d.max(axis=1))  # [3 6 9]​&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python3</category>
      <category>Numpy</category>
      <category>Python</category>
      <category>넘파이</category>
      <category>브로드캐스트</category>
      <category>파이썬</category>
      <category>파이썬 브로드캐스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/147</guid>
      <comments>https://jae-study.tistory.com/147#entry147comment</comments>
      <pubDate>Thu, 13 Feb 2025 16:56:36 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] NumPy(넘파이) 기본 개념</title>
      <link>https://jae-study.tistory.com/146</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;NumPy&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;NumPy는 Numerical Python의 약자로, 수치 연산을 효율적으로 처리할 수 있는 파이썬의 핵심 라이브러리이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;배열(Array), 행렬(Matrix), 고차원 배열 및 그에 대한 연산을 지원하고, 수학적&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&amp;middot;과학적 계산을 할 때 필수적으로 사용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;고속 연산:&amp;nbsp; Numpy는 C로 구현되어 있어 파이썬의 기본 리스트보다 훨씬 빠르게 수치 연산을 수행할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다차원 배열 지원: 파이썬의 기본 리스트는 1차원 배열만 지원하지만, Numpy는 다차원 배열을 지원해 다양한 차원의 데이터를 처리할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;백터화 연산: 반복문을 사용하지 않고, 배열에 대한 연산을 백터화하여 빠르게 처리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다양한 수학 함수: 수학 함수, 선형 대수 연산, 푸리에 변환 등 수치적 계산을 위한 함수들을 제공한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;NumPy Install&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1739427676257&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install numpy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;NumPy Import&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1739427755459&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from numpy import *
또는
import numpy as np&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;NumPy Type&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;List (리스트)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리스트는 파이썬의 기본 자료형으로, 순서가 있는 집합이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리스트는 여러 데이터를 순차적으로 저장하고, 다양한 타입의 요소를 포함한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인덱싱, 슬라이싱 등을 통해 요소에 접근할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리스트의 요소를 추가, 수정, 삭제할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;667&quot; data-start=&quot;629&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;numpy.ndarray (NumPy 배열)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;823&quot; data-start=&quot;669&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;고정 크기 배열이고, 메모리 효율적이다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-start=&quot;669&quot; data-end=&quot;823&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다차원 배열 객체로, 고속 연산이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;823&quot; data-start=&quot;669&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;백터화 연산 덕분에 반복문 없이 배열에 대한 연산이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;823&quot; data-start=&quot;669&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동일한 타입의 데이터만 저장할 수 있다. 즉, 하나의 배열 안에는 모든 원소의 데이터 타입이 동일하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1739428285539&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np

data = [1, 2, 3, 4] # type = list
np_data = np.array(data) # type = numpy.ndarray

print(data) # [1, 2, 3, 4]
print(np_data) # [1 2 3 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739428968319&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np

data = [1, 2, 3, 4]

list_arr = data * 10
np_arr = np.array(data) * 10

print(list_arr)
print(np_arr)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcZKSV/btsMhcGLjHb/OUAZwTzGXcR3wk7JlhcKa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcZKSV/btsMhcGLjHb/OUAZwTzGXcR3wk7JlhcKa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcZKSV/btsMhcGLjHb/OUAZwTzGXcR3wk7JlhcKa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcZKSV%2FbtsMhcGLjHb%2FOUAZwTzGXcR3wk7JlhcKa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1914&quot; height=&quot;96&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739429229684&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;multi_arr = np.array([
    [1, 2, 3, 4],
    [10, 20, 30, 40],
    [100, 200, 300, 400]
])

# 행 &amp;gt; 열 순서로 접근
print(multi_arr[0]) # [1 2 3 4]
print(multi_arr[1][2]) # 30
print(multi_arr[1, 2]) # 30
print(multi_arr[:, 3]) # [4 40 400]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Python3</category>
      <category>Numpy</category>
      <category>Python</category>
      <category>넘파이</category>
      <category>파이썬</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/146</guid>
      <comments>https://jae-study.tistory.com/146#entry146comment</comments>
      <pubDate>Thu, 13 Feb 2025 15:49:35 +0900</pubDate>
    </item>
    <item>
      <title>[React Native] Expo로 리액트 네이티브 설치하기</title>
      <link>https://jae-study.tistory.com/145</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왕초보를 위한 React Native 101&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/react-native-for-beginners&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nomadcoders.co/react-native-for-beginners&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;리액트 네이티브란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 네이티브(React Native)는 페이스북이 개발한 오픈 소스 모바일 애플리케이션 프레임워크로서, React와 JavaScript를 사용하여 Android 및 IOS 모바일 애플리케이션을 개발할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리액트를 기반으로 하고 있어 &lt;u&gt;컴포넌트를 사용해 재사용성이 높은 UI 구성요소&lt;/u&gt;를 만들 수 있다.&lt;/li&gt;
&lt;li&gt;앱이 실행 중일 때 코드를 변경하면 &lt;u&gt;핫 리로딩을 통해 변경 사항을 즉시 반영&lt;/u&gt;할 수 있다.&lt;/li&gt;
&lt;li&gt;네이티브 모듈을 통해 &lt;u&gt;카메라, 위치 정보, 파일 시스템 등 네이티브 기능&lt;/u&gt;에 직접 액세스 할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Expo 툴킷&lt;/u&gt;을 사용해 별도의 네이티브 코드를 작성하지 않고, 앱을 빠르게 개발할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리액트 네이티브는 React와 JavaScript를 사용하기 때문에 &lt;u&gt;동일한 코드 베이스로 Android와 IOS 모바일 애플리케이션 개발&lt;/u&gt;이 가능하다.&lt;/li&gt;
&lt;li&gt;리액트 네이티브는 &lt;u&gt;활발한 커뮤니티와 다양한 패키지&lt;/u&gt;를 가지고 있어 문제 해결이나 새로운 기능 추가에 대해 도움을 받을 수 있다.&lt;/li&gt;
&lt;li&gt;네이티브 모듈을 활용해 개발 생산성이 향상된다.&lt;/li&gt;
&lt;li&gt;핫 리로딩 기능이 활용해 개발 주기가 빠르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네이티브 앱(특정 플랫폼 또는 운영 체제에 최적화되어 개발된 모바일 애플리케이션)에 비해 성능의 제약이 있을 수 있다.&lt;/li&gt;
&lt;li&gt;특정 플랫폼에 특화된 기능이 필요한 경우, 네이티브 모듈의 사용해야 해서 추가적인 작업이 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Expo란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expo는 리액트 네이티브 앱을 개발하고 배포하기 위한 도구와 서비스를 제공하는 오픈 소스 프레임워크이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expo를 사용하면 네이티브 개발 환경(Java, Android studio 등)을 설정하는 번거로움 없이 빠르게 리액트 네이티브 애플리케이션을 개발할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Expo로 리액트 네이티브 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://expo.dev/&quot;&gt;https://expo.dev/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706255036529&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lLOVI/hyVb9GrIbp/0rkgnpF7br2Rt30f4QfWxk/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788,https://scrap.kakaocdn.net/dn/bGjg0n/hyVb2m0XvL/ImNZetIVK5tArYkBIGTKg1/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788,https://scrap.kakaocdn.net/dn/ci85Ib/hyU8YmgnMu/KkKD4mQYawEeIkhA20rAK0/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788&quot; data-og-url=&quot;https://expo.dev/&quot; data-og-source-url=&quot;https://expo.dev/&quot; data-og-host=&quot;expo.dev&quot; data-og-description=&quot;Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.&quot; data-og-title=&quot;Expo&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://expo.dev/&quot; data-source-url=&quot;https://expo.dev/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lLOVI/hyVb9GrIbp/0rkgnpF7br2Rt30f4QfWxk/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788,https://scrap.kakaocdn.net/dn/bGjg0n/hyVb2m0XvL/ImNZetIVK5tArYkBIGTKg1/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788,https://scrap.kakaocdn.net/dn/ci85Ib/hyU8YmgnMu/KkKD4mQYawEeIkhA20rAK0/img.jpg?width=1500&amp;amp;height=788&amp;amp;face=0_0_1500_788');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Expo&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;expo.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노마드 강의는 2021년 버전이기 때문에 Expo 공식 문서를 참고해 리액트 네이티브를 설치했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;node 버전 18 이상&lt;/i&gt;&lt;/u&gt;&lt;u&gt;&lt;i&gt;&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. expo-app 설치하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706255333495&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-expo-app 폴더명&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 종속성 설치하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치한 폴더로 이동 후, 아래 패키지를 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706255659028&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx expo install react-dom react-native-web @expo/webpack-config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 웹에서 실행하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에 qr 코드만 나오고 웹이 실행되지 않는다면 w 옵션(open web)을 누른다.&lt;/p&gt;
&lt;pre id=&quot;code_1706255883631&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx expo start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkYDb9/btsD1ap1Qmt/mkfTsoClpDK15jzMTG6awK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkYDb9/btsD1ap1Qmt/mkfTsoClpDK15jzMTG6awK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkYDb9/btsD1ap1Qmt/mkfTsoClpDK15jzMTG6awK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkYDb9%2FbtsD1ap1Qmt%2FmkfTsoClpDK15jzMTG6awK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;579&quot; height=&quot;186&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 웹 결과 화면&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTNpaz/btsD3MO8am9/uQKARtRDDUUnQcXQKsEtn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTNpaz/btsD3MO8am9/uQKARtRDDUUnQcXQKsEtn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTNpaz/btsD3MO8am9/uQKARtRDDUUnQcXQKsEtn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTNpaz%2FbtsD3MO8am9%2FuQKARtRDDUUnQcXQKsEtn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;302&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 모바일(핸드폰)에서 확인하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드를 사용하면 플레이 스토어에서 Expo 앱 설치하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOS를 사용하면 앱 스토어에서 Expo Go 앱 설치하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 설치가 완료된 후, 회원가입과 로그인을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸드폰으로 터미널에 나온 qr 코드를 스캔하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 &lt;u&gt;npx expo login 명령어&lt;/u&gt;를 입력해 expo에 로그인을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMouSv/btsDZ1NR4dn/lZrJecKHT0KXKIkvWWTQmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMouSv/btsDZ1NR4dn/lZrJecKHT0KXKIkvWWTQmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMouSv/btsDZ1NR4dn/lZrJecKHT0KXKIkvWWTQmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMouSv%2FbtsDZ1NR4dn%2FlZrJecKHT0KXKIkvWWTQmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;699&quot; height=&quot;95&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expo 앱에 내 프로젝트가 연결된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;i&gt;※ 주의, 컴퓨터와 핸드폰 와이파이가 같은 인터넷을 사용해야만 핸드폰에서 확인이 가능하다. ※ &lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4RX1r/btsDY9eDOux/KwZffWtCryNV1XElZWYx61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4RX1r/btsDY9eDOux/KwZffWtCryNV1XElZWYx61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4RX1r/btsDY9eDOux/KwZffWtCryNV1XElZWYx61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4RX1r%2FbtsDY9eDOux%2FKwZffWtCryNV1XElZWYx61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;739&quot; height=&quot;398&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 브라우저에서 코딩 및 앱 화면 확인하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://snack.expo.dev/?platform=ios&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://snack.expo.dev/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 브라우저만 사용해서 코딩을 해야 하는 상황이라면 위의 홈페이지에서 작업을 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 설치 없이 중앙 편집기에서 코드를 작성하면 우측에서 IOS, Android, Web의 결과 화면을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 회원가입 및 로그인을 한 후에 저장을 하면 나만의 URL이 생성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;875&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTyTgX/btsD7lkMD8p/OnEzAOSkt8xqszW0KkHIS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTyTgX/btsD7lkMD8p/OnEzAOSkt8xqszW0KkHIS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTyTgX/btsD7lkMD8p/OnEzAOSkt8xqszW0KkHIS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTyTgX%2FbtsD7lkMD8p%2FOnEzAOSkt8xqszW0KkHIS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1401&quot; height=&quot;875&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;875&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>React/React Native</category>
      <category>Expo</category>
      <category>Expo 리액트 네이티브</category>
      <category>react native</category>
      <category>리액트 네이티브</category>
      <category>리액트 네이티브 개념</category>
      <category>리액트 네이티브 개발 환경</category>
      <category>리액트 네이티브 설치하기</category>
      <category>리액트 네이티브 장단점</category>
      <category>리액트 네이티브 특징</category>
      <category>리액트 네이티브 프로젝트 만들기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/145</guid>
      <comments>https://jae-study.tistory.com/145#entry145comment</comments>
      <pubDate>Fri, 26 Jan 2024 17:20:53 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] #4 E2E TESTING - Jest 앤드 투 앤드 테스트</title>
      <link>https://jae-study.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS로&amp;nbsp;API&amp;nbsp;만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/nestjs-fundamentals&quot;&gt;https://nomadcoders.co/nestjs-fundamentals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;e2e-spec.ts&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js에서 E2E(End to End) 테스트는 애플리케이션의 전체적인 동작을 테스트하는 방법 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 e2e-spec.ts 파일이 있을 수 있고, E2E 테스트는 사용자가 실제 애플리케이션을 사용할 때와 유사한 환경에서 동작을 검증할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 HTTP 요청을 서버에 보내고, 응답을 검증하기 때문에 테스트할 때에도 실제 애플리케이션과 동일한 환경을 세팅해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. app.e2e-spec.ts&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;GET 요청 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe('/movies', ~), describe('/movies/:id', ~) 2가지 엔드포인트에 대해 &lt;u&gt;GET 요청을 테스트한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET 요청 시, 값이 있으면 200 응답이 예측되고, 값이 없으면 404 응답이 예측된다.&lt;/p&gt;
&lt;pre id=&quot;code_1704870313809&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('AppController (e2e)', () =&amp;gt; {
  describe('/movies', () =&amp;gt; {
    it('GET 200', () =&amp;gt; {
      return request(app.getHttpServer())
        .get('/movies')
        .expect(200)
        .expect([])
    });
  });

  describe('/movies/:id', () =&amp;gt; {
    it('GET 200', () =&amp;gt; {
      return request(app.getHttpServer())
        .get('/movies/1')
        .expect(200)
    });

    it('GET 404', () =&amp;gt; {
      return request(app.getHttpServer())
        .get('/movies/999')
        .expect(404)
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;POST 요청 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;describe('/movies', ~),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;describe('/movies/:id', ~)&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2가지 엔드포인트에 대해 &lt;u&gt;POST 요청을 테스트한다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;POST 요청 시, 올바른 값을 전송하면 201 응답이 예측되고, 잘못된 값을 전송하면 400 응답이 예측된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704870841029&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('AppController (e2e)', () =&amp;gt; {
  describe('/movies', () =&amp;gt; {
    it('POST 201', () =&amp;gt; {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test',
          year: 2024,
          genres: ['Test'],
        })
        .expect(201)
    });

    it('POST 400', () =&amp;gt; {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          name: 'Name',
        })
        .expect(400)
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DELETE 요청 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;describe('/movies', ~),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;describe('/movies/:id', ~)&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2가지 엔드포인트에 대해 &lt;u&gt;DELETE 요청을 테스트한다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;DELETE 요청 시, 전체 배열은 삭제할 수 없기 때문에 404 응답이 예측되고, 하나의 배열은 삭제할 수 있기 때문에 200 응답이 예측된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704870936649&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('AppController (e2e)', () =&amp;gt; {
  describe('/movies', () =&amp;gt; {
    it('DELETE 404', () =&amp;gt; {
      return request(app.getHttpServer())
        .delete('/movies')
        .expect(404)
    });
  });

  describe('/movies/:id', () =&amp;gt; {
    it('DELETE 200', () =&amp;gt; {
      return request(app.getHttpServer())
        .delete('/movies/1')
        .expect(200)
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PATCH 요청 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe('/movies/:id', ~) &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;엔드포인트에 대해&lt;u&gt;&lt;span&gt; PATCH&lt;/span&gt;&amp;nbsp;요청을 테스트한다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PATCH 요청 시, 올바른 값을 전송하면 200 응답이 예측되고, 잘못된 값을 전송하면 400 응답이 예측된다.&lt;/p&gt;
&lt;pre id=&quot;code_1704871110191&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('AppController (e2e)', () =&amp;gt; {
  describe('/movies/:id', () =&amp;gt; {
    it('PATCH 200', () =&amp;gt; {
      return request(app.getHttpServer())
        .patch('/movies/1')
        .send({ title: 'Update title' })
        .expect(200)
    });
    
    it('PATCH 400', () =&amp;gt; {
      return request(app.getHttpServer())
        .patch('/movies/1')
        .send({ name: 'Update name' })
        .expect(400)
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 테스트 환경 맞추기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;test/app.e2e-spec.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/main.ts 파일에서 파이프 옵션을 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;E2E 테스트는 실제 애플리케이션과 테스트 환경이 동일해야 하기 때문에 main.ts에서 설정한 옵션들을 spec.ts 파일에도 동일하게 설정한다. (app.useGlobalPipes() 부분)&lt;/p&gt;
&lt;pre id=&quot;code_1704871834192&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from &quot;@nestjs/common&quot;;
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () =&amp;gt; {
  let app: INestApplication;

  beforeAll(async () =&amp;gt; {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    app.useGlobalPipes(new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
      }),
    );

    await app.init();
  });

  describe('/movies', () =&amp;gt; {
      ...
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 터미널에서 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;e2e-spec 파일에 대해 테스트가 진행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1704872119256&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run test:e2e&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbkrai/btsDj0HQH5m/v2P0yDKKAzl2DG08nGb66K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbkrai/btsDj0HQH5m/v2P0yDKKAzl2DG08nGb66K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbkrai/btsDj0HQH5m/v2P0yDKKAzl2DG08nGb66K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbkrai%2FbtsDj0HQH5m%2Fv2P0yDKKAzl2DG08nGb66K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;293&quot; height=&quot;401&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>NestJs/Nest 기초</category>
      <category>nest</category>
      <category>nest e2e test</category>
      <category>nest e2e 테스트</category>
      <category>nest e2e 테스트 환경</category>
      <category>nest e2e-spec.ts</category>
      <category>nest Jest test</category>
      <category>nest Jest 테스트</category>
      <category>nest spec.ts</category>
      <category>Nest.js</category>
      <category>네스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/144</guid>
      <comments>https://jae-study.tistory.com/144#entry144comment</comments>
      <pubDate>Wed, 10 Jan 2024 16:41:01 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] #3 UNIT TESTING - 단위 테스트</title>
      <link>https://jae-study.tistory.com/143</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS로&amp;nbsp;API&amp;nbsp;만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/nestjs-fundamentals&quot;&gt;https://nomadcoders.co/nestjs-fundamentals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;spec.ts&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js에서 spec.ts 파일은 유닛 테스트를 작성하는 데 사용하는 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 모듈, 서비스, 컨트롤러 등의 단위에 대해 테스트를 정의하는 데 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 Nest.js에서 유닛 테스트를 하기 위해 Jest 프레임워크를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json 파일을 보면 이미 jest 설정이 되어있는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Jest&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;describe 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;describe 함수는 테스트 파일이나 테스트 블록을 정의할 때 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704784160299&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('Math operations', () =&amp;gt; {
  // 덧셈에 대한 테스트 그룹
  describe('Addition', () =&amp;gt; {
    it('should correctly add two numbers', () =&amp;gt; {
      const result = 1 + 2;
      expect(result).toBe(3);
    });
  });

  // 뺄셈에 대한 테스트 그룹
  describe('Subtraction', () =&amp;gt; {
    it('should correctly subtract two numbers', () =&amp;gt; {
      const result = 5 - 2;
      expect(result).toBe(3);
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;it 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;it 함수는 테스트 케이스를 정의할 때 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704782195953&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('테스트 설명', () =&amp;gt; {
  // 테스트 로직
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;expect 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;expect 함수는 예상한 결과와 실제 결과를 비교하고, 테스트가 성공적으로 통과했는지 여부를 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑에 예시에서 result가 배열의 인스턴스인지 검사한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704782618826&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('should return an array', () =&amp;gt; {
  const result = someFunction();
  expect(result).toBeInstanceOf(Array);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAqzOm/btsDav9Kyhe/s2FUXlVULw321ostlUH3zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAqzOm/btsDav9Kyhe/s2FUXlVULw321ostlUH3zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAqzOm/btsDav9Kyhe/s2FUXlVULw321ostlUH3zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAqzOm%2FbtsDav9Kyhe%2Fs2FUXlVULw321ostlUH3zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;209&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;209&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. service.spec.ts&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;getAll 메서드 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;getAll 메서드로 가지고 온 값이 Array 인스턴스인지 확인한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704781792853&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('MoviesService', () =&amp;gt; {
  describe('getAll', () =&amp;gt; {
    it('should return an array', () =&amp;gt; {
      const result = service.getAll();
      expect(result).toBeInstanceOf(Array);
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;getOne 메서드 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;service.create로 영화 데이터를 만든다.&lt;/li&gt;
&lt;li&gt;getOne 메서드로 id가 1인 영화 데이터를 가지고 와 id가 1이 맞는지 비교한다.&lt;/li&gt;
&lt;li&gt;id가 1이 아니라면(getOne(999)) 404 에러를 발생시킨다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704782453808&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('MoviesService', () =&amp;gt; {
  describe('getOne', () =&amp;gt; {
    it('should return a movie', () =&amp;gt; {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const movie = service.getOne(1);
      expect(movie).toBeDefined();
      expect(movie.id).toEqual(1);
    });

    it('should throw 404 error', () =&amp;gt; {
      try {
        service.getOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;deleteOne 메서드 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;service.create로 영화 데이터를 만든다.&lt;/li&gt;
&lt;li&gt;getAll 메서드로 영화의 길이를 변수에 저장한다.&lt;/li&gt;
&lt;li&gt;deleteOne 메서드로 id가 1인 영화를 삭제한다.&lt;/li&gt;
&lt;li&gt;그 후 다시 getAll 메서드로 영화의 길이를 변수에 저장해 영화를 삭제하기 전과 후의 값을 비교한다.&lt;/li&gt;
&lt;li&gt;없는 id의 영화(deleteOne(999))를 삭제하면 404 에러를 발생시킨다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704783100014&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('MoviesService', () =&amp;gt; {
  describe('deleteOne', () =&amp;gt; {
    it('deletes a movie', () =&amp;gt; {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const beforeDelete = service.getAll().length;
      service.deleteOne(1);

      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(beforeDelete);
    });

    it('should return a 404', () =&amp;gt; {
      try {
        service.deleteOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;create 메서드 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;getAll 메서드로 영화의 길이를 변수에 저장한다.&lt;/li&gt;
&lt;li&gt;create 메서드로 새로운 영화를 생성한다.&lt;/li&gt;
&lt;li&gt;그 후 다시 getAll 메서드로 영화의 길이를 변수에 저장해 영화를 생성하기 전과 후의 값을 비교한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704783901676&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('MoviesService', () =&amp;gt; {
  describe('create', () =&amp;gt; {
    it('should create a movie', () =&amp;gt; {
      const beforeCreate = service.getAll().length;

      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const afterCreate = service.getAll().length;
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;update 메서드 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;service.create로 영화 데이터를 만든다.&lt;/li&gt;
&lt;li&gt;update 메서드로 id가 1인 영화의 title을 수정한다.&lt;/li&gt;
&lt;li&gt;getOne 메서드로 해당 영화를 가져와 영화의 title이 'Updated Test'가 맞는지 비교한다.&lt;/li&gt;
&lt;li&gt;없는 id의 영화(update())를 수정하면 404 에러를 발생시킨다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704784509796&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe('MoviesService', () =&amp;gt; {
  describe('update', () =&amp;gt; {
    it('should throw a NotFoundException', () =&amp;gt; {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      service.update(1, { title: 'Updated Test' });

      const movie = service.getOne(1);
      expect(movie.title).toEqual('Updated Test');

      try {
        service.update(999, {});
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 터미널에서 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 spec 파일에 대해 테스트가 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;:watch 옵션을 사용하면 저장할 때마다 자동으로 테스트를 시작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704786280858&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run test
또는
npm run test:watch&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A3jJ2/btsC7mTf49g/eUGrzefMIUVQ25fytfJKe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A3jJ2/btsC7mTf49g/eUGrzefMIUVQ25fytfJKe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A3jJ2/btsC7mTf49g/eUGrzefMIUVQ25fytfJKe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA3jJ2%2FbtsC7mTf49g%2FeUGrzefMIUVQ25fytfJKe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;380&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.service.spec.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1704785974951&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';
import { NotFoundException } from '@nestjs/common';

describe('MoviesService', () =&amp;gt; {
  let service: MoviesService;
  let testMovie;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [MoviesService],
    }).compile();

    service = module.get&amp;lt;MoviesService&amp;gt;(MoviesService);

    // 테스트에 사용될 영화 객체 생성, id는 자동으로 생성됨
    testMovie = {
      title: 'Test Movie',
      year: 2024,
      genres: ['Test'],
    };
  });

  describe('getAll', () =&amp;gt; {
    it('should return an array', () =&amp;gt; {
      expect(service.getAll()).toBeInstanceOf(Array);
    });
  });

  describe('getOne', () =&amp;gt; {
    it('should return a movie', () =&amp;gt; {
      service.create(testMovie);

      const movie = service.getOne(1);
      expect(movie).toBeDefined();
      expect(movie.id).toEqual(1);
    });

    it('should throw 404 error', () =&amp;gt; {
      try {
        service.getOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });

  describe('deleteOne', () =&amp;gt; {
    it('deletes a movie', () =&amp;gt; {
      service.create(testMovie);

      const beforeDelete = service.getAll().length;
      
      service.deleteOne(1);

      const afterDelete = service.getAll().length;
      expect(beforeDelete).toBeLessThan(afterDelete);
    });

    it('should return a 404', () =&amp;gt; {
      try {
        service.deleteOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });

  describe('create', () =&amp;gt; {
    it('should create a movie', () =&amp;gt; {
      const beforeCreate = service.getAll().length;

      service.create(testMovie);

      const afterCreate = service.getAll().length;
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    });
  });

  describe('update', () =&amp;gt; {
    it('should throw a NotFoundException', () =&amp;gt; {
      service.create(testMovie);

      service.update(1, { title: 'Updated Test' });

      const movie = service.getOne(1);
      expect(movie.title).toEqual('Updated Test');

      try {
        service.update(999, {});
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});&lt;/code&gt;&lt;/pre&gt;</description>
      <category>NestJs/Nest 기초</category>
      <category>nest</category>
      <category>nest Jest test</category>
      <category>nest Jest 테스트</category>
      <category>nest spec.ts</category>
      <category>nest unit test</category>
      <category>nest unit testing</category>
      <category>nest unit 테스트</category>
      <category>nest unit 테스트 환경</category>
      <category>Nest.js</category>
      <category>네스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/143</guid>
      <comments>https://jae-study.tistory.com/143#entry143comment</comments>
      <pubDate>Tue, 9 Jan 2024 16:47:29 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] #2.2 REST API - DTO</title>
      <link>https://jae-study.tistory.com/142</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS로&amp;nbsp;API&amp;nbsp;만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/nestjs-fundamentals&quot;&gt;https://nomadcoders.co/nestjs-fundamentals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/entities/movies.entity.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entity 파일은 데이터베이스의 테이블과 상호 작용하기 위해 데이터 모델을 정의하고 캡슐화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 정의된 값(id, title, year, geners)이 아닌 다른 값(hacked)을 전송해도 HTTP 요청을 성공적으로 처리한다. (Status 200)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 문제를 해결하기 위해서는 DTO를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704346629407&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class Movie {
  id: number;
  title: string;
  year: number;
  genres: string[];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPXsnS/btsC4wglSyI/K3ukk2qBdaRaL3kXnpgPB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPXsnS/btsC4wglSyI/K3ukk2qBdaRaL3kXnpgPB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPXsnS/btsC4wglSyI/K3ukk2qBdaRaL3kXnpgPB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPXsnS%2FbtsC4wglSyI%2FK3ukk2qBdaRaL3kXnpgPB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1005&quot; height=&quot;446&quot; data-origin-width=&quot;1005&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DTO란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 전송 객체(DTO, Data Transfer Object)는 클라이언트와 서버 간 데이터 교환을 위한 객체로 사용된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트에서 서버로 데이터를 전송할 때 정확한 데이터 형식을 정의할 수 있어 잘못된 데이터 전송을 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;클라이언트가 전송하는 데이터는 종종 서버에서 사용되는 형식과 다를 수 있는데 DTO를 사용해 서버에서 필요한 형식으로 변환할 수 있다.&lt;/li&gt;
&lt;li&gt;필요한 데이터만 전송받아 불필요한 정보 노출을 방지해 보안을 강화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. create DTO 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/dto/create-movies.dto.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;dto 폴더를 만들고, create-movies.dto.ts 파일을 만든다.&lt;/li&gt;
&lt;li&gt;class-validator, class-transformer 패키지를 설치한다. 이 패키지들은 데이터 유효성 검사와 객체 변환을 쉽게 수행할 수 있도록 도와준다. (@IsString(), @IsNumber(), @IsOptional(), @MinLength() 등..)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704347284572&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install class-validator class-transformer&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1704347235564&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { IsString, IsNumber, IsOptional } from &quot;class-validator&quot;;

export class CreateMoviesDto {
  @IsString()
  readonly title: string;

  @IsNumber()
  readonly year: number;

  @IsOptional()
  @IsString({ each: true })
  readonly genres: string[];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. update DTO 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/dto/update-movies.dto.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;dto 폴더에 update-movies.dto.ts 파일을 만든다.&lt;/li&gt;
&lt;li&gt;PartialType()은 DTO 클래스의 모든 필드를 선택적으로 만들어주는 역할을 하고, 부분 업데이트를 수행할 때 사용한다. &lt;span style=&quot;color: #111827; text-align: left;&quot;&gt;CreateMoviesDto의 모든 필드를 선택적으로 가지게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #111827; text-align: left;&quot;&gt;업데이트는 모든 필드의 수정이 필요 없기 때문에 ? 물음표를 사용해 선택 속성임을 나타낸다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704432282054&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { IsString, IsNumber } from 'class-validator';
import { PartialType } from '@nestjs/mapped-types';
import { CreateMoviesDto } from './create-movies.dto';

export class UpdateMoviesDto extends PartialType(CreateMoviesDto) {
  @IsString()
  readonly title?: string;

  @IsNumber()
  readonly year?: number;

  @IsString({ each: true })
  readonly genres?: string[];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. DTO import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.service.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CreateMoviesDto, UpdateMoviesDto를 import 한다.&lt;/li&gt;
&lt;li&gt;create 함수에 movieData 데이터 타입을&lt;span&gt;&amp;nbsp;&lt;/span&gt;CreateMoviesDto로 명시한다.&lt;/li&gt;
&lt;li&gt;update 함수에 updateData 데이터 타입을 UpdateMoviesDto로 명시한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704433337257&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { CreateMoviesDto } from './dto/create-movies.dto';
import { UpdateMoviesDto } from './dto/update-movies.dto';
...

@Injectable()
export class MoviesService {
  private movies: Movie[] = [];

  create(movieData: CreateMoviesDto) {
    this.movies.push({
      id: this.movies.length + 1,
      ...movieData,
    });
  }

  update(id: number, updateData: UpdateMoviesDto) {
    const movie = this.getOne(id);

    this.deleteOne(id);
    this.movies.push({ ...movie, ...updateData });
  }
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.controller.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CreateMoviesDto, UpdateMoviesDto를 import 한다.&lt;/li&gt;
&lt;li&gt;POST 요청을 보낼 때 데이터 타입을 CreateMoviesDto로 명시한다.&lt;/li&gt;
&lt;li&gt;PATCH 요청을 보낼 때 데이터 타입을 UpdateMoviesDto로 명시한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704433063199&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { CreateMoviesDto } from './dto/create-movies.dto';
import { UpdateMoviesDto } from './dto/update-movies.dto';
...

@Controller('movies') // Entry Point(URL)
export class MoviesController {
  constructor(private readonly moviesService: MoviesService) {}

  @Post()
  create(@Body() movieData: CreateMoviesDto) {
    return this.moviesService.create(movieData);
  }

  @Patch('/:id')
  patch(@Param('id') movieId: number, @Body() updateData: UpdateMoviesDto) {
    return this.moviesService.update(movieId, updateData);
  }
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 결과 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO에 정의되지 않은 속성 또는 잘못된 타입을 POST 하면 에러 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;메세지가&amp;nbsp;&lt;/span&gt;나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmMxB/btsC4rMnjMU/4PfwDlKim8ZJb9P1fFFSv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmMxB/btsC4rMnjMU/4PfwDlKim8ZJb9P1fFFSv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmMxB/btsC4rMnjMU/4PfwDlKim8ZJb9P1fFFSv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvmMxB%2FbtsC4rMnjMU%2F4PfwDlKim8ZJb9P1fFFSv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1010&quot; height=&quot;579&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO에 정의되지 않은 속성 또는 잘못된 타입을 PATCH 하면 에러 메세지가 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nIheF/btsC1nR1tv8/xdAnXo0jSNbpb3Vbn1UuyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nIheF/btsC1nR1tv8/xdAnXo0jSNbpb3Vbn1UuyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nIheF/btsC1nR1tv8/xdAnXo0jSNbpb3Vbn1UuyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnIheF%2FbtsC1nR1tv8%2FxdAnXo0jSNbpb3Vbn1UuyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;564&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>NestJs/Nest 기초</category>
      <category>nest</category>
      <category>nest api</category>
      <category>nest create dto</category>
      <category>nest dto</category>
      <category>nest rest api</category>
      <category>nest update dto</category>
      <category>Nest.js</category>
      <category>nest.js 데이터 전송 객체</category>
      <category>REST API</category>
      <category>네스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/142</guid>
      <comments>https://jae-study.tistory.com/142#entry142comment</comments>
      <pubDate>Fri, 5 Jan 2024 14:48:26 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] #2.1 REST API - 모듈, 컨트롤러, 서비스</title>
      <link>https://jae-study.tistory.com/141</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS로&amp;nbsp;API&amp;nbsp;만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/nestjs-fundamentals&quot;&gt;https://nomadcoders.co/nestjs-fundamentals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0FbGQ/btsCX6oOdBK/jGvo8YO4kAG3OkMXolGvs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0FbGQ/btsCX6oOdBK/jGvo8YO4kAG3OkMXolGvs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0FbGQ/btsCX6oOdBK/jGvo8YO4kAG3OkMXolGvs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0FbGQ%2FbtsCX6oOdBK%2FjGvo8YO4kAG3OkMXolGvs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;135&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 컨트롤러(controller) 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영화 API를 만들 것이기 때문에 컨트롤러의 이름은 movies로 한다. (이름은 API 성격에 맞게 자유롭게 작성하면 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;app.module.ts 파일에서 MoviesController가 자동으로 import 된 것을 확인할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704269530490&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nest generate controller
또는
nest g co&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;참고&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;터미널에서 nest 명령어를 실행하면 nest에서 사용할 수 있는 명령어 리스트를 확인할 수 있다.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deX6vz/btsCWM43FJb/DSQVP2yyvFxbyKfjyfmqKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deX6vz/btsCWM43FJb/DSQVP2yyvFxbyKfjyfmqKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deX6vz/btsCWM43FJb/DSQVP2yyvFxbyKfjyfmqKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeX6vz%2FbtsCWM43FJb%2FDSQVP2yyvFxbyKfjyfmqKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;662&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.controller.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;기본 형태&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704270386197&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller } from '@nestjs/common';

@Controller('movies')
export class MoviesController {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1. @Controller('movies') &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러를 정의하고, 해당 컨트롤러의 &lt;u&gt;기본 URL 경로를 /movies로 지정한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;2. @Get() getAll()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP GET 메서드에 대한 핸들러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/movies 경로의 GET 요청에 대한 응답을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;3. @Get('/:id') getOne()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 URL 파라미터인 :id를 사용해 특정 영화에 대한 정보를 가지고 오는 핸들러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/movies/:id 경로의 GET 요청에 대한 응답을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;4. @Post() create()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP POST 메서드에 대한 핸들러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/movies 경로의 POST 요청에 대한 응답을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;5. @Delete('/:id') remove()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 URL 파라미터인 :id를 사용해 특정 영화에 대한 정보를 삭제하는 핸들러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/movies/:id 경로의 DELETE 요청에 대한 응답을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;6. @Parch('/:id') patch()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 URL 파라미터인 :id를 사용해 특정 영화에 대한 정보를 업데이트하는 핸들러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/movies/:id 경로의 PATCH 요청에 대한 응답을 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704262714967&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get, Post, Delete, Patch, Param, Body } from '@nestjs/common';

@Controller('movies') // Entry Point(URL)
export class MoviesController {
  @Get()
  getAll() {
    return 'This will return all movies.';
  }

  @Get('/:id')
  getOne(@Param('id') movieId: string) {
    return `This will return one movie with the id: ${movieId}`;
  }

  @Post()
  create() {
    return 'This will create a movie.';
  }

  @Delete('/:id')
  remove(@Param('id') movieId: string) {
    return `This will delete a movie with the id: ${movieId}`;
  }

  @Patch('/:id')
  patch(@Param('id') movieId: string) {
    return `This will patch a movie with the id: ${movieId}`;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 서비스(service) 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서비스의 이름은 컨트롤러의 이름과 동일하게 movies로 한다. (네이밍 규칙에 따라 이름을 동일하게 작성한다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;app.module.ts 파일에 MoviesService가 자동으로 import 된 것을 확인할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704271204697&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nest generate services
또는
nest g s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.service.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;기본 형태&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704271356676&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';

@Injectable()
export class MoviesService {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;원래는 데이터베이스가 들어오는 영역&lt;/u&gt;이지만, 데이터베이스를 만들지 않을 것이기 때문에 가짜 데이터베이스를 위한 비즈니스 로직을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;1. private movies&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가짜 데이터베이스를 만들기 위해 빈 배열은 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;2. getAll()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 영화 정보를 반환하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;movies 배열 전체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;3. getOne()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 id에 해당하는 영화 정보를 반환하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;movies 배열에서 해당 id의 영화를 찾아 반환하고, id가 존재하지 않는다면 NotFoundException()을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;4. deleteOne()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 id에 해당하는 영화 정보를 삭제하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getOne() 메서드를 사용해 해당 id의 영화가 존재하는지 확인한 후, 영화를 movies 배열에서 삭제한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;5. create()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 영화 정보를 추가하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;movies 배열에 새로운 영화를 추가하고, id는 현재 배열 길이 +1로 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;6. update()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 id에 해당하는 영화 정보를 업데이트 하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getOne() 메서드를 사용해 해당 id의 영화를 가져와 deleteOne() 메서드를 사용해 삭제한 후, 업데이트된 영화를 movies 배열에 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704271375601&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable, NotFoundException } from &quot;@nestjs/common&quot;;
import { Movie } from './entities/movies.entity';

@Injectable()
export class MoviesService {
  private movies: Movie[] = [];

  getAll(): Movie[] {
    return this.movies;
  }

  getOne(id: string): Movie {
    const movie = this.movies.find((movie) =&amp;gt; movie.id === +id);

    if (!movie) {
      throw new NotFoundException(`Movie with ID: ${id} not found.`);
    }

    return movie;
  }

  deleteOne(id: string) {
    this.getOne(id);
    this.movies = this.movies.filter((movie) =&amp;gt; movie.id !== +id);
  }

  create(movieData) {
    this.movies.push({
      id: this.movies.length + 1,
      ...movieData,
    });
  }

  update(id: string, updateData) {
    const movie = this.getOne(id);
    
    this.deleteOne(id);
    this.movies.push({ ...movie, ...updateData });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2-1. 엔티티(entity) 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/entities/movies.entity.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js는 타입스크립트 기반이기 때문에 데이터 타입을 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704271509173&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class Movie {
  id: number;
  title: string;
  year: number;
  genres: string[];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 컨트롤러 수정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/movies/movies.controller.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번에서 컨트롤러에 대한 개념을 잡기 위해 문자열을 return을 했지만, &lt;u&gt;HTTP 요청을 처리할 수 있도록 서비스에 만든 비즈니스 로직을 return 한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;b&gt;1. constructor(private ~) {}&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입을 사용해 MoviesService를 주입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;2. @Get() getAll()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;movieService의 getAll() 메서드를 호출해 모든 영화에 대한 정보를 반환한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;3. @Get('/:id') getOne()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;@Param 데코레이터를 사용해 URL 파라미터인 id를 추출하고,&amp;nbsp;&lt;/span&gt;moviesService의 getOne() 메서드를 호출해 id에 해당하는 영화 정보를 반환한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4. @Post() create()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@Body 데코레이터를 사용해 요청 본문에서 전달된 데이터를 moviesSevice의 create() 메서드를 호출해 새로운 영화 정보를 추가한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;5. @Delete('/:id') remove()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@Param 데코레이터를 사용해 URL 파라미터인 id를 추출하고, moviesService의 deleteOne() 메서드를 호출해 id에 해당하는 영화 정보를 삭제한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;6. @Parch('/:id') patch()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@Param 데코레이터를 사용해 URL 파라미터인 id를 추출하고, @Body 데코레이터를 사용해 요청 본문에서 데이터를 전달한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;moviesService의 update() 메서드를 호출해 id에 해당하는 영화 정보를 업데이트한다.&lt;/p&gt;
&lt;pre id=&quot;code_1704272799631&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get, Post, Delete, Patch, Param, Query, Body } from '@nestjs/common';
import { MoviesService } from './movies.service';
import { Movie } from './entities/movies.entity';

@Controller('movies')
export class MoviesController {
  constructor(private readonly moviesService: MoviesService) {}

  @Get()
  getAll(): Movie[] {
    return this.moviesService.getAll();
  }

  @Get('/:id')
  getOne(@Param('id') movieId: string) {
    return this.moviesService.getOne(movieId);
  }

  @Post()
  create(@Body() movieData) {
    return this.moviesService.create(movieData);
  }

  @Delete('/:id')
  remove(@Param('id') movieId: string) {
    return this.moviesService.deleteOne(movieId);
  }

  @Patch('/:id')
  patch(@Param('id') movieId: string, @Body() updateData) {
    return this.moviesService.update(movieId, updateData);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데코레이터란,&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@로 시작하는 함수를 데코레이터 라고 부르며, 클래스, 메서드, 프로터디 또는 매개변수에 부가적인 메타데이터를 제공하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Module&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈을 정의하는데 사용되며, 모듈은 애플리케이션을 구성하고 기능을 캡슐화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Controller&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러를 정의하는데 사용되며, HTTP 요청을 처리하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Injectable&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 정의하는데 사용되며, 의존성 주입을 가능하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Body&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST, PUT, PATCH 등의 HTTP 메서드에서 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json 또는 대량의 데이터 전송에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Query&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET HTTP 메서드에서 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 필터링하거나 정렬하는 기분값을 전송에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) /movies?year=2024&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Param&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 경로를 가지는 라우팅에서 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 데이터를 식별할 때 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) /movies/2024&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 결과 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postman 또는 Insomnia로 HTTP에 대한 요청을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 배열을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceyzhf/btsC37UvVjr/nhQyqND0kukcEpnJjiuX01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceyzhf/btsC37UvVjr/nhQyqND0kukcEpnJjiuX01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceyzhf/btsC37UvVjr/nhQyqND0kukcEpnJjiuX01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fceyzhf%2FbtsC37UvVjr%2FnhQyqND0kukcEpnJjiuX01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1008&quot; height=&quot;442&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Status 201을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMBDn2/btsCTX7kgfA/x6BRMXK0IKSBvNU9GmuLt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMBDn2/btsCTX7kgfA/x6BRMXK0IKSBvNU9GmuLt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMBDn2/btsCTX7kgfA/x6BRMXK0IKSBvNU9GmuLt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMBDn2%2FbtsCTX7kgfA%2Fx6BRMXK0IKSBvNU9GmuLt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1009&quot; height=&quot;445&quot; data-origin-width=&quot;1009&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST로 전송한 데이터를 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baPXze/btsC2zKzS7u/c0AVYRmuRSGiWBw8wDFLkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baPXze/btsC2zKzS7u/c0AVYRmuRSGiWBw8wDFLkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baPXze/btsC2zKzS7u/c0AVYRmuRSGiWBw8wDFLkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaPXze%2FbtsC2zKzS7u%2Fc0AVYRmuRSGiWBw8wDFLkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1011&quot; height=&quot;577&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DELETE&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Status 200을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOYQXk/btsC4o2RnTw/z1seB2rivB6PAqLEcTe8C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOYQXk/btsC4o2RnTw/z1seB2rivB6PAqLEcTe8C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOYQXk/btsC4o2RnTw/z1seB2rivB6PAqLEcTe8C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOYQXk%2FbtsC4o2RnTw%2Fz1seB2rivB6PAqLEcTe8C0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1011&quot; height=&quot;443&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>NestJs/Nest 기초</category>
      <category>nest</category>
      <category>nest api</category>
      <category>nest rest api</category>
      <category>nest 데코레이터</category>
      <category>Nest.js</category>
      <category>nest.js controller</category>
      <category>nest.js module</category>
      <category>nest.js service</category>
      <category>REST API</category>
      <category>네스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/141</guid>
      <comments>https://jae-study.tistory.com/141#entry141comment</comments>
      <pubDate>Thu, 4 Jan 2024 10:43:29 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] #1 ARCHITECTURE OF NESTJS - 기본 개념</title>
      <link>https://jae-study.tistory.com/140</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS로&amp;nbsp;API&amp;nbsp;만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nomadcoders.co/nestjs-fundamentals&quot;&gt;https://nomadcoders.co/nestjs-fundamentals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;노마드코더 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T3r0a/btsCSdCrd9W/DtyeXuqJJUAhtGKux0LeHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T3r0a/btsCSdCrd9W/DtyeXuqJJUAhtGKux0LeHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T3r0a/btsCSdCrd9W/DtyeXuqJJUAhtGKux0LeHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT3r0a%2FbtsCSdCrd9W%2FDtyeXuqJJUAhtGKux0LeHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;134&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buOToQ/btsCX5C63sE/o8ECJ6qNlyaF6yBI789ysK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buOToQ/btsCX5C63sE/o8ECJ6qNlyaF6yBI789ysK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buOToQ/btsCX5C63sE/o8ECJ6qNlyaF6yBI789ysK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuOToQ%2FbtsCX5C63sE%2Fo8ECJ6qNlyaF6yBI789ysK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;140&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.JPG&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/om2Ll/btsC31NjJ1l/06fMeGFVUP3F88fGWjZyuK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/om2Ll/btsC31NjJ1l/06fMeGFVUP3F88fGWjZyuK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/om2Ll/btsC31NjJ1l/06fMeGFVUP3F88fGWjZyuK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fom2Ll%2FbtsC31NjJ1l%2F06fMeGFVUP3F88fGWjZyuK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;269&quot; height=&quot;427&quot; data-filename=&quot;1.JPG&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Nest.js 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;NestJs 설치에 대한 설명은 아래 링크를 참고한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/78&quot;&gt;https://jae-study.tistory.com/78&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1704261563929&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ceUt8P/hyUXLNgFNf/DzkkNYqDXN5AhVkiAxTKy1/img.png?width=256&amp;amp;height=117&amp;amp;face=0_0_256_117,https://scrap.kakaocdn.net/dn/cBl7rA/hyUXX71B2U/fwHqYEK9YluNTY6KEYtKnK/img.png?width=256&amp;amp;height=117&amp;amp;face=0_0_256_117&quot; data-og-url=&quot;https://jae-study.tistory.com/78&quot; data-og-source-url=&quot;https://jae-study.tistory.com/78&quot; data-og-host=&quot;jae-study.tistory.com&quot; data-og-description=&quot;NestJS(Nest)란? https://docs.nestjs.com/ NestJs는 효율적이고, 확장 가능한 Node.js 서버 애플리케이션을 구축하기 위한 프레임워크이다. 프로그레시브 Javascript를 사용하고, Typescript로 구축되어 Typescript를&quot; data-og-title=&quot;[Nest] #1 NestJs 설치하기&quot; data-og-type=&quot;article&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://jae-study.tistory.com/78&quot; data-source-url=&quot;https://jae-study.tistory.com/78&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ceUt8P/hyUXLNgFNf/DzkkNYqDXN5AhVkiAxTKy1/img.png?width=256&amp;amp;height=117&amp;amp;face=0_0_256_117,https://scrap.kakaocdn.net/dn/cBl7rA/hyUXX71B2U/fwHqYEK9YluNTY6KEYtKnK/img.png?width=256&amp;amp;height=117&amp;amp;face=0_0_256_117');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;[Nest] #1 NestJs 설치하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;NestJS(Nest)란? https://docs.nestjs.com/ NestJs는 효율적이고, 확장 가능한 Node.js 서버 애플리케이션을 구축하기 위한 프레임워크이다. 프로그레시브 Javascript를 사용하고, Typescript로 구축되어 Typescript를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;jae-study.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Nest.js&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네스트(Nest.js)는 Node.js를 위한 서버 사이드 애플리케이션을 개발하기 위한 프레임워크이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 구성하는데 모듈, 컨트롤러, 서비스의 개념을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;모듈 (Module)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Module 데코레이터를 사용해 모듈을 정의하고, 해당 모듈은 컨트롤러, 서비스, 미들웨어 및 다른 컴포넌트들을 그룹화하는 방법을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js 애플리케이션을 여러 모듈로 구성되며, 의존성 주입을 통해 모듈 간에 서비스 및 기능을 공유하고, 코드의 재사용성을 높인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/app.module.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1704250637553&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;컨트롤러 (Controller)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Controller 테코레이터를 사용해 컨트롤러를 정의하고, 해당 컨트롤러에는 특정 엔드포인트(경로)에 대한 라우팅 정보가 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 각 컨트롤러는 HTTP 메서드(GET, POST 등)에 메핑 되며, HTTP 요청을 처리하고 응답하는 역할을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/app.controller.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1704250726901&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @Get('/hi')
  sayHello(): string {
    return this.appService.getHi();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서비스 (Service)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Injectable() 데코레이션을 사용해 서비스를 정의하고, 해당 서비스에는 필요한 비즈니스 로직이나 데이터를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러에서 호출되어 컨트롤러에게 데이터가 기능을 제공하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/app.service.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1704250912107&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello Nest!';
  }

  getHi(): string {
    return 'Hi Nest!';
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;주의&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;데코레이터는 함수나 클래스랑 붙어있어야 한다. (&lt;u&gt;스페이지 또는 엔터를 사용하면 안 된다.&lt;/u&gt;)&lt;/i&gt;&lt;/p&gt;</description>
      <category>NestJs/Nest 기초</category>
      <category>nest</category>
      <category>Nest.js</category>
      <category>nest.js controller</category>
      <category>nest.js module</category>
      <category>nest.js service</category>
      <category>Nest.js 개념</category>
      <category>Nest.js 설치하기</category>
      <category>Nest.js 시작하기</category>
      <category>Nest.js 정의</category>
      <category>네스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/140</guid>
      <comments>https://jae-study.tistory.com/140#entry140comment</comments>
      <pubDate>Wed, 3 Jan 2024 14:25:21 +0900</pubDate>
    </item>
    <item>
      <title>[리액트][타입스크립트] #7 게시판 만들기 - 목록 페이지네이션 (NestJs pagination)</title>
      <link>https://jae-study.tistory.com/139</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1485&quot; data-origin-height=&quot;977&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqs8Oi/btsCOCgaWMG/zSiuHroTriILkkKcF7Uchk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqs8Oi/btsCOCgaWMG/zSiuHroTriILkkKcF7Uchk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqs8Oi/btsCOCgaWMG/zSiuHroTriILkkKcF7Uchk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqs8Oi%2FbtsCOCgaWMG%2FzSiuHroTriILkkKcF7Uchk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1485&quot; height=&quot;977&quot; data-origin-width=&quot;1485&quot; data-origin-height=&quot;977&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;수정사항&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;a href=&quot;https://jae-study.tistory.com/85&quot;&gt;https://jae-study.tistory.com/85&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 react-js-pagination 패키지를 사용해 페이지네이션을 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 페이지네이션을 프론트에서 만들었을 경우, 서버와 데이터베이스의 부하가 발생할 수 있기 때문에 백앤드의 작업이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백앤드 없이 프론트에서 페이지네이션을 구현하고 싶다면 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/138&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/138&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJs로 페이지네이션을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지네이션을 백앤드에서 만들어야 하는 이유에 대한 설명은 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. boardReducer.tsx&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/store/boardReducer.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;page 파라미터를 받는다. 타입스크립트이기 때문에 타입을 정의한다.&lt;/li&gt;
&lt;li&gt;axios.get을 사용해 page에 해당하는 데이터를 요청한다. URL은 쿼리 파라미터가 붙은 key=value 형태이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703742529726&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const getBoardList = createAsyncThunk(
  'GET_BOARD_LIST',
  async (page: number) =&amp;gt; {
    try {
      const response = await axios.get(`http://localhost:3001/board?page=${page}`)
      return response.data
    } catch (error) {
      console.log(error)
    }
  }
)

...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지네이션에 해당하는 데이터 가져오기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/pages/board/list/index.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;dispatch를 사용해 page에 해당하는 게시판 데이터를 가져온다.&lt;/li&gt;
&lt;li&gt;axios를 통해 받아온 데이터가 객채(object) 형태이기 때문에 (배열처럼 보이지만 typeof로 확인하면 object이다.) [board, setBoard] state 변수를 만들고, 전개 연산자를 사용해 배열 형태로 바꾼다.&lt;/li&gt;
&lt;li&gt;axios를 통해 받아온 page 데이터가 문자(string) 형태이기 때문에 [page, setPage] state 변수를 만들고, Number로 타입을 변환한다.&lt;/li&gt;
&lt;li&gt;페이지네이션 버튼에 대한 공통 함수(handlePagination)를 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703743172222&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useEffect, useState } from 'react'
import { useAppDispatch, useAppSelector } from '../../../hooks/useApp'
...

const BoardList = () =&amp;gt; {
  // ** Hooks
  const dispatch = useAppDispatch()

  // ** Redux States
  const boardList = useAppSelector(state =&amp;gt; state.boardReducer)

  // ** States
  const [board, setBoard] = useState&amp;lt;boardType[]&amp;gt;([])
  const [page, setPage] = useState&amp;lt;number&amp;gt;(1)

  // 페이지네이션
  function handlePagination(newPage: number) {
    if(newPage &amp;gt;= 1 &amp;amp;&amp;amp; newPage &amp;lt;= boardList.meta.last_page) {
      dispatch(getBoardList(newPage))
    }
  }

  // 페이지가 로딩되면 게시판 리스트 가져옴
  useEffect(() =&amp;gt; {
    dispatch(getBoardList(page))
  }, [])

  // 페이지가 로딩된 후 state 변수에 boardList 데이터 저장함
  useEffect(() =&amp;gt; {
    if (boardList &amp;amp;&amp;amp; boardList.data) {
      setBoard([...boardList.data])
      setPage(Number(boardList.meta.page))
    }
  }, [boardList])

  return (
    ...
  )
}

export default BoardList&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8BusP/btsCIEfhkUb/VMwqOTEb3KSYDy2Y7HflBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8BusP/btsCIEfhkUb/VMwqOTEb3KSYDy2Y7HflBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8BusP/btsCIEfhkUb/VMwqOTEb3KSYDy2Y7HflBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8BusP%2FbtsCIEfhkUb%2FVMwqOTEb3KSYDy2Y7HflBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;789&quot; height=&quot;187&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 마크업 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/pages/board/list/index.tsx.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;삼항연산자를 사용해 데이터가 있고, 없을 때 마크업을 다르게 표현한다.&lt;/li&gt;
&lt;li&gt;map 메서드를 사용해 게시판 데이터를 보여준다.&lt;/li&gt;
&lt;li&gt;처음으로, 이전, 다음, 마지막으로 버튼 기능을 구현한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703743889605&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const BoardList = () =&amp;gt; {
  ...

  return (
    &amp;lt;div className=&quot;board-list&quot;&amp;gt;
      &amp;lt;Title children=&quot;Board list&quot;/&amp;gt;

      &amp;lt;h4&amp;gt;Total post : {boardList.meta?.total}&amp;lt;/h4&amp;gt;

      &amp;lt;table&amp;gt;
        &amp;lt;colgroup&amp;gt;
          &amp;lt;col width=&quot;15%&quot;/&amp;gt;
          &amp;lt;col width=&quot;65%&quot;/&amp;gt;
          &amp;lt;col width=&quot;20%&quot;/&amp;gt;
        &amp;lt;/colgroup&amp;gt;

        &amp;lt;thead&amp;gt;
          &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;No&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;Date&amp;lt;/th&amp;gt;
          &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;

        &amp;lt;tbody&amp;gt;
          {
            board.length === 0 ? (
              &amp;lt;tr&amp;gt;
                &amp;lt;td colSpan={3}&amp;gt;데이터가 없습니다.&amp;lt;/td&amp;gt;
              &amp;lt;/tr&amp;gt;
            ) : (
              board.map((board, index) =&amp;gt; {
                return (
                  &amp;lt;tr key={index}&amp;gt;
                    &amp;lt;td&amp;gt;{board.id}&amp;lt;/td&amp;gt;
                    &amp;lt;td className=&quot;title&quot;&amp;gt;
                      &amp;lt;Link to={`/board/${board.id}`}&amp;gt;{board.title}&amp;lt;/Link&amp;gt;
                    &amp;lt;/td&amp;gt;
                    &amp;lt;td&amp;gt;{dayjs(board.created_at).format('YYYY.MM.DD')}&amp;lt;/td&amp;gt;
                  &amp;lt;/tr&amp;gt;
                )
              })
            )
          }
        &amp;lt;/tbody&amp;gt;
      &amp;lt;/table&amp;gt;

      {
        board.length === 0 ? (
          &amp;lt;&amp;gt;&amp;lt;/&amp;gt;
        ) : (
          &amp;lt;div className=&quot;pagination&quot;&amp;gt;
            {
              boardList.meta.last_page === 1 ? (
                &amp;lt;&amp;gt;
                  &amp;lt;button disabled&amp;gt;&amp;amp;#60;&amp;lt;/button&amp;gt;
                  &amp;lt;p&amp;gt;{page}&amp;lt;/p&amp;gt;
                  &amp;lt;button disabled&amp;gt;&amp;amp;#62;&amp;lt;/button&amp;gt;
                &amp;lt;/&amp;gt;
              ) : (
                &amp;lt;&amp;gt;
                  &amp;lt;button onClick={() =&amp;gt; handlePagination(1)}&amp;gt;&amp;amp;#60;&amp;amp;#60;&amp;lt;/button&amp;gt;
                  &amp;lt;button onClick={() =&amp;gt; handlePagination(page - 1)}&amp;gt;&amp;amp;#60;&amp;lt;/button&amp;gt;
                  &amp;lt;p&amp;gt;{page} / {boardList.meta.last_page}&amp;lt;/p&amp;gt;
                  &amp;lt;button onClick={() =&amp;gt; handlePagination(page + 1)}&amp;gt;&amp;amp;#62;&amp;lt;/button&amp;gt;
                  &amp;lt;button onClick={() =&amp;gt; handlePagination(boardList.meta.last_page)}&amp;gt;&amp;amp;#62;&amp;amp;#62;&amp;lt;/button&amp;gt;
                &amp;lt;/&amp;gt;
              )
            }
          &amp;lt;/div&amp;gt;
        )
      }

      &amp;lt;Link to=&quot;/board/create&quot;&amp;gt;
        &amp;lt;Button children=&quot;Write&quot; variant=&quot;primary&quot;/&amp;gt;
      &amp;lt;/Link&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default BoardList&lt;/code&gt;&lt;/pre&gt;</description>
      <category>React/게시판 만들기(TS)</category>
      <category>react</category>
      <category>react nestjs pagination</category>
      <category>react pagination</category>
      <category>react typescript pagination</category>
      <category>react typescript 게시판</category>
      <category>react 게시판</category>
      <category>react 백앤드 페이지네이션</category>
      <category>react-js-pagination</category>
      <category>리액트 게시판</category>
      <category>리액트 페이지네이션</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/139</guid>
      <comments>https://jae-study.tistory.com/139#entry139comment</comments>
      <pubDate>Thu, 28 Dec 2023 15:24:35 +0900</pubDate>
    </item>
    <item>
      <title>[Nest] NestJs 페이지네이션 만들기 (쿼리 파라미터)</title>
      <link>https://jae-study.tistory.com/138</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UTtso/btsCJkgLZ1U/WtbjFPKvFit4k6K2T8BHh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UTtso/btsCJkgLZ1U/WtbjFPKvFit4k6K2T8BHh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UTtso/btsCJkgLZ1U/WtbjFPKvFit4k6K2T8BHh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUTtso%2FbtsCJkgLZ1U%2FWtbjFPKvFit4k6K2T8BHh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;729&quot; height=&quot;207&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;페이지네이션(Pagination)이란&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciX1AA/btsCN2F57ql/pkxSzzYHlm2w1IqfQ0dzIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciX1AA/btsCN2F57ql/pkxSzzYHlm2w1IqfQ0dzIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciX1AA/btsCN2F57ql/pkxSzzYHlm2w1IqfQ0dzIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciX1AA%2FbtsCN2F57ql%2FpkxSzzYHlm2w1IqfQ0dzIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;68&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지네이션은 대량의 데이터를 관리하고 효율적으로 표시하기 위한 기술로 사용자가 웹 페이지 상에서 여러 페이지로 나뉜 데이터를 탐색할 수 있도록 하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;페이지네이션을 백앤드에서 만들어야 하는 이유&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;서버 리소스 효율성 증가 &lt;/b&gt;: 페이지네이션은 클라이언트가 필요로 하는 양의 데이터만 전송하여 서버 리소스를 효율적으로 활용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 부하 감소 &lt;/b&gt;: 페이지네이션을 통해 서버는 필요한 데이터만 데이터베이스에서 가져와 부하를 감소시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트 성능 향상 &lt;/b&gt;: 서버와 데이터베이스에서 필요한 데이터만 요청하여 클라이언트의 로딩 시간을 최소화해 사용자의 경험을 향상한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검색 엔진 최적화(SEO) &lt;/b&gt;: 페이지네이션은 검색 엔진이 페이지 간 이동을 파악하고 데이터를 효과적으로 색인화할 수 있도록 도와준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말해, 데이터의 양이 상대적으로 적은 경우(예: 100개), 페이지네이션의 유무에 따른 성능 차이를 느끼지 못할 수 있지만, 데이터의 양이 많아지면(예: 10만개 이상) 클라이언트에서 서버로 데이터를 요청하고 수신하는 과정에서 서버 및 데이터베이스 부하가 증가하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 백엔드에서 페이지네이션을 구현해 데이터를 효율적으로 관리하고 사용자의 경험을 최적화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. board.service.ts&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;service 파일에는 비즈니스 로직이나 데이터 조작 등을 수행하는 메서드를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/board/board.service.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;paginate 메서드를 만든다.&lt;/li&gt;
&lt;li&gt;page 매개변수로 페이지 번호를 지정하고, 기본값을 1로 설정한다.&lt;/li&gt;
&lt;li&gt;take 변수는 한 페이지에 표시될 아이템 수를 나타낸다.&lt;/li&gt;
&lt;li&gt;findAndCount 메서드는 데이터베이스에서 페이징 된 데이터를 검색하고, 해당 데이터와 전체 아이템 수를 배열로 반환한다.&lt;/li&gt;
&lt;li&gt;페이지와 관련된 meta 정보를 return 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703740142686&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class BoardService {
  constructor(private readonly boardRepository: BoardRepository) {}

  async paginate(page = 1): Promise&amp;lt;any&amp;gt; {
    const take = 5;

    const [board, total] = await this.boardRepository.findAndCount({
      take,
      skip: (page - 1) * take,
    });

    return {
      data: board,
      meta: { take, total, page, last_page: Math.ceil(total / take) },
    };
  }
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. board.controller.ts&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/board/board.controller.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;@Get()으로 HTTP GET 요청을 처리하는 핸들러임을 나타낸다.&lt;/li&gt;
&lt;li&gt;@Query('page')를 통해 쿼리 파라미터를 받아와 page 변수에 할당하고, 기본값을 1로 설정한다.&lt;/li&gt;
&lt;li&gt;boardService 클래스에 정의된 paginate 메서드를 호출해서 return 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703740692335&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller('board')
export class BoardController {
  constructor(private readonly boardService: BoardService) {}

  @Get()
  async all(@Query('page') page = 1): Promise&amp;lt;any[]&amp;gt; {
    return await this.boardService.paginate(page);
  }
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스트맨(postman)을 통해서 결과를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url 뒤에 page=1 쿼리 파라미터가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 파라미터(Query Parameter)는 URL 끝에 ?로 시작하며, 그 뒤에 'key=value' 형태로 데이터를 전달하는 방식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmlIfC/btsCJiwsO0o/Sbe6rC4dBieMvpPFzOpBDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmlIfC/btsCJiwsO0o/Sbe6rC4dBieMvpPFzOpBDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmlIfC/btsCJiwsO0o/Sbe6rC4dBieMvpPFzOpBDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmlIfC%2FbtsCJiwsO0o%2FSbe6rC4dBieMvpPFzOpBDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;490&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>NestJs/Nest CRUD</category>
      <category>CRUD</category>
      <category>nest</category>
      <category>nest CRUD</category>
      <category>nest pagination</category>
      <category>nest typeorm</category>
      <category>nest 페이지네이션</category>
      <category>nestjs</category>
      <category>nestjs pagination</category>
      <category>nestjs 페이지네이션</category>
      <category>typeorm</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/138</guid>
      <comments>https://jae-study.tistory.com/138#entry138comment</comments>
      <pubDate>Thu, 28 Dec 2023 14:31:39 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #7 ToDo List 만들기 - Nest.js + PSQL 상세페이지 만들기 (useFetch())</title>
      <link>https://jae-study.tistory.com/137</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;투두리스트 상세페이지 만들기&lt;/li&gt;
&lt;li&gt;useRoute()로 파라미터 가져오기&lt;/li&gt;
&lt;li&gt;useFetch()로 서버 데이터 가져오기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JjhAU/btsCy4Zu1wi/zJWTz1NmltgHIorZWksq7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JjhAU/btsCy4Zu1wi/zJWTz1NmltgHIorZWksq7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JjhAU/btsCy4Zu1wi/zJWTz1NmltgHIorZWksq7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJjhAU%2FbtsCy4Zu1wi%2FzJWTz1NmltgHIorZWksq7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;756&quot; height=&quot;524&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 상세페이지 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/[id].vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;pages 디렉터리 내에 [id].vue 파일을 만든다. 별도의 설정 없이 자동으로 동적 라우팅이 생성된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투두리스트 목록 페이지 = index.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투두리스트 상세 페이지 = [id].vue&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;143&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AAKgH/btsCAhxhPZD/E2rf0mezQfrkXXdZpKCIZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AAKgH/btsCAhxhPZD/E2rf0mezQfrkXXdZpKCIZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AAKgH/btsCAhxhPZD/E2rf0mezQfrkXXdZpKCIZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAAKgH%2FbtsCAhxhPZD%2FE2rf0mezQfrkXXdZpKCIZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;143&quot; height=&quot;101&quot; data-origin-width=&quot;143&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt3의 핵심 기능 중 하나는 파일 시스템 라우터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pages/ 디렉터리 내의 모든 Vue 파일은 URL을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/routing&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/getting-started/routing&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우팅에 대한 자세한 설명은 공식문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;주의&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Vue나 Nuxt2에서는 동적 라우팅 페이지가 _id.vue(언더바 _) 였다. Nuxt3부터는 [id].vue(대괄호 []) 이다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 파라미터 가져오기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/[id].vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;route 변수를 만든다.&lt;/li&gt;
&lt;li&gt;${route.params.id}로 url의 파라미터 값을 가져온다.&lt;/li&gt;
&lt;li&gt;useFetch()로 해당 파라미터에 대한 서버 데이터를 가져온다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-route&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/api/composables/use-route&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useRoute()에 대한 자세한 설명은 공식 문서를 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1703554957782&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const route = useRoute()
console.log(route)

const { data } = await useFetch(`http://localhost:3001/todo/${route.params.id}`)
console.log(data)
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;273&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHmVjc/btsCzIaLf0t/q8GKx0tLgL7BAlyAD1FOK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHmVjc/btsCzIaLf0t/q8GKx0tLgL7BAlyAD1FOK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHmVjc/btsCzIaLf0t/q8GKx0tLgL7BAlyAD1FOK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHmVjc%2FbtsCzIaLf0t%2Fq8GKx0tLgL7BAlyAD1FOK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;273&quot; height=&quot;247&quot; data-origin-width=&quot;273&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m70fu/btsCKqflUDI/ktR6La7SuPhnWP2hQixN10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m70fu/btsCKqflUDI/ktR6La7SuPhnWP2hQixN10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m70fu/btsCKqflUDI/ktR6La7SuPhnWP2hQixN10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm70fu%2FbtsCKqflUDI%2FktR6La7SuPhnWP2hQixN10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;727&quot; height=&quot;133&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 마크업&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/[id].vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;테일윈드를 사용해 CSS를 작성했다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;{ data }의 id와 todo 값을 화면에 보여준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703555760475&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const route = useRoute()

const { data } = await useFetch(`http://localhost:3001/todo/${route.params.id}`)
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section&amp;gt;
    &amp;lt;h1 class=&quot;mt-6 mb-12 md:mt-10 text-5xl font-bold text-center&quot;&amp;gt;To Do Detail&amp;lt;/h1&amp;gt;

    &amp;lt;div class=&quot;p-4 md:p-6 md:pb-12 border rounded&quot;&amp;gt;
      &amp;lt;p class=&quot;block mb-6 text-xl font-bold text-right&quot;&amp;gt;No.{{ data.id }}&amp;lt;/p&amp;gt;
      &amp;lt;p class=&quot;flex gap-2 text-base md:text-lg&quot;&amp;gt;{{ data.todo }}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;NuxtLink to=&quot;/&quot;  class=&quot;block w-full md:w-1/3 m-auto mt-12 px-3 py-4 bg-teal-950 hover:bg-teal-500 transition rounded text-center&quot;&amp;gt;
      Go to To Do List
    &amp;lt;/NuxtLink &amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt todoList</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt 투두리스트 만들기</category>
      <category>nuxt3 api 연결하기</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 useFetch()</category>
      <category>nuxt3 useRoute()</category>
      <category>nuxt3 두투리스트 상세페이지</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/137</guid>
      <comments>https://jae-study.tistory.com/137#entry137comment</comments>
      <pubDate>Tue, 26 Dec 2023 11:06:46 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #6 ToDo List 만들기 - Nest.js + PSQL 연결하기 (useFetch())</title>
      <link>https://jae-study.tistory.com/136</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;useFetch()로 서버 데이터 가져오기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;watch()를 사용해 서버 데이터 변경 감지하기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;$fetch 사용해 HTTP 메서드 사용하기 (GET, POST, DELETE)&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;서버 데이터를 등록순/최신순 정렬하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIc0Ss/btsCoFZVs4n/StPhW5IqoMQbTyEmgFQFk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIc0Ss/btsCoFZVs4n/StPhW5IqoMQbTyEmgFQFk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIc0Ss/btsCoFZVs4n/StPhW5IqoMQbTyEmgFQFk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIc0Ss%2FbtsCoFZVs4n%2FStPhW5IqoMQbTyEmgFQFk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1482&quot; height=&quot;784&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Nest.js + PSQL (백앤드 + 데이터베이스)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/80&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js와&amp;nbsp;Psql을&amp;nbsp;사용해서&amp;nbsp;백앤드와&amp;nbsp;데이터베이스를&amp;nbsp;만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 백앤드와 데이터베이스를 만들어도 되고,&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://jsonplaceholder.typicode.com/&quot;&gt;JSONPlaceholder 사이트&lt;/a&gt;를 통해 가짜 데이터를 받아와도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. toDo 가져오기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt3에서는 axios 대신 &lt;u&gt;useFetch()를 사용해 데이터 패칭을 한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch()는 데이터를 비동기적으로 불러올 수 있고, 기존 axios 코드보다 로직을 간소화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/127&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/127&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch()에 대한 자세한 설명은 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Nuxt3는 타입스크립트 기반이기 때문에 useFetch()로 받아오는 데이터의 타입을 정의한다. (IToDo[])&lt;/li&gt;
&lt;li&gt;서버에서 받은 데이터를 가공하기 위해 toDoData 변수를 만든다. useFetch()로 받아오는 데이터의 타입은 기본적으로 객체(object)이다. 이것을 배열로 만들어 정렬(sort 메서드)을 하고 싶어 toDoData 변수를 만들었다.&lt;/li&gt;
&lt;li&gt;toDo를 추가하고 삭제할 때마다 실시간으로 렌더링 하기&amp;nbsp;위해 watch 함수를 사용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703149718190&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
interface IToDo {
  id: number
  todo: string
  created_at: Date
}

// axios.get 기능 (toDo 가져오기)
const { data, refresh } = await useFetch&amp;lt;IToDo[]&amp;gt;('http://localhost:3001/todo')
const toDoData = ref(data.value ? [...data.value] : [])

watch(() =&amp;gt; data.value, () =&amp;gt; {
  toDoData.value = isActive.value ? [...data.value] : [...data.value].reverse()
})

...
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. toDo 추가하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;newToDo 변수를 만들어 빈 값이면 alert() 창이 나오게 하고, 값이 있으면 POST 메서드를 실행한다.&lt;/li&gt;
&lt;li&gt;POST가 완료되면 newToDo를 빈 값으로 만들고, 실시간 값 변화를 감지하기 위해 refresh()를 실행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703151516114&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const newToDo = ref('')

// axios.post 기능 (toDo 추가하기)
async function addToDo() {
  if(newToDo.value === '') {
    alert('할 일을 입력해 주세요.')
  } else {
    await $fetch('http://localhost:3001/todo', {
      method: 'POST',
      body: { todo: newToDo.value }
    })

    newToDo.value = ''
    await refresh()
  }
}

...
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. toDo 삭제하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;리스트 1개만 삭제하고 싶으면 해당하는 id 값을 매개변수로 받아 DELETE 메서드를 실행한다.&lt;/li&gt;
&lt;li&gt;리스트 전체를 삭제하고 싶으면 api 전체 리스트에서 DELETE 메서드를 실행한다.&lt;/li&gt;
&lt;li&gt;DELETE가 완료되면 실시간 값 변화를 감지하기 위해 refresh()를 실행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703151687656&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
// axios.delete 기능 (toDo 삭제하기)
async function deleteToDo(id: number) {
  await $fetch(`http://localhost:3001/todo/${id}`, {
    method: 'DELETE'
  })

  await refresh()
}

// axios.delete 기능 (toDo 전체 삭제하기)
async function clearToDo() {
  if(window.confirm('리스트를 모두 삭제하시겠습니까?')) {
    await $fetch(`http://localhost:3001/todo`, {
      method: 'DELETE'
    })

    await refresh()
  }
}

...
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. toDo 정렬하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;useFetch()로 받은 데이터를 배열로 만들어 sort() 메서드를 사용해 등록순/최신순으로 정렬한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703151913793&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const isActive = ref(true)

// 등록순, 최신순 정렬하기
function sortToDo(compareFn: (a: IToDo, b: IToDo) =&amp;gt; number) {
  toDoData.value = [...data.value].sort(compareFn)
  isActive.value = !isActive.value
}

...
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg min-h-screen m-auto&quot;&amp;gt;
    ...

    &amp;lt;div v-if=&quot;toDoData.length &amp;gt; 0&quot;&amp;gt;
      &amp;lt;div class=&quot;flex gap-2 mb-6&quot;&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : isActive }&quot;
          @click=&quot;() =&amp;gt; sortToDo((a, b) =&amp;gt; a.id - b.id)&quot;&amp;gt;
          등록순
        &amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : !isActive }&quot;
          @click=&quot;() =&amp;gt; sortToDo((a, b) =&amp;gt; b.id - a.id)&quot;&amp;gt;
          최신순
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    
    ...
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 마크업&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;테일윈드를 사용해 CSS를 작성했다.&lt;/li&gt;
&lt;li&gt;각각의 버튼에 맞는 @click 이벤트를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703207705269&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg min-h-screen m-auto&quot;&amp;gt;
    &amp;lt;h1 class=&quot;mt-6 mb-12 md:mt-10 text-5xl font-bold text-center&quot;&amp;gt;To Do List&amp;lt;/h1&amp;gt;

    &amp;lt;form
      class=&quot;mb-6&quot;
      @submit.prevent=&quot;addToDo()&quot;&amp;gt;
      &amp;lt;label
        for=&quot;toDo&quot;
        class=&quot;block mb-3 text-xl font-bold&quot;&amp;gt;
        New To Do
      &amp;lt;/label&amp;gt;

      &amp;lt;div class=&quot;flex gap-3 md:gap-5&quot;&amp;gt;
        &amp;lt;input
          v-model=&quot;newToDo&quot;
          type=&quot;text&quot;
          id=&quot;toDo&quot;
          class=&quot;w-3/4 px-3 py-4 rounded outline-none text-black&quot;
          placeholder=&quot;할 일을 입력해 주세요.&quot;/&amp;gt;
        &amp;lt;button class=&quot;w-1/4 bg-teal-600 hover:bg-teal-500 transition rounded&quot;&amp;gt;추가하기&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;

    &amp;lt;div v-if=&quot;toDoData.length &amp;gt; 0&quot;&amp;gt;
      &amp;lt;div class=&quot;flex gap-2 mb-6&quot;&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : isActive }&quot;
          @click=&quot;() =&amp;gt; sortToDo((a, b) =&amp;gt; a.id - b.id)&quot;&amp;gt;
          등록순
        &amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : !isActive }&quot;
          @click=&quot;() =&amp;gt; sortToDo((a, b) =&amp;gt; b.id - a.id)&quot;&amp;gt;
          최신순
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;ul&amp;gt;
        &amp;lt;li
            v-for=&quot;(data, key) in toDoData&quot;
            :key=&quot;key&quot;
            class=&quot;flex justify-between items-center gap-3 mb-6 px-4 py-3 md:px-5 border rounded&quot;&amp;gt;
          &amp;lt;p class=&quot;flex gap-2 text-base md:text-lg&quot;&amp;gt;
            &amp;lt;span&amp;gt;{{ key + 1 }}.&amp;lt;/span&amp;gt; {{ data.todo }}
          &amp;lt;/p&amp;gt;

          &amp;lt;button
            class=&quot;min-w-fit px-5 py-2 bg-teal-600 hover:bg-teal-500 transition rounded&quot;
            @click=&quot;deleteToDo(data.id)&quot;&amp;gt;
            삭제
          &amp;lt;/button&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;button
        class=&quot;block w-full md:w-1/3 m-auto mt-12 px-3 py-4 bg-teal-950 hover:bg-teal-500 transition rounded&quot;
        @click=&quot;clearToDo()&quot;&amp;gt;
        전체 삭제하기
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;상세 코드는 깃허브 페이지를 참고한다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/heejae0811/nuxt3-todo/tree/axios&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/heejae0811/nuxt3-todo/tree/axios&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703208600315&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - heejae0811/nuxt3-todo: main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch)&quot; data-og-description=&quot;main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch) - GitHub - heejae0811/nuxt3-todo: main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/heejae0811/nuxt3-todo/tree/axios&quot; data-og-url=&quot;https://github.com/heejae0811/nuxt3-todo&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eMJtE/hyUPJh3pL8/upxYa39EPdCkBpovKzHVak/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/heejae0811/nuxt3-todo/tree/axios&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/heejae0811/nuxt3-todo/tree/axios&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eMJtE/hyUPJh3pL8/upxYa39EPdCkBpovKzHVak/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - heejae0811/nuxt3-todo: main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch) - GitHub - heejae0811/nuxt3-todo: main: Pinia To Do List / axios: Nest.js + PSQL To Do List (useFetch)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/heejae0811/todo-backend&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/heejae0811/todo-backend&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703209613945&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - heejae0811/todo-backend: Nest.js + PSQL ToDo 백앤드&quot; data-og-description=&quot;Nest.js + PSQL ToDo 백앤드. Contribute to heejae0811/todo-backend development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/heejae0811/todo-backend&quot; data-og-url=&quot;https://github.com/heejae0811/todo-backend&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SiFH6/hyUPzNhlko/BzvTUStXeoCYF9YG4KUf2k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/heejae0811/todo-backend&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/heejae0811/todo-backend&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SiFH6/hyUPzNhlko/BzvTUStXeoCYF9YG4KUf2k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - heejae0811/todo-backend: Nest.js + PSQL ToDo 백앤드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nest.js + PSQL ToDo 백앤드. Contribute to heejae0811/todo-backend development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt todoList</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt 투두리스트 만들기</category>
      <category>nuxt3 api 연결하기</category>
      <category>nuxt3 axios</category>
      <category>nuxt3 nest.js</category>
      <category>nuxt3 psql</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 useFetch()</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/136</guid>
      <comments>https://jae-study.tistory.com/136#entry136comment</comments>
      <pubDate>Fri, 22 Dec 2023 10:20:29 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] Nuxt.js 깃허브 페이지 배포하기</title>
      <link>https://jae-study.tistory.com/135</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://heejae0811.github.io/vue-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://heejae0811.github.io/vue-components/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701740810061&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Vue/Nuxt Components&quot; data-og-description=&quot;뷰/넉스트 컴포넌트입니다.&quot; data-og-host=&quot;heejae0811.github.io&quot; data-og-source-url=&quot;https://heejae0811.github.io/vue-components/&quot; data-og-url=&quot;https://heejae0811.github.io/vue-components/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bwOZpW/hyUE5Geq81/v15AqdiVmLfHOqDkuXJfOk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://heejae0811.github.io/vue-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://heejae0811.github.io/vue-components/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bwOZpW/hyUE5Geq81/v15AqdiVmLfHOqDkuXJfOk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Vue/Nuxt Components&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;뷰/넉스트 컴포넌트입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;heejae0811.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://v2.nuxt.com/deployments/github-pages#github-actions&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://v2.nuxt.com/deployments/github-pages#github-actions&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701677774782&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;GitHub Pages&quot; data-og-description=&quot;How to deploy Nuxt app on GitHub Pages?&quot; data-og-host=&quot;v2.nuxt.com&quot; data-og-source-url=&quot;https://v2.nuxt.com/deployments/github-pages#github-actions&quot; data-og-url=&quot;https://v2.nuxt.com/deployments/github-pages/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bbe22C/hyUE2ilxkX/PxcR3HvBLIdNQMikBbDZT0/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/cTHJxC/hyUIrU3Rh9/bDttkB9FAjMGXSH8Byleh1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/ZlG44/hyUFbTQ2E4/IHwOwxuUgklE4Dnl73nsL1/img.png?width=756&amp;amp;height=986&amp;amp;face=0_0_756_986&quot;&gt;&lt;a href=&quot;https://v2.nuxt.com/deployments/github-pages#github-actions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://v2.nuxt.com/deployments/github-pages#github-actions&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bbe22C/hyUE2ilxkX/PxcR3HvBLIdNQMikBbDZT0/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/cTHJxC/hyUIrU3Rh9/bDttkB9FAjMGXSH8Byleh1/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/ZlG44/hyUFbTQ2E4/IHwOwxuUgklE4Dnl73nsL1/img.png?width=756&amp;amp;height=986&amp;amp;face=0_0_756_986');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Pages&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;How to deploy Nuxt app on GitHub Pages?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;v2.nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 깃허브 배포에 대한 자세한 설명은 위의 공식문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. nuxt.config.js&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 사이트로 배포해야 하기 때문에 target: 'static'을 추가하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;router에는 깃 레포지토리 이름을 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701677319538&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  target: 'static',
  router: {
    base: '/깃 레포지토리 이름/'
  },
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. push-dir 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치된 버전은 package.json 파일에서 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1701677404872&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add --dev push-dir&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. package.json&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;scripts 부분에 &quot;deploy&quot; : &quot;~~&quot; 를 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701677483788&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  ...
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;nuxt&quot;,
    &quot;build&quot;: &quot;nuxt build&quot;,
    &quot;start&quot;: &quot;nuxt start&quot;,
    &quot;generate&quot;: &quot;nuxt generate&quot;,
    &quot;deploy&quot;: &quot;push-dir --dir=dist --branch=gh-pages --cleanup&quot;
  },
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 배포하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 yarn generate 명령어를 실행하면 dist 폴더가 생기는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;yarn deploy 명령어를 실행하면 깃허브에 배포된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701677550646&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn generate
yarn deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 깃허브 Settings&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 과정을 수행했음에도 깃허브 페이지가 배포가 되지 않는다면 깃 레포지토리 Settings을 확인해 본다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;깃 레포지토리 - Settings - Pages에서 Branch가 gh-pages로 되어있는지 확인한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsyD0C/btsBqgZ1dch/hBIldyojHP807Ak6DCCrr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsyD0C/btsBqgZ1dch/hBIldyojHP807Ak6DCCrr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsyD0C/btsBqgZ1dch/hBIldyojHP807Ak6DCCrr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsyD0C%2FbtsBqgZ1dch%2FhBIldyojHP807Ak6DCCrr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;331&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>nuxt gh-pages</category>
      <category>nuxt github pages</category>
      <category>nuxt 깃허브 배포하기</category>
      <category>nuxt 배포하기</category>
      <category>nuxt 정적 사이트 배포</category>
      <category>nuxt.js 깃허브 배포하기</category>
      <category>nuxt.js 배포하기</category>
      <category>nuxt2 깃허브 배포하기</category>
      <category>vue 깃허브 배포하기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/135</guid>
      <comments>https://jae-study.tistory.com/135#entry135comment</comments>
      <pubDate>Mon, 4 Dec 2023 17:19:13 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #5 ToDo List 만들기 - meta 태그 추가하기</title>
      <link>https://jae-study.tistory.com/134</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://heejae0811.github.io/nuxt3-todo/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701769031528&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;오늘의 할 일&quot; data-og-description=&quot;오늘의 할 일은 무엇인가요?&quot; data-og-host=&quot;heejae0811.github.io&quot; data-og-source-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; data-og-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rZghj/hyUE7c3Un5/ubi3Ie0fin71bsqe1oFsqk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rZghj/hyUE7c3Un5/ubi3Ie0fin71bsqe1oFsqk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;오늘의 할 일&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘의 할 일은 무엇인가요?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;heejae0811.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU8qRX/btsBunra5nK/LgjyR0mk5G7s2qgDveRWHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU8qRX/btsBunra5nK/LgjyR0mk5G7s2qgDveRWHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU8qRX/btsBunra5nK/LgjyR0mk5G7s2qgDveRWHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU8qRX%2FbtsBunra5nK%2FLgjyR0mk5G7s2qgDveRWHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;254&quot; height=&quot;224&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. nuxt.config.ts&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;head 태그 아래에 추가하고 싶은 메타태그를 작성한다. (title, meta, link가 HTML 태그로 변환된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name, content, property 등 작성한 값들이 메타태그 속성으로 들어가기 때문에 다른 메타태그를 추가하고 싶다면 속성에 맞는 값들을 입력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메타태그 이미지와 파비콘 이미지 경로는 절대 경로를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브 페이지를 통해 빌드된 파일을 배포하고 있기 때문에 메타태그 이미지는 assets 폴더가 아닌 public 폴더에 넣는다.&lt;/p&gt;
&lt;pre id=&quot;code_1701336097378&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  app: {
    head: {
      title: 'ToDo List',
      meta: [
        { name: 'description', content: '오늘의 할 일은 무엇인가요?' },
        { property: 'og:title', content: '오늘의 할 일' },
        { property: 'og:description', content: '오늘의 할 일은 무엇인가요?' },
        { property: 'og:image', content: 'https://heejae0811.github.io/nuxt3-todo/meta.jpg' }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: 'https://heejae0811.github.io/nuxt3-todo/favicon.ico' }
      ]
    },
  },
  
  ...
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH2Q5w/btsBb8PpqFZ/0kxqsP8B7BLVKvk9BkNYx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH2Q5w/btsBb8PpqFZ/0kxqsP8B7BLVKvk9BkNYx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH2Q5w/btsBb8PpqFZ/0kxqsP8B7BLVKvk9BkNYx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH2Q5w%2FbtsBb8PpqFZ%2F0kxqsP8B7BLVKvk9BkNYx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;286&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF2CIC/btsBcb6uSxE/BMmAFT89DKo99DwRNjmH00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF2CIC/btsBcb6uSxE/BMmAFT89DKo99DwRNjmH00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF2CIC/btsBcb6uSxE/BMmAFT89DKo99DwRNjmH00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF2CIC%2FbtsBcb6uSxE%2FBMmAFT89DKo99DwRNjmH00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;306&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지 별 메타태그 설정하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;nuxt.config.ts에 정의한 메타태그는 모든 페이지에서 공통으로 적용된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 페이지 별로 메타태그를 다르게 설정하고 싶으면 아래 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/129&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/129&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701336130088&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nuxt3] #16 Nuxt 3 SEO (메타태그 설정하기)&quot; data-og-description=&quot;SEO &amp;amp; metas with Nuxt 3 &amp;mdash; Course part 16 https://www.youtube.com/watch?v=PpyXtoM5HWQ&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=16 유튜브 강의를 참고하고 있습니다. 공통 메타태그 설정하기 nuxt.config.ts 모든 페이지에서 &quot; data-og-host=&quot;jae-study.tistory.com&quot; data-og-source-url=&quot;https://jae-study.tistory.com/129&quot; data-og-url=&quot;https://jae-study.tistory.com/129&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kdDan/hyUE6KSpQi/o5EgGqlVMyE7318dShPgj0/img.png?width=800&amp;amp;height=261&amp;amp;face=0_0_800_261,https://scrap.kakaocdn.net/dn/CrUld/hyUFfgLqey/ZYteF8TMgb1LFj6OCp0qf0/img.png?width=800&amp;amp;height=261&amp;amp;face=0_0_800_261,https://scrap.kakaocdn.net/dn/bb5KPK/hyUFcRRDgA/kGQNg0ijKK8yBkJyLbKUk0/img.png?width=928&amp;amp;height=581&amp;amp;face=0_0_928_581&quot;&gt;&lt;a href=&quot;https://jae-study.tistory.com/129&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jae-study.tistory.com/129&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kdDan/hyUE6KSpQi/o5EgGqlVMyE7318dShPgj0/img.png?width=800&amp;amp;height=261&amp;amp;face=0_0_800_261,https://scrap.kakaocdn.net/dn/CrUld/hyUFfgLqey/ZYteF8TMgb1LFj6OCp0qf0/img.png?width=800&amp;amp;height=261&amp;amp;face=0_0_800_261,https://scrap.kakaocdn.net/dn/bb5KPK/hyUFcRRDgA/kGQNg0ijKK8yBkJyLbKUk0/img.png?width=928&amp;amp;height=581&amp;amp;face=0_0_928_581');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nuxt3] #16 Nuxt 3 SEO (메타태그 설정하기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SEO &amp;amp; metas with Nuxt 3 &amp;mdash; Course part 16 https://www.youtube.com/watch?v=PpyXtoM5HWQ&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=16 유튜브 강의를 참고하고 있습니다. 공통 메타태그 설정하기 nuxt.config.ts 모든 페이지에서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jae-study.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt meta</category>
      <category>nuxt pinia</category>
      <category>nuxt seo</category>
      <category>nuxt todoList</category>
      <category>nuxt 검색엔진</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt 투두리스트 만들기</category>
      <category>nuxt3 pinia</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/134</guid>
      <comments>https://jae-study.tistory.com/134#entry134comment</comments>
      <pubDate>Thu, 30 Nov 2023 18:41:02 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #4 ToDo List 만들기 - 깃허브 페이지 배포하기</title>
      <link>https://jae-study.tistory.com/133</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://heejae0811.github.io/nuxt3-todo/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701769142758&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;오늘의 할 일&quot; data-og-description=&quot;오늘의 할 일은 무엇인가요?&quot; data-og-host=&quot;heejae0811.github.io&quot; data-og-source-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; data-og-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rZghj/hyUE7c3Un5/ubi3Ie0fin71bsqe1oFsqk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://heejae0811.github.io/nuxt3-todo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://heejae0811.github.io/nuxt3-todo/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rZghj/hyUE7c3Un5/ubi3Ie0fin71bsqe1oFsqk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;오늘의 할 일&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘의 할 일은 무엇인가요?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;heejae0811.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. gh-pages 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치된 버전은 package.json 파일에서 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1701324815644&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install gh-pages

또는

yarn add gh-pages&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. package.json&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json 파일의 scripts 부분에 &quot;deploy&quot;: &quot;~~&quot;를 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-f 옵션은 gh-pages 브랜치 깃 히스토리를 삭제한다. 깃 히스토리를 남기고 싶다면 해당 옵션을 제외한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701324854254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;scripts&quot;: {
    &quot;build&quot;: &quot;nuxt build&quot;,
    &quot;dev&quot;: &quot;nuxt dev&quot;,
    &quot;generate&quot;: &quot;nuxt generate&quot;,
    &quot;preview&quot;: &quot;nuxt preview&quot;,
    &quot;postinstall&quot;: &quot;nuxt prepare&quot;,
    &quot;deploy&quot;: &quot;gh-pages --dotfiles -d .output/public -f&quot;
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. nuxt.config.ts&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nuxt.config.ts 파일의 app 부분에 baseUrl과 buildAssetsDir를 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 baseUrl은 깃허브 레포지토리 이름으로 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701324955155&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  app: {
    baseURL: '/깃 레포지토리 이름/',
    buildAssetsDir: 'assets'
  },
  
  ...
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.&amp;nbsp; 깃허브 페이지 배포하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 npm run generate 명령어를 실행하면 .output 폴더와 dist 폴더가 생기는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm run deploy 명령어를 실행하면 깃허브에 배포된다.&lt;/p&gt;
&lt;pre id=&quot;code_1701325074580&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run generate
npm run deploy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLWeys/btsBeUvR9X0/1NUjUsbPdPaEkOBK4HTCIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLWeys/btsBeUvR9X0/1NUjUsbPdPaEkOBK4HTCIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLWeys/btsBeUvR9X0/1NUjUsbPdPaEkOBK4HTCIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLWeys%2FbtsBeUvR9X0%2F1NUjUsbPdPaEkOBK4HTCIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;224&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 깃허브 Settings&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 과정을 수행했음에도 깃허브 페이지가 배포가 되지 않는다면 깃 레포지토리 Settings을 확인해 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃 레포지토리 - Settings - Pages에서 Branch가 gh-pages로 되어있는지 확인한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wks1k/btsBcSrHOBU/UZM8i2RnoKjjIS1CTkMGX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wks1k/btsBcSrHOBU/UZM8i2RnoKjjIS1CTkMGX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wks1k/btsBcSrHOBU/UZM8i2RnoKjjIS1CTkMGX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwks1k%2FbtsBcSrHOBU%2FUZM8i2RnoKjjIS1CTkMGX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;331&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt gh-pages</category>
      <category>nuxt pinia</category>
      <category>nuxt todoList</category>
      <category>nuxt 깃허브 배포하기</category>
      <category>nuxt 배포하기</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt 투두리스트 만들기</category>
      <category>nuxt3 pinia</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/133</guid>
      <comments>https://jae-study.tistory.com/133#entry133comment</comments>
      <pubDate>Thu, 30 Nov 2023 15:58:58 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #3 ToDo List 만들기 - 등록순/최신순 정렬하기</title>
      <link>https://jae-study.tistory.com/132</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;sort 메서드를 이용해 toDoList 정렬하기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;v-bind를 이용해 class 바인딩하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbGm17/btsBeNDqsRr/3uxXnGcanUAf9y0k8wq1zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbGm17/btsBeNDqsRr/3uxXnGcanUAf9y0k8wq1zK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbGm17/btsBeNDqsRr/3uxXnGcanUAf9y0k8wq1zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbGm17%2FbtsBeNDqsRr%2F3uxXnGcanUAf9y0k8wq1zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;956&quot; height=&quot;603&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;603&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;0. 정렬 함수 하나로 만들기 (23.12.27 추가)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복된 코드가 많고, 토글 형태로 isActive 변수를 만들어 등록순을 클릭하고 또 등록순을 클릭하면 최신순으로 변경되는 오류가 발생해 코드를 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;sortToDo() 함수를 만든다.&lt;/li&gt;
&lt;li&gt;compareFn 매개변수를 만들어 @click 이벤트에서 받아온다. Nuxt3은 타입스크립트 기반이기 때문에 타입을 작성한다.&lt;/li&gt;
&lt;li&gt;data.value는 axios에서 받아오는 toDoData이다. 객체 형태이기 때문에 전개연산자를 사용했지만, 배열이라면 바로 sort 메서드를 사용한다.&lt;/li&gt;
&lt;li&gt;@click 이벤트에서 isActive를 true/false로 바꿔 class를 바인딩한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1703642676110&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
...

interface IToDo {
  id: number
  todo: string
  created_at: Date
}

function sortToDo(compareFn: (a: IToDo, b: IToDo) =&amp;gt; number) {
  toDoData.value = [...data.value].sort(compareFn)
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
    &amp;lt;section&amp;gt;
    	...
    
        &amp;lt;div v-if=&quot;toDoData.length &amp;gt; 0&quot;&amp;gt;
            &amp;lt;div class=&quot;flex gap-2 mb-6&quot;&amp;gt;
                &amp;lt;button
                    :class=&quot;{ 'underline underline-offset-4': isActive }&quot;
                    @click=&quot;() =&amp;gt; {
                    isActive = true
                    sortToDo((a, b) =&amp;gt; a.id - b.id)}&quot;&amp;gt;
                    등록순
                &amp;lt;/button&amp;gt;
                &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
                &amp;lt;button
                    :class=&quot;{ 'underline underline-offset-4': !isActive }&quot;
                    @click=&quot;() =&amp;gt; {
                    isActive = false
                    sortToDo((a, b) =&amp;gt; b.id - a.id)}&quot;&amp;gt;
                    최신순
                &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        
        ...
    &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 등록순/최신순 정렬 함수 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;sort 메서드로 toDoList의 id를 비교해 등록순/최신순 정렬 함수를 만든다.&lt;/li&gt;
&lt;li&gt;&amp;lt;button&amp;gt; 태그에 @click 이벤트를 걸어준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701320255738&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
...

function sortRegistered() {
  toDo.toDoList.sort((a, b) =&amp;gt; a.id - b.id)
}

function sortLatest() {
  toDo.toDoList.sort((a, b) =&amp;gt; b.id - a.id)
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg m-auto&quot;&amp;gt;
    ...
  
    &amp;lt;div v-if=&quot;toDo.toDoList.length &amp;gt; 0&quot;&amp;gt;
      &amp;lt;div class=&quot;flex gap-2&quot;&amp;gt;
        &amp;lt;button @click=&quot;sortRegistered()&quot;&amp;gt;등록순&amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button @click=&quot;sortLatest()&quot;&amp;gt;최신순&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      
      ...
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. v-bind로 class 바인딩하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;isActive 변수를 Boolean으로 만든다. (등록순/최신순 버튼에 on/off 효과를 주기 위해서)&lt;/li&gt;
&lt;li&gt;sort 함수가 동작할 때마다 isActive 변수가 true/false 될 수 있게 만든다.&lt;/li&gt;
&lt;li&gt;v-bind( : )를 이용해 클래스를 바인딩한다. (1개의 클래스만 바인딩하며 ''이 없어도 되지만, 여러 개 클래스를 바인딩할 경우 '' 안에 작성한다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701320632121&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
...

let isActive = true

function sortRegistered() {
  toDo.toDoList.sort((a, b) =&amp;gt; a.id - b.id)
  isActive = !isActive
}

function sortLatest() {
  toDo.toDoList.sort((a, b) =&amp;gt; b.id - a.id)
  isActive = !isActive
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg m-auto&quot;&amp;gt;
    ...
    
    &amp;lt;div v-if=&quot;toDo.toDoList.length &amp;gt; 0&quot;&amp;gt;
      &amp;lt;div class=&quot;flex gap-2&quot;&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : isActive }&quot;
          @click=&quot;sortRegistered()&quot;&amp;gt;등록순&amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button
          :class=&quot;{ 'underline underline-offset-4' : !isActive }&quot;
          @click=&quot;sortLatest()&quot;&amp;gt;최신순&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
      
      ...
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt :class</category>
      <category>nuxt sort</category>
      <category>nuxt todoList</category>
      <category>nuxt v-bind</category>
      <category>nuxt 정렬하기</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt 투두리스트 만들기</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 정렬하기</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/132</guid>
      <comments>https://jae-study.tistory.com/132#entry132comment</comments>
      <pubDate>Thu, 30 Nov 2023 14:20:02 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #2 ToDo List 만들기 - Pinia store로 ToDo 추가, 삭제하기</title>
      <link>https://jae-study.tistory.com/131</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Pinia 설치하기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Pinia store에서 데이터 불러오기&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;toDo 추가 및 삭제하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNB9OV/btsA6Uxey07/23Ly6LW4Hj6ElOHAKzEc4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNB9OV/btsA6Uxey07/23Ly6LW4Hj6ElOHAKzEc4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNB9OV/btsA6Uxey07/23Ly6LW4Hj6ElOHAKzEc4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNB9OV%2FbtsA6Uxey07%2F23Ly6LW4Hj6ElOHAKzEc4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;954&quot; height=&quot;439&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Pinia 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/123&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/123&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701246589430&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nuxt3] #10 Nuxt 3 State Management (일반 변수, useState, pinia 상태 관리 비교)&quot; data-og-description=&quot;State management with Nuxt 3 &amp;mdash; Course part 10 https://www.youtube.com/watch?v=IkpoAKS1s-k&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=10 유튜브 강의를 참고하고 있습니다. State Management란 상태 관리(State Management)에서 상태(Sta&quot; data-og-host=&quot;jae-study.tistory.com&quot; data-og-source-url=&quot;https://jae-study.tistory.com/123&quot; data-og-url=&quot;https://jae-study.tistory.com/123&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brGrnL/hyUE5EP3cr/CZOFvkgMy3yCpArxnFZEG0/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413,https://scrap.kakaocdn.net/dn/kFEvx/hyUE3Age2J/nrBmeIWYOBFfmlaHOvhVZk/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413,https://scrap.kakaocdn.net/dn/Xbq7e/hyUFccUnLM/0u1m3LJzawKTp4ZvfQwivk/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413&quot;&gt;&lt;a href=&quot;https://jae-study.tistory.com/123&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jae-study.tistory.com/123&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brGrnL/hyUE5EP3cr/CZOFvkgMy3yCpArxnFZEG0/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413,https://scrap.kakaocdn.net/dn/kFEvx/hyUE3Age2J/nrBmeIWYOBFfmlaHOvhVZk/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413,https://scrap.kakaocdn.net/dn/Xbq7e/hyUFccUnLM/0u1m3LJzawKTp4ZvfQwivk/img.png?width=676&amp;amp;height=413&amp;amp;face=0_0_676_413');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nuxt3] #10 Nuxt 3 State Management (일반 변수, useState, pinia 상태 관리 비교)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;State management with Nuxt 3 &amp;mdash; Course part 10 https://www.youtube.com/watch?v=IkpoAKS1s-k&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=10 유튜브 강의를 참고하고 있습니다. State Management란 상태 관리(State Management)에서 상태(Sta&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jae-study.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pinia 및 Nuxt3 state에 대한 자세한 설명은 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. json 데이터 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/toDoList.json&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api가 없기 때문에 json 파일로 빈 배열을 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1701246818940&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Pinia store 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stores/toDoStore.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;pinia를 import 한다.&lt;/li&gt;
&lt;li&gt;만든 toDoList.json 파일을 import 한다.&lt;/li&gt;
&lt;li&gt;useToDoStore 변수를 만들고, state를 정의한다. (초기값은 toDoList.json 파일의 빈 배열)&lt;/li&gt;
&lt;li&gt;Nuxt3은 타입스크립트 기반이기 때문에 interface을 이용해 state의 타입을 정의한다. (배열 안에 객체가 있는 형태)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701306246406&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { defineStore } from 'pinia'
import toDoList from '../server/api/toDoList.json'

interface ItoDo {
  id: number,
  content: string
}

export const useToDoStore = defineStore('toDo', {
  state: () =&amp;gt; ({
    toDoList: toDoList as ItoDo[]
  }),

  actions: {}
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. actions 정의하기&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4-1. toDoList 추가하기 (addToDo())&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;입력한 toDo(content)를 배열에 push한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이때 id는 고유한 값을 나타내기 위해 현재 시간(Date.now())으로 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4-2. toDoList 삭제하기 (deleteToDo())&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;findIndex 메서드와 id를 이용해 삭제할 toDo의 index를 찾는다.&lt;/li&gt;
&lt;li&gt;splice 메서드를 이용해 배열에서 해당 index의 toDo를 자른다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4-3. toDoList 전체 삭제하기 (clearToDo())&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;toDoList를 빈 배열로 만든다.&lt;/li&gt;
&lt;li&gt;전체 삭제이기 때문에 window.confirm 창을 통해 알럿 메세지를 보여준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701246934276&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...

export const useToDoStore = defineStore('toDo', {
  state: () =&amp;gt; ({
    toDoList: toDoList as ItoDo[]
  }),

  actions: {
    addToDo(content: string) {
      this.toDoList.push({ id: Date.now(), content: content })
    },

    deleteToDo(id: number) {
      const index = this.toDoList.findIndex(list =&amp;gt; list.id === id)

      if(index &amp;gt; -1) {
        this.toDoList.splice(index, 1)
      }
    },

    clearToDo() {
      if(window.confirm('리스트를 모두 삭제하시겠습니까?')) {
        this.toDoList = []
      }
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 페이지에서 Pinia store 불러오기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;toDoStore를 import 한다.&lt;/li&gt;
&lt;li&gt;newToDo 변수를 만들고, v-model를 이용해 input에 입력한 내용이 양방향 바인딩 될 수 있게 한다.&lt;/li&gt;
&lt;li&gt;Pinia store에 만든 actions을 클릭 이벤트로 만들어 toDo를 추가, 삭제, 전체 삭제한다. (&lt;u&gt;toDo.addToDo(), toDo.deleteToDo(), toDo.clearToDo()&lt;/u&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701247108973&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useToDoStore } from '@/stores/toDoStore'

const toDo = useToDoStore()
const newToDo = ref('')

function addToDo() {
  if(newToDo.value) {
    toDo.addToDo(newToDo.value)
    newToDo.value = ''
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg m-auto&quot;&amp;gt;
    &amp;lt;h1 class=&quot;mb-10 text-5xl font-bold text-center&quot;&amp;gt;ToDo List&amp;lt;/h1&amp;gt;

    &amp;lt;form
        class=&quot;mb-5&quot;
        @submit.prevent=&quot;addToDo()&quot;&amp;gt;
      &amp;lt;label for=&quot;toDo&quot; class=&quot;block mb-3 text-xl font-bold&quot;&amp;gt;New ToDo&amp;lt;/label&amp;gt;

      &amp;lt;div class=&quot;flex justify-between gap-5&quot;&amp;gt;
        &amp;lt;input
            v-model=&quot;newToDo&quot;
            type=&quot;text&quot;
            id=&quot;toDo&quot;
            class=&quot;w-3/4 px-3 py-4 rounded text-black&quot;
            placeholder=&quot;할 일을 입력해 주세요.&quot;/&amp;gt;
        &amp;lt;button class=&quot;w-1/4 bg-slate-500 rounded&quot;&amp;gt;추가하기&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;

    &amp;lt;div v-if=&quot;toDo.toDoList.length &amp;gt; 0&quot;&amp;gt;
      &amp;lt;div class=&quot;flex gap-2&quot;&amp;gt;
        &amp;lt;button&amp;gt;등록순&amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button&amp;gt;최신순&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;ul&amp;gt;
        &amp;lt;li
            v-for=&quot;(list, key) in toDo.toDoList&quot;
            :key=&quot;key&quot;
            class=&quot;flex justify-between items-center gap-5 mt-5 px-5 py-2 border rounded&quot;&amp;gt;
          &amp;lt;p class=&quot;flex gap-5 text-lg&quot;&amp;gt;
            &amp;lt;span&amp;gt;{{ key + 1 }}.&amp;lt;/span&amp;gt; {{ list.content }}
          &amp;lt;/p&amp;gt;
          &amp;lt;button
              @click=&quot;toDo.deleteToDo(list.id)&quot;
              class=&quot;px-5 py-2 bg-slate-500 rounded&quot;&amp;gt;
            삭제
          &amp;lt;/button&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;button
          @click=&quot;toDo.clearTodo()&quot;
          class=&quot;block w-1/3 mt-10 m-auto px-3 py-4 bg-slate-400 rounded&quot;&amp;gt;
        전체 삭제하기
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;toDoStore를 콘솔로 확인하면 store에 만든 state와 action 등 모든 정보를 확인할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAwzJs/btsBbOJv19U/qW4RhYvrePuUjbe4RWc0sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAwzJs/btsBbOJv19U/qW4RhYvrePuUjbe4RWc0sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAwzJs/btsBbOJv19U/qW4RhYvrePuUjbe4RWc0sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAwzJs%2FbtsBbOJv19U%2FqW4RhYvrePuUjbe4RWc0sk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;617&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt pinia</category>
      <category>nuxt pinia store</category>
      <category>nuxt state</category>
      <category>nuxt store</category>
      <category>nuxt todoList</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt3 pinia</category>
      <category>nuxt3 pinia store</category>
      <category>nuxt3 todoList</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/131</guid>
      <comments>https://jae-study.tistory.com/131#entry131comment</comments>
      <pubDate>Wed, 29 Nov 2023 17:47:13 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #1 ToDo List 만들기 - 테일윈드 CSS로 레이아웃 만들기</title>
      <link>https://jae-study.tistory.com/130</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Nuxt3 설치 및 테일윈드 CSS 설치&lt;/li&gt;
&lt;li&gt;투두 리스트 마크업&lt;/li&gt;
&lt;li&gt;투두 리스트 테일윈드 css 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;587&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv3LWD/btsA4VJT49d/e9ZPkC9yQXubJwJ7AQW8Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv3LWD/btsA4VJT49d/e9ZPkC9yQXubJwJ7AQW8Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv3LWD/btsA4VJT49d/e9ZPkC9yQXubJwJ7AQW8Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv3LWD%2FbtsA4VJT49d%2Fe9ZPkC9yQXubJwJ7AQW8Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;587&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;587&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;node v.20.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;nuxt v.3.8.1&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue v.3.3.8&lt;/i&gt;&lt;i&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Nuxt3 설치 및 테일윈드 CSS 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://jae-study.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jae-study.tistory.com/114&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701245232558&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nuxt3] #1 Nuxt 3 설치 및 테일윈드 CSS 적용하기&quot; data-og-description=&quot;Create an app with Nuxt 3 &amp;mdash; Course part 1 https://www.youtube.com/watch?v=hj3NNlTqIJg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=1 유튜브 강의를 참고하고 있습니다. Nuxt는 Vue.js를 사용하여 안전하고 성능이 뛰어난 풀 스&quot; data-og-host=&quot;jae-study.tistory.com&quot; data-og-source-url=&quot;https://jae-study.tistory.com/114&quot; data-og-url=&quot;https://jae-study.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brXxZc/hyUB2CZfTq/7KpOep9vV0mRgn2J7BeiX1/img.png?width=800&amp;amp;height=372&amp;amp;face=0_0_800_372,https://scrap.kakaocdn.net/dn/HOjwB/hyUCeKbnof/2shstKdm7YVfHmKtDh1k60/img.png?width=800&amp;amp;height=372&amp;amp;face=0_0_800_372,https://scrap.kakaocdn.net/dn/bznaSL/hyUEZkkZ0O/ZTZkyGxanVltzsKrKS0c6k/img.png?width=1870&amp;amp;height=870&amp;amp;face=0_0_1870_870&quot;&gt;&lt;a href=&quot;https://jae-study.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jae-study.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brXxZc/hyUB2CZfTq/7KpOep9vV0mRgn2J7BeiX1/img.png?width=800&amp;amp;height=372&amp;amp;face=0_0_800_372,https://scrap.kakaocdn.net/dn/HOjwB/hyUCeKbnof/2shstKdm7YVfHmKtDh1k60/img.png?width=800&amp;amp;height=372&amp;amp;face=0_0_800_372,https://scrap.kakaocdn.net/dn/bznaSL/hyUEZkkZ0O/ZTZkyGxanVltzsKrKS0c6k/img.png?width=1870&amp;amp;height=870&amp;amp;face=0_0_1870_870');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nuxt3] #1 Nuxt 3 설치 및 테일윈드 CSS 적용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create an app with Nuxt 3 &amp;mdash; Course part 1 https://www.youtube.com/watch?v=hj3NNlTqIJg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=1 유튜브 강의를 참고하고 있습니다. Nuxt는 Vue.js를 사용하여 안전하고 성능이 뛰어난 풀 스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jae-study.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt3 설치 및 테일윈드 CSS 설치에 대한 설명은 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 테일윈드 CSS를 이용해서 마크업 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;새로운 toDo를 입력할 &amp;lt;form&amp;gt; 태그를 만들고, 입력한 toDo들이 나타날 수 있게 &amp;lt;ul&amp;gt; 태그로 목록을 만든다.&lt;/li&gt;
&lt;li&gt;테일윈드를 사용해 CSS를 적용한다.&lt;/li&gt;
&lt;li&gt;toDoList 변수와 v-for를 이용해 toDoList를 보여준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1701245141849&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const toDoList = [
  {
    id: 1,
    content: '첫번째 할 일'
  },
  {
    id: 2,
    content: '두번째 할 일'
  },
  {
    id: 3,
    content: '세번째 할 일'
  }
]
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;w-full max-w-screen-lg m-auto&quot;&amp;gt;
    &amp;lt;h1 class=&quot;mb-10 text-5xl font-bold text-center&quot;&amp;gt;ToDo List&amp;lt;/h1&amp;gt;

    &amp;lt;form class=&quot;mb-5&quot;&amp;gt;
      &amp;lt;label for=&quot;toDo&quot; class=&quot;block mb-3 text-xl font-bold&quot;&amp;gt;New ToDo&amp;lt;/label&amp;gt;

      &amp;lt;div class=&quot;flex justify-between gap-5&quot;&amp;gt;
        &amp;lt;input
            type=&quot;text&quot;
            id=&quot;toDo&quot;
            class=&quot;w-3/4 px-3 py-4 rounded text-black&quot;
            placeholder=&quot;할 일을 입력해 주세요.&quot;/&amp;gt;
        &amp;lt;button class=&quot;w-1/4 bg-slate-500 rounded&quot;&amp;gt;추가하기&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/form&amp;gt;

    &amp;lt;div&amp;gt;
      &amp;lt;div class=&quot;flex gap-2&quot;&amp;gt;
        &amp;lt;button&amp;gt;등록순&amp;lt;/button&amp;gt;
        &amp;lt;i&amp;gt;|&amp;lt;/i&amp;gt;
        &amp;lt;button&amp;gt;최신순&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;ul&amp;gt;
        &amp;lt;li
            v-for=&quot;(list, key) in toDoList&quot;
            :key=&quot;key&quot;
            class=&quot;flex justify-between items-center gap-5 mt-5 px-5 py-2 border rounded&quot;&amp;gt;
          &amp;lt;p class=&quot;flex gap-5 text-lg&quot;&amp;gt;
            &amp;lt;span&amp;gt;{{ key + 1 }}.&amp;lt;/span&amp;gt; {{ list.content }}
          &amp;lt;/p&amp;gt;
          &amp;lt;button class=&quot;px-5 py-2 bg-slate-500 rounded&quot;&amp;gt;
            삭제
          &amp;lt;/button&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;button class=&quot;block w-1/3 mt-10 m-auto px-3 py-4 bg-slate-400 rounded&quot;&amp;gt;
        전체 삭제하기
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 ToDo 만들기</category>
      <category>nuxt pinia</category>
      <category>nuxt todoList</category>
      <category>nuxt 설치하기</category>
      <category>nuxt 테일윈드 설치하기</category>
      <category>nuxt 투두리스트</category>
      <category>nuxt3 pinia</category>
      <category>nuxt3 todoList</category>
      <category>Nuxt3 설치하기</category>
      <category>nuxt3 테일윈드 css</category>
      <category>nuxt3 투두리스트</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/130</guid>
      <comments>https://jae-study.tistory.com/130#entry130comment</comments>
      <pubDate>Wed, 29 Nov 2023 17:20:44 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #16 Nuxt 3 SEO (메타태그 설정하기)</title>
      <link>https://jae-study.tistory.com/129</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SEO &amp;amp; metas with Nuxt 3 &amp;mdash; Course part 16&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PpyXtoM5HWQ&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=16&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=PpyXtoM5HWQ&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=16&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;공통 메타태그 설정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nuxt.config.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 페이지에서 동일한 title과 description이 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1701050482647&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  app: {
    head: {
      title: 'Nuxt course on Youtube',
      meta: [
        { name: 'description', content: 'This is a repository for a course about Nuxt 3 for youtube.' }
      ]
    }
  },
  ...
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uZBBy/btsASVJY2jy/c4RMv1xJYiX9HR1rycn650/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uZBBy/btsASVJY2jy/c4RMv1xJYiX9HR1rycn650/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uZBBy/btsASVJY2jy/c4RMv1xJYiX9HR1rycn650/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuZBBy%2FbtsASVJY2jy%2Fc4RMv1xJYiX9HR1rycn650%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;985&quot; height=&quot;322&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;페이지 별 메타태그 설정하기&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. useHead()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useHead() 컴포져블을 사용하면 unhead에서 제공하는 프로그래밍 방식 및 반응형 방식으로 &amp;lt;head&amp;gt; 태그를 관리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'~~' 따음표를 이용한 텍스트 또는 변수로 SEO 설정이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701050869572&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const route = useRoute()

useHead({
  title: `타이틀: ${route.name}`,
  meta: [
    { name: 'description', content: 'This is an index page.' }
  ],
  bodyAttrs: {
    class: 'test'
  },
  script: [ { innerHTML: 'console.log(\'Hello world\')' } ]
})
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;인덱스 페이지&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIHvuY/btsA1dIYodN/cGHNv12kHftwMIpJORJ9r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIHvuY/btsA1dIYodN/cGHNv12kHftwMIpJORJ9r0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIHvuY/btsA1dIYodN/cGHNv12kHftwMIpJORJ9r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIHvuY%2FbtsA1dIYodN%2FcGHNv12kHftwMIpJORJ9r0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;696&quot; height=&quot;326&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. useSeoMeta()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useSeoMeta() 컴포져블을 사용하면 타입스크립트가 완전히 지원하는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SEO 메타 태그 &lt;/span&gt;객체를 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'~~' 따음표를 이용한 텍스트 또는 변수로 SEO 설정이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/auth/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701051528375&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const route = useRoute()

useSeoMeta({
  title: route.name,
  ogTitle: 'Login Page',
  description: 'This is a login page.',
  ogDescription: 'This is a login page.',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;로그인 페이지&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQ6G9/btsASGsDOCh/mnEgVezErQOQ2TNj8zECL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQ6G9/btsASGsDOCh/mnEgVezErQOQ2TNj8zECL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQ6G9/btsASGsDOCh/mnEgVezErQOQ2TNj8zECL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQ6G9%2FbtsASGsDOCh%2FmnEgVezErQOQ2TNj8zECL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;633&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. &amp;lt;Head&amp;gt; 태그&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 &amp;lt;Head&amp;gt;, &amp;lt;Title&amp;gt;, &amp;lt;Style&amp;gt;, &amp;lt;Meta&amp;gt;, &amp;lt;Link&amp;gt; 등의 태그를 제공하기 때문에 HTML 영역에 직접적으로 메타태그를 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/auth/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701051920672&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const description = ref('This is dynamic description.')
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;Head&amp;gt;
    &amp;lt;Title&amp;gt;Login Page&amp;lt;/Title&amp;gt;
    &amp;lt;Meta name=&quot;description&quot; :content=&quot;description&quot;/&amp;gt;
    &amp;lt;Style type=&quot;text/css&quot; children=&quot;body { background-color: gray !important; }&quot; /&amp;gt;
  &amp;lt;/Head&amp;gt;

  &amp;lt;div&amp;gt;{{ description }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rg8IV/btsAYGq7bEp/uvvbX06isPmkBr8wfarXDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rg8IV/btsAYGq7bEp/uvvbX06isPmkBr8wfarXDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rg8IV/btsAYGq7bEp/uvvbX06isPmkBr8wfarXDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frg8IV%2FbtsAYGq7bEp%2FuvvbX06isPmkBr8wfarXDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;928&quot; height=&quot;581&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;581&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt meta</category>
      <category>nuxt seo</category>
      <category>nuxt 메타태그 설정하기</category>
      <category>nuxt3 meta</category>
      <category>useHead()</category>
      <category>useSeoMeta()</category>
      <category>vue meta</category>
      <category>vue seo</category>
      <category>vue 메타태그 설정하기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/129</guid>
      <comments>https://jae-study.tistory.com/129#entry129comment</comments>
      <pubDate>Mon, 27 Nov 2023 11:52:32 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #15 Nuxt 3 useAsycnData, useLazyAsyncData (useFetch, useAsyncData, $fetch 비교)</title>
      <link>https://jae-study.tistory.com/128</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useAsyncData with Nuxt 3 &amp;mdash; Course part 15&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=3xeAElHzMe4&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=15&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=3xeAElHzMe4&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=15&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. useAsyncData&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useAsyncData()는 비동기 로직의 resolve 동작을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch('url')과 useAsyncData('url', () =&amp;gt; $fetch('url')) 와 거의 동일하게 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/products.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;async, await를 사용해 비동기 함수를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수가 동작하면 1초 뒤에 productCount가 1씩 증가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700805720994&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let productCount = 0

export default async() =&amp;gt; {
  await new Promise((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(productCount++)
    }, 1000)
  })

  return { productCount }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useAsyncData()를 사용해 data를 가지고 온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클릭 이벤트를 만들어 버튼을 클릭하면 data가 새로고침 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1700805775188&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data: productCount, pending } = await useAsyncData('count', () =&amp;gt; $fetch('/api/products'))

const refresh = () =&amp;gt; refreshNuxtData('count')

&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;div v-if=&quot;pending&quot;&amp;gt;
    &amp;lt;p&amp;gt;pending&amp;lt;/p&amp;gt;
    {{ productCount }}
  &amp;lt;/div&amp;gt;

  &amp;lt;div v-else&amp;gt;
    &amp;lt;p&amp;gt;resolve&amp;lt;/p&amp;gt;
    {{ productCount }}
  &amp;lt;/div&amp;gt;

  &amp;lt;button @click=&quot;refresh&quot;&amp;gt;Refresh&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2RWzs/btsASGxQ7g0/ywFEAnfp84BokJIhRwhUuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2RWzs/btsASGxQ7g0/ywFEAnfp84BokJIhRwhUuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2RWzs/btsASGxQ7g0/ywFEAnfp84BokJIhRwhUuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2RWzs%2FbtsASGxQ7g0%2FywFEAnfp84BokJIhRwhUuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;295&quot; height=&quot;186&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useLazyAsyncData&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useLazyAsyncData()를 사용하는 것만 제외하면 나머지는 동일한 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼핏 보면 차이점이 없는 것처럼 보이지만, 페이지 처음 진입 시 useLazyAsyncData()를 사용하면 v-if=&quot;pending&quot; 부분이 나타나는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pending 상태의 화면 로직을 보여주고 싶을 때 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700807629444&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data: productCount, pending } = await useLazyAsyncData('count', () =&amp;gt; $fetch('/api/products'))

const refresh = () =&amp;gt; refreshNuxtData('count')

&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;div v-if=&quot;pending&quot;&amp;gt;
    &amp;lt;p&amp;gt;pending&amp;lt;/p&amp;gt;
    {{ productCount }}
  &amp;lt;/div&amp;gt;

  &amp;lt;div v-else&amp;gt;
    &amp;lt;p&amp;gt;resolve&amp;lt;/p&amp;gt;
    {{ productCount }}
  &amp;lt;/div&amp;gt;

  &amp;lt;button @click=&quot;refresh&quot;&amp;gt;Refresh&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YEiEu/btsAO65WBrS/GqCHJNgwARpioS662A7TK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YEiEu/btsAO65WBrS/GqCHJNgwARpioS662A7TK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YEiEu/btsAO65WBrS/GqCHJNgwARpioS662A7TK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYEiEu%2FbtsAO65WBrS%2FGqCHJNgwARpioS662A7TK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;292&quot; height=&quot;179&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;$fetch&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$fetch는 Nuxt3에서 제공하는 전역 메서드이고, HTTP request를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$fetch는 서버와 클라이언트 환경에서의 중복 호출 문제가 있기 때문에 클라이언트 사이드에서만 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 사이트 렌더링을 위해서는 useFetch나 useAsyncData를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useFetch() vs useAsyncData()&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2가지 메서드는 동일한 기능을 하는 것처럼 보이지만, 사용법에서 몇 가지 차이가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그중 가능 큰 차이는 실행 context의 차이이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useAsyncData()는 page 값이 바뀌면 url의 params도 변경되지만, useFetch()는 page 값이 바뀌어도 params가 바뀌지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;확실히 이해한 부분이 아니기 때문에 실제로 사용해 보면서 공부가 더 필요하다..&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;참고자료&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/api/composables/use-fetch&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-async-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/api/composables/use-async-data&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://jongmin4943.tistory.com/entry/Nuxt3-fetch-useAsyncData-useFetch-%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot;&gt;https://jongmin4943.tistory.com/entry/Nuxt3-fetch-useAsyncData-useFetch-%EC%9D%98-%EC%B0%A8%EC%9D%B4&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>data fetching</category>
      <category>nuxt useAsyncData</category>
      <category>nuxt useLazyAsyncData</category>
      <category>useAsyncData</category>
      <category>useAsyncData()</category>
      <category>useLazyAsyncData</category>
      <category>useLazyAsyncData()</category>
      <category>vue useAsyncData</category>
      <category>vue useLazyAsyncData</category>
      <category>vue 데이터 패칭</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/128</guid>
      <comments>https://jae-study.tistory.com/128#entry128comment</comments>
      <pubDate>Fri, 24 Nov 2023 15:40:50 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #14 Nuxt 3 useFetch, useLazyFetch</title>
      <link>https://jae-study.tistory.com/127</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useFetch, useLazyfetch with Nuxt 3 &amp;mdash; Course part 14&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=rU92oLYjTGY&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=14&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=rU92oLYjTGY&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=14&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Data Fetching&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 서버 또는 브라우저에서 데이터를 가져와 처리하는 컴포저블을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useFetch()&lt;/li&gt;
&lt;li&gt;useAsyncData&lt;/li&gt;
&lt;li&gt;$fetch&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. useFetch()&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch()는 컴포넌트 설정 기능 중에서 데이터 패칭을 수행하는 가장 간단한 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/products.json&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data를 json 파일로 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1700791813851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
  {
    &quot;name&quot;: &quot;책상&quot;,
    &quot;price&quot;: &quot;$50.99&quot;,
    &quot;description&quot;: &quot;책상입니다.&quot;
  },
  {
    &quot;name&quot;: &quot;의자&quot;,
    &quot;price&quot;: &quot;$30.99&quot;,
    &quot;description&quot;: &quot;의자입니다.&quot;
  },
  {
    &quot;name&quot;: &quot;컴퓨터&quot;,
    &quot;price&quot;: &quot;$999.99&quot;,
    &quot;description&quot;: &quot;컴퓨터입니다.&quot;
  }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/products.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json 파일을 import 해 return 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700791867727&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import data from './products.json'

export default defineEventHandler((event) =&amp;gt; {
  return {
    data
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6UDBL/btsAMqReXeT/9k7RKow8uxaH7VGVsixkCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6UDBL/btsAMqReXeT/9k7RKow8uxaH7VGVsixkCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6UDBL/btsAMqReXeT/9k7RKow8uxaH7VGVsixkCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6UDBL%2FbtsAMqReXeT%2F9k7RKow8uxaH7VGVsixkCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;330&quot; height=&quot;395&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch()를 사용해 data를 가지고 온다.&lt;/p&gt;
&lt;pre id=&quot;code_1700791916334&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data } = await useFetch('/api/products')

console.log(data)
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  {{ data }}
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HfTfe/btsAL0kKacA/yXh1OPHfkAOvxgnZXdPA4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HfTfe/btsAL0kKacA/yXh1OPHfkAOvxgnZXdPA4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HfTfe/btsAL0kKacA/yXh1OPHfkAOvxgnZXdPA4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHfTfe%2FbtsAL0kKacA%2FyXh1OPHfkAOvxgnZXdPA4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1275&quot; height=&quot;388&quot; data-origin-width=&quot;1275&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{ data: products } 라고 변수 이름을 설정할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 동일하다.&lt;/p&gt;
&lt;pre id=&quot;code_1700792428868&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data: products } = await useFetch('/api/products')

console.log(toRaw(products.value))
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  {{ products }}
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIZ07q/btsAPwvKf5k/JIrxzuKkrAiHnkb5HsdFs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIZ07q/btsAPwvKf5k/JIrxzuKkrAiHnkb5HsdFs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIZ07q/btsAPwvKf5k/JIrxzuKkrAiHnkb5HsdFs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIZ07q%2FbtsAPwvKf5k%2FJIrxzuKkrAiHnkb5HsdFs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1198&quot; height=&quot;364&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useLazyFetch()&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useLazyFetch()는 데이터 패칭을 하기 전(EventHandler가 resolve 되기 전)의 과정을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/products.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;asycn()과 setTimeout()을 사용해 data를 2초 뒤에 return 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700793924182&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import data from './products.json'

export default defineEventHandler(async()=&amp;gt; {
  return new Promise&amp;lt;any&amp;gt;((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(data)
    }, 2000)
  })
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useLazyFetch()를 사용해 data를 가지고 온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 pending(보류: 초기 상태로 이행되기 전이나 거절되기 전의 상태)을 사용해 data를 가지고 오기 전에 화면 로직을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data가 화면에 보이기 전에 Loading 텍스트가 나오고, console.log도 그전에 실행되기 때문에 null 값이 찍힌다.&lt;/p&gt;
&lt;pre id=&quot;code_1700794239047&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data: products, pending } = await useLazyFetch('/api/products')

console.log(toRaw(products.value))
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  {{ pending ? 'Loading' : products }}
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vMEls/btsAMl3j60U/94fSM2DjNQc1gyUDywKiD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vMEls/btsAMl3j60U/94fSM2DjNQc1gyUDywKiD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vMEls/btsAMl3j60U/94fSM2DjNQc1gyUDywKiD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvMEls%2FbtsAMl3j60U%2F94fSM2DjNQc1gyUDywKiD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1052&quot; height=&quot;281&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nuxt.config.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 useLazyFetch()와 pending을 사용했는데도 새로고침 즉시 data가 나온다면 SSR 설정이 false인지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR은 서버에서 렌더링이 완료된 다음에 브라우저에 보여지기 때문에 useLazyFetch()가 동작하지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1700794638845&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [],
  ...
  ssr: false
})&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>$fetch</category>
      <category>data fetching</category>
      <category>nuxt useFetch</category>
      <category>nuxt useLazyFetch</category>
      <category>nuxt 데이터 패칭</category>
      <category>useFetch()</category>
      <category>useLazyFetch()</category>
      <category>vue useFetch</category>
      <category>vue useLazyFetch</category>
      <category>vue 데이터 패칭</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/127</guid>
      <comments>https://jae-study.tistory.com/127#entry127comment</comments>
      <pubDate>Fri, 24 Nov 2023 14:09:19 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #13 Nuxt 3 렌더링 모드 (Universal Mode와 CSR/SSR/SSG, SPA/MPA)</title>
      <link>https://jae-study.tistory.com/126</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Rendering modes with Nuxt 3 &amp;mdash; Course part 13&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=TmgIylXsLuE&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=13&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=TmgIylXsLuE&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=13&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Nuxt 모드&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 프로젝트를 설치할 때 2가지의 렌더링 모드를 선택할 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Universal (SSR/SSG)&lt;/li&gt;
&lt;li&gt;Single Page App&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Universal 모드를 설명하기 전에 웹 페이지 렌더링 방식에 대해 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Client Side Rendering (CSR, 클라이언트 사이드 렌더링)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트(브라우저)에서 웹 페이지를 렌더링 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용가가 웹 페이지를 방문하면(서버 요청을 받으면) 서버는 클라이언트에게 HTML과 JS를 보내고, 클라이언트가 그것을 렌더링 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) React, Vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;CSR 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 이동시 전체 HTML을 로드할 필요가 없기 때문에 SSR에 비해 속도가 빠르다.&lt;/li&gt;
&lt;li&gt;필요한 부분만 변경되기 때문에 새로고침이 발생하지 않아 사용성이 뛰어나다.&lt;/li&gt;
&lt;li&gt;API 호출이 필요 없기 때문에 지연 로딩 모듈이 필요하지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;CSR 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 페이지 로드 시간이 SSR에 비해 느리다.&lt;/li&gt;
&lt;li&gt;SEO(Search Engine Optimization, 검색 엔진 최적화)가 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Server Side Rendering (SSR, 서버 사이드 렌더링)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 웹 페이지를 렌더링 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 웹 페이지를 방문하면 서버는 리소스를 확인해 렌더링이 끝난 상태로 클라이언트에게 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Next, Nuxt&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SSR 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 페이지 로드 시간이 CSR에 비해 빠르다.&lt;/li&gt;
&lt;li&gt;SEO가 유리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SSR 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 이동시 서버에서 새로운 html을 불러와야 하기 때문에 CSR보다 속도가 느리고, 새로고침이 발생해 사용성이 떨어진다.&lt;/li&gt;
&lt;li&gt;렌더링을 서버에서 하기 때문에 서버에 부담이 크다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Static Site Generation (SSG)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서 필요한 페이지들을 사전에 미리 준비하고, 서버 요청을 받으면 이미 완성된 파일을 브라우저에 렌더링 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR과 비슷하지만 서버에서 요청을 할 때 즉시 만드는지 미리 만들어 놓는지의 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SSG 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐싱이 가능하다.&lt;/li&gt;
&lt;li&gt;SEO가 유리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SSG 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 URL에 대해 개별 HTML 파일을 생성해야 한다. URL을 예측할 수 없다면 적용하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;검색 엔진 노출보다 서버의 부담이나 데이터 보호가 중요하다 -&amp;gt; CSR&lt;br /&gt;검색 엔진이 중요하고, 업데이트가 자주 일어난다 -&amp;gt; SSR&lt;br /&gt;검색 엔진이 중요하고, 업데이트가 거의 없다. -&amp;gt; SSG&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;만약 검색 엔진과 새로고침 없는 인터렉션이 모두 중요하다면 CSR + SST인 Universal 렌더링을 고려해야 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Single Page Application (&lt;/b&gt;&lt;b&gt;SPA, 단일 페이지 애플리케이션)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SPA는 말 그대로 하나의 페이지를 사용하는 애플리케이션이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에서 새로운 페이지를 요청하는 것이 아니라 하나의 페이지에서 내용만 동적으로 변경한다. (CSR 방식으로 렌더링 한다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SPA 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 이동 시 변경된 부분만 갱신되기 때문에 앱과 같은 자연스러운 사용자 경험을 제공한다.&lt;/li&gt;
&lt;li&gt;서버가 해야 하는 화면 구성을 클라이언트가 수행하기 때문에 서버 부담이 경감된다.&lt;/li&gt;
&lt;li&gt;모듈화 또는 컴포넌트 개발이 용이해 효율성이 증가한다.&lt;/li&gt;
&lt;li&gt;프론트앤드와 백앤드 구분이 확실하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SPA 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 사이트 접속 시 모든 리소스를 한 번에 받기 때문에 초기 로딩 속도가 느리다.&lt;/li&gt;
&lt;li&gt;비즈니스 로직(화면이 변하는 모습)이 사용자에게 노출될 수 있다.&lt;/li&gt;
&lt;li&gt;SEO가 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Multiple Page Application (MPA, 다중 페이지 애플리케이션)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MPA는 말 그대로 여러 개의 싱글 페이지를 사용하는 애플리케이션이고, 전통적인 웹 방식이라고도 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 페이지를 요청할 때마다 서버에서 리소스가 다운되며 전체 페이지를 다시 렌더링(새로고침)해 내용을 변경한다. (SSR 방식으로 렌더링한다.)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MPA 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 사이트 접속 시 초기 로딩 속도가 빠르다.&lt;/li&gt;
&lt;li&gt;SEO가 유리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MPA 단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 이동 시 새로고침이 발생해 깜빡임이 발생한다.&lt;/li&gt;
&lt;li&gt;서버 요청이 있을 때마다 서버에서 렌더링을 하기 때문에 서버 부담이 증가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;CSR과 SPA, SSR과 MAP는 개념이 비슷해서 같은 것이라고 착각할 수 있지만,&lt;br /&gt;렌더링을 어떻게 하는지와 페이지를 몇 개 사용하는지의 차이이기 때문에 단어 사용에 주의해야 한다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Universal Mode (유니버셜 모드)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 CSR과 SSR의 장점을 모두 합친 Universal Mode 렌더링을 선택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 Nuxt 페이지를 처음 접속하면 서버에서 렌더링 하고, 이후 페이지 간 이동은 클라이언트에서 렌더링 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2c3e50; text-align: start;&quot;&gt;이를 위해서 Nuxt는 클라이언트 사이드 하이드레이션(Client Side Hydration)과 코드 분할(Code Splitting)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #2c3e50; text-align: start;&quot;&gt;, 프리패칭(Prefetching)을 활용하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;클라이언트 사이드 하이드레이션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2c3e50; text-align: start;&quot;&gt;서버로부터 받은 정적 HTML을 사용자와 상호작용할 수 있는 다이나믹 DOM으로 바꾸는 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;코드 분할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 전체를 로드하지 않고 분할해서 필요에 맞는 번들로 나눠 가져오는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 번들만 가져오기 때문에 로딩 속도가 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프리패칭&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 화면에 보이는 &amp;lt;NuxtLink&amp;gt; 컴포넌트에 한해서 해당 페이지들을 렌더링 하는데 필요한 파일들을 미리 서버에 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 사용자가 클릭하기도 전에 이미 CSR에 준비가 되어있고, 사용자가 패칭을 요구하기 전에 미리 패칭 되어 있는 것을 프리패칭이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nuxt.config.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #334155; text-align: start;&quot;&gt;클라이언트 측 전용 렌더링을 활성화할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700730403926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  ssr: false
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로 규칙을 사용해 경로별로 다른 캐싱 규칙을 허용하고 서버가 지정된 URL의 요청을 응답하는 방법을 결정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700730563809&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  routeRules: {
    // Homepage pre-rendered at build time
    '/': { prerender: true },
    
    // Product page generated on-demand, revalidates in background
    '/products/**': { swr: 3600 },
    
    // Blog post generated on-demand once until next deploy
    '/blog/**': { isr: true },
    
    // Admin dashboard renders only on client-side
    '/admin/**': { ssr: false },
    
    // Add cors headers on API routes
    '/api/**': { cors: true },
    
    // Redirects legacy urls
    '/old-page': { redirect: '/new-page' }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;참고자료&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://nuxt.com/docs/guide/concepts/rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/guide/concepts/rendering&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;a href=&quot;https://joshua1988.github.io/vue-camp/nuxt/universal-mode.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://joshua1988.github.io/vue-camp/nuxt/universal-mode.html&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://hanamon.kr/spa-mpa-ssr-csr-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EB%9C%BB%EC%A0%95%EB%A6%AC/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hanamon.kr/spa-mpa-ssr-csr-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EB%9C%BB%EC%A0%95%EB%A6%AC/&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://velog.io/@ka0son/%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%82%BC%ED%98%95%EC%A0%9C-CSR-SSR-SSG-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot;&gt;https://velog.io/@ka0son/%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%82%BC%ED%98%95%EC%A0%9C-CSR-SSR-SSG-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&lt;/a&gt; &lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>CSR</category>
      <category>CSR SSR SSG</category>
      <category>MPA</category>
      <category>Nuxt 렌더링 모드</category>
      <category>Spa</category>
      <category>spa mpa</category>
      <category>SSG</category>
      <category>SSR</category>
      <category>universal mode</category>
      <category>유니버셜 모드</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/126</guid>
      <comments>https://jae-study.tistory.com/126#entry126comment</comments>
      <pubDate>Thu, 23 Nov 2023 18:11:15 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #12 Nuxt 3 Nitro 서버</title>
      <link>https://jae-study.tistory.com/125</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Nitro with Nuxt 3 &amp;mdash; Course part 12&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=1J-ywLgs--s&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=12&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=1J-ywLgs--s&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=12&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Nitro란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nitro는 초고속 웹 서버를 구축하기 위한 오픈 소스 타입스크립트 프레임워크이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt3는 Nitro를 서버 엔진으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js, 브라우저, service-workers 등을 위한 크로스 플랫폼 지원&lt;/li&gt;
&lt;li&gt;즉시 사용 가능한 서버리스(serverless, 개발자가 서버를 관리할 필요 없이 빌드하고 실행할 수 있도록 하는 클라우드 네이티브 개발 모델) 지원&lt;/li&gt;
&lt;li&gt;API 경로 지원&lt;/li&gt;
&lt;li&gt;자동 코드 분할 및 비동기 로드&amp;nbsp;&lt;/li&gt;
&lt;li&gt;정적 + 서버리스 사이트를 위한 하이브리드 모드&lt;/li&gt;
&lt;li&gt;핫 모듈을 다시 로드하는 개발 서버&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;useNitro &lt;/b&gt;: Nitro 인스턴스를 반환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; addServerHandler &lt;/b&gt;: 서버 핸들러를 추가한다. 서버 미들웨어나 커스텀 라우터를 생성하고 싶을 때 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; addDevServerHandler &lt;/b&gt;: 개발 모드에서만 사용할 서버 핸들러를 추가한다. 프로덕션 빌드에서 제외된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; addServerPlugin &lt;/b&gt;: Nitro의 런타임 동작을 확장하기 위한 플러그인을 추가한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; addPrerenderRoutes &lt;/b&gt;: Nitro에서 사전 렌더링할 경로를 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/kit/nitro&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/docs/api/kit/nitro&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nitro 메서드에 대한 자세한 설명은 공식 문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;API 레이어&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버 API 엔드포인트와 미들웨어는 Nitro에 의해 추가된다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;핸들러는 자동으로 처리되는 JSON 응답에 대해 객체/베열을 직접 반환할 수 있다.&lt;/li&gt;
&lt;li&gt;핸들러는 Promise를 반환할 수 있다. (res.end(), next() 지원 가능)&lt;/li&gt;
&lt;li&gt;본문 구문 분석, 쿠키 처리, 리디렉션, 헤더 등을 위한 기능이 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>api nitro</category>
      <category>nitro</category>
      <category>nuxt nitro</category>
      <category>server nitro</category>
      <category>vue nitro</category>
      <category>니트로</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/125</guid>
      <comments>https://jae-study.tistory.com/125#entry125comment</comments>
      <pubDate>Wed, 22 Nov 2023 15:17:51 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #11 Nuxt 3 Server (API 연결, HTTP 메서드)</title>
      <link>https://jae-study.tistory.com/124</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Server with Nuxt 3 &amp;mdash; Course part 11&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=RQhWvHz3I5I&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=11&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=RQhWvHz3I5I&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=11&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Server란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt Server 디렉토리는 데이터베이스나 다른 서버에서 데이터를 가져오고, API를 생성하고, 사이트맵이나 RSS 피드와 같은 정적 서버 측 컨텐츠를 생성하는 작업까지 모두 단일 코드베이스에서 수행할 수 있다. 또한 디렉토리 내의 파일을 자동으로 스캔하여 HMR(Hot Module Replacement) 지원으로 API 및 서버 핸들러를 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. /server/api&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/hello.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1700621563680&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineEventHandler((event) =&amp;gt; {
  return {
    api: 'hello world'
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useFetch를 통해서 API를 호출할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1700621592381&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { data } = await useFetch('/api/hello')
console.log(data)
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;{{ data }}&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbuABx/btsAJhTshth/F57pXC3jD5Zflupk7v7LMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbuABx/btsAJhTshth/F57pXC3jD5Zflupk7v7LMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbuABx/btsAJhTshth/F57pXC3jD5Zflupk7v7LMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbuABx%2FbtsAJhTshth%2FF57pXC3jD5Zflupk7v7LMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;906&quot; height=&quot;383&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x8R01/btsAHYmzk4H/FPMyVD5Ew1AxrRBFPeCMb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x8R01/btsAHYmzk4H/FPMyVD5Ew1AxrRBFPeCMb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x8R01/btsAHYmzk4H/FPMyVD5Ew1AxrRBFPeCMb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx8R01%2FbtsAHYmzk4H%2FFPMyVD5Ew1AxrRBFPeCMb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;306&quot; height=&quot;171&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. /server/routes&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/routes/hello.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/api 접두사 없이 서버 경로를 추가하려면 /server/routes/ 디렉터리를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700621910727&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineEventHandler(() =&amp;gt; 'Hello World!')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfzz2D/btsAHXVsSAq/8IWaQaKXmKYz0pEqvwZFX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfzz2D/btsAHXVsSAq/8IWaQaKXmKYz0pEqvwZFX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfzz2D/btsAHXVsSAq/8IWaQaKXmKYz0pEqvwZFX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbfzz2D%2FbtsAHXVsSAq%2F8IWaQaKXmKYz0pEqvwZFX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;295&quot; height=&quot;132&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. HTTP 메서드&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server/api 디렉터리의 파일에는 HTTP 메서드를 붙일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;GET&lt;/b&gt; /api/users - 등록된 모든 사용자를 가져온다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;POST &lt;/b&gt;/api/users - 새로운 사용자를 생성한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PUT&lt;/b&gt; /api/users/{id} - 사용자의 상태를 변경한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DELETE &lt;/b&gt;/api/users/{id} - 사용자를 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/test.get.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1700630796160&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineEventHandler(() =&amp;gt; 'Test get handler')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfTsY/btsAJgf46je/wIkvscAIY6yHokeWN9U4lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfTsY/btsAJgf46je/wIkvscAIY6yHokeWN9U4lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfTsY/btsAJgf46je/wIkvscAIY6yHokeWN9U4lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfTsY%2FbtsAJgf46je%2FwIkvscAIY6yHokeWN9U4lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;296&quot; height=&quot;134&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;server/api/test.post.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1700630820995&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineEventHandler(() =&amp;gt; 'Test post handler')&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt api</category>
      <category>nuxt http</category>
      <category>nuxt routes</category>
      <category>nuxt server</category>
      <category>nuxt 서버</category>
      <category>vue api</category>
      <category>vue http</category>
      <category>vue routes</category>
      <category>vue server</category>
      <category>vue 서버</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/124</guid>
      <comments>https://jae-study.tistory.com/124#entry124comment</comments>
      <pubDate>Wed, 22 Nov 2023 14:30:42 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #10 Nuxt 3 State Management (일반 변수, useState, pinia 상태 관리 비교)</title>
      <link>https://jae-study.tistory.com/123</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;State management with Nuxt 3 &amp;mdash; Course part 10&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=IkpoAKS1s-k&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=10&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=IkpoAKS1s-k&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=10&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;State Management란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태 관리(State Management)에서 상태(State)란, 앱 구동에 필요한 기본 데이터 소스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태를 변경시킬 때 사용하는 것이 상태 관리이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 컴포넌트 간의 데이터 전달이나 데이터 변경을 효율적으로 하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 일반 변수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 변수를 선언하듯이 counter 변수를 만들면 클릭 이벤트를 만들어도 화면에는 반영되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔창에서만 counter 변수가 증가, 감소한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700612709705&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
let counter = 0

function increment() {
  counter++
  console.log('증가', counter)
}

function decrease() {
  counter--
  console.log('감소', counter)
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section&amp;gt;
    &amp;lt;h2&amp;gt;counter 변수&amp;lt;/h2&amp;gt;

    &amp;lt;p&amp;gt;{{ counter }}&amp;lt;/p&amp;gt;

    &amp;lt;button @click=&quot;increment&quot;&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;button @click=&quot;decrease&quot;&amp;gt;-&amp;lt;/button&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7Aw6T/btsAKbEIJJK/swNihTJas08QpwZWF2M90k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7Aw6T/btsAKbEIJJK/swNihTJas08QpwZWF2M90k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7Aw6T/btsAKbEIJJK/swNihTJas08QpwZWF2M90k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7Aw6T%2FbtsAKbEIJJK%2FswNihTJas08QpwZWF2M90k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;676&quot; height=&quot;413&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useState 변수&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;composables/state.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState에 counter 변수를 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1700613473883&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const useCounter = () =&amp;gt; useState&amp;lt;number&amp;gt;('counter', () =&amp;gt; 0)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState를 통해 변수를 만들면 데이터가 변하는 즉시, 화면에서도 변경된다.&lt;/p&gt;
&lt;pre id=&quot;code_1700613606279&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useCounter } from '@/composables/state';

const stateCounter = useCounter()
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section&amp;gt;
    &amp;lt;h2&amp;gt;useState 변수&amp;lt;/h2&amp;gt;

    &amp;lt;p&amp;gt;{{ stateCounter }}&amp;lt;/p&amp;gt;

    &amp;lt;button @click=&quot;stateCounter++&quot;&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;button @click=&quot;stateCounter--&quot;&amp;gt;-&amp;lt;/button&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kILWq/btsAJGrqMGC/ESWaCEANEwMKn2Z9xhY1Ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kILWq/btsAJGrqMGC/ESWaCEANEwMKn2Z9xhY1Ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kILWq/btsAJGrqMGC/ESWaCEANEwMKn2Z9xhY1Ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkILWq%2FbtsAJGrqMGC%2FESWaCEANEwMKn2Z9xhY1Ik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;216&quot; height=&quot;143&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Pinia store 라이브러리&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://pinia.vuejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pinia.vuejs.org/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pinia store에 대한 자세한 설명은 위의 링크를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stores/counter.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;터미널에서 yarn add pinia 또는 npm install pinia 명령어를 입력해 pinia 패키기를 설치한다.&lt;/li&gt;
&lt;li&gt;pinia를 import 한다.&lt;/li&gt;
&lt;li&gt;useCounterStore를 만들고, state에 초기값을 선언한다.&lt;/li&gt;
&lt;li&gt;actions에 이벤트를 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1700613841338&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () =&amp;gt; {
    return { count: 0 }
  },

  actions: {
    increment() {
      this.count++
    },

    decrement() {
      this.count--
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pinia를 통해 변수를 만들면 데이터가 변하는 즉시, 화면에서도 변경된다.&lt;/p&gt;
&lt;pre id=&quot;code_1700614049573&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useCounterStore } from '@/stores/counter';

const piniaCounter = useCounterStore()
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;section&amp;gt;
    &amp;lt;h2&amp;gt;Pinia 변수&amp;lt;/h2&amp;gt;

    &amp;lt;p&amp;gt;{{ piniaCounter.counter }}&amp;lt;/p&amp;gt;

    &amp;lt;button @click=&quot;piniaCounter.increment&quot;&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;button @click=&quot;piniaCounter.decrement&quot;&amp;gt;-&amp;lt;/button&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcD6dl/btsAIHqQigp/d8Qhb2fn2saARqis2jqkQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcD6dl/btsAIHqQigp/d8Qhb2fn2saARqis2jqkQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcD6dl/btsAIHqQigp/d8Qhb2fn2saARqis2jqkQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcD6dl%2FbtsAIHqQigp%2Fd8Qhb2fn2saARqis2jqkQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;169&quot; height=&quot;133&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useState vs Pinia&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt을 사용해 개발을 하기 위해서는 상태 관리를 어떻게 할지 정해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;간단한 앱에서는 useState를 사용하고, 복잡한 앱에서는 Pinia를 사용한다&lt;/u&gt;는 의견이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pinia는 Vue.js용 스토어 라이브러리 및 상태 관리 프레임워크이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pinia에서 제공하는 많은 기능들이 있고, 개발자는 그 기능들을 직접 만들 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DevTools를 통합할 수 있고, getter와 actions 기능을 통해 상태를 변경할 수 있는 구체적인 방법을 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 앱의 얼마나 복잡한지 파악한 다음에 어떤 수준의 도구를 선택할지 결정하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eEPFYt/btsAJg0TgJn/KboINVBIvrIKX0SBYPRGqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eEPFYt/btsAJg0TgJn/KboINVBIvrIKX0SBYPRGqk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eEPFYt/btsAJg0TgJn/KboINVBIvrIKX0SBYPRGqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEPFYt%2FbtsAJg0TgJn%2FKboINVBIvrIKX0SBYPRGqk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1226&quot; height=&quot;372&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt pinia</category>
      <category>nuxt useState</category>
      <category>nuxt 상태 관리</category>
      <category>pinia</category>
      <category>pinia state management</category>
      <category>pinia 상태 관리</category>
      <category>useState</category>
      <category>useState 상태 관리</category>
      <category>vue pinia</category>
      <category>vue 상태 관리</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/123</guid>
      <comments>https://jae-study.tistory.com/123#entry123comment</comments>
      <pubDate>Wed, 22 Nov 2023 10:09:52 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #9 Nuxt 3 Modules (모듈 리스트, Nuxt Content, Auto Animate)</title>
      <link>https://jae-study.tistory.com/122</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Modules with Nuxt 3 &amp;mdash; Course part 9&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=JQLH9MDtRQk&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=9&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=JQLH9MDtRQk&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=9&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Modules이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt를 사용하여 프로덕션급 애플리케이션을 개발할 때 프레임워크의 핵심 기능이 충분하지 않다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Nuxt 모듈을 이용해서 프레임워크 코어를 확장하고 통합을 단순화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 모듈 공식문서에서 다양한 모듈 리스트들을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/modules&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/modules&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Nuxt Content&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt Content는 프로젝트의 content 디렉터리를 읽고 .md, .yml, .csv 또는 .json 파일을 구문 분석하고 애플리케이션을 위한 강력한 데이터 계층을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt Content에 자세한 설명은 아래 공식 문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://content.nuxt.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://content.nuxt.com/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Nuxt Content 설치하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json 파일에서 설치된 버전을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1700016291936&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add @nuxt/content

또는

npm install @nuxt/content&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. nuxt.config.ts에 모듈 추가하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;modules 배열 부분에 사용할 모듈 리스트들을 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700016363861&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [
    '@vueuse/nuxt',
    '@nuxt/content'
  ],
  css: ['@/assets/scss/main.scss'],
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {}
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. content 폴더 만들기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;content/index.md&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1700016449573&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# content에서 작성한 hello world&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. ContentDoc 컴포넌트 사용하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1700016506959&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;ContentDoc/&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tIdOC/btsAjWbfJsp/dnc6Kv1MLyd4ugWs7BRuF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tIdOC/btsAjWbfJsp/dnc6Kv1MLyd4ugWs7BRuF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tIdOC/btsAjWbfJsp/dnc6Kv1MLyd4ugWs7BRuF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtIdOC%2FbtsAjWbfJsp%2Fdnc6Kv1MLyd4ugWs7BRuF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;296&quot; height=&quot;198&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Auto Animate&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Auto Animate는 웹 앱에 부드러운 전환을 추가하는 드롭인 애니메이션 유틸리티이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue, Nuxt 뿐만 아니라 React, Solid, Svelte 또는 자바스크립트 애플리케이션에서도 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Auto Animate에 자세한 설명은 아래 공식 문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://auto-animate.formkit.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://auto-animate.formkit.com/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. auto-animate 설치하기&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;package.json 파일에서 설치된 버전을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1700023967154&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add @formkit/auto-animate

또는

npm install @formkit/auto-animate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 정렬 애니메이션 만들기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;auto-aminate를 import 한다.&lt;/li&gt;
&lt;li&gt;[sortList] 변수를 만든다.&lt;/li&gt;
&lt;li&gt;&amp;lt;ul&amp;gt; 태그에 ref를 이용해 [sortList] 변수를 참조한다.&lt;/li&gt;
&lt;li&gt;정렬 버튼을 누를 때 마다 &amp;lt;li&amp;gt; 태그들이 animation이 추가되어 움직이는 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1700024088367&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
import { ref } from 'vue'
import { useAutoAnimate } from '@formkit/auto-animate/vue'

const [sortList] = useAutoAnimate()
const items = ref([&quot;React&quot;, &quot;Vue&quot;, &quot;Svelte&quot;, &quot;Angular&quot;])

function sortAsc() {
  items.value.sort()
}
function sortDesc() {
  items.value.sort().reverse()
}
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;mb-5&quot;&amp;gt;
    &amp;lt;button
        class=&quot;me-5 px-4 py-2 bg-slate-500 rounded&quot;
        @click=&quot;sortAsc&quot;&amp;gt;
      Sort A-Z &amp;uarr;
    &amp;lt;/button&amp;gt;
    &amp;lt;button
        class=&quot;px-4 py-2 bg-slate-500 rounded&quot;
        @click=&quot;sortDesc&quot;&amp;gt;
      Sort Z-A &amp;darr;
    &amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;ul ref=&quot;sortList&quot;&amp;gt;
    &amp;lt;li
        v-for=&quot;item in items&quot;
        :key=&quot;item&quot;&amp;gt;
      {{ item }}
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;183&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ZWP5/btsAmZerjPk/OsvkFypnzhkAefDS1Rj051/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ZWP5/btsAmZerjPk/OsvkFypnzhkAefDS1Rj051/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ZWP5/btsAmZerjPk/OsvkFypnzhkAefDS1Rj051/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ZWP5%2FbtsAmZerjPk%2FOsvkFypnzhkAefDS1Rj051%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;280&quot; height=&quot;183&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>nuxt auto animate</category>
      <category>nuxt content</category>
      <category>nuxt modules</category>
      <category>nuxt 모듈</category>
      <category>vue</category>
      <category>vue auto-animate</category>
      <category>vue content</category>
      <category>vue modules</category>
      <category>vue 모듈</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/122</guid>
      <comments>https://jae-study.tistory.com/122#entry122comment</comments>
      <pubDate>Wed, 15 Nov 2023 14:04:06 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #8 Nuxt 3 Middleware (전역 미들웨어 만들기)</title>
      <link>https://jae-study.tistory.com/121</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Middlewares with Nuxt 3 &amp;mdash; Course part 8&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PhuJE0ayD6A&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=PhuJE0ayD6A&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=8&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Middleware란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt에서 미들웨어(Middleware)는 페이지나 레이아웃이 렌더링 되기 전에 호출되는 커스텀 훅(Hook)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store, route, params, query, redirect 등에 접근할 수 있기 때문에 내비게이션 가드 형태로 미들웨어 제작이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 특정 경로로 이동하기 전에 실행하려는 코드를 만들 때 이상적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. middleware 폴더 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;middleware/auth.global.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;middleware 폴더 안에 파일을 만들 때 파일명 뒤에 .global을 붙이면 별도의 import 없이 전역에서 사용할 수 있는 미들웨어가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1699864006299&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtRouteMiddleware((to, from) =&amp;gt; {
  console.log(to)
  console.log(from)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEzqhd/btsAhgmPN2a/TnQ5ceBakNxFeAmmCHZbP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEzqhd/btsAhgmPN2a/TnQ5ceBakNxFeAmmCHZbP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEzqhd/btsAhgmPN2a/TnQ5ceBakNxFeAmmCHZbP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEzqhd%2FbtsAhgmPN2a%2FTnQ5ceBakNxFeAmmCHZbP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;396&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. auth.global.ts (글로벌 미들웨어)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;middleware/auth.global.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌로 만든 미들웨어에서 navigateTo를 이용해 리다이렉트를 할 경우, isLoggedIn이 계속 false이기 때문에 무한 리다이렉트에 빠져 주의해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1700011759868&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtRouteMiddleware((to, from) =&amp;gt; {
  let isLoggedIn = false

  if(isLoggedIn) {
    return navigateTo(to.fullPath)
  } else {
    return navigateTo('/auth')
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oftdh/btsAhdEMM5z/aaOB2MMHuLeIkQLm7jGK81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oftdh/btsAhdEMM5z/aaOB2MMHuLeIkQLm7jGK81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oftdh/btsAhdEMM5z/aaOB2MMHuLeIkQLm7jGK81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOftdh%2FbtsAhdEMM5z%2FaaOB2MMHuLeIkQLm7jGK81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1271&quot; height=&quot;592&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. auth.ts (페이지 정의 미들웨어)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;auth.global.ts 미들웨어에서 .global을 지운다.&lt;/li&gt;
&lt;li&gt;auth.ts 미들웨어를 사용할 페이지에 import 한다.&lt;/li&gt;
&lt;li&gt;/ 루트 페이지에 접속하면 바로 /auth 페이지로 이동됨을 볼 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1700012126407&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;Main page&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
definePageMeta({
  middleware: 'auth'
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sn2kL/btsAjkDtdt3/Qtp5qyn6aUcHrnRaYz4Dy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sn2kL/btsAjkDtdt3/Qtp5qyn6aUcHrnRaYz4Dy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sn2kL/btsAjkDtdt3/Qtp5qyn6aUcHrnRaYz4Dy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsn2kL%2FbtsAjkDtdt3%2FQtp5qyn6aUcHrnRaYz4Dy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;292&quot; height=&quot;201&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>nuxt global middleware</category>
      <category>nuxt middleware</category>
      <category>nuxt 글로벌 미들웨어</category>
      <category>nuxt 미들웨어</category>
      <category>nuxt3 middleware</category>
      <category>vue</category>
      <category>vue middleware</category>
      <category>vue 글로벌 미들웨어</category>
      <category>vue 미들웨어</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/121</guid>
      <comments>https://jae-study.tistory.com/121#entry121comment</comments>
      <pubDate>Wed, 15 Nov 2023 10:48:11 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #7 Nuxt 3 Plugins (커스텀 플러그인 만들기)</title>
      <link>https://jae-study.tistory.com/120</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Plugins with Nuxt 3 &amp;mdash; Course part 7&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=9MCVjsq35I8&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=7&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=9MCVjsq35I8&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=7&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Plugins이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt에는 Vue 애플리케이션 생성 시 Vue 플러그인을 사용할 수 있는 플러그인 시스템이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 자동으로 plugins 디렉터리 파일을 읽고, Vue 애플리케이션 생성 시 이를 로드한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. plugins 폴더 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;plugins/myPlugins.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699861762001&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtPlugin((nuxtApp) =&amp;gt; {
  return {
    provide: {
      hello: (msg: string) =&amp;gt; console.log(`Hello ${msg}`)
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 플러그인 import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;plugins 디렉터리 최상위에 있는 파일(또는 하위 디렉터리 내의 index 파일)은 별로의 import 없이 &lt;u&gt;자동으로 플러그인으로 등록된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699861868999&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
console.log(useNuxtApp())
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ktoqj/btsAjk91G19/IPd5Qkd56MOG0KwMRYmjKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ktoqj/btsAjk91G19/IPd5Qkd56MOG0KwMRYmjKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ktoqj/btsAjk91G19/IPd5Qkd56MOG0KwMRYmjKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKtoqj%2FbtsAjk91G19%2FIPd5Qkd56MOG0KwMRYmjKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;863&quot; height=&quot;472&quot; data-origin-width=&quot;863&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 플러그인 사용하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699862004127&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
const { $hello } = useNuxtApp()

$hello('world')
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;28&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bofjPV/btsAjnyWObt/m8beHKSbxJn0DQrbfRHFNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bofjPV/btsAjnyWObt/m8beHKSbxJn0DQrbfRHFNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bofjPV/btsAjnyWObt/m8beHKSbxJn0DQrbfRHFNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbofjPV%2FbtsAjnyWObt%2Fm8beHKSbxJn0DQrbfRHFNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;371&quot; height=&quot;28&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;28&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>nuxt custom plugins</category>
      <category>nuxt plugins</category>
      <category>vue</category>
      <category>vue custom plugins</category>
      <category>vue plugins</category>
      <category>넉스트 커스텀 플러그인 만들기</category>
      <category>넉스트 플러그인</category>
      <category>뷰 커스텀 플러그인 만들기</category>
      <category>뷰 플러그인</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/120</guid>
      <comments>https://jae-study.tistory.com/120#entry120comment</comments>
      <pubDate>Mon, 13 Nov 2023 16:57:23 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #6 Nuxt 3 Composables (VueUse 설치 및 예제)</title>
      <link>https://jae-study.tistory.com/119</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Composables with Nuxt 3 &amp;mdash; Course part 6&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cWX4b2qD6sg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=6&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=cWX4b2qD6sg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=6&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Composables이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue 애플리케이션에서 composable(컴포저블)이란, Vue의 Composition API를 활용하여 상태 저장 논리를 캡슐화하고 재사용하는 함수를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수의 이름은 'use'로 시작하고, 카멜 케이스 형식으로 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. composables 폴더 만들기&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;composables/useUtils.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699857402409&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const useUtils = () =&amp;gt; {
  const sayHello = () =&amp;gt; console.log('Hello from useHello')

  return {
    sayHello
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useUtils 함수 불러오기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699857453573&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useUtils } from &quot;~/composables/ussUtils&quot;;

const { sayHello } = useUtils()

sayHello()
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2PmFv/btsz93PvwNN/Tk3bDmKtF8EvtOrX8CUtv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2PmFv/btsz93PvwNN/Tk3bDmKtF8EvtOrX8CUtv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2PmFv/btsz93PvwNN/Tk3bDmKtF8EvtOrX8CUtv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2PmFv%2Fbtsz93PvwNN%2FTk3bDmKtF8EvtOrX8CUtv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;654&quot; height=&quot;162&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;VueUse란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VueUse 모듈은 Vue Composition(컴포지션, import 한 함수를 사용해서 Vue 컴포넌트를 작성할 수 있는 API) 유틸리티 모음이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VueUse에 대한 자세한 설명을 아래 공식 문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://vueuse.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://vueuse.org/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/modules/vueuse&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nuxt.com/modules/vueuse&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;VueUse 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치된 버전은 package.json 파일에서 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699857784860&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i -D @vueuse/nuxt @vueuse/core&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nuxt.config.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 부분에 @vueuse/nuxt를 import 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699858109993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [
    '@vueuse/nuxt'
  ],
  css: ['@/assets/scss/main.scss'],
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {}
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. useMouse&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699858314321&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;Mouse position: {{ x }}, {{ y }}&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useMouse } from '@vueuse/core'

const { x, y } = useMouse()
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMavRm/btsAaVYay8s/egibC65putmaTWxBuer0RK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMavRm/btsAaVYay8s/egibC65putmaTWxBuer0RK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMavRm/btsAaVYay8s/egibC65putmaTWxBuer0RK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMavRm%2FbtsAaVYay8s%2FegibC65putmaTWxBuer0RK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;291&quot; height=&quot;205&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useLocalStorage&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699858524767&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useLocalStorage } from '@vueuse/core'

const store = useLocalStorage(
    'my-storage',
    {
      name: 'Apple',
      color: 'red'
    }
)
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;153&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kzuCq/btsAaFnkarE/6tMoXzzSXAVekf0M5w1Jc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kzuCq/btsAaFnkarE/6tMoXzzSXAVekf0M5w1Jc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kzuCq/btsAaFnkarE/6tMoXzzSXAVekf0M5w1Jc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkzuCq%2FbtsAaFnkarE%2F6tMoXzzSXAVekf0M5w1Jc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;153&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;153&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. usePreferredDark&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699858779214&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { usePreferredDark } from '@vueuse/core'

const isDark = usePreferredDark()

console.log(isDark)

if(isDark.value) {
  console.log('다크모드 true')
} else {
  console.log('다크모드 false')
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;199&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bodrHL/btsAaRafze7/6MncXNcAviI8Ok54g2qFBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bodrHL/btsAaRafze7/6MncXNcAviI8Ok54g2qFBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bodrHL/btsAaRafze7/6MncXNcAviI8Ok54g2qFBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbodrHL%2FbtsAaRafze7%2F6MncXNcAviI8Ok54g2qFBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;199&quot; height=&quot;160&quot; data-origin-width=&quot;199&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. useTitle&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699859306137&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;{{ themeTitle }}&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { usePreferredDark, useTitle } from '@vueuse/core'

const isDark = usePreferredDark()

const themeTitle = useTitle(() =&amp;gt; isDark.value ? '다크모드 true' : '다크모드 false')
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/75Tvr/btsAcQIRb6w/D4PiezTF5qA6hLrnRlIqgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/75Tvr/btsAcQIRb6w/D4PiezTF5qA6hLrnRlIqgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/75Tvr/btsAcQIRb6w/D4PiezTF5qA6hLrnRlIqgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F75Tvr%2FbtsAcQIRb6w%2FD4PiezTF5qA6hLrnRlIqgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;200&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. onClickOutside&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699859601094&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div ref=&quot;el&quot;&amp;gt;
    Click Outside of Me
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'

const el = ref()

function close () {
  alert('영역의 바깥을 클릭했습니다.')
}

onClickOutside(el, close)
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4dD0u/btsAjVozyEy/HHjkKIVFEaVbn6Ac42G5nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4dD0u/btsAjVozyEy/HHjkKIVFEaVbn6Ac42G5nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4dD0u/btsAjVozyEy/HHjkKIVFEaVbn6Ac42G5nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4dD0u%2FbtsAjVozyEy%2FHHjkKIVFEaVbn6Ac42G5nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;774&quot; height=&quot;241&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt composables</category>
      <category>nuxt3 composables</category>
      <category>vue composables</category>
      <category>vue onClickOutside</category>
      <category>vue useLocalStorage</category>
      <category>vue useMouse</category>
      <category>vue usePreferredDark</category>
      <category>vue useTitle</category>
      <category>넉스트 컴포저블</category>
      <category>뷰 컴포저블</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/119</guid>
      <comments>https://jae-study.tistory.com/119#entry119comment</comments>
      <pubDate>Mon, 13 Nov 2023 16:16:41 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #5 Nuxt 3 이미지 업로드하기 (assets, public)</title>
      <link>https://jae-study.tistory.com/118</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Images, assets &amp;amp; public folder with Nuxt 3 &amp;mdash; Course part 5&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tWQ2LWplmDc&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=tWQ2LWplmDc&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=5&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. assets 폴더에 이미지 올리기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;assets 폴더에 images 폴더를 만들고 이미지를 올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;173&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqZeKW/btsz2VDnlUa/rwKDknrL6sesJN13ay9ZwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqZeKW/btsz2VDnlUa/rwKDknrL6sesJN13ay9ZwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqZeKW/btsz2VDnlUa/rwKDknrL6sesJN13ay9ZwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqZeKW%2Fbtsz2VDnlUa%2FrwKDknrL6sesJN13ay9ZwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;173&quot; height=&quot;105&quot; data-origin-width=&quot;173&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~ 또는 @를 이용해서 루트 경로를 설정하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1699515448606&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;img src=&quot;~/assets/images/1.jpg&quot; alt=&quot;이미지1&quot;&amp;gt;
  &amp;lt;img src=&quot;@/assets/images/2.jpg&quot; alt=&quot;이미지2&quot;&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBTUsT/btsz1rQxXGm/LjUUqjJFVKaJ2hW0M3w4X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBTUsT/btsz1rQxXGm/LjUUqjJFVKaJ2hW0M3w4X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBTUsT/btsz1rQxXGm/LjUUqjJFVKaJ2hW0M3w4X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBTUsT%2Fbtsz1rQxXGm%2FLjUUqjJFVKaJ2hW0M3w4X1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;552&quot; height=&quot;740&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;assets 폴더에 넣은 이미지는 빌드돼서 이미지가 업로드되기 때문에 직접적인 접근이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/74J39/btsz5iERiyo/LmWnBkrzLX4b5SsaP4uupK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/74J39/btsz5iERiyo/LmWnBkrzLX4b5SsaP4uupK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/74J39/btsz5iERiyo/LmWnBkrzLX4b5SsaP4uupK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F74J39%2Fbtsz5iERiyo%2FLmWnBkrzLX4b5SsaP4uupK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;722&quot; height=&quot;533&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. public 폴더에 이미지 올리기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;public 폴더에 images 폴더를 만들고 이미지를 올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vgAah/btsz6fVabIX/9JtlBkSlmkURJwOkkxHPC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vgAah/btsz6fVabIX/9JtlBkSlmkURJwOkkxHPC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vgAah/btsz6fVabIX/9JtlBkSlmkURJwOkkxHPC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvgAah%2Fbtsz6fVabIX%2F9JtlBkSlmkURJwOkkxHPC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;178&quot; height=&quot;108&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;public&amp;nbsp;&lt;/span&gt;폴더에 넣은 이미지는 서버 루트에서 그대로 제공되기 때문에 직접적인 접근이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, public 폴더는 모두가 접근할 수 있기 때문에 안전 이슈가 발생할 수 있어 주의해서 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/otUzg/btsz3LHlZer/BZHXcp2RkrGGjhjBRhr7BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/otUzg/btsz3LHlZer/BZHXcp2RkrGGjhjBRhr7BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/otUzg/btsz3LHlZer/BZHXcp2RkrGGjhjBRhr7BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FotUzg%2Fbtsz3LHlZer%2FBZHXcp2RkrGGjhjBRhr7BK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;842&quot; height=&quot;512&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>Nuxt assets</category>
      <category>Nuxt image</category>
      <category>Nuxt public</category>
      <category>Nuxt 이미지</category>
      <category>Nuxt 이미지 경로</category>
      <category>Nuxt 이미지 업로드</category>
      <category>Nuxt3</category>
      <category>vue</category>
      <category>vue3</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/118</guid>
      <comments>https://jae-study.tistory.com/118#entry118comment</comments>
      <pubDate>Thu, 9 Nov 2023 16:56:28 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #4 Nuxt 3 레이아웃 만들기 (페이지별 레이아웃 다르게 하기, slot)</title>
      <link>https://jae-study.tistory.com/117</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Layouts with Nuxt 3 &amp;mdash; Course part 4&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GQjU4FfM3II&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=GQjU4FfM3II&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=4&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. DefaultLayout 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;layouts 폴더를 만들고, 그 안에 default.vue 파일을 만든다.&lt;/li&gt;
&lt;li&gt;&amp;lt;slot&amp;gt;을 사용해 pages/~.vue 파일의 내용을 &amp;lt;slot&amp;gt; 부분으로 대체한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;layouts/default.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;layouts 폴더 안에 defalut.vue 파일을 만들면 별도의 import 없이 자동으로 DefalutLayout이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1699509517196&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;h-screen p-5 bg-slate-700 text-base text-white&quot;&amp;gt;
    &amp;lt;Header/&amp;gt;

    &amp;lt;slot/&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699509646465&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;index page&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;app.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699509660623&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;NuxtLayout&amp;gt;
    &amp;lt;NuxtPage/&amp;gt;
  &amp;lt;/NuxtLayout&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. CustomLayout 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DefaultLayout 말고, 다른 레이아웃을 만들고 싶을 때 layout 폴더 안에 custom.vue 파일을 만든다.&lt;/li&gt;
&lt;li&gt;CustomLayout은 기본 레이아웃이 아니기 때문에 &amp;lt;script&amp;gt; 태그 안에 정의를 해야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;layouts/custom.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699509869798&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;h-screen p-5 bg-slate-500 text-base text-white&quot;&amp;gt;
    &amp;lt;h1 class=&quot;text-lg font-bold&quot;&amp;gt;Custom layout&amp;lt;/h1&amp;gt;

    &amp;lt;slot/&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/custom.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699510582028&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;h1&amp;gt;Custom page&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
definePageMeta({
  layout: &quot;custom&quot;
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vxBiE/btsz6ijVLlv/bBARLCKtD0sL8h6s7dSk90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vxBiE/btsz6ijVLlv/bBARLCKtD0sL8h6s7dSk90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vxBiE/btsz6ijVLlv/bBARLCKtD0sL8h6s7dSk90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvxBiE%2Fbtsz6ijVLlv%2FbBARLCKtD0sL8h6s7dSk90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;345&quot; height=&quot;165&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GWxg5/btsz42B5FMO/xr2khoM5QHU4E7kpWrIKg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GWxg5/btsz42B5FMO/xr2khoM5QHU4E7kpWrIKg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GWxg5/btsz42B5FMO/xr2khoM5QHU4E7kpWrIKg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGWxg5%2Fbtsz42B5FMO%2Fxr2khoM5QHU4E7kpWrIKg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;345&quot; height=&quot;146&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>Nuxt CustomLayout</category>
      <category>Nuxt DefalutLayout</category>
      <category>Nuxt layout</category>
      <category>Nuxt3</category>
      <category>vue</category>
      <category>vue3</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/117</guid>
      <comments>https://jae-study.tistory.com/117#entry117comment</comments>
      <pubDate>Thu, 9 Nov 2023 15:20:20 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #3 Nuxt 3 컴포넌트 만들기 (auto-imports)</title>
      <link>https://jae-study.tistory.com/116</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Components with Nuxt 3 &amp;mdash; Course part 3&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=o4SkcTupZBo&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=3&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=o4SkcTupZBo&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=3&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. components 폴더 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components 폴더를 만들고, 그 안에 vue 파일을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트로 사용할 vue 파일의 첫 글자 이름은 반드시 대문자로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/Alert.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699506379240&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;p-2 bg-slate-500 rounded text-white text-lg font-bold&quot;&amp;gt;
    This is an alert component.
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/Profile/Header/Avatar.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699506457712&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;p-2 bg-slate-700 rounded text-white text-lg font-bold&quot;&amp;gt;
    This is a Profile/Header/Avatar component.
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 컴포넌트 import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;nuxt3에는 auto-importing 기능이 있어 별도의 import문 없이 바로 컴포넌트를 사용할 수 있다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일명이 컴포넌트의 이름이 되고, 뎁스 안에 있는 컴포넌트는 '폴더명 폴더명 ... 파일명' 으로 이름을 지으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'components/Profile/Header/Avatar.vue' 의 경우 &amp;lt;ProfileHeaderAvatar&amp;gt;가 컴포넌트의 이름이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699506862566&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;Alert/&amp;gt;

  &amp;lt;ProfileHeaderAvatar/&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H25Ak/btsz5A53rri/CVnOwtxxaZQggoZV33zYhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H25Ak/btsz5A53rri/CVnOwtxxaZQggoZV33zYhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H25Ak/btsz5A53rri/CVnOwtxxaZQggoZV33zYhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH25Ak%2Fbtsz5A53rri%2FCVnOwtxxaZQggoZV33zYhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;152&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>Nuxt auto importing</category>
      <category>Nuxt component</category>
      <category>Nuxt component 만들기</category>
      <category>Nuxt 컴포넌트</category>
      <category>Nuxt 컴포넌트 만들기</category>
      <category>Nuxt3</category>
      <category>vue</category>
      <category>vue3</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/116</guid>
      <comments>https://jae-study.tistory.com/116#entry116comment</comments>
      <pubDate>Thu, 9 Nov 2023 14:17:07 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #2 Nuxt 3 페이지 만들기 및 페이지 이동 (라우팅)</title>
      <link>https://jae-study.tistory.com/115</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pages &amp;amp; Routing with Nuxt 3 &amp;mdash; Course part 2&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tdgUDuD3fS4&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=tdgUDuD3fS4&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=2&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. pages 폴더 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pages 폴더를 만들고, 그 안에 ~.vue 파일을 만들면 http://localhost:3000/ 주소에서 500 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pages 폴더가 만들어지면 app.vue 파일에서 pages/~.vue 파일과 경로를 매칭하지 못하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. app.vue 파일 수정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;app.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;lt;NuxtLayout&amp;gt;, &amp;lt;NuxtPage&amp;gt; 컴포넌트를 이용해 pages/~.vue 파일들이 &amp;lt;NuxtPage&amp;gt; 태그 대신에 보이도록 한다.&lt;/li&gt;
&lt;li&gt;&amp;lt;header&amp;gt; 태그를 추가해서 모든 pages/~.vue 파일에서 &amp;lt;header&amp;gt; 태그가 import 되게 만든다.&lt;/li&gt;
&lt;li&gt;&amp;lt;style&amp;gt; 태그를 추가해서 css를 적용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699495637695&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;NuxtLayout&amp;gt;
    &amp;lt;div class=&quot;wrap&quot;&amp;gt;
      &amp;lt;header&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;
            &amp;lt;NuxtLink to=&quot;/&quot;&amp;gt;Home&amp;lt;/NuxtLink&amp;gt;
            &amp;lt;NuxtLink to=&quot;/events&quot;&amp;gt;Events&amp;lt;/NuxtLink&amp;gt;
          &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/header&amp;gt;

      &amp;lt;NuxtPage/&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/NuxtLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
header {
  ul {
    height: 50px;

    li {
      display: flex;
      justify-content: start;
      align-items: center;
      gap: 20px;

      a {
        font-size: 20px;
        font-weight: 700;
      }
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. vue 파일 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699495654332&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;index page&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/event/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699495675562&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;events page&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFPuwN/btsz1TFfjM4/szsfO1ljMKTzCodLo8sKtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFPuwN/btsz1TFfjM4/szsfO1ljMKTzCodLo8sKtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFPuwN/btsz1TFfjM4/szsfO1ljMKTzCodLo8sKtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFPuwN%2Fbtsz1TFfjM4%2FszsfO1ljMKTzCodLo8sKtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;338&quot; height=&quot;164&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F3ftM/btsz3evlYKo/gR5O3UmoyFHD06ch3Bwk20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F3ftM/btsz3evlYKo/gR5O3UmoyFHD06ch3Bwk20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F3ftM/btsz3evlYKo/gR5O3UmoyFHD06ch3Bwk20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF3ftM%2Fbtsz3evlYKo%2FgR5O3UmoyFHD06ch3Bwk20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;344&quot; height=&quot;170&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>Nuxt Routing</category>
      <category>Nuxt 라우팅</category>
      <category>Nuxt 페이지 만들기</category>
      <category>Nuxt3</category>
      <category>NuxtLayout 컴포넌트</category>
      <category>NuxtPage 컴포넌트</category>
      <category>vue</category>
      <category>vue3</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/115</guid>
      <comments>https://jae-study.tistory.com/115#entry115comment</comments>
      <pubDate>Thu, 9 Nov 2023 11:14:35 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] #1 Nuxt 3 설치 및 테일윈드 CSS 적용하기</title>
      <link>https://jae-study.tistory.com/114</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Create an app with Nuxt 3 &amp;mdash; Course part 1&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=hj3NNlTqIJg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=hj3NNlTqIJg&amp;amp;list=PL8HkCX2C5h0XT3xWYn71TlsAAo0kizmVc&amp;amp;index=1&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 강의를 참고하고 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Nuxt&lt;/b&gt;는 Vue.js를 사용하여 안전하고 성능이 뛰어난 풀 스택 웹 애플리케이션과 웹 사이트를 만들 수 있는 직관적이고 확장 가능성을 가진 무료 오픈 소스 프레임워크이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;서버 측 렌더링(빠른 페이지 로드 시간, 캐싱, SEO)&lt;/li&gt;
&lt;li&gt;파일 기반 라우팅&lt;/li&gt;
&lt;li&gt;Auto-imports 컴포넌트&lt;/li&gt;
&lt;li&gt;타입스크립트 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0f0f0f; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Nuxt 3 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;필수 조건&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Node.js v18.0.0 이상&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행 후, 설치가 완료되면 해당 폴더로 이동한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699493540846&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx nuxi init &amp;lt;project-name&amp;gt;

// 가장 최신 버전을 설치하고 싶으면
npx nuxi@latest init &amp;lt;project-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 로컬호스트 연결 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;터미널에서 yarn dev 명령어를 실행하고&lt;/u&gt;, 아래 사진과 같은 화면이 나온다면 로컬호스트 연결에 성공한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lm6Bg/btsz3KAR5RS/IHprkm7iGAYUitsYFdvKlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lm6Bg/btsz3KAR5RS/IHprkm7iGAYUitsYFdvKlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lm6Bg/btsz3KAR5RS/IHprkm7iGAYUitsYFdvKlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLm6Bg%2Fbtsz3KAR5RS%2FIHprkm7iGAYUitsYFdvKlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1870&quot; height=&quot;870&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. app.vue 수정하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;app.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.vue 파일은 로컬호스트에서 보이는 메인 화면이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;NuxtWelcome&amp;gt; 컴포넌트를 삭제하고, 다른 태그를 작성하면 화면이 수정된 것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699494504463&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;NuxtWelcome&amp;gt;&amp;lt;/NuxtWelcome&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 테일윈드 CSS 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://tailwindcss.com/docs/guides/nuxtjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tailwindcss.com/docs/guides/nuxtjs&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 테일윈드 CSS 설치에 대한 자세한 설명은 위의 공식문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699494338711&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;assets/scss/main.scss&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699510910487&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nuxt.config.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699494298716&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  css: ['@/assets/scss/main.scss'],
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {}
    }
  }
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;app.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1699494669624&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;h1 class=&quot;text-3xl font-bold underline&quot;&amp;gt;
    Hello world!
  &amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfUrIK/btsz1JiqxZb/IqwzHfvNr4ixMMRpz11Iv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfUrIK/btsz1JiqxZb/IqwzHfvNr4ixMMRpz11Iv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfUrIK/btsz1JiqxZb/IqwzHfvNr4ixMMRpz11Iv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfUrIK%2Fbtsz1JiqxZb%2FIqwzHfvNr4ixMMRpz11Iv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;295&quot; height=&quot;98&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Vue, Nuxt/Nuxt 3 기초</category>
      <category>nuxt</category>
      <category>Nuxt Tailwind CSS</category>
      <category>nuxt 설치하기</category>
      <category>Nuxt 테일윈드 CSS</category>
      <category>Nuxt3</category>
      <category>Nuxt3 설치</category>
      <category>Nuxt3 설치하기</category>
      <category>vue</category>
      <category>vue3</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/114</guid>
      <comments>https://jae-study.tistory.com/114#entry114comment</comments>
      <pubDate>Thu, 9 Nov 2023 10:55:35 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 vue-awesome-swiper 이용해서 autoplay, progress bar 만들기</title>
      <link>https://jae-study.tistory.com/112</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mfk41/btszRSfBP2H/eGZ9siMVc5vdUyimkzJhlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mfk41/btszRSfBP2H/eGZ9siMVc5vdUyimkzJhlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mfk41/btszRSfBP2H/eGZ9siMVc5vdUyimkzJhlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmfk41%2FbtszRSfBP2H%2FeGZ9siMVc5vdUyimkzJhlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;744&quot; height=&quot;316&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;vue: 2.7.10&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;nuxt: 2.15.8&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue, nuxt 버전&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;2.x.x&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;기준으로 작성한 글이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;버전&lt;/i&gt;&amp;nbsp; 3.x.x에서는 &lt;i&gt;동작하지 않을 수 있다.&lt;/i&gt; &lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2023.11 기준 스와이퍼 버전 11까지 나왔다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최신 버전의 뷰 스와이퍼에 대한 자세한 설명은 공식 문서를 참고한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swiperjs.com/vue&quot;&gt;https://swiperjs.com/vue&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. swiper, vue-awesome-swiper 패키기 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;swiper와 vue-awesome-swiper 패키지를 설치한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반드시 해당 버전으로 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699259168219&quot; class=&quot;bash&quot; style=&quot;background-color: #fafafa; color: #000000; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;yarn add swiper@5.4.5
yarn add vue-awesome-swiper@4.1.1

또는

npm install swiper@5.4.5
npm install vue-awesome-swiper@4.1.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 마크업 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/swiper.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컴포넌트가 아닌 HTML로 마크업 한다. 이때 class명은 swiper 패키지에서 제공하는 것으로 사용한다.&lt;br /&gt;(swiper-container, swiper-wrapper, swiper-slide)&lt;/li&gt;
&lt;li&gt;커스텀으로 autoplay, progress를 만들 것이기 때문에 마찬가지로 HTML로 마크업 한다.&lt;br /&gt;autoplay 속성의 true/false에 따라서 css가 바뀌어야 하기 때문에 클릭 이벤트와 :class 속성을 추가한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699260137155&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;kv-swiper&quot;&amp;gt;
    &amp;lt;div
      v-once
      v-swiper:swiper=&quot;kvSwiperOption&quot;
      class=&quot;swiper-container&quot;&amp;gt;
      &amp;lt;ul class=&quot;swiper-wrapper&quot;&amp;gt;
        &amp;lt;li class=&quot;swiper-slide&quot;&amp;gt;Slide 1&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;swiper-slide&quot;&amp;gt;Slide 2&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;swiper-slide&quot;&amp;gt;Slide 3&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class=&quot;swiper-function&quot;&amp;gt;
      &amp;lt;div
        class=&quot;swiper-autoplay&quot;
        :class=&quot;{ stop: kvAutoplay }&quot;
        @click=&quot;kvSwiperAutoplay&quot;&amp;gt;
        &amp;lt;span/&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div
        class=&quot;swiper-progress&quot;
        :class=&quot;{ start: kvProgress }&quot;&amp;gt;
        &amp;lt;span class=&quot;bar&quot;/&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div class=&quot;swiper-pagination&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. script 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;v-once, v-swiper 디렉티브를 사용하기 위해서 vue 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;vue-awesome-swiper와 swiper.css를 import 한다.&lt;/li&gt;
&lt;li&gt;kvAutoplay, kvProgress를 false로 설정한다. (페이지가 로딩되기 전에 동작되면 안 되기 때문에)&lt;/li&gt;
&lt;li&gt;kvSwiperOption을 작성한다. &lt;u&gt;kvSwiperOption의 on 부분에 autoplay에 관한 메서드를 작성한다.&lt;/u&gt;&lt;br /&gt;(다음 슬라이드로 넘길 때 autoplay와 progress를 초기화하기 위해서) &lt;br /&gt;스와이퍼의 다양한 속성들을 사용하고 싶으면 공식 문서를 참고한다. (&lt;a href=&quot;https://swiperjs.com/demos&quot;&gt;https://swiperjs.com/demos&lt;/a&gt;)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;autoplay와 progress 동작에 필요한 메서드를 작성한다. 이때 try/catch 구조로 작성해야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699260454913&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

Vue.use(VueAwesomeSwiper)

export default {
  name: 'SwiperPage',

  data() {
    return {
      // Kv autoplay, progress
      kvAutoplay: false,
      kvProgress: false,

      // Kv swiper option
      kvSwiperOption: {
        effect: 'fade',
        slidesPerView: 1,
        spaceBetween: 0,
        loop: true,
        autoplay: {
          delay: 5000
        },
        pagination: {
          el: '.swiper-pagination',
          type: 'fraction'
        },
        on: {
          init: this.init,
          sliderMove: this.stopAutoplay,
          slideChangeTransitionStart: this.stopAutoplay,
          transitionEnd: this.startAutoplay
        }
      }
    }
  },

  methods: {
    init() {
      this.kvProgress = true
    },

    kvSwiperAutoplay() {
      this.kvAutoplay = !this.kvAutoplay

      if (this.kvProgress) {
        this.stopAutoplay()
      } else {
        this.startAutoplay()
      }
    },

    stopAutoplay() {
      try {
        this.swiper.autoplay.stop()
        this.kvProgress = false
      } catch (err) {
        console.error(err)
      }
    },

    startAutoplay() {
      try {
        this.swiper.autoplay.start()
        this.kvProgress = true
        this.kvAutoplay = false
      } catch (err) {
        console.error(err)
      }
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. css/scss 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;progress는 script의 autoplay 속도와 css의 keyframes과 animation 속도에 맞춰 움직일 수 있도록 css를 작성한다. (&lt;u&gt;animation: kvProgress 5s linear infinite;&lt;/u&gt;)&lt;/li&gt;
&lt;li&gt;스와이퍼에 필요한 css를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699261136451&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
@keyframes kvProgress {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

.kv-swiper {
  position: relative;
  height: 300px;
  padding: 20px;

  .swiper-container {
    height: 100%;

    .swiper-slide {
      ...
    }
  }

  .swiper-function {
    ...

    .swiper-autoplay {
      position: relative;
      cursor: pointer;

      span {
        &amp;amp;::after {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          width: 4px;
          height: 12px;
          border-left: 2px solid #fff;
          border-right: 2px solid #fff;
          content: '';
        }
      }

      &amp;amp;.stop {
        span {
          &amp;amp;::after {
            width: 0;
            height: 0;
            border-right: 0;
            border-left: 10px solid #fff;
            border-top: 6px solid transparent;
            border-bottom: 6px solid transparent;
          }
        }
      }
    }

    .swiper-progress {
      overflow: hidden;
      width: 300px;
      height: 4px;
      background-color: rgba(255, 255, 255, 0.5);
      border-radius: 4px;

      &amp;amp;.start {
        .bar {
          animation: kvProgress 5s linear infinite;
        }
      }

      .bar {
        display: block;
        width: 100%;
        height: 4px;
        transform: translateX(-100%);
        background-color: #fff;
      }
    }

    .swiper-pagination {
      ...
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>vue autoplay</category>
      <category>vue autoplay progress</category>
      <category>vue progress bar</category>
      <category>vue swiper autoplay</category>
      <category>vue swiper progerss bar</category>
      <category>vue swiper progress</category>
      <category>vue-awesome-swiper</category>
      <category>vue2 swiper</category>
      <category>뷰 스와이퍼</category>
      <category>뷰 스와이퍼 사용법</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/112</guid>
      <comments>https://jae-study.tistory.com/112#entry112comment</comments>
      <pubDate>Wed, 8 Nov 2023 11:34:51 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 swiper와 svg를 이용해서 autoplay, progress 페이지네이션 만들기 (vue swiper custom pagination)</title>
      <link>https://jae-study.tistory.com/113</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciQIn5/btszXmOhIiQ/CA3KR5z2JnGCXvz2hWQ1Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciQIn5/btszXmOhIiQ/CA3KR5z2JnGCXvz2hWQ1Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciQIn5/btszXmOhIiQ/CA3KR5z2JnGCXvz2hWQ1Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciQIn5%2FbtszXmOhIiQ%2FCA3KR5z2JnGCXvz2hWQ1Qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;316&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;vue: 2.7.10&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;nuxt: 2.15.8&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue, nuxt 버전&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;2.x.x&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;기준으로 작성한 글이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;버전&lt;/i&gt;&amp;nbsp; 3.x.x에서는 동작하지 않을 수 있다.&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2023.11 기준 스와이퍼 버전 11까지 나왔다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최신 버전의 뷰 스와이퍼에 대한 자세한 설명은 공식 문서를 참고한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swiperjs.com/vue&quot;&gt;https://swiperjs.com/vue&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. swiper, vue-awesome-swiper 패키기 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;swiper와 vue-awesome-swiper 패키지를 설치한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반드시 해당 버전으로 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699344400733&quot; class=&quot;bash&quot; style=&quot;background-color: #fafafa; color: #000000; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;yarn add swiper@5.4.5
yarn add vue-awesome-swiper@4.1.1

또는

npm install swiper@5.4.5
npm install vue-awesome-swiper@4.1.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Swiper, SwiperSlide 컴포넌트 사용해서 마크업 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/swiper.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;슬라이드 부분은 &amp;lt;Swiper&amp;gt;와 &amp;lt;SwiperSlide&amp;gt; 컴포넌트를 사용해서 마크업 한다.&lt;/li&gt;
&lt;li&gt;autoplay 버튼과 pagination 부분은 HTML로 마크업 한다.&lt;/li&gt;
&lt;li&gt;autoplay의 true/false에 따라 css가 달라져야 하기 때문에 :class 속성을 추가한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699344454370&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;kv-swiper&quot;&amp;gt;
    &amp;lt;Swiper
      :options=&quot;kvSwiperOptions&quot;
      ref=&quot;kvSwiper&quot;&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 1&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 2&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 3&amp;lt;/SwiperSlide&amp;gt;
    &amp;lt;/Swiper&amp;gt;

    &amp;lt;div class=&quot;kv-function&quot;&amp;gt;
      &amp;lt;div
        class=&quot;swiper-autoplay&quot;
        :class=&quot;{ stop: kvAutoplay }&quot;
        @click=&quot;kvSwiperAutoplay&quot;&amp;gt;
        &amp;lt;span/&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div
        class=&quot;swiper-pagination&quot;
        :class=&quot;{ stop: kvPagination }&quot;
        slot=&quot;pagination&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. script 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Swiper, SwiperSlide 컴포넌트와 swiper.css 파일을 import 한다.&lt;/li&gt;
&lt;li&gt;커스텀 페이지네이션을 만들기 위해서 &lt;u&gt;kvSwiperOptions의 pagination 부분에 renderBullet 속성을 추가한다.&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;renderBullet 부분에 &amp;lt;svg&amp;gt; 태그를 사용해서 기존 페이지네이션 태그 대신에 &amp;lt;svg&amp;gt; 태그가 대신 렌더링 되게 한다.&lt;/li&gt;
&lt;li&gt;autoplay와 pagination 동작에 필요한 메서드를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699344935645&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

export default {
  name: 'SwiperPage',

  components: {
    Swiper,
    SwiperSlide
  },

  data() {
    return {
      // kv autoplay, pagination
      kvAutoplay: false,
      kvPagination: false,

      // kv swiper options
      kvSwiperOptions: {
        effect: 'fade',
        slidesPerView: 1,
        spaceBetween: 0,
        loop: true,
        autoplay: {
            delay: 3800,
            disableOnInteraction: false
        },
        pagination: {
          el: '.swiper-pagination',
          clickable: true,
          paginationType: 'custom',
          renderBullet: function () {
            return `&amp;lt;div class=&quot;swiper-pagination-bullet&quot;&amp;gt;
              &amp;lt;svg viewBox=&quot;0 0 48 48&quot; width=&quot;24&quot; height=&quot;24&quot; xml:space=&quot;preserve&quot; id=&quot;svg&quot;&amp;gt;
                &amp;lt;circle class=&quot;pagination-loader&quot; cx=&quot;24&quot; cy=&quot;24&quot; r=&quot;23&quot; stroke=&quot;#da291c&quot; fill=&quot;none&quot; stroke-width=&quot;4&quot; stroke-linecap=&quot;round&quot;&amp;gt;&amp;lt;/circle&amp;gt;
                &amp;lt;circle class=&quot;pagination-circle&quot; cx=&quot;24&quot; cy=&quot;24&quot; r=&quot;23&quot; stroke=&quot;#fff&quot; fill=&quot;none&quot; stroke-width=&quot;4&quot; stroke-linecap=&quot;round&quot;&amp;gt;&amp;lt;/circle&amp;gt;
              &amp;lt;/svg&amp;gt;
            &amp;lt;/div&amp;gt;`
          }
        }
      }
    }
  },

  computed: {
    kvSwiper() {
      return this.$refs.kvSwiper.$swiper
    }
  },

  methods: {
    kvSwiperAutoplay() {
      this.kvAutoplay = !this.kvAutoplay
      this.kvPagination = !this.kvPagination

      if (this.kvAutoplay) {
        this.kvSwiper.autoplay.stop()
      } else {
        this.kvSwiper.autoplay.start()
      }
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. css/scss 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;움직이는 svg 이미지를 만들기 위해서는 css가 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;stroke-dasharray 속성은 선을 dash(점선) 형태로 만든다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dasharray 값은 점선을 만드는 간격을 의미하고, 숫자가 작아질수록 점선이 촘촘하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;stroke-dashoffset 속성은 svg 이미지가 어떤 지점부터 시작할지 정해준다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작점은 시계방향의 90도이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 dash 값들은 svg 태그의 path 값과 관련이 있어 글로 된 설명보다는 직접 숫자를 수정해 가며 결과로 확인하는 것이 낫다.&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@keyframe, animation을 사용해서 svg 이미지가 움직일 수 있도록 css를 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699345529438&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
@keyframes loading {
  0% {
    stroke-dashoffset: 192;
  }
  100% {
    stroke-dashoffset: 0;
  }
}

.kv-swiper {
  position: relative;
  height: 300px;

  .swiper-container {
    height: 100%;

    .swiper-slide {
      ...
    }
  }

  .kv-function {
    position: absolute;
    left: 50%;
    bottom: 30px;
    z-index: 1;
    transform: translateX(-50%);

    .swiper-autoplay {
      ...
    }

    .swiper-pagination::v-deep {
      position: relative;

      .swiper-pagination-bullet {
        width: 10px;
        height: 10px;
        margin: 0 5px;
        background-color: #fff;
        opacity: 1;
        cursor: pointer;

        svg {
          display: none;
          transform: rotate(-90deg);

          .pagination-loader {
            stroke-dasharray: 192;
            stroke-dashoffset: 192;
            animation: loading 5s linear infinite;
          }

          .pagination-circle {
            stroke-opacity: 0.2;
          }
        }
      }

      .swiper-pagination-bullet-active {
        width: 24px;
        height: 15px;
        background-color: transparent;

        svg {
          display: block;
        }
      }

      &amp;amp;.stop {
        .swiper-pagination-bullet {
          svg {
            .pagination-loader {
              stroke: none;
              animation-play-state: paused;
            }
          }
        }
      }
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>vue autoplay</category>
      <category>vue custom pagination</category>
      <category>vue pagination</category>
      <category>vue swiper</category>
      <category>vue swiper custom pagination</category>
      <category>vue swiper pagination</category>
      <category>vue-awesome-pagination</category>
      <category>vue2 swiper</category>
      <category>뷰 스와이퍼</category>
      <category>뷰 스와이퍼 사용법</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/113</guid>
      <comments>https://jae-study.tistory.com/113#entry113comment</comments>
      <pubDate>Tue, 7 Nov 2023 17:51:24 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 swiper 이용해서 슬라이드 만들기 (vue swiper 사용법)</title>
      <link>https://jae-study.tistory.com/111</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FKJTv/btszLk45qqh/8S6Co0gXQQPLueWJArA1I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FKJTv/btszLk45qqh/8S6Co0gXQQPLueWJArA1I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FKJTv/btszLk45qqh/8S6Co0gXQQPLueWJArA1I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFKJTv%2FbtszLk45qqh%2F8S6Co0gXQQPLueWJArA1I1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;349&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;버전&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue: 2.7.10&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nuxt: 2.15.8&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;vue, nuxt 버전 &lt;i&gt;2.x.x &lt;/i&gt;기준으로 작성한 글이기 때문에 &lt;i&gt;버전&lt;/i&gt;&amp;nbsp; 3.x.x에서는 &lt;i&gt;동작하지 않을 수 있다.&lt;/i&gt; &lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023.11 기준 스와이퍼 버전 11까지 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 버전의 뷰 스와이퍼에 대한 자세한 설명은 공식 문서를 참고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swiperjs.com/vue&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://swiperjs.com/vue&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. swiper, vue-awesome-swiper 패키기 설치하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;swiper와 vue-awesome-swiper 패키지를 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 해당 버전으로 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699248612856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add swiper@5.4.5
yarn add vue-awesome-swiper@4.1.1

또는

npm install swiper@5.4.5
npm install vue-awesome-swiper@4.1.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Swiper, SwiperSlide 컴포넌트 사용하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/swiper.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Swiper, SwiperSlide 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;swiper.css를 import 한다.&lt;/li&gt;
&lt;li&gt;&amp;lt;Swiper&amp;gt;와 &amp;lt;SwiperSlier&amp;gt; 컴포넌트를 사용해 마크업을 한다. &lt;br /&gt;이때 prev, next 버튼과 페이지네이션은 &amp;lt;Swiper&amp;gt; 컴포넌트 밖에 작성한다. (안에 있으면 SwiperSlide와 같이 움직이기 때문에 밖으로 뺀다.)&lt;/li&gt;
&lt;li&gt;kvSwiperOptions을 작성한다. &lt;br /&gt;가장 많이 사용하는 속성은 slidesPerView(슬라이드가 몇 개씩 노출되는지), spaceBetween(슬라이드&amp;nbsp;간의 간격)이고, 이외의 다양한 속성들은 공식 문서를 참고한다. (&lt;a href=&quot;https://swiperjs.com/demos&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://swiperjs.com/demos&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;swiper.css는 기본적인 스타일만 제공하기 때문에 크기, 배경, 글자, 위치 등은 css를 추가로 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1699248719922&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;section class=&quot;kv-swiper&quot;&amp;gt;
    &amp;lt;Swiper :options=&quot;kvSwiperOptions&quot;&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 1&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 2&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 3&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 4&amp;lt;/SwiperSlide&amp;gt;
      &amp;lt;SwiperSlide&amp;gt;Slide 5&amp;lt;/SwiperSlide&amp;gt;
    &amp;lt;/Swiper&amp;gt;

    &amp;lt;div class=&quot;swiper-button-prev&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;swiper-button-next&quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;div class=&quot;swiper-pagination&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { Swiper, SwiperSlide } from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

export default {
  name: 'SwiperPage',

  components: {
    Swiper,
    SwiperSlide
  },

  data() {
    return {
      kvSwiperOptions: {
        slidesPerView: 2,
        spaceBetween: 20,
        loop: true,
        navigation: {
          prevEl: '.swiper-button-prev',
          nextEl: '.swiper-button-next'
        },
        pagination: {
          el: '.swiper-pagination'
        }
      }
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.kv-swiper {
  position: relative;
  height: 300px;

  .swiper-container {
    height: 100%;

    .swiper-slide {
      ...
    }
  }

  .swiper-button-prev,
  .swiper-button-next {
    &amp;amp;::after {
      color: #333;
    }
  }

  .swiper-pagination::v-deep {
    bottom: -30px;
    width: 100%;

    .swiper-pagination-bullet {
      margin: 0 5px;
      cursor: pointer;
    }

    .swiper-pagination-bullet-active {
      background-color: #333;
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>nuxt</category>
      <category>nuxt swiper</category>
      <category>vue</category>
      <category>vue swiper</category>
      <category>vue swiper 사용법</category>
      <category>vue-awesome-swiepr 사용법</category>
      <category>vue-awesome-swiper</category>
      <category>vue2 swiper</category>
      <category>뷰 스와이퍼</category>
      <category>뷰 스와이퍼 사용법</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/111</guid>
      <comments>https://jae-study.tistory.com/111#entry111comment</comments>
      <pubDate>Tue, 7 Nov 2023 14:40:28 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 mounted() 이용해서 이미지에 효과 넣기</title>
      <link>https://jae-study.tistory.com/110</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/claCh8/btszC0LNAcw/x3Z7s6vtgIxfYA9Gp0ikrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/claCh8/btszC0LNAcw/x3Z7s6vtgIxfYA9Gp0ikrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/claCh8/btszC0LNAcw/x3Z7s6vtgIxfYA9Gp0ikrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclaCh8%2FbtszC0LNAcw%2Fx3Z7s6vtgIxfYA9Gp0ikrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;479&quot; height=&quot;334&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;생명 주기 훅&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;mounted()는 뷰의 생명 주기 훅 중에 하나이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DOM에 노드 생성 및 삽입(초기 렌더링)이 된 직후이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;2246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blE7Z7/btszGCKaMBx/ADUsB3ka6C2ClBG3E16OUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blE7Z7/btszGCKaMBx/ADUsB3ka6C2ClBG3E16OUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blE7Z7/btszGCKaMBx/ADUsB3ka6C2ClBG3E16OUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblE7Z7%2FbtszGCKaMBx%2FADUsB3ka6C2ClBG3E16OUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1376&quot; height=&quot;2246&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;2246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BaseKeyVisual 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/base/BaseKeyVisual.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;lt;picture&amp;gt; HTML 태그를 사용해 뷰포트에 따라 다른 이미지를 적용할 수 있게 만든다. (피씨 이미지, 모바일 이미지)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;kvActive 속성을 false로 설정&lt;/u&gt;해 이미지가 화면에 보이지 않게 만든다. css도 opacity: 0; 으로 한다.&lt;/li&gt;
&lt;li&gt;mounted()에 setTimeout을 사용해 &lt;u&gt;kvActive 속성을 true로 바꿔 렌더링이 된 직후 'active' 클래스&lt;/u&gt;가 붙도록 만든다.&lt;/li&gt;
&lt;li&gt;'active' 클래스가 붙으면 opacity: 1; 이 되고, transform 등 다른 효과를 추가해도 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698903018904&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div
    class=&quot;base-key-visual&quot;
    :class=&quot;{ 'active': kvActive }&quot;&amp;gt;
    &amp;lt;picture&amp;gt;
      &amp;lt;source :srcset=&quot;kvMoImgSrc&quot; media=&quot;(max-width: 720px)&quot;&amp;gt;
      &amp;lt;img :src=&quot;kvImgSrc&quot; alt=&quot;Key visual&quot;&amp;gt;
    &amp;lt;/picture&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  name: 'BaseKeyVisual',

  props: {
    kvImgSrc: {
      type: String
    },
    kvMoImgSrc: {
      type: String
    }
  },

  data() {
    return {
      kvActive: false
    }
  },

  mounted() {
    setTimeout(() =&amp;gt; {
      this.kvActive = true
    }, 0)
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot;&amp;gt;
.base-key-visual {
  overflow: hidden;
  width: 100%;
  background-color: #111;
  border-radius: 16px;

  img {
    width: 100%;
    opacity: 0;
    transform: scale(1.1);
    transition: all 2s;
  }

  &amp;amp;.active {
    img {
      opacity: 1;
      transform: scale(1);
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지에 BaseKeyVisual 컴포넌트&amp;nbsp;import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만든 &amp;lt;BaseKeyVisual&amp;gt; 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;kvImgSrc, kvMoImgSrc 속성을 작성한다. &lt;u&gt;이미지 경로를 작성할 때에는 required('~~')를 사용&lt;/u&gt;한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698903908212&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;BaseKeyVisual
      :kvImgSrc=&quot;kvImgSrc&quot;
      :kvMoImgSrc=&quot;kvMoImgSrc&quot;/&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'
import BaseKeyVisual from '@/components/base/BaseKeyVisual'

export default {
  name: 'Main',

  components: {
    TheLayout,
    BaseKeyVisual
  },

  data() {
    return {
      kvImgSrc: require('@/static/image/kv.jpg'),
      kvMoImgSrc: require('@/static/image/kv.jpg')
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>nuxt</category>
      <category>vue keyvisual</category>
      <category>vue mounted</category>
      <category>vue mounted 사용법</category>
      <category>뷰 라이프사이클</category>
      <category>뷰 생명주기</category>
      <category>뷰 생명주기 훅</category>
      <category>뷰 이미지 나타나게 하기</category>
      <category>뷰 이미지 효과</category>
      <category>뷰 키비주얼</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/110</guid>
      <comments>https://jae-study.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 2 Nov 2023 14:52:16 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 셀렉트 박스 만들기 (셀렉트 박스 커스텀하기, custom select box)</title>
      <link>https://jae-study.tistory.com/109</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dri3jq/btszyRvH1r8/OfCHPKXUzNCtaghkf0M0bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dri3jq/btszyRvH1r8/OfCHPKXUzNCtaghkf0M0bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dri3jq/btszyRvH1r8/OfCHPKXUzNCtaghkf0M0bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdri3jq%2FbtszyRvH1r8%2FOfCHPKXUzNCtaghkf0M0bk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;474&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BaseSelect 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/base/BaseSelect.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;form-select와 form-select-list로 나누어 html을 작성한다. 이때 form-select-list 부분은 리스트의 길이가 3개가 넘어갈 경우, 스크롤이 나타날 수 있게끔 class 속성을 추가한다.&lt;/li&gt;
&lt;li&gt;isOpen Boolean 속성을 이용해 form-select 영역을 클릭했을 때 form-select-list가 나타날 수 있도록 v-if와 @click 이벤트를 추가한다.&lt;/li&gt;
&lt;li&gt;props로 전달받을 데이터의 타입을 정의한다.&lt;/li&gt;
&lt;li&gt;computed와 methods를 이용해 form-select-list를 클릭했을 때 그 값이 form-select에 노출될 수 있도록 만든다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;공통으로 적용할 css/scss를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698890000259&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div
    class=&quot;base-select&quot;
    :class=&quot;[
      shape,
      { 'open': isOpen }
    ]&quot;&amp;gt;

    &amp;lt;div
      class=&quot;form-select&quot;
      @click=&quot;isOpen = !isOpen&quot;&amp;gt;
      &amp;lt;p :class=&quot;[{ 'selected': isSelect }]&quot;&amp;gt;{{ selected }}&amp;lt;/p&amp;gt;
      &amp;lt;svg width=&quot;12&quot; height=&quot;8&quot; viewBox=&quot;0 0 12 8&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
        &amp;lt;path d=&quot;M11 1.17C10.8126 0.983753 10.5592 0.879211 10.295 0.879211C10.0308 0.879211 9.77737 0.983753 9.59001 1.17L6.00001 4.71L2.46001 1.17C2.27265 0.983753 2.0192 0.879211 1.75501 0.879211C1.49082 0.879211 1.23737 0.983753 1.05001 1.17C0.956281 1.26297 0.881887 1.37357 0.831118 1.49543C0.780349 1.61729 0.754211 1.74799 0.754211 1.88C0.754211 2.01202 0.780349 2.14272 0.831118 2.26458C0.881887 2.38644 0.956281 2.49704 1.05001 2.59L5.29001 6.83C5.38297 6.92373 5.49357 6.99813 5.61543 7.04889C5.73729 7.09966 5.868 7.1258 6.00001 7.1258C6.13202 7.1258 6.26273 7.09966 6.38459 7.04889C6.50645 6.99813 6.61705 6.92373 6.71001 6.83L11 2.59C11.0937 2.49704 11.1681 2.38644 11.2189 2.26458C11.2697 2.14272 11.2958 2.01202 11.2958 1.88C11.2958 1.74799 11.2697 1.61729 11.2189 1.49543C11.1681 1.37357 11.0937 1.26297 11 1.17Z&quot; fill=&quot;#111111&quot;/&amp;gt;
      &amp;lt;/svg&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div
      v-if=&quot;isOpen&quot;
      class=&quot;form-select-list&quot;&amp;gt;
      &amp;lt;div :class=&quot;{ 'scroll': options.length &amp;gt; 3 }&quot;&amp;gt;
        &amp;lt;ul&amp;gt;
          &amp;lt;li
            v-for=&quot;(option, key) in options&quot;
            :key=&quot;`option-${key}`&quot;
            @click=&quot;selectOption(option)&quot;&amp;gt;
            {{ option.name }}
          &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  name: 'BaseSelect',

  props: {
    shape: {
      type: String
    },
    isSelect: {
      type: Boolean,
      default: false
    },
    options: {
      type: Array
    },
    defaultValue: {
      type: String
    }
  },

  data() {
    return {
      isOpen: false
    }
  },

  computed: {
    selected: {
      get() {
        return this.options.find(item =&amp;gt; item.name === this.defaultValue)?.name || this.defaultValue || '옵션을 선택해 주세요.'
      }
    }
  },

  methods: {
    selectOption(option) {
      this.selected = option.name
      this.isOpen = false
      this.isSelect = true
      this.$emit('input', option.name)
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.base-select {
  position: relative;
  
  .form-select {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    height: 60px;
    padding: 0 15px;
    background-color: #fff;
    border: 1px solid #ddd;
    cursor: pointer;

    svg {
      transition: all 0.3s;
    }
  }

  .form-select-list {
    position: absolute;
    top: 65px;
    left: 0;
    right: 0;
    z-index: 10;

    &amp;amp; &amp;gt; div {
      &amp;amp;.scroll {
        height: 240px;

        ul {
          overflow-y: auto;
          height: 100%;
          padding-right: 5px;

          &amp;amp;::-webkit-scrollbar {
            width: 5px;
          }

          &amp;amp;::-webkit-scrollbar-thumb {
            background-color: #f5f5f5;
          }
        }
      }
    }

    ul {
      background-color: #fff;
      border: 1px solid #333;

      li {
        height: 60px;
        padding: 0 15px;
        line-height: 60px;
        transition: all .3s;
        cursor: pointer;

        &amp;amp;:hover {
          background-color: #f5f5f5;
        }
      }
    }
  }
  ...
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지에 BaseSelect 컴포넌트 import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만든 &amp;lt;BaseSelect&amp;gt; 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;data() 부분에 props로 넘길 데이터를 작성한다. selectValue1, selectValue2는 빈 값으로 만들어 클릭한 값이 들어올 수 있도록 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;v-model을 통해서 selectValue 값이 바뀌는 것을 확인한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698891021132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;div class=&quot;select&quot;&amp;gt;
      &amp;lt;BaseSelect
        :options=&quot;selectList&quot;
        :defaultValue=&quot;selectValue1&quot;
        v-model=&quot;selectValue1&quot;/&amp;gt;

      &amp;lt;BaseSelect
        shape=&quot;black&quot;
        :options=&quot;selectList&quot;
        :defaultValue=&quot;selectValue2&quot;
        v-model=&quot;selectValue2&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'
import BaseSelect from '@/components/base/BaseSelect'

export default {
  name: 'Main',

  components: {
    TheLayout,
    BaseSelect
  },

  data() {
    return {
      selectValue1: '',
      selectValue2: '',

      selectList: [
        {
          name: '1번'
        },
        {
          name: '2번'
        },
        {
          name: '3번'
        },
        {
          name: '4번'
        },
        {
          name: '5번'
        }
      ]
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
...
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>BaseSelect</category>
      <category>BaseSlect 만들기</category>
      <category>nuxt</category>
      <category>vue custom select</category>
      <category>vue select</category>
      <category>뷰 셀렉트</category>
      <category>뷰 셀렉트 만들기</category>
      <category>뷰 셀렉트박스</category>
      <category>뷰 커스텀 셀렉트</category>
      <category>뷰 커스텀 셀렉트박스</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/109</guid>
      <comments>https://jae-study.tistory.com/109#entry109comment</comments>
      <pubDate>Thu, 2 Nov 2023 11:13:48 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 아코디언 만들기 (BaseAccordion 만들기)</title>
      <link>https://jae-study.tistory.com/108</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l6JDC/btszAXOXq7C/7z8fHT2KZnWIv0jDplkOJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l6JDC/btszAXOXq7C/7z8fHT2KZnWIv0jDplkOJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l6JDC/btszAXOXq7C/7z8fHT2KZnWIv0jDplkOJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl6JDC%2FbtszAXOXq7C%2F7z8fHT2KZnWIv0jDplkOJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;388&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BaseAccordion 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/base/BaseAccordion.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아코디언은 제목 부분을 클릭하면 내용 부분이 나타나는 레이아웃을 의미한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;title과 content로 나누어 html을 작성한다. 이때 content 부분은 펼쳐지는 느낌이 날 수 있도록 &amp;lt;transition&amp;gt; 컴포넌트를 이용한다.&lt;/li&gt;
&lt;li&gt;&amp;lt;transition&amp;gt; 컴포넌트의 &lt;u&gt;@enter, @leave 메소드에 el.scrollHeight를 사용&lt;/u&gt;해서 내용에 따라서 높이값을 정할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;toggle 클릭 이벤트와 currentAccordion 속성을 이용해 title 부분을 클릭할 때마다 content 부분을 show/hide 시킨다.&lt;/li&gt;
&lt;li&gt;공통으로 적용할 css/scss를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698819701369&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;base-accordion&quot;&amp;gt;
    &amp;lt;div
      class=&quot;title&quot;
      @click=&quot;toggle&quot;&amp;gt;
      &amp;lt;slot name=&quot;title&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;transition
      name=&quot;accordion&quot; appear
      @before-enter=&quot;beforeEnter&quot; @enter=&quot;enter&quot;
      @before-leave=&quot;beforeLeave&quot; @leave=&quot;leave&quot;&amp;gt;
      &amp;lt;div
        v-show=&quot;currentAccordion&quot;
        class=&quot;content&quot;&amp;gt;
        &amp;lt;slot name=&quot;content&quot;/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/transition&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  name: 'BaseAccordion',

  data() {
    return {
      currentAccordion: false
    }
  },

  methods: {
    toggle() {
      this.currentAccordion = !this.currentAccordion
    },
    beforeEnter(el) {
      el.style.height = '0'
    },
    enter(el) {
      el.style.height = el.scrollHeight + 'px'
    },
    beforeLeave(el) {
      el.style.height = el.scrollHeight + 'px'
    },
    leave(el) {
      el.style.height = '0'
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.base-accordion {
  .title {
    padding: 20px;
    border-bottom: 1px solid #ddd;
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
  }

  .content {
    overflow: hidden;
    padding: 20px;
    background-color: #f5f5f5;
    transition: all 0.3s;
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지에 BaseAccordion 컴포넌트 import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만든 &amp;lt;BaseAccordion&amp;gt; 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;&amp;lt;slot&amp;gt;으로 만든 부분에 내용이 들어갈 수 있도록 속성에 맞추어 내용을 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698820542151&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;div class=&quot;accordion&quot;&amp;gt;
      &amp;lt;BaseAccordion&amp;gt;
        &amp;lt;h3 slot=&quot;title&quot;&amp;gt;첫번째 제목&amp;lt;/h3&amp;gt;
        &amp;lt;p slot=&quot;content&quot;&amp;gt;
          내용입니다. 내용입니다. 내용입니다.
          내용입니다. 내용입니다. 내용입니다.
          내용입니다. 내용입니다. 내용입니다.
        &amp;lt;/p&amp;gt;
      &amp;lt;/BaseAccordion&amp;gt;

      &amp;lt;BaseAccordion&amp;gt;
        &amp;lt;h3 slot=&quot;title&quot;&amp;gt;두번째 제목&amp;lt;/h3&amp;gt;
        &amp;lt;p slot=&quot;content&quot;&amp;gt;
          내용입니다. 내용입니다. 내용입니다.
          내용입니다. 내용입니다. 내용입니다.
        &amp;lt;/p&amp;gt;
      &amp;lt;/BaseAccordion&amp;gt;

      &amp;lt;BaseAccordion&amp;gt;
        &amp;lt;h3 slot=&quot;title&quot;&amp;gt;세번째 제목&amp;lt;/h3&amp;gt;
        &amp;lt;p slot=&quot;content&quot;&amp;gt;
          내용입니다. 내용입니다. 내용입니다.
          내용입니다. 내용입니다. 내용입니다.
        &amp;lt;/p&amp;gt;
      &amp;lt;/BaseAccordion&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'
import BaseAccordion from '@/components/base/BaseAccordion'

export default {
  name: 'Main',

  components: {
    TheLayout,
    BaseAccordion
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.accordion {
  border: 1px solid #ddd;

  .base-accordion::v-deep {
    &amp;amp;:last-child {
      .title {
        border-bottom: 0;
      }
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>BaseAccordion</category>
      <category>BaseAccordion 만들기</category>
      <category>nuxt</category>
      <category>vue accordion</category>
      <category>vue BaseAccrodion</category>
      <category>Vue.js</category>
      <category>뷰 아코디언</category>
      <category>뷰 아코디언 만들기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/108</guid>
      <comments>https://jae-study.tistory.com/108#entry108comment</comments>
      <pubDate>Wed, 1 Nov 2023 15:39:22 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 탭 만들기 (BaseTab 만들기)</title>
      <link>https://jae-study.tistory.com/107</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;140&quot; data-origin-height=&quot;113&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCAQkG/btszyEu0vvY/fvJ9WcDQ50CZm2HY5nBHK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCAQkG/btszyEu0vvY/fvJ9WcDQ50CZm2HY5nBHK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCAQkG/btszyEu0vvY/fvJ9WcDQ50CZm2HY5nBHK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCAQkG%2FbtszyEu0vvY%2FfvJ9WcDQ50CZm2HY5nBHK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;140&quot; height=&quot;113&quot; data-origin-width=&quot;140&quot; data-origin-height=&quot;113&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BaseTab 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/base/BaseTab.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;tab이 몇 개인지 모르니 배열 타입으로 props 받는다.&lt;/li&gt;
&lt;li&gt;key와 currentTab에 따라서 탭의 on/off 상태를 나타낸다.&lt;/li&gt;
&lt;li&gt;클릭하면 탭이 변경되어야 하기 때문에 $emit으로 클릭 이벤트를 만든다.&lt;/li&gt;
&lt;li&gt;공통으로 적용할 css/scss를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698735800541&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class=&quot;base-tab&quot;&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li
        v-for=&quot;(item, key) in tab&quot;
        :key=&quot;`tab-${key}`&quot;
        :class=&quot;{ 'on': key === currentTab }&quot;
        @click=&quot;$emit('click', key)&quot;&amp;gt;
        {{ item.name }}
      &amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  name: 'BaseTab',

  props: {
    tab: {
      type: Array,
      required: true
    },
    currentTab: {
      type: Number,
      default: 0
    }
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.base-tab {
  margin-bottom: 30px;

  ul {
    display: flex;
    justify-content: start;
    align: center;
    gap:  20px;

    li {
      padding: 0 5px;
      border-bottom: 2px solid transparent;
      color: #888;
      font-size: 20px;
      font-weight: 700;
      transition: all 0.3s;
      cursor: pointer;

      &amp;amp;:hover {
        color: #333;
      }

      &amp;amp;.on {
        color: #333;
        border-bottom: 2px solid #333;
      }
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 페이지에 BaseTab import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만든 &amp;lt;BaseTab&amp;gt; 컴포넌트를 import 한다.&lt;/li&gt;
&lt;li&gt;currentTab, tab 속성을 만들어 &amp;lt;BaseTab&amp;gt;에 데이터를 넘긴다.&lt;/li&gt;
&lt;li&gt;changeTab() 클릭 이벤트를 만들어 currentTab이 &amp;lt;BaseTab&amp;gt;의 key 값과 동일하게 만든다.&lt;/li&gt;
&lt;li&gt;v-if를 통해서 currentTab 값에 따라 영역을 나타나고, 안 보이게 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698736230445&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;BaseTab
      :tab=&quot;tab&quot;
      :currentTab=&quot;currentTab&quot;
      @click=&quot;changeTab&quot;/&amp;gt;

    &amp;lt;section v-if=&quot;currentTab === 0&quot;&amp;gt;
      탭 1 영역입니다.
    &amp;lt;/section&amp;gt;

    &amp;lt;section v-if=&quot;currentTab === 1&quot;&amp;gt;
      탭 2 영역입니다.
    &amp;lt;/section&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'

export default {
  name: 'Index',

  components: {
    TheLayout
  },

  data() {
    return {
      currentTab: 0,
      tab: [
        { name: '탭 1' },
        { name: '탭 2' }
      ]
    }
  },

  methods: {
    changeTab(key) {
      this.currentTab = key
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>BaseTab</category>
      <category>BaseTab 만들기</category>
      <category>nuxt</category>
      <category>vue BaseTab</category>
      <category>vue tab</category>
      <category>Vue.js</category>
      <category>뷰 탭</category>
      <category>뷰 탭 만들기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/107</guid>
      <comments>https://jae-study.tistory.com/107#entry107comment</comments>
      <pubDate>Tue, 31 Oct 2023 16:24:33 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 모달 만들기 (BaseModal 만들기)</title>
      <link>https://jae-study.tistory.com/106</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bixUZQ/btszpzvkf9U/3CKV2qm2bnbng3FxKy0H8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bixUZQ/btszpzvkf9U/3CKV2qm2bnbng3FxKy0H8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bixUZQ/btszpzvkf9U/3CKV2qm2bnbng3FxKy0H8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbixUZQ%2Fbtszpzvkf9U%2F3CKV2qm2bnbng3FxKy0H8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;495&quot; height=&quot;445&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. BaseModal 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/base/BaseModal.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;BaseModal&amp;gt; 컴포넌트는 여러 가지 모양의 모달에서 사용될 기본 틀이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;모달의 경우, 주로 닫기 버튼과 제목, 내용 영역으로 구성되기 때문에 &lt;u&gt;닫기 버튼과 &amp;lt;slot&amp;gt;으로 기본 레이아웃&lt;/u&gt;을 만든다.&lt;/li&gt;
&lt;li&gt;모달 바깥쪽 영역과 닫기 버튼을 누르면 모달이 닫히는 이벤트가 필요하기 때문에 &lt;u&gt;$emit 을 이용해 클릭 이벤트&lt;/u&gt;를 만든다.&lt;/li&gt;
&lt;li&gt;공통으로 적용할 css/scss를 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698728851821&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div
    class=&quot;base-modal&quot;
    @click.self=&quot;$emit('close')&quot;&amp;gt;
    &amp;lt;div class=&quot;wrap&quot;&amp;gt;
      &amp;lt;BaseButton @click=&quot;$emit('close')&quot;&amp;gt;X&amp;lt;/BaseButton&amp;gt;

      &amp;lt;div class=&quot;title&quot;&amp;gt;
        &amp;lt;slot name=&quot;title&quot;/&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div class=&quot;content&quot;&amp;gt;
        &amp;lt;slot name=&quot;content&quot;/&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import BaseButton from '@/components/base/BaseButton'

export default {
  name: 'BaseModal',

  components: {
    BaseButton
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
.base-modal {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1000;
  background-color: rgba(0, 0, 0, 0.5);

  .wrap {
    position: relative;
    width: 90%;
    max-width: 500px;
    min-height: 300px;
    background-color: #fff;
    border-radius: 16px;

    .base-button {
      position: absolute;
      top: 20px;
      right: 20px;
      font-size: 20px;
      font-weight: 700;
    }

    .title {
      margin: 20px auto;

      h3 {
        font-size: 26px;
        font-weight: 700;
        text-align: center;
      }
    }

    .content {
      p {
        font-size: 16px;
      }
    }
  }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 필요한 modal 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/modal/ModalCookie.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;slot&amp;gt;을 사용해 모달 안의 내용을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 방식으로 여러 가지 모달을 만들 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1698730247143&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;BaseModal @close=&quot;$emit('close')&quot;&amp;gt;
    &amp;lt;h3 slot=&quot;title&quot;&amp;gt;Cookie Modal&amp;lt;/h3&amp;gt;
    &amp;lt;p slot=&quot;content&quot;&amp;gt;쿠키 모달입니다.&amp;lt;/p&amp;gt;
  &amp;lt;/BaseModal&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import BaseModal from '@/components/base/BaseModal'

export default {
  name: 'ModalCookie',

  components: {
    BaseModal
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 페이지에 modal import 하기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;만든 &amp;lt;ModalCookie&amp;gt; 컴포넌트를 import 시킨다.&lt;/li&gt;
&lt;li&gt;isModalCookie 속성을 만들어 v-if가 true 이면 모달이 나타나고, false 이면 모달이 사라지게 만든다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ModalCookieToggle 클릭 이벤트를 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698730318779&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;BaseButton @click=&quot;ModalCookieToggle&quot;&amp;gt;쿠키 모달 열기&amp;lt;/BaseButton&amp;gt;

    &amp;lt;ModalCookie
      v-if=&quot;isModalCookie&quot;
      @close=&quot;ModalCookieToggle&quot;/&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'
import BaseButton from '@/components/base/BaseButton'
import ModalCookie from '@/components/modal/ModalCookie'

export default {
  name: 'Main',

  components: {
    TheLayout,
    BaseButton,
    ModalCookie
  },

  data() {
    return {
      isModalCookie: false
    }
  },

  methods: {
    ModalCookieToggle() {
      this.isModalCookie = !this.isModalCookie
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>BaseModal</category>
      <category>BaseModal 만들기</category>
      <category>nuxt</category>
      <category>vue BaseModal</category>
      <category>vue modal</category>
      <category>Vue.js</category>
      <category>모달 만들기</category>
      <category>뷰</category>
      <category>뷰 모달</category>
      <category>뷰 모달 만들기</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/106</guid>
      <comments>https://jae-study.tistory.com/106#entry106comment</comments>
      <pubDate>Tue, 31 Oct 2023 14:45:19 +0900</pubDate>
    </item>
    <item>
      <title>[Vue/Nuxt] 뷰 Router 적용하기 (라우터 변수 만들어 전역에서 관리하기)</title>
      <link>https://jae-study.tistory.com/105</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o7HBt/btszuHkPgCL/W9qduI7Ft8HnBAsISD6kSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7HBt/btszuHkPgCL/W9qduI7Ft8HnBAsISD6kSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7HBt/btszuHkPgCL/W9qduI7Ft8HnBAsISD6kSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7HBt%2FbtszuHkPgCL%2FW9qduI7Ft8HnBAsISD6kSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;578&quot; height=&quot;248&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. RouterName 변수 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;configs/router.js&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;RouterName 변수(객체)를 만든다.&lt;/li&gt;
&lt;li&gt;라우터 변수의 이름과 경로를 정의한다. (경로는 pages 폴더에 만든 .vue 파일의 경로와 동일하게 만든다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RouterName 변수 파일을 따로 만드는 이유는 피씨 메뉴, 모바일 메뉴, 사이트맵 등 여러 곳에서 사용했을 경우, 이름 또는 경로가 변경되면 여러 번 수정해야 하기 때문에 router 파일을 하나 만들어 import 시켜서 사용하면 한 번만 수정하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1698643759569&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const RouterName = {
  MAIN: '/',
  SUB: '/sub',

  AUTH_LOGIN: '/auth/login'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. TheHeader 컴포넌트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/layout/TheHeader.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;lt;script&amp;gt; 태그에 { RouterName }을&amp;nbsp; import 시킨다.&lt;/li&gt;
&lt;li&gt;&amp;lt;script&amp;gt; 태그의 data() 영역에 navigation 변수(배열)를 만든다.&lt;/li&gt;
&lt;li&gt;name은 네비게이션 이름, to는 RouterName에 작성한 라우터 변수를 작성한다.&lt;/li&gt;
&lt;li&gt;&amp;lt;nav&amp;gt; 태그에 v-for를 사용해 네비게이션을 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1698644343095&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;header class=&quot;wrap&quot;&amp;gt;
    &amp;lt;nav&amp;gt;
      &amp;lt;NuxtLink
        v-for=&quot;(nav, key) in navigation&quot;
        :key=&quot;`nav-${key}`&quot;
        :to=&quot;{ path: `${nav.to}`}&quot;&amp;gt;
        {{ nav.name }}
      &amp;lt;/NuxtLink&amp;gt;
    &amp;lt;/nav&amp;gt;
  &amp;lt;/header&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { RouterName } from '@/configs/router'

export default {
  name: 'TheHeader',

  data() {
    return {
      navigation: [
        {
          name: '메인',
          to: RouterName.MAIN
        },
        {
          name: '서브',
          to: RouterName.SUB
        },
        {
          name: '로그인',
          to: RouterName.AUTH_LOGIN
        }
      ]
    }
  }
}

&amp;lt;style lang=&quot;scss&quot; scoped&amp;gt;
header {
  ...
}
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. TheHeader 컴포넌트 import 시키기&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;components/layout/TheLayout.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1698645849348&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;TheHeader/&amp;gt;

    &amp;lt;main class=&quot;wrap&quot;&amp;gt;
      &amp;lt;slot/&amp;gt;
    &amp;lt;/main&amp;gt;

    &amp;lt;footer&amp;gt;&amp;lt;/footer&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheHeader from '@/components/layout/TheHeader'

export default {
  name: 'TheLayout',

  components: {
    TheHeader
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pages/index.vue&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1698645890776&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;TheLayout&amp;gt;
    &amp;lt;h1&amp;gt;메인 페이지&amp;lt;/h1&amp;gt;
  &amp;lt;/TheLayout&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import TheLayout from '@/components/layout/TheLayout'

export default {
  name: 'Main',

  components: {
    TheLayout
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vue, Nuxt/문법</category>
      <category>nuxt</category>
      <category>nuxtlink</category>
      <category>vue router</category>
      <category>Vue.js</category>
      <category>뷰</category>
      <category>뷰 라우터</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/105</guid>
      <comments>https://jae-study.tistory.com/105#entry105comment</comments>
      <pubDate>Mon, 30 Oct 2023 15:07:52 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] Grid를 사용해서 반응형 차트 만들기 (grid-column, grid-row)</title>
      <link>https://jae-study.tistory.com/104</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt; grid-column, grid-row &lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;grid-column&lt;/b&gt; 속성은 그리드 라인 숫자에 맞춰 &lt;u&gt;시작 열과 끝 열을 지정&lt;/u&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;grid-row&lt;/b&gt; 속성은 그리드 라인 숫자에 맞춰 &lt;u&gt;시작 행과 끝 행을 지정&lt;/u&gt;할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lxAiO/btszgmINOpV/F2T7onl19q0VEleblcLj5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lxAiO/btszgmINOpV/F2T7onl19q0VEleblcLj5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lxAiO/btszgmINOpV/F2T7onl19q0VEleblcLj5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlxAiO%2FbtszgmINOpV%2FF2T7onl19q0VEleblcLj5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;507&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피씨&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WV7Jp/btszf33ysyQ/rSLxDFxHhBtdOb8KITFOoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WV7Jp/btszf33ysyQ/rSLxDFxHhBtdOb8KITFOoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WV7Jp/btszf33ysyQ/rSLxDFxHhBtdOb8KITFOoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWV7Jp%2Fbtszf33ysyQ%2FrSLxDFxHhBtdOb8KITFOoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1028&quot; height=&quot;234&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모바일&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p3EPq/btszhuffJPD/Fy7HLrqECUaICGKifBUp3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p3EPq/btszhuffJPD/Fy7HLrqECUaICGKifBUp3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p3EPq/btszhuffJPD/Fy7HLrqECUaICGKifBUp3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp3EPq%2FbtszhuffJPD%2FFy7HLrqECUaICGKifBUp3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;476&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;CSS / SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리드 레이아웃 안에 또 그리드를 사용해도 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 display: grid; 만 사용하면 원하는 영역만큼 공간을 차지하지 않기 때문에 grid-column, grid-row를 함께 사용한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4kYI2/btszgxXTKrc/L4MkLnSiWhiiCbNKGMCBk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4kYI2/btszgxXTKrc/L4MkLnSiWhiiCbNKGMCBk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4kYI2/btszgxXTKrc/L4MkLnSiWhiiCbNKGMCBk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4kYI2%2FbtszgxXTKrc%2FL4MkLnSiWhiiCbNKGMCBk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;338&quot; height=&quot;235&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귤 영역: &lt;u&gt;grid-column: 1 / 3;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열의 1번째 라인부터 3번째 라인까지 영역을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HEwuR/btszfYhhgT5/Lo4X6m6s0QH9k4mVJ613A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HEwuR/btszfYhhgT5/Lo4X6m6s0QH9k4mVJ613A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HEwuR/btszfYhhgT5/Lo4X6m6s0QH9k4mVJ613A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHEwuR%2FbtszfYhhgT5%2FLo4X6m6s0QH9k4mVJ613A0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;233&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귤 영역: &lt;u&gt;grid-column: 1/2; grid-row: 1/3;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열의 1번째 라인부터 2번째 라인까지 영역을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행의 1번째 라인부터 3번째 라인까지 영역을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오렌지 영역: &lt;u&gt;grid-column: 2/3;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열의 2번째 라인부터 3번째 라인까지 영역을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;레몬 영역:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;grid-column: 2/3;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;열의 2번째 라인부터 3번째 라인까지 영역을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698384463509&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.chart {
  ul {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    width: 100%;

    li {
      ...
    }
  }

  // 첫번째 차트 (회색)
  .first {
    background-color: #999;
  }

  // 두번째 차트 (진한 회색)
  .second {
    ul {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      grid-template-rows: 100px 100px;
      gap: 20px;

      li {
        background-color: #333;

        &amp;amp;:nth-child(1) {
          grid-column: 1 / 3;
        }
      }
    }
  }

  // 세번째 차트 (빨강)
  .third {
    ul {
      display: grid;
      grid-template-columns: 1fr;
      grid-template-rows: 100px 100px;
      gap: 20px;

      li {
        background-color: #d90000;
      }
    }
  }
}

@media screen and (max-width: 1024px) {
  .chart {
    ul {
      grid-template-columns: repeat(1, 1fr);

      li {
        ...
      }
    }

    // 첫번째 차트 (회색)
    .first {
      height: 100px;
    }

    // 두번째 차트 (진한 회색)
    .second {
      ul {
        grid-template-columns: repeat(2, 1fr);
        grid-template-rows: repeat(2, 100px);

        li {
          &amp;amp;:nth-child(1) {
            grid-column: 1 / 2;
            grid-row: 1 / 3;
          }

          &amp;amp;:nth-child(2) {
            grid-column: 2 / 3;
          }

          &amp;amp;:nth-child(3) {
            grid-column: 2 / 3;
          }
        }
      }
    }

    // 세번째 차트 (빨강)
    .third {
      ul {
        grid-template-columns: repeat(2, 1fr);
        grid-template-rows: repeat(1, 100px);
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>HTML, CSS</category>
      <category>CSS</category>
      <category>CSS 그래프 만들기</category>
      <category>CSS 차트 만들기</category>
      <category>CSS 표 만들기</category>
      <category>grid</category>
      <category>그리드</category>
      <category>반응형 grid</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/104</guid>
      <comments>https://jae-study.tistory.com/104#entry104comment</comments>
      <pubDate>Fri, 27 Oct 2023 15:24:08 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] Grid로 레이아웃 만들기</title>
      <link>https://jae-study.tistory.com/103</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CSS Grid&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리드 레이아웃은 웹페이지를 위한 2차원 레이아웃 시스템이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행(row, &lt;b&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;&amp;rarr;&lt;/span&gt;&lt;/b&gt;)과 열(column, &lt;b&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;&amp;darr;&lt;/span&gt;&lt;/b&gt;)에 콘텐츠를 배치할 수 있고, 쉽게 말해 격자무늬로 생긴 레이아웃을 만들 때 그리드를 사용하면 편리하게 작업할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OAYKG/btsziQV6G6A/rbmIqFVKVZtLYk1rBRfnt1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OAYKG/btsziQV6G6A/rbmIqFVKVZtLYk1rBRfnt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OAYKG/btsziQV6G6A/rbmIqFVKVZtLYk1rBRfnt1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOAYKG%2FbtsziQV6G6A%2FrbmIqFVKVZtLYk1rBRfnt1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 x 3 레이아웃 만들기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGiXYg/btszfvyPKYA/G84djefqudq0807uwaXSlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGiXYg/btszfvyPKYA/G84djefqudq0807uwaXSlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGiXYg/btszfvyPKYA/G84djefqudq0807uwaXSlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGiXYg%2FbtszfvyPKYA%2FG84djefqudq0807uwaXSlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;687&quot; height=&quot;361&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. grid 선언&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZjT17/btszglP0XBx/SyScyunGA3dgWqMM6XFjf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZjT17/btszglP0XBx/SyScyunGA3dgWqMM6XFjf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZjT17/btszglP0XBx/SyScyunGA3dgWqMM6XFjf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZjT17%2FbtszglP0XBx%2FSyScyunGA3dgWqMM6XFjf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;257&quot; height=&quot;290&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 코드는 계속 동일하다.&lt;/p&gt;
&lt;pre id=&quot;code_1698369423389&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;ul class=&quot;grid&quot;&amp;gt;
  &amp;lt;li&amp;gt;산&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;바다&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;구름&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;자전거&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;자동차&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;비행기&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;사자&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;호랑이&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;곰&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS / SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;display: grid;&lt;/u&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 선언하면 위의 이미지처럼 격자무늬로 레이아웃이 나뉜 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1698369448878&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.grid {
  display: grid;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. rows와 columns를 이용해 행과 열의 모양 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YOc7r/btszb6z8gSV/lhpeDvgNKGDmTXtV1pPyDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YOc7r/btszb6z8gSV/lhpeDvgNKGDmTXtV1pPyDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YOc7r/btszb6z8gSV/lhpeDvgNKGDmTXtV1pPyDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYOc7r%2Fbtszb6z8gSV%2FlhpeDvgNKGDmTXtV1pPyDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;321&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS / SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;grid-template-columns&lt;/u&gt; 는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;열(column,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;&amp;darr;&lt;/span&gt;&lt;/b&gt;)을 개수는 정할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;gtid-template-rows&lt;/u&gt; 는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;행(row,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;&amp;rarr;&lt;/span&gt;&lt;/b&gt;)의 높이를 정할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 그리드 레이아웃은 &lt;u&gt;반응형 웹 사이트&lt;/u&gt;에서 많이 사용하기 때문에 &lt;u&gt;columns는 1fr 단위&lt;/u&gt;를 많이 사용하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rows는 고정 높이 값이 아니라면 콘텐츠 높이만큼 영역을 차지하기 때문에 &lt;u&gt;rows는 값을 지정하지 않는다.&lt;/u&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;fr은 유연한 크기를 가지는 단위이다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;그리드 컨테이너 내의 공간 비율을 분수(fraction)로 나타낸다.&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1698371145491&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr); // = grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: repeat(3, 100px); // = grid-template-rows: 100px 100px 100px;

  // 레이아웃 구별을 위해 색상 CSS를 추가했다.
  li {
    padding: 20px;

    &amp;amp;:nth-child(1),
    &amp;amp;:nth-child(2),
    &amp;amp;:nth-child(3) {
      background-color: blanchedalmond;
    }

    &amp;amp;:nth-child(4),
    &amp;amp;:nth-child(5),
    &amp;amp;:nth-child(6) {
      background-color: darkseagreen;
    }

    &amp;amp;:nth-child(7),
    &amp;amp;:nth-child(8),
    &amp;amp;:nth-child(9) {
      background-color: cadetblue;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. gap을 이용해서 행과 열에 간격 맞추기&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnHOKP/btszcoHiWAv/EQaCkVEQwAXfih6dR3SZFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnHOKP/btszcoHiWAv/EQaCkVEQwAXfih6dR3SZFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnHOKP/btszcoHiWAv/EQaCkVEQwAXfih6dR3SZFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnHOKP%2FbtszcoHiWAv%2FEQaCkVEQwAXfih6dR3SZFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;423&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS / SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;column-gap&lt;/u&gt; 은 열과 열 사이의 간격을 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;row-gap&lt;/u&gt; 은 행과 행 사이의 간격을 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gap 은 행과 열을 동일한 간격으로 지정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1698372097852&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  column-gap: 20px;
  row-gap: 50px;

  li {
    ...
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. flex를 사용해 컨텐츠 가운데 정렬&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJIxgK/btszhvklnoz/rQHdNmWc8sHkfIlwaTvbX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJIxgK/btszhvklnoz/rQHdNmWc8sHkfIlwaTvbX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJIxgK/btszhvklnoz/rQHdNmWc8sHkfIlwaTvbX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJIxgK%2Fbtszhvklnoz%2FrQHdNmWc8sHkfIlwaTvbX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;687&quot; height=&quot;361&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS / SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gird와 flex를 함께 사용하면 보다 쉽게 레이아웃을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gird는 컨테이너 영역의 레이아웃을 만들 때 사용하면 좋고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flex는 컨테이너 영역 안의 콘텐츠를 정렬(왼쪽 정렬, 가운데 정렬, 오른쪽 정렬)할 때 사용하면 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1698372475095&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  gap: 20px;

  li {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
    border-radius: 10px;

    &amp;amp;:nth-child(1),
    &amp;amp;:nth-child(2),
    &amp;amp;:nth-child(3) {
      background-color: blanchedalmond;
    }

    &amp;amp;:nth-child(4),
    &amp;amp;:nth-child(5),
    &amp;amp;:nth-child(6) {
      background-color: darkseagreen;
    }

    &amp;amp;:nth-child(7),
    &amp;amp;:nth-child(8),
    &amp;amp;:nth-child(9) {
      background-color: cadetblue;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>HTML, CSS</category>
      <category>CSS</category>
      <category>css flex</category>
      <category>css grid</category>
      <category>Flex</category>
      <category>grid</category>
      <category>grid 레이아웃</category>
      <category>grid 레이아웃 만들기</category>
      <category>그리드</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/103</guid>
      <comments>https://jae-study.tistory.com/103#entry103comment</comments>
      <pubDate>Fri, 27 Oct 2023 11:11:58 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] 스켈레톤 UI 만들기 (linear-gradient, 움직이는 그라데이션)</title>
      <link>https://jae-study.tistory.com/102</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스켈레톤 UI (skeleton UI)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스켈레톤 UI는 실제 데이터가 렌더링 되기 전에 보이는 화면의 윤곽을 표현한 로딩 애니메이션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적인 화면을 보여주는 대신 스켈레톤 애니메이션을 화면에 보여줌으로써 &lt;u&gt;사용자의 요청이 진행 중임을 표시한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 정적인 화면보다 동적인 화면을 보여주었을 때 &lt;u&gt;로딩 효과&lt;/u&gt;를 잘 표현할 수 있어 움직이는 그라데이션 효과를 자주 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결과 화면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진이어서 움직이지 않지만, keyframes과 animation을 사용해서 좌에서 우로 그라데이션 효과가 움직인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t2Qa1/btszeJXNAV5/ZxJNojvCS4bkv4Uj5Nm5e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t2Qa1/btszeJXNAV5/ZxJNojvCS4bkv4Uj5Nm5e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t2Qa1/btszeJXNAV5/ZxJNojvCS4bkv4Uj5Nm5e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft2Qa1%2FbtszeJXNAV5%2FZxJNojvCS4bkv4Uj5Nm5e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;311&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1698306842956&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;gradient&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;css/scss&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색상과 크기는 본인이 원하는 스타일로 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keyframes 효과를 다르게 주면 여러 움직임으로 표현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1698308488314&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

.gradient {
  position: relative;
  overflow: hidden;
  width: 300px;
  height: 300px;
  background-color: #555;
  border-radius: 16px;

  &amp;amp;::after {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, rgba(#dfdfdf, 0) 0, rgba(#dfdfdf, 0.2) 20%, rgba(#dfdfdf, 0.5) 60%, rgba(#dfdfdf, 0));
    animation: shimmer 5s infinite;
    content: '';
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>HTML, CSS</category>
      <category>CSS</category>
      <category>CSS 그라데이션</category>
      <category>css 움직이는 그라데이션</category>
      <category>linear-gradient</category>
      <category>skeleton ui</category>
      <category>스켈레톤</category>
      <category>스켈레톤 UI</category>
      <author>JAEEE</author>
      <guid isPermaLink="true">https://jae-study.tistory.com/102</guid>
      <comments>https://jae-study.tistory.com/102#entry102comment</comments>
      <pubDate>Thu, 26 Oct 2023 17:37:22 +0900</pubDate>
    </item>
  </channel>
</rss>