<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>방구석 코딩</title>
    <link>https://msm1307.tistory.com/</link>
    <description>HTML / CSS / Javascript 정보방</description>
    <language>ko</language>
    <pubDate>Mon, 18 May 2026 08:09:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>석미니</managingEditor>
    <item>
      <title>바이브 코딩 도전기 (with 라이브 방송 플랫폼)</title>
      <link>https://msm1307.tistory.com/204</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;나는&amp;nbsp;&lt;b&gt;프론트엔드 개발자&lt;/b&gt;이고,&amp;nbsp;&lt;b&gt;앱 개발은 처음 도전&lt;/b&gt;하는 편이다. 그런데 이걸 굴려본 건,&amp;nbsp;&lt;b&gt;바이브 코딩&lt;/b&gt;으로 시작해 보면서 &amp;ldquo;이 방식이 도대체&amp;nbsp;&lt;b&gt;어디까지 가능한지&lt;/b&gt;, 한계가 어디인지&amp;rdquo;를&amp;nbsp;&lt;b&gt;직접 확인해 보고 싶어서&lt;/b&gt;이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, 처음부터 &amp;ldquo;뭔가 거창한 서비스를 만들어야지&amp;rdquo; 이런 마음으로 시작한 건 아니었다. 누나는 일본에 출장가서 라이브로 물건을 팔고, 대행까지 이어지는&amp;nbsp;&lt;b&gt;사업&lt;/b&gt;을 돌리고 있고, 나는 그걸&amp;nbsp;&lt;b&gt;덜 지치게&lt;/b&gt;&amp;nbsp;돌아가게 만드는 쪽을 맡고 싶었다.&amp;nbsp;&lt;b&gt;출장 현장을 내가 직접 본 건 아니다.&lt;/b&gt;&amp;nbsp;누나가&amp;nbsp;&lt;b&gt;평소에 이런 식으로 일한다고 전해 준 이야기&lt;/b&gt;를 듣고, 그걸 토대로 만들기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누나가 말해 준 흐름으로만 잡아 보면 대략 이렇다.&amp;nbsp;&lt;b&gt;일본에 출장을 가서&lt;/b&gt;&amp;nbsp;현지에서 라이브 방송을 켜고, 실시간으로 물품을 소개한다. 사겠다는 사람이 나오면 그 상품에&amp;nbsp;&lt;b&gt;택을 붙여서&lt;/b&gt;&amp;nbsp;누가 뭘 샀는지&amp;nbsp;&lt;b&gt;분류&lt;/b&gt;해 두는데, 택에는&amp;nbsp;&lt;b&gt;이름&amp;middot;수량&amp;middot;단가&lt;/b&gt;를 수기로 직접 적어 둔다. 밤에는&amp;nbsp;&lt;b&gt;숙소로 돌아와서&lt;/b&gt;&amp;nbsp;택배를 싸면서, 그걸 또&amp;nbsp;&lt;b&gt;엑셀에 수기로&lt;/b&gt;&amp;nbsp;옮겨 적는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이야기를 듣고, &amp;ldquo;택 붙이고&amp;middot;분류하고&amp;middot;포장 리스트&amp;middot;엑셀&amp;rdquo;처럼&amp;nbsp;&lt;b&gt;반복되고 헷갈리기 쉬운 구간은 시스템이 대신 짚어주면&lt;/b&gt;&amp;nbsp;누나는 소개랑 현장 응대에만 더 쓸 수 있지 않을까 싶었다. 그래서 이 프로젝트는 그 흐름을&amp;nbsp;&lt;b&gt;자동화하려고&lt;/b&gt;&amp;nbsp;만든 거다. 완벽하게 사람을 없애는 게 목표는 아니고, 출장 중에 특히 시간이 없을 때 덜 미친 듯이 돌아가게 만드는 쪽에 가깝다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&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;위에 적은&amp;nbsp;&lt;b&gt;손&amp;middot;택&amp;middot;엑셀&lt;/b&gt;&amp;nbsp;중심 흐름을,&amp;nbsp;&lt;b&gt;프로젝트를 시작하기 전에&lt;/b&gt;&amp;nbsp;머릿속으로만 이렇게&amp;nbsp;&lt;b&gt;갈아타고 싶다&lt;/b&gt;고 그려 두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라이브 방송 중에&lt;/b&gt;&amp;nbsp;소개할&amp;nbsp;&lt;b&gt;상품을 카메라로 찍으면&lt;/b&gt;, AI가 그 사진을 보고&amp;nbsp;&lt;b&gt;상품명을 분석해서 자동으로 기입&lt;/b&gt;한다. 그다음&amp;nbsp;&lt;b&gt;채팅&lt;/b&gt;에서 &amp;ldquo;살게요&amp;rdquo; 같은 식으로 **구매하겠다고 한 사람(구매자)**을 골라 연결하면, 화면에&amp;nbsp;&lt;b&gt;구매 확정&lt;/b&gt;&amp;nbsp;같은 버튼이 나오고&amp;nbsp;&lt;b&gt;수량&lt;/b&gt;도 같이 보여 준다.&amp;nbsp;&lt;b&gt;확인&lt;/b&gt;을 누르면 그걸&amp;nbsp;&lt;b&gt;엑셀에 자동으로 밀어 넣고&lt;/b&gt;, 마지막으로&amp;nbsp;&lt;b&gt;내가 만든 앱에서 모바일 프린터를 제어&lt;/b&gt;해서&amp;nbsp;&lt;b&gt;구매자 이름이랑 수량&lt;/b&gt;이 찍히게 하려고 한다. (택에 손으로 적던 구간을&amp;nbsp;&lt;b&gt;프린트 출력&lt;/b&gt;으로 대신 가져가는 그림이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히&amp;nbsp;&lt;b&gt;전부 다 이미 돌아간다&lt;/b&gt;는 뜻은 아니고, &amp;ldquo;&lt;b&gt;이 순서로 움직이게 만들고 싶다&lt;/b&gt;&amp;rdquo;는 목표 쪽에 가깝다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&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;모노레포 느낌으로&amp;nbsp;&lt;b&gt;패키지별로&lt;/b&gt;&amp;nbsp;쪼개서 가져갔다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;web&amp;nbsp;(시청자 &amp;middot; React + 웹 + PWA)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;React&lt;/b&gt;,&amp;nbsp;&lt;b&gt;Vite&lt;/b&gt;,&amp;nbsp;&lt;b&gt;TypeScript&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PWA&lt;/b&gt;&amp;nbsp;(vite-plugin-pwa)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI&lt;/b&gt;: Mantine, Emotion&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라우팅&amp;middot;데이터&lt;/b&gt;: TanStack Router, TanStack Query, TanStack Virtual&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증&lt;/b&gt;: Valibot&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간&lt;/b&gt;: &lt;a href=&quot;http://Socket.IO&quot;&gt;Socket.IO&lt;/a&gt; 클라이언트(채팅 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;admin&amp;nbsp;(운영 &amp;middot; React + 웹 + PWA)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;React&lt;/b&gt;,&amp;nbsp;&lt;b&gt;Vite&lt;/b&gt;,&amp;nbsp;&lt;b&gt;TypeScript&lt;/b&gt;&amp;nbsp;(web이랑 같은 계열)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PWA&lt;/b&gt;&amp;nbsp;(vite-plugin-pwa)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI&lt;/b&gt;: Mantine, Emotion, TipTap(에디터)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라우팅&amp;middot;데이터&lt;/b&gt;: TanStack Router, TanStack Query&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증&lt;/b&gt;: Valibot&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;server&amp;nbsp;(API &amp;middot; NestJS)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;NestJS&lt;/b&gt;,&amp;nbsp;&lt;b&gt;TypeScript&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ORM&amp;middot;DB&lt;/b&gt;: Prisma, PostgreSQL(Supabase 쪽 DB)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일&amp;middot;스토리지&lt;/b&gt;: Supabase Storage&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간&lt;/b&gt;: &lt;a href=&quot;http://Socket.IO&quot;&gt;Socket.IO&lt;/a&gt;(게이트웨이)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타&lt;/b&gt;: Swagger, JWT 기반 인증, 웹 푸시, 스케줄링 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;app&amp;nbsp;(방송자 &amp;middot; Flutter)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Flutter&lt;/b&gt;&amp;nbsp;&amp;mdash; 지금은&amp;nbsp;&lt;b&gt;방송하는 사람만&lt;/b&gt;&amp;nbsp;쓰는 용도로 한정해 두었다.&amp;nbsp;&lt;b&gt;앱 개발이 처음&lt;/b&gt;이라 스토어 출시까지 한꺼번에 끌고 가기엔 빡세다고 느껴져서,&amp;nbsp;&lt;b&gt;일단 범위를 거기까지만&lt;/b&gt;&amp;nbsp;잡은 거다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;web&amp;middot;admin&amp;nbsp;배포는&amp;nbsp;&lt;b&gt;Cloudflare&lt;/b&gt;&amp;nbsp;쪽 워크플로에 맞춰&amp;nbsp;&lt;b&gt;wrangler&lt;/b&gt;를 쓰는 구성이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;React Native는 버리고 Flutter를 택한 이유, 그리고 웹은 왜 React였나&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 쪽을 고를 때&amp;nbsp;&lt;b&gt;React Native를 먼저&lt;/b&gt;&amp;nbsp;생각하는 게 당연했다. 나 프론트니까. 그런데 막상 고르려니&amp;nbsp;&lt;b&gt;성능&lt;/b&gt;이 제일 걸렸다. RN은 JS 쪽이랑 네이티브 UI를 이어 주는 구조라서, 화면이 바뀌는 게 잦거나 리스트가 길어지면&amp;nbsp;&lt;b&gt;한 박자 늦게&lt;/b&gt;&amp;nbsp;붙거나&amp;nbsp;&lt;b&gt;버벅이는 느낌&lt;/b&gt;이 나기 쉽다고 알고 있다. 나는 방송 쪽이라&amp;nbsp;&lt;b&gt;화면이 쫓아오는 속도&lt;/b&gt;가 중요해서, 그냥&amp;nbsp;&lt;b&gt;성능 때문에&lt;/b&gt;&amp;nbsp;RN 대신&amp;nbsp;&lt;b&gt;Flutter&lt;/b&gt;를 택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Flutter&lt;/b&gt;는 UI를&amp;nbsp;&lt;b&gt;직접 그리는 쪽&lt;/b&gt;이라, 내가 원한&amp;nbsp;&lt;b&gt;성능&lt;/b&gt;에 더 잘 맞는다고 판단했다. 그래서 RN은 여기서&amp;nbsp;&lt;b&gt;접고&lt;/b&gt;, 앱은&amp;nbsp;&lt;b&gt;Flutter로 간다&lt;/b&gt;&amp;nbsp;쪽으로 마음을 정했다. (지금 돌아가는 건&amp;nbsp;&lt;b&gt;방송자용&lt;/b&gt;만이지만.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼&amp;nbsp;&lt;b&gt;Flutter가 웹도 지원하는데 왜 시청자 웹은 React&lt;/b&gt;냐면, 솔직히&amp;nbsp;&lt;b&gt;나한테 웹은 React가 제일 익숙한 손&lt;/b&gt;이다. Flutter web도 가능은 한데,&amp;nbsp;&lt;b&gt;지금 당장&lt;/b&gt;&amp;nbsp;PWA까지 엮어서 빨리 쓸만하게 올리려면 Vite + React 쪽이&amp;nbsp;&lt;b&gt;패키지 생태계랑 레퍼런스&lt;/b&gt;에서 덜 막막했다. 영상&amp;middot;실시간 채팅 같은 것도&amp;nbsp;&lt;b&gt;브라우저에서 검증된 조합&lt;/b&gt;으로 가져가고 싶었고. 방송자 쪽은 Flutter로&amp;nbsp;&lt;b&gt;네이티브에 가깝게&lt;/b&gt;, 시청자 쪽은&amp;nbsp;&lt;b&gt;웹답게&lt;/b&gt;&amp;nbsp;React로 쪼개는 게 나한테는 타협이 덜 꼬이는 선택이었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&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;&lt;b&gt;백엔드 앞단&lt;/b&gt;: Traefik으로 리버스 프록시&amp;middot;라우팅을 잡았다. 서버에&amp;nbsp;&lt;b&gt;nginx를 안 붙이고&lt;/b&gt;&amp;nbsp;Traefik을 고른 이유는 단순하다.&amp;nbsp;&lt;b&gt;HTTPS 인증서 자동 발급&lt;/b&gt;이 잘 묶여 있고,&amp;nbsp;&lt;b&gt;설정을 고쳐도 매번 재시작할 필요가 없다&lt;/b&gt;는 점을 가져가고 싶었다. (라우팅만 손볼 때 덜 귀찮다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버 머신&lt;/b&gt;: GCP 위에 올려 두었고, 메모리는&amp;nbsp;&lt;b&gt;2GB RAM&lt;/b&gt;짜리 인스턴스에서 돌아가게 맞췄다. (비용이랑 현실적인 한계 사이에서 타협한 결과다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프론트 호스팅&lt;/b&gt;:&amp;nbsp;&lt;b&gt;Cloudflare&lt;/b&gt;&amp;nbsp;(Pages 느낌으로 정적 배포 + 엣지 쪽 이점)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영상&lt;/b&gt;:&amp;nbsp;&lt;b&gt;Cloudflare Stream&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&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;요즘 말로 하면 그냥 바이브 코딩이다. 스펙을 처음부터 완벽하게 박아두고 칼같이 구현한다기보다는, &amp;ldquo;여기까지는 되면 좋겠다&amp;rdquo; 정도의 감을 잡고 가면서 계속 다듬는 스타일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는&amp;nbsp;&lt;b&gt;Cursor Pro Plus&lt;/b&gt;랑&amp;nbsp;&lt;b&gt;Gemini&lt;/b&gt;를 같이 쓴다. Cursor는 에디터 안에서 코드를 빠르게 굴리고,&amp;nbsp;&lt;b&gt;Gemini는 기술적인 질문&lt;/b&gt;을 던질 때 쓴다. (아키텍처나 동작 원리, 에러 맥락 정리 같은 것들.)&amp;nbsp;&lt;b&gt;인프라 구성&lt;/b&gt;을 짤 때도 같이 썼다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이 글도 사실&amp;hellip;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 블로그 글(초안)도 결국&amp;nbsp;&lt;b&gt;AI한테 시켜서&lt;/b&gt;&amp;nbsp;쓴 거다. 내가 하고 싶은 말의 뼈대랑 팩트는 내가 정했고, 문장 다듬기랑 &amp;ldquo;사람 말투로 읽히게&amp;rdquo; 만드는 건 AI가 도왔다. 그래서 너무 매끈하면 그게 이유다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>Project/코하루 마켓</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/204</guid>
      <comments>https://msm1307.tistory.com/204#entry204comment</comments>
      <pubDate>Thu, 16 Apr 2026 02:16:34 +0900</pubDate>
    </item>
    <item>
      <title>@chakra-ui/react V3 커스텀 them 설정</title>
      <link>https://msm1307.tistory.com/191</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;src/them.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732674811992&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {
  createSystem,
  defaultConfig,
  SystemConfig,
  SystemStyleObject,
} from '@chakra-ui/react';

// container 커스텀 스타일 설정
const containerStyle: SystemStyleObject = {
  maxWidth: '100%',
  paddingInline: '0',
};

const config: SystemConfig = {
  // 전역 스타일 설정
  globalCss: {
    'html, body': {
      letterSpacing: '-0.02em',
      color: 'black',
      fontFamily: `'Pretendard Variable', Pretendard,
                  -apple-system,
                  BlinkMacSystemFont,
                  system-ui,
                  Roboto,
                  'Helvetica Neue',
                  'Segoe UI',
                  'Apple SD Gothic Neo',
                  'Noto Sans KR',
                  'Malgun Gothic',
                  'Apple Color Emoji',
                  'Segoe UI Emoji',
                  'Segoe UI Symbol',
                  sans-serif`,
    },

    '*::-webkit-scrollbar': {
      width: '5px',
      backgroundColor: 'transparent',
    },
    '*::-webkit-scrollbar-thumb': {
      backgroundColor: 'gray02',
      borderRadius: '100px',
    },
    '*::-webkit-scrollbar-track': {
      backgroundColor: 'transparent',
    },
  },

  theme: {
    // 컴포넌트 커스텀 스타일 설정
    recipes: {
      container: {
        base: containerStyle,
      },
    },
    tokens: {
      // 색상 커스텀 설정
      colors: {
        black: { value: '#1e1e1e' },
        primary: { value: '#09bb91' },
        red: { value: '#f01313' },
        blue: { value: '#0094ff' },
        gray01: {
          value: '#8c96a0',
        },
        gray02: {
          value: '#caccd6',
        },
        gray03: {
          value: '#f5f6f9',
        },
        gray04: {
          value: '#e5e6ed',
        },
        gray05: {
          value: '#e9eaf1',
        },
      },
      // 사이즈 커스텀 설정
      sizes: {
        wrap: { value: '1180px' },
        paddingWrap: { value: '1780px' },
      },
    },
  },
};

export const system = createSystem(defaultConfig, config);&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;src/components/ui/ChakraProvider.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1732674918571&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';

import { ChakraProvider as Provider } from '@chakra-ui/react';
import { ThemeProvider } from 'next-themes';
import { system } from '@/theme';

export default function ChakraProvider(props: { children: React.ReactNode }) {
  return (
    &amp;lt;Provider value={system}&amp;gt;
      &amp;lt;ThemeProvider attribute=&quot;class&quot; disableTransitionOnChange&amp;gt;
        {props.children}
      &amp;lt;/ThemeProvider&amp;gt;
    &amp;lt;/Provider&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;src/app/layout.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1732675059982&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import type { Metadata } from 'next';
import ChakraProvider from '@/components/ui/ChakraProvider';

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};

export default function RootLayout({
  children,
}: Readonly&amp;lt;{
  children: React.ReactNode;
}&amp;gt;) {
  return (
    &amp;lt;html suppressHydrationWarning&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;ChakraProvider&amp;gt;{children}&amp;lt;/ChakraProvider&amp;gt;
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&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;/p&gt;
&lt;pre id=&quot;code_1732674982302&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx @chakra-ui/cli typegen ./src/theme.ts&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프레임워크/NextJS</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/191</guid>
      <comments>https://msm1307.tistory.com/191#entry191comment</comments>
      <pubDate>Wed, 27 Nov 2024 11:38:06 +0900</pubDate>
    </item>
    <item>
      <title>nvm 설치 및 버전관리</title>
      <link>https://msm1307.tistory.com/182</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. homebrew로 nvm 설치&lt;/p&gt;
&lt;pre id=&quot;code_1724828405645&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install nvm&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;2. nvm 설정&lt;/p&gt;
&lt;pre id=&quot;code_1724828450832&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;code ~/.zshrc&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;3. 파일 끝에 아래 내용 추가 &amp;lt;- &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;사용자마다 다를 수 있음 !&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724828472908&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export NVM_DIR=&quot;/opt/homebrew/Cellar/nvm/0.40.0&quot;
[ -s &quot;/opt/homebrew/Cellar/nvm/0.40.0/nvm.sh&quot; ] &amp;amp;&amp;amp; \. &quot;/opt/homebrew/Cellar/nvm/0.40.0/nvm.sh&quot;  # This loads nvm
[ -s &quot;/opt/homebrew/Cellar/nvm/0.40.0/etc/bash_completion.d/nvm&quot; ] &amp;amp;&amp;amp; \. &quot;/opt/homebrew/Cellar/nvm/0.40.0/etc/bash_completion.d/nvm&quot;  # This loads nvm bash_completion&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;4. nvm을 이용해 노드 특정 버전 설치&lt;/p&gt;
&lt;pre id=&quot;code_1724828499323&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm install 16.18.0&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;5. 설치된 node.js 버전을 사용&lt;/p&gt;
&lt;pre id=&quot;code_1724828523044&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm use 16.18.0&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;6. 기본 버전을 설정&lt;/p&gt;
&lt;pre id=&quot;code_1724828535978&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm alias default 16.18.0&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;설치된 모든 node.js 버전 확인&lt;/p&gt;
&lt;pre id=&quot;code_1724828634933&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm ls&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;현재 사용중인 node.js 버전 확인&lt;/p&gt;
&lt;pre id=&quot;code_1724831509689&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm current&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;nvm에서 설치 가능한 버전 보기&lt;/p&gt;
&lt;pre id=&quot;code_1724831459878&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm ls-remote&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/182</guid>
      <comments>https://msm1307.tistory.com/182#entry182comment</comments>
      <pubDate>Wed, 28 Aug 2024 16:13:08 +0900</pubDate>
    </item>
    <item>
      <title>nestjs https 적용 (feat: mkcert)</title>
      <link>https://msm1307.tistory.com/179</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;mkcert란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 개발 환경에서 쉽게 신뢰할 수 있는 인증서를 생성할 수 있는 도구이다. mkcert를 사용하면 로컬에서 브라우저가 신뢰할 수 있는 인증서를 생성할 수 있다.&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;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;mkcert&amp;nbsp;설치&lt;/h3&gt;
&lt;pre id=&quot;code_1722928098827&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install mkcert
brew install nss # Firefox를 지원하기 위해 필요&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;로컬&amp;nbsp;CA&amp;nbsp;설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mkcert를 처음 사용할 때 로컬 CA(Certificate Authority)를 설치해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1722928157221&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkcert -install&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;인증서&amp;nbsp;생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 호스트를 위한 인증서를 생성&lt;/p&gt;
&lt;pre id=&quot;code_1722928196862&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkcert localhost&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;위 명령어를 입력하면 현재 경로에 `localhost-key.pem` 파일과 `localhost.pem` 파일이 설치된다.&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;nestjs https 설정&lt;/h3&gt;
&lt;pre id=&quot;code_1722928390866&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as fs from 'fs';

async function bootstrap() {
  const httpsOptions = {
    key: fs.readFileSync('./localhost-key.pem'),
    cert: fs.readFileSync('./localhost.pem'),
  };

  const app = await NestFactory.create(AppModule, {
    httpsOptions,
  });

  await app.listen(3000);
}
bootstrap();&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;</description>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/179</guid>
      <comments>https://msm1307.tistory.com/179#entry179comment</comments>
      <pubDate>Tue, 6 Aug 2024 16:13:57 +0900</pubDate>
    </item>
    <item>
      <title>OpenSSL로 인증서 발급 방법</title>
      <link>https://msm1307.tistory.com/178</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;OpenSSL 설치&lt;/h2&gt;
&lt;pre id=&quot;code_1722926179740&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install openssl&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;/h2&gt;
&lt;pre id=&quot;code_1722926227706&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;openssl req -x509 -nodes -newkey rsa:4096 -keyout ./secrets/private-key.pem -out ./secrets/public-certificate.pem -days 365&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;&lt;b&gt;x509:&lt;/b&gt; X.509&amp;nbsp;인증서&amp;nbsp;생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;nodes:&lt;/b&gt;&amp;nbsp;비밀키를&amp;nbsp;암호화하지&amp;nbsp;않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;newkey&amp;nbsp;rsa:4096:&lt;/b&gt;&amp;nbsp;4096비트&amp;nbsp;RSA&amp;nbsp;비밀키를&amp;nbsp;생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;keyout:&lt;/b&gt;&amp;nbsp;비밀키를&amp;nbsp;저장할&amp;nbsp;파일&amp;nbsp;경로&lt;/li&gt;
&lt;li&gt;&lt;b&gt;out:&lt;/b&gt;&amp;nbsp;인증서를&amp;nbsp;저장할&amp;nbsp;파일&amp;nbsp;경로&lt;/li&gt;
&lt;li&gt;&lt;b&gt;days&amp;nbsp;365:&lt;/b&gt;&amp;nbsp;인증서의&amp;nbsp;유효&amp;nbsp;기간을&amp;nbsp;365일로&amp;nbsp;설정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로컬 개발 환경에서 CSR 생성 시 입력할 정보&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Country Name (2 letter code)&lt;/b&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;예시: KR (대한민국), US (미국)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;State or Province Name (full name)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주(State)나 도(Province)의 전체 이름을 입력합니다.&lt;/li&gt;
&lt;li&gt;예시: Seoul, California&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Locality Name (e.g., city)&lt;/b&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;예시: Gangnam, San Francisco&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Organization Name (e.g., company)&lt;/b&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;예시: MyLocalDev&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Organizational Unit Name (e.g., section)&lt;/b&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;예시: Development Team 또는 생략 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Common Name (e.g., server FQDN or YOUR name)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 환경에서는 도메인 이름이 없으므로, 로컬 IP 주소나 로컬 서버의 호스트 이름을 입력합니다. 예를 들어, 로컬 서버가 localhost로 설정되어 있다면 localhost를 입력할 수 있습니다.&lt;/li&gt;
&lt;li&gt;예시: localhost, 127.0.0.1, my-local-server&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Email Address&lt;/b&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;예시: admin@localhost&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/178</guid>
      <comments>https://msm1307.tistory.com/178#entry178comment</comments>
      <pubDate>Tue, 6 Aug 2024 15:42:27 +0900</pubDate>
    </item>
    <item>
      <title>[postgreSQL] 명령어 모음</title>
      <link>https://msm1307.tistory.com/177</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터베이스 접속&lt;/p&gt;
&lt;pre id=&quot;code_1722671591449&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;psql postgres&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;2. 유저 생성&lt;/p&gt;
&lt;pre id=&quot;code_1722671557281&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE USER admin WITH LOGIN PASSWORD '1234';&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;admin이라는 사용자 아이디를 갖고, 비밀번호는 1234인 새 유저를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 유저 확인&lt;/p&gt;
&lt;pre id=&quot;code_1722674244790&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;\du&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;4. 권한 부여&lt;/p&gt;
&lt;pre id=&quot;code_1722674368324&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# admin에게 슈퍼유저 부여
ALTER ROLE admin SUPERUSER;
 
# admin에게 DB 생성 권한 부여
ALTER ROLE admin CREATEDB;
 
# admin에게 권한 생성 부여
ALTER ROLE admin CREATEROLE;&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;5. 데이터베이스 생성&lt;/p&gt;
&lt;pre id=&quot;code_1722674620571&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 소유자가 admin이고 인코딩은 UTF-8이며 연결제한이 없는 'koharu' 라는 데이터베이스 생성
CREATE DATABASE koharu
    WITH
    OWNER = admin
    ENCODING = 'UTF8'
    CONNECTION LIMIT = -1;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>database/PostgreSQL</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/177</guid>
      <comments>https://msm1307.tistory.com/177#entry177comment</comments>
      <pubDate>Sat, 3 Aug 2024 17:34:06 +0900</pubDate>
    </item>
    <item>
      <title>homebrew postgreSQL 설치 방법</title>
      <link>https://msm1307.tistory.com/176</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 설치&lt;/p&gt;
&lt;pre id=&quot;code_1722671229681&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install postgresql&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;2. 서비스 실행&lt;/p&gt;
&lt;pre id=&quot;code_1722671247226&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew services start postgresql&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;3. 접속&lt;/p&gt;
&lt;pre id=&quot;code_1722671425007&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;psql postgres&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;4. 삭제&lt;/p&gt;
&lt;pre id=&quot;code_1722673545825&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# PostgreSQL 서비스 중지
brew services stop postgresql@14

# PostgreSQL 14와 관련된 모든 데이터를 삭제
rm -rf /opt/homebrew/var/postgresql@14
rm -rf /usr/local/var/postgresql

# PostgreSQL 삭제
brew uninstall --force postgresql&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Homebrew</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/176</guid>
      <comments>https://msm1307.tistory.com/176#entry176comment</comments>
      <pubDate>Sat, 3 Aug 2024 16:50:53 +0900</pubDate>
    </item>
    <item>
      <title>prettier 설정</title>
      <link>https://msm1307.tistory.com/175</link>
      <description>&lt;pre id=&quot;code_1722493991155&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;shift + cmd + p // 명령 팔렛트 열기

open user settings 명령어 입력 -&amp;gt; 실행&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722478746008&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;terminal.integrated.fontFamily&quot;: &quot;MesloLGS NF&quot;,
  &quot;workbench.colorTheme&quot;: &quot;Material Theme High Contrast&quot;,
  &quot;workbench.iconTheme&quot;: &quot;material-icon-theme&quot;,
  &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;, // 포맷터를 prettier로 설정
  &quot;[javascript]&quot;: {
    &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;
  },
  &quot;svelte.enable-ts-plugin&quot;: true,
  &quot;editor.formatOnPaste&quot;: true, // 붙여넣기시 자동 포맷팅
  &quot;editor.formatOnSave&quot;: true, // 저장시 자동 포맷팅
  &quot;prettier.tabWidth&quot;: 2, // 탭 너비
  &quot;prettier.singleQuote&quot;: true, // single 쿼테이션 사용 여부
  &quot;prettier.printWidth&quot;: 80, // 줄 바꿈 할 폭 길이
  &quot;prettier.useTabs&quot;: false, // 탭 사용 여부
  &quot;prettier.semi&quot;: true, // 세미콜론 사용 여부
  &quot;[prisma]&quot;: {
    &quot;editor.defaultFormatter&quot;: &quot;Prisma.prisma&quot; // prisma 포맷터 설정
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/175</guid>
      <comments>https://msm1307.tistory.com/175#entry175comment</comments>
      <pubDate>Thu, 1 Aug 2024 11:21:54 +0900</pubDate>
    </item>
    <item>
      <title>원시 값과 객체의 비교</title>
      <link>https://msm1307.tistory.com/171</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;원시 값&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원시 타입(숫자 타입, 문자열 타입, 불리언 타입, undefined 타입, null 타입, 심벌 타입)의 값, 즉 &lt;b&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;&quot;원시 값은 변경 불가능하다&quot;는 말은 &lt;u&gt;원시 값 자체를 변경할 수 없다는 것이지 변수 값을 변경할 수 없다는 것이 아니다.&lt;/u&gt; 변수는 언제든지 재할당을 통해 변수 값을 변경(교체)할 수 있다. 단 상수는 단 한 번만 할당이 허용되므로 변수 값을 변경(교체)할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719935800311&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// const 키워드를 사용해 선언한 변수는 재할당이 금지된다.
const name = &quot;Kim&quot;;
s = &quot;Jung&quot;; // TypeError: Assignment to constant variable.

// 하지만 const 키워드를 사용해 선언한 변수에 할당한 객체는 변경할 수 있다.
const o = {};
o.a = 1;
console.log(o);  // {a: 1}&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-07-03 오전 1.16.24.png&quot; data-origin-width=&quot;2540&quot; data-origin-height=&quot;984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nwjfw/btsImfzpR12/Shkx9NUYW8WMiWfEf4tQy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nwjfw/btsImfzpR12/Shkx9NUYW8WMiWfEf4tQy0/img.png&quot; data-alt=&quot;원시 값은 변경 불가능한 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nwjfw/btsImfzpR12/Shkx9NUYW8WMiWfEf4tQy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnwjfw%2FbtsImfzpR12%2FShkx9NUYW8WMiWfEf4tQy0%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;2540&quot; height=&quot;984&quot; data-filename=&quot;스크린샷 2024-07-03 오전 1.16.24.png&quot; data-origin-width=&quot;2540&quot; data-origin-height=&quot;984&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원시 값은 변경 불가능한 값&lt;/figcaption&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;u&gt;원시 값을 재할당하면 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가리킨다&lt;/u&gt;. 이때 변수가 참조하던 메모리 공간의 주소가 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값의 이러한 특성을 &lt;b&gt;불변성&lt;/b&gt;이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없다.&lt;/b&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;유사 배열 객체란 마치 배열처럼 인덱스로 프로퍼티 값에 접근할 수 있고 length 프로퍼티를 갖는 객체를 말한다. 문자열은 마치 배열처럼 인덱스를 통해 각 문자에 접근할 수 있으며, length 프로퍼티를 갖기 때문에 유사 배열 객체이고 for 문으로 순회할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719935808207&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var str = 'string';

// 문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 각 문자에 접근할 수 있다.
console.log(str[0]);  // s

// 원시 값인 문자열이 객체처럼 동작한다.
console.log(str.length);  // 6
console.log(str.toUpperCase());  // STRING

// 문자열은 원시 값이므로 변경할 수 없다. 이때 에러가 발생하지 않는다.
str[0] = &quot;S&quot;;

console.log(str);  // string&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;/h3&gt;
&lt;pre id=&quot;code_1719844534048&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score = 80;

// copy 변수에는 score 변수의 값 80이 복사되어 할당된다.
var copy = score;

console.log(score, copy);  // 80 80
console.log(score === copy);  // true&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;변수에 원시 값을 갖는 변수를 할당하면 할당받은 변수(copy)에는 할당되는 변수(score)의 &lt;b&gt;원시 값&lt;/b&gt;이 복사되어 전달된다. 이를 &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;값에 의한 전달.png&quot; data-origin-width=&quot;1365&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wLQ8a/btsIjx96HoO/WxfqyyPLHNpMR0xmPk4wkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wLQ8a/btsIjx96HoO/WxfqyyPLHNpMR0xmPk4wkK/img.png&quot; data-alt=&quot;값에 의한 전달&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wLQ8a/btsIjx96HoO/WxfqyyPLHNpMR0xmPk4wkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwLQ8a%2FbtsIjx96HoO%2FWxfqyyPLHNpMR0xmPk4wkK%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;1365&quot; height=&quot;654&quot; data-filename=&quot;값에 의한 전달.png&quot; data-origin-width=&quot;1365&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;값에 의한 전달&lt;/figcaption&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_1720356590580&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score = 80;

// copy 변수에는 score 변수의 값 80이 복사되어 할당된다.
var copy = score;

console.log(score, copy);  // 80 80
console.log(score === copy);  // true

// score 변수와 copy 변수의 값은 다른 메모리 공간에 저장된 별개의 값이다.
// 따라서 score 변수의 값을 변경해도 copy 변수의 값에는 영향을 주지 않는다.
score = 100;

console.log(score, copy);  // 100 80
console.log(score === copy);  // false&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image1.png&quot; data-origin-width=&quot;1453&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct5lEA/btsIpUDyFS3/12sDSjE0mRCgPmMV5esoQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct5lEA/btsIpUDyFS3/12sDSjE0mRCgPmMV5esoQK/img.png&quot; data-alt=&quot;값에 의해 전달된 값은 다른 메모리 공간에 저장된 별개의 값이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct5lEA/btsIpUDyFS3/12sDSjE0mRCgPmMV5esoQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct5lEA%2FbtsIpUDyFS3%2F12sDSjE0mRCgPmMV5esoQK%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;1453&quot; height=&quot;506&quot; data-filename=&quot;image1.png&quot; data-origin-width=&quot;1453&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;값에 의해 전달된 값은 다른 메모리 공간에 저장된 별개의 값이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;&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;&lt;b&gt;객체(참조) 타입의 값, 즉 객체는 변경 가능한 값&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1720356806842&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성된다.
var person = {
  name: 'Lee'
};

// person 변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다.
console.log(person);  // {name: &quot;Lee&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2024-04-08-1557.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceFfUD/btsIAys0I9v/E8QOdh8hjKdphbUBBoKAh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceFfUD/btsIAys0I9v/E8QOdh8hjKdphbUBBoKAh1/img.png&quot; data-alt=&quot;객체의 할당&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceFfUD/btsIAys0I9v/E8QOdh8hjKdphbUBBoKAh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceFfUD%2FbtsIAys0I9v%2FE8QOdh8hjKdphbUBBoKAh1%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;528&quot; data-filename=&quot;제목 없음-2024-04-08-1557.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체의 할당&lt;/figcaption&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;b&gt;참조 값&lt;/b&gt;을 통해 실제 객체에 접근한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721044962425&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;var person = {
  name: 'Lee'
};

// 프로퍼티 값 갱신
person.name = 'Kim';

// 프로퍼티 동적 생성
person.address = 'Seoul';

console.log(person);  // {name: &quot;Kim&quot;, address: &quot;Seoul&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2024-04-08-1558.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KFyWr/btsIBakUmpF/1eME8fsTsYwltqCOGqM6A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KFyWr/btsIBakUmpF/1eME8fsTsYwltqCOGqM6A0/img.png&quot; data-alt=&quot;객체 값 변경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KFyWr/btsIBakUmpF/1eME8fsTsYwltqCOGqM6A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKFyWr%2FbtsIBakUmpF%2F1eME8fsTsYwltqCOGqM6A0%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;731&quot; height=&quot;560&quot; data-filename=&quot;제목 없음-2024-04-08-1558.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체 값 변경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;객체를 생성하고 관리하는 방식은 매우 복잡하며 비용이 많이 드는 일이다. 객체를 변경할 때마다 원시 값처럼 이전 값을 복사해서 새롭게 생성한다면 명확하고 신뢰성이 확보되겠지만 객체는 크기가 매우 클 수도 있고, 원시 값처럼 크기가 일정하지도 않으며, 프로퍼티 값이 객체일 수도 있어서 복사해서 생성하는 비용이 많이 든다. 다시 말해, 메모리의 효울적 소비가 어렵고 성능이 나빠진다.&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;h3 data-ke-size=&quot;size23&quot;&gt;참조에 의한 전달&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 식별자가 하나의 객체를 공유할 수 있다는 것이 무엇인지 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1721046573839&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var pserson = {
  name: 'Lee'
};

// 참조 값을 복사(얕은 복사)
var copy = person;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2024-04-08-1559.png&quot; data-origin-width=&quot;1627&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P1fOO/btsIyKBlsAE/vt4UTqDBRKI2bmnBq8HK90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P1fOO/btsIyKBlsAE/vt4UTqDBRKI2bmnBq8HK90/img.png&quot; data-alt=&quot;참조에 의한 전달&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P1fOO/btsIyKBlsAE/vt4UTqDBRKI2bmnBq8HK90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP1fOO%2FbtsIyKBlsAE%2Fvt4UTqDBRKI2bmnBq8HK90%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;1627&quot; height=&quot;615&quot; data-filename=&quot;제목 없음-2024-04-08-1559.png&quot; data-origin-width=&quot;1627&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참조에 의한 전달&lt;/figcaption&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;객체를 가리키는 변수(원본, person)를 다른 변수(사본, copy)에 할당하면 원본의 &lt;b&gt;참조 값이 복사되어 전달&lt;/b&gt;된다. 이를 &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;위 그림처럼 원본 person을 사본 copy에 할당하면 원본 person의 참조 값을 복사해서 copy에 저장한다. 이때 &lt;u&gt;원본 person과 사본 copy는 저장된 메모리 주소는 다르지만 동일한 참조 값을 갖는다.&lt;/u&gt; 즉, 원본 person과 사본 copy 모두 동일한 객체를 가리킨다. 이것은 &lt;b&gt;두 개의 식별자가 하나의 객체를 공유&lt;/b&gt;한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;따라서 원본 또는 사본 중 어느 한쪽에서 객체를 변경하면 서로 영향을 주고받는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721047630562&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var person = {
  name: 'Lee',
};

// 참조 값을 복사(얕은 복사). copy와 person은 동일한 참조 값을 갖는다.
var copy = person;

// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person);  // true

// copy를 통해 객체를 변경한다.
copy.name = 'Kim';

// person를 통해 객체를 변경한다.
person.address = 'Seoul';

// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고받는다.
console.log(person);  // { name: 'Kim', address: 'Seoul' }
console.log(copy);  // { name: 'Kim', address: 'Seoul' }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/171</guid>
      <comments>https://msm1307.tistory.com/171#entry171comment</comments>
      <pubDate>Mon, 1 Jul 2024 23:11:25 +0900</pubDate>
    </item>
    <item>
      <title>객체 리터럴</title>
      <link>https://msm1307.tistory.com/170</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체 리터럴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript 객체 리터럴은 객체를 생성하는 간단하고 직관적인 방법이다. 객체 리터럴을 사용하면 &lt;u&gt;중괄호 {}를 사용하여 객체를 생성하고, 객체의 속성(key)과 값(value)을 콜론 ' : '을 통해 정의&lt;/u&gt;할 수 있다. 이&amp;nbsp;방법은&amp;nbsp;코드가&amp;nbsp;간결해지고&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;h3 data-ke-size=&quot;size23&quot;&gt;객체 리터럴에 의한 객체 생성&lt;/h3&gt;
&lt;pre id=&quot;code_1719336690663&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  // 프로퍼티 키 : 프로퍼티 값
  name: &quot;Alice&quot;,
  age: 25,
  city: &quot;Wonderland&quot;,
  greet: function() {
    console.log(&quot;Hello, my name is &quot; + this.name);
  }
};

console.log(person);  // {name: 'Alice', age: 25, city: 'Wonderland', greet: &amp;fnof;}&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;span style=&quot;color: #ee2323;&quot;&gt;식별자 네이밍 규칙을 따르지 않는 이름에는 반드시 따옴표를 사용&lt;/span&gt;해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719337168693&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  firstName: 'Ung-mo',  // 식별자 네이밍 규칙을 준수하는 프로퍼티 키
  'last-name': 'Lee'    // 식별자 네이밍 규칙을 준수하지 않는 프로퍼티 키
}

console.log(person);  // {firstName: 'Ung-mo', last-name: 'Lee'}&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;/h4&gt;
&lt;pre id=&quot;code_1719337685945&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let obj = {};
let key = 'hello';

// 프로퍼티 키 동적 생성
obj[key] = 'world';
obj['name'] = 'jim';
obj.city = 'seoul';

console.log(obj);  // {hello: 'world', name: 'jim', city: 'seoul'}&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;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;마침표 표기법&lt;/h4&gt;
&lt;pre id=&quot;code_1719337996690&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  name: &quot;Alice&quot;,
  age: 25,
  city: &quot;Wonderland&quot;
};

console.log(person.name); // &quot;Alice&quot;
console.log(person.age);  // 25
console.log(person.city); // &quot;Wonderland&quot;&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대괄호 프로퍼티 접근 연산자 내부에 지정하는 프로퍼티 키는 반드시 &lt;b&gt;따옴표로 감싼 문자열&lt;/b&gt;이어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719338054920&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  name: &quot;Alice&quot;,
  age: 25,
  city: &quot;Wonderland&quot;
};

console.log(person[&quot;name&quot;]); // &quot;Alice&quot;
console.log(person[&quot;age&quot;]);  // 25
console.log(person[&quot;city&quot;]); // &quot;Wonderland&quot;&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;/h3&gt;
&lt;pre id=&quot;code_1719338308840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  name: 'Lee'
};

// person 객체에 name 프로퍼티가 존재하므로 name 프로퍼티의 값이 갱신
person.name = 'Kim';

console.log(person);  // {name: 'Kim'}

person[&quot;name&quot;] = 'Moon';

console.log(person);  // {name: 'Moon'};&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;/h3&gt;
&lt;pre id=&quot;code_1719338532964&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  name: &quot;Alice&quot;,
  age: 25,
  city: &quot;Wonderland&quot;
};

// delete 연산자로 city 프로퍼티를 삭제할 수 있다.
delete person.city;

console.log(person);  // {name: 'Alice', age: 25}&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;ES6에서 추가된 객체 리터럴의 확장 기능&lt;/h3&gt;
&lt;pre id=&quot;code_1719338763893&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let name = &quot;Alice&quot;;
let age = 30;

let person = {
  name, // 속성 이름이 변수명과 동일하여 생략 가능
  age,  // 속성 이름이 변수명과 동일하여 생략 가능
  greet() { // 메서드 축약 function 키워드 생략
    console.log(&quot;Hello!&quot;);
  }
};

console.log(person.name); // &quot;Alice&quot;
person.greet(); // &quot;Hello!&quot;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/170</guid>
      <comments>https://msm1307.tistory.com/170#entry170comment</comments>
      <pubDate>Wed, 26 Jun 2024 02:51:08 +0900</pubDate>
    </item>
    <item>
      <title>타입 변환과 단축 평가</title>
      <link>https://msm1307.tistory.com/169</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;명시적 타입 변환&lt;/b&gt; 또는 &lt;b&gt;타입 캐스팅&lt;/b&gt;&amp;nbsp;
&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;/li&gt;
&lt;li&gt;&lt;b&gt;암묵적 타입 변환&lt;/b&gt; 또는 &lt;b&gt;타입 강제 변환&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;개발자의 의도와는 상관없이 JavaScript 엔진에 의해 자동으로 타입을 변환하는 것&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적&amp;nbsp;타입&amp;nbsp;변환은&amp;nbsp;개발자가&amp;nbsp;의도적으로&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;h4 data-ke-size=&quot;size20&quot;&gt;문자열 변환&lt;/h4&gt;
&lt;pre id=&quot;code_1719328014245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let num = 123;

// 방법 1
let str1 = String(num);  // &quot;123&quot;

// 방법 2
let str2 = num.toString();  // &quot;123&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;String() 함수와 toString() 메서드의 차이점&lt;/blockquote&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;String() 함수&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;&lt;u&gt;undefined&lt;/u&gt;와&amp;nbsp;&lt;u&gt;null&lt;/u&gt;을 포함하여 모든 타입을 문자열로 변환할 수 있다.&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;toString() 메서드&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;&lt;u&gt;undefined&lt;/u&gt;나&amp;nbsp;&lt;u&gt;null&lt;/u&gt;&amp;nbsp;값에&amp;nbsp;대해서는&amp;nbsp;toString()&amp;nbsp;메서드를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1719328429316&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// String() 함수 사용
console.log(String(123));      // &quot;123&quot;
console.log(String(true));     // &quot;true&quot;
console.log(String(null));     // &quot;null&quot;
console.log(String(undefined)); // &quot;undefined&quot;

// toString() 메서드 사용
console.log((123).toString()); // &quot;123&quot;
console.log(true.toString());  // &quot;true&quot;
console.log(null.toString());  // TypeError: Cannot read property 'toString' of null
console.log(undefined.toString());  // TypeError: Cannot read property 'toString' of undefined&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;/h4&gt;
&lt;pre id=&quot;code_1719329293915&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let str = &quot;123&quot;;

// 방법 1
let num1 = Number(str);  // 123

// 방법 2 (정수만)
// parseInt 두번째 인자는 option
// 진수를 나타내는 2부터 36까지의 정수 - default 10 진수
let num2 = parseInt(str);  // 123
num2 = parseInt(str, 2); // 1

// 방법 3 (정수, 실수)
let num3 = parseFloat(str);  // 123&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;/h4&gt;
&lt;pre id=&quot;code_1719330065321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 방법 1
console.log(Boolean('x'));  // true
console.log(Boolean(''));  // false
console.log(Boolean('false'));  // true
console.log(Boolean(0));  // false
console.log(Boolean(1));  // true
// 빈 배열이나 빈 객체는 true로 인식 - 실수 많이함
console.log(Boolean({}));  // true
console.log(Boolean([])));  // true

// 방법2
console.log(!!'x');  // true
console.log(!!'');  // false
console.log(!!'false');  // true
console.log(!!0);  // false
console.log(!!1);  // true
console.log(!!{});  // true
console.log(!![]);  // true&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암묵적&amp;nbsp;타입&amp;nbsp;변환은&amp;nbsp;개발자의&amp;nbsp;의도와는&amp;nbsp;상관없이&amp;nbsp;JavaScript&amp;nbsp;엔진에&amp;nbsp;의해&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;h4 data-ke-size=&quot;size20&quot;&gt;문자열 변환&lt;/h4&gt;
&lt;pre id=&quot;code_1719330694891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let num = 123;
let str = num + &quot;&quot;;  // &quot;123&quot;&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;/h4&gt;
&lt;pre id=&quot;code_1719330947210&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let str = &quot;456&quot;;
let num1 = str * 1;  // 456
let num2 = str / 1;  // 456
let num3 = str - 1;  // 455

// + 를 제외한 산술 연산자는 숫자 타입으로 변환&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;/h4&gt;
&lt;pre id=&quot;code_1719331216847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if ('')     console.log('1');
if (true)   console.log('2');
if (0)      console.log('3');
if ('str')  console.log('4');
if (null)   console.log('5');
if ({})     console.log('6');
if ([])     console.log('7');

// 2 4 6 7&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;불리언 타입이 아닌 값을 Truthy 값(참으로 평가되는 값) 또는 Falsy 값(거짓으로 평가되는 값)&lt;/b&gt;으로 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 제어문의 조건식과 같이 불리언 값으로 평가되어야 할 문맥에서 Truthy 값은 true로, Falsy 값은 false로 암묵적 타입 변환된다.&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;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;논리 연산자를 사용한 단축 평가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 연산자 &quot;&amp;amp;&amp;amp;(AND) 또는 ||(OR)&quot;를 사용할 때 특정 조건이 만족되면 더 이상 나머지 조건을 평가하지 않는 것을 의미한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;OR 연산자 ('||')&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OR 연산자는 첫 번째 피연산자가 Truthy이면 그 값을 반환하고, 그렇지 않으면 두 번째 피연산자를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719331908184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let a = false || &quot;hello&quot;;
console.log(a); // &quot;hello&quot; (첫 번째 피연산자가 Falsy이므로 두 번째 피연산자가 반환됨)

let b = &quot;world&quot; || &quot;hello&quot;;
console.log(b); // &quot;world&quot; (첫 번째 피연산자가 Truthy이므로 그 값이 반환됨)

// 활용
function greet(name) {
  name = name || &quot;Guest&quot;;
  console.log(&quot;Hello, &quot; + name);
}

greet(&quot;Alice&quot;); // &quot;Hello, Alice&quot;
greet();        // &quot;Hello, Guest&quot; (name이 undefined이므로 기본값 사용)&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;AND 연산자 ('&amp;amp;&amp;amp;')&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND 연산자는 첫 번째 피연산자가 Falsy이면 그 값을 반환하고, 그렇지 않으면 두 번째 피연산자를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719332071764&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let a = true &amp;amp;&amp;amp; &quot;hello&quot;;
console.log(a); // &quot;hello&quot; (첫 번째 피연산자가 Truthy이므로 두 번째 피연산자가 반환됨)

let b = false &amp;amp;&amp;amp; &quot;world&quot;;
console.log(b); // false (첫 번째 피연산자가 Falsy이므로 그 값이 반환됨)

// 활용 1
let user = { name: &quot;Alice&quot;, age: 25 };

user &amp;amp;&amp;amp; console.log(user.name); // &quot;Alice&quot; (user가 Truthy이므로 이름 출력)

let nullUser = null;

nullUser &amp;amp;&amp;amp; console.log(nullUser.name); // 실행되지 않음 (nullUser가 Falsy이므로 평가 중단)

// 활용 2
let execute = true;

execute &amp;amp;&amp;amp; someFunction(); // execute가 true일 때만 someFunction() 호출

function someFunction() {
  console.log(&quot;Function executed!&quot;);
}&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단축&amp;nbsp;평가를&amp;nbsp;사용할&amp;nbsp;때는&amp;nbsp;예상치&amp;nbsp;못한&amp;nbsp;부작용을&amp;nbsp;방지하기&amp;nbsp;위해&amp;nbsp;조건문에서&amp;nbsp;Truthy와&amp;nbsp;Falsy&amp;nbsp;값을&amp;nbsp;명확히&amp;nbsp;이해하고&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;중요하다.&lt;br /&gt;예를&amp;nbsp;들어,&amp;nbsp;&lt;u&gt;값이&amp;nbsp;0이나&amp;nbsp;빈&amp;nbsp;문자열(&quot;&quot;)인&amp;nbsp;경우에도&amp;nbsp;Falsy로&amp;nbsp;평가될&amp;nbsp;수&amp;nbsp;있으므로&lt;/u&gt;,&amp;nbsp;상황에&amp;nbsp;따라서는&amp;nbsp;이러한&amp;nbsp;값들을&amp;nbsp;별도로&amp;nbsp;처리해야&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719332250232&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let count = 0;

let result = count || 10;
console.log(result); // 10 (count가 0이므로 Falsy로 평가됨)&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵셔널&amp;nbsp;체이닝&amp;nbsp;연산자(?.)는&amp;nbsp;ES11(ECMAScript2020)에서&amp;nbsp;도입된&amp;nbsp;문법으로,&amp;nbsp;객체의&amp;nbsp;속성에&amp;nbsp;접근할&amp;nbsp;때&amp;nbsp;&lt;u&gt;좌항의&amp;nbsp;피연산자가&amp;nbsp;null&amp;nbsp;또는&amp;nbsp;undefined인&amp;nbsp;경우&amp;nbsp;오류를&amp;nbsp;발생시키지&amp;nbsp;않고&amp;nbsp;undefined를&amp;nbsp;반환하고,&amp;nbsp;그렇지&amp;nbsp;않으면&amp;nbsp;우항의&amp;nbsp;프로퍼티&amp;nbsp;참조를&amp;nbsp;이어간다.&lt;/u&gt;&lt;br /&gt;이를 통해 코드가 더 간결하고 안전하게 작성될 수 있다. 특히 깊이 중첩된 객체 구조를 다룰 때 유용하다. (ts에서 매우 유용)&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;/h4&gt;
&lt;pre id=&quot;code_1719332938093&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = {
  name: &quot;Alice&quot;,
  address: {
    city: &quot;Wonderland&quot;,
  }
};

let city = user?.address?.city;
console.log(city); // &quot;Wonderland&quot;

let street = user?.address?.street;
console.log(street); // undefined (address 객체에는 street 속성이 없음)&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;/h4&gt;
&lt;pre id=&quot;code_1719332962114&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let users = [
  { name: &quot;Alice&quot; },
  { name: &quot;Bob&quot; }
];

console.log(users?.[0]?.name); // &quot;Alice&quot;
console.log(users?.[2]?.name); // undefined (세 번째 요소가 없음)&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;null 병합 연산자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null&amp;nbsp;병합&amp;nbsp;연산자(??)는&amp;nbsp;ES11(ECMAScript2020)에서&amp;nbsp;도입된&amp;nbsp;문법으로,&amp;nbsp;&lt;u&gt;좌측&amp;nbsp;피연산자가&amp;nbsp;null&amp;nbsp;또는&amp;nbsp;undefined일&amp;nbsp;때만&amp;nbsp;우측&amp;nbsp;피연산자를&amp;nbsp;반환&lt;/u&gt;한다.&lt;br /&gt;이를&amp;nbsp;통해&amp;nbsp;기본값을&amp;nbsp;설정하거나&amp;nbsp;null&amp;nbsp;또는&amp;nbsp;undefined&amp;nbsp;값을&amp;nbsp;처리할&amp;nbsp;때&amp;nbsp;더&amp;nbsp;명확하고&amp;nbsp;간결한&amp;nbsp;코드를&amp;nbsp;작성할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719333310046&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = {
  name: &quot;Alice&quot;,
  age: 0
};

let name = user.name ?? &quot;Guest&quot;;
console.log(name); // &quot;Alice&quot; (name 속성이 존재하므로 &quot;Alice&quot; 반환)

let age = user.age ?? 18;
console.log(age); // 0 (age 속성이 0이므로 0 반환)

let city = user.city ?? &quot;Unknown&quot;;
console.log(city); // &quot;Unknown&quot; (city 속성이 없으므로 &quot;Unknown&quot; 반환)&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;null&amp;nbsp;병합&amp;nbsp;연산자&amp;nbsp;vs.&amp;nbsp;논리&amp;nbsp;OR&amp;nbsp;연산자&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리&amp;nbsp;OR&amp;nbsp;연산자(||)와&amp;nbsp;null&amp;nbsp;병합&amp;nbsp;연산자(??)의&amp;nbsp;주요&amp;nbsp;차이점은&amp;nbsp;논리&amp;nbsp;&lt;u&gt;&lt;b&gt;OR&amp;nbsp;연산자&lt;/b&gt;는&amp;nbsp;Falsy&amp;nbsp;값&amp;nbsp;(0,&amp;nbsp;NaN,&amp;nbsp;&quot;&quot;,&amp;nbsp;false,&amp;nbsp;null,&amp;nbsp;undefined)을&amp;nbsp;모두&amp;nbsp;고려&lt;/u&gt;하는&amp;nbsp;반면,&amp;nbsp;&lt;u&gt;&lt;b&gt;null&amp;nbsp;병합&amp;nbsp;연산자&lt;/b&gt;는&amp;nbsp;null과&amp;nbsp;undefined만&amp;nbsp;고려&lt;/u&gt;한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719333426628&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let value = 0;

let resultOr = value || 10;
console.log(resultOr); // 10 (0은 Falsy 값이므로 10 반환)

let resultNullish = value ?? 10;
console.log(resultNullish); // 0 (0은 null 또는 undefined가 아니므로 0 반환)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/169</guid>
      <comments>https://msm1307.tistory.com/169#entry169comment</comments>
      <pubDate>Wed, 26 Jun 2024 00:06:57 +0900</pubDate>
    </item>
    <item>
      <title>sveltekit에서 https 사용</title>
      <link>https://msm1307.tistory.com/166</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리 설치&lt;/p&gt;
&lt;pre id=&quot;code_1714574596466&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i vite-plugin-mkcert -D&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;span style=&quot;background-color: #ffffff; color: #0c0d0e; text-align: left;&quot;&gt;vite.config.js에서 아래 코드로 수정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714574668166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	server: { proxy: {} },
	plugins: [sveltekit(), mkcert()]
});&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_1714574706158&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프레임워크/Svelte</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/166</guid>
      <comments>https://msm1307.tistory.com/166#entry166comment</comments>
      <pubDate>Wed, 1 May 2024 23:41:43 +0900</pubDate>
    </item>
    <item>
      <title>구글 앱 비밀번호 발급 방법</title>
      <link>https://msm1307.tistory.com/164</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;구글&amp;nbsp;앱&amp;nbsp;비밀번호&amp;nbsp;발급&amp;nbsp;방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 구글 홈에서 계정 관리 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-30 오전 11.54.54.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kJzWD/btsG2XVqXd0/WuoTjH4lI1DEGL0MGIUfm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kJzWD/btsG2XVqXd0/WuoTjH4lI1DEGL0MGIUfm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kJzWD/btsG2XVqXd0/WuoTjH4lI1DEGL0MGIUfm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkJzWD%2FbtsG2XVqXd0%2FWuoTjH4lI1DEGL0MGIUfm0%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;1920&quot; height=&quot;936&quot; data-filename=&quot;스크린샷 2024-04-30 오전 11.54.54.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;936&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;2. 상단 검색창에서 &quot;앱 비밀번호&quot; 입력 후 엔터 또는 아래 &quot;앱 비밀번호&quot; 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-30 오전 11.58.09.png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EpEFN/btsG3gtOaj7/MFp8kJiQcL6xQFK8zaFlT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EpEFN/btsG3gtOaj7/MFp8kJiQcL6xQFK8zaFlT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EpEFN/btsG3gtOaj7/MFp8kJiQcL6xQFK8zaFlT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEpEFN%2FbtsG3gtOaj7%2FMFp8kJiQcL6xQFK8zaFlT0%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;483&quot; data-filename=&quot;스크린샷 2024-04-30 오전 11.58.09.png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;483&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;3. 앱 이름 입력 후 만들기 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-30 오후 12.00.29.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;669&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmy97v/btsG3fn6VMV/Z4JqbmhiteWhnzNAPHUKwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmy97v/btsG3fn6VMV/Z4JqbmhiteWhnzNAPHUKwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmy97v/btsG3fn6VMV/Z4JqbmhiteWhnzNAPHUKwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmy97v%2FbtsG3fn6VMV%2FZ4JqbmhiteWhnzNAPHUKwK%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;1920&quot; height=&quot;669&quot; data-filename=&quot;스크린샷 2024-04-30 오후 12.00.29.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;669&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;4. 비밀번호 복사 후 사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-04-30 오후 12.02.17.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;835&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezAMsq/btsG4jXCeea/UKOing6KPmkaq4q0kou1bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezAMsq/btsG4jXCeea/UKOing6KPmkaq4q0kou1bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezAMsq/btsG4jXCeea/UKOing6KPmkaq4q0kou1bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezAMsq%2FbtsG4jXCeea%2FUKOing6KPmkaq4q0kou1bk%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;1066&quot; height=&quot;835&quot; data-filename=&quot;스크린샷 2024-04-30 오후 12.02.17.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;835&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/164</guid>
      <comments>https://msm1307.tistory.com/164#entry164comment</comments>
      <pubDate>Tue, 30 Apr 2024 12:04:48 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript Class</title>
      <link>https://msm1307.tistory.com/161</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;용어 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인스턴스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스를&amp;nbsp;통해&amp;nbsp;만들어진&amp;nbsp;객체&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1712066225343&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 자동차 클래스 정의
class Car {
  constructor(make, model) {
    this.make = make;
    this.model = model;
  }

  drive() {
    console.log(&quot;The car is driving.&quot;);
  }
}

// Car 클래스를 사용하여 인스턴스 생성
const myCar = new Car(&quot;Toyota&quot;, &quot;Camry&quot;);
const yourCar = new Car(&quot;Honda&quot;, &quot;Accord&quot;);

// myCar와 yourCar는 Car 클래스의 인스턴스이다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;캡슐화&lt;/h3&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;pre id=&quot;code_1712066367700&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ES6 이후에는 클래스 내에서 #을 사용하여 private 필드를 정의할 수 있다.
// (ts에서는 private 키워드 사용 가능)
// private 필드는 클래스 외부에서 직접 접근할 수 없으므로 정보 은닉을 달성

class Car {
  #make;   // 제조사 (private 필드)
  #model;  // 모델 (private 필드)
  #year;   // 연도 (private 필드)
  #speed;  // 현재 속도 (private 필드)

  constructor(make, model, year) {
    this.#make = make;
    this.#model = model;
    this.#year = year;
    this.#speed = 0;
  }

  // 속도를 증가시키는 메서드
  accelerate(amount) {
    this.#speed += amount;
  }

  // 속도를 감소시키는 메서드
  brake(amount) {
    this.#speed -= amount;
  }

  // 현재 속도를 반환하는 메서드
  getSpeed() {
    return this.#speed;
  }

  // 제조사를 반환하는 메서드
  getMake() {
    return this.#make;
  }

  // 모델을 반환하는 메서드
  getModel() {
    return this.#model;
  }

  // 연도를 반환하는 메서드
  getYear() {
    return this.#year;
  }
}

// Car 클래스의 사용 예시
const myCar = new Car(&quot;Toyota&quot;, &quot;Camry&quot;, 2022);

// 속도를 증가시킴
myCar.accelerate(20);

// 현재 속도를 출력
console.log(&quot;Current Speed:&quot;, myCar.getSpeed());

// 모델을 출력
console.log(&quot;Car Model:&quot;, myCar.getModel());

// private 필드는 클래스 외부에서 접근할 수 없으므로 직접적인 변경을 막을 수 있다.
// myCar.#make = &quot;Honda&quot;;  // 이 코드는 에러를 발생시킨다.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클래스&amp;nbsp;변수와&amp;nbsp;인스턴스&amp;nbsp;변수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정의&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;모든&amp;nbsp;인스턴스가&amp;nbsp;공유하는&amp;nbsp;공통된&amp;nbsp;값을&amp;nbsp;저장&lt;/b&gt;하며,&amp;nbsp;&lt;u&gt;클래스명을&amp;nbsp;통해&amp;nbsp;직접&amp;nbsp;접근&lt;/u&gt;하고,&amp;nbsp;&lt;b&gt;static&lt;/b&gt; 키워드를 사용하여 선언&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;각 인스턴스마다 개별적으로 존재&lt;/b&gt;하는 변수&lt;/li&gt;
&lt;li&gt;인스턴스의 고유한 특성을 나타내는 값을 저장하며, &lt;b&gt;this&lt;/b&gt; 키워드를 사용하여 접근&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;모든 인스턴스가 공유&lt;/b&gt;하기 때문에 메모리 효율성을 높인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값 변경 시 모든 인스턴스에 영향을 미친다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;클래스 초기화 시 자동으로 초기화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;static&lt;/b&gt; 키워드를 사용하여 선언&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;각 인스턴스마다 독립적으로 값&lt;/b&gt;을 가질 수 있다.&lt;/li&gt;
&lt;li&gt;특정 인스턴스의 고유한 정보를 저장하는 데 유용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;this&lt;/b&gt; 키워드를 사용하여 접근&lt;/li&gt;
&lt;li&gt;인스턴스 생성 시 자동으로 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스 변수&lt;/h4&gt;
&lt;pre id=&quot;code_1712064923377&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  static count = 0; // 클래스 변수 선언

  constructor(name) {
    this.name = name;
    Person.count++; // 클래스 변수 접근 및 변경
  }
}

console.log(Person.count); // 0

const p1 = new Person('Alice');
console.log(Person.count); // 1

const p2 = new Person('Bob');
console.log(Person.count); // 2&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인스턴스 변수&lt;/h4&gt;
&lt;pre id=&quot;code_1712064945594&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  getName() {
    return this.name;
  }

  getAge() {
    return this.age;
  }
}

const p1 = new Person('Alice', 30);
console.log(p1.getName()); // Alice
console.log(p1.getAge()); // 30

const p2 = new Person('Bob', 25);
console.log(p2.getName()); // Bob
console.log(p2.getAge()); // 25&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근&amp;nbsp;제한자&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;static&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;클래스 자체&lt;/b&gt;&lt;u&gt;에 속하는 변수와 메서드를 선언할 때 사용&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;클래스명&lt;/b&gt;을 통해 직접 접근&lt;/li&gt;
&lt;li&gt;인스턴스 생성 없이도 사용 가능&lt;/li&gt;
&lt;li&gt;메모리 효율성을 높이고 코드 간결성을 유지하는 데 도움된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;public&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;클래스 외부에서 자유롭게 접근&lt;/b&gt;하고 사용할 수 있는 속성과 메서드를 선언할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;private&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;클래스 내부에서만 접근&lt;/b&gt;하고 사용할 수 있는 속성과 메서드를 선언할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;b&gt;클래스 외부에서 직접 접근하거나 변경할 수 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 캡슐화를 통해 정보 은닉과 보안을 강화&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;코드 복잡성을 증가시킬 수 있으며, 테스트하기 어려울 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JavaScript&lt;/h4&gt;
&lt;pre id=&quot;code_1712065493097&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Foo {
  x = 1;            // Field declaration
  #p = 0;           // Private field
  static y = 20;    // Static public field
  static #sp = 30;  // Static private field

  bar() {
    this.#p = 10; // private 필드 참조
    // this.p = 10; // 새로운 public p 필드를 동적 추가한다.
    return this.#p;
  }
}

const foo = new Foo();
console.log(foo); // Foo {#p: 10, x: 1}

console.log(foo.x); // 1
// console.log(foo.#p); // SyntaxError: Undefined private field #p: must be declared in an enclosing class
console.log(Foo.y); // 20
// console.log(Foo.#sp); // SyntaxError: Undefined private field #sp: must be declared in an enclosing class
console.log(foo.bar()); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;TypeScript&lt;/h4&gt;
&lt;pre id=&quot;code_1712066027602&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Foo {
  public x = 1; // Field declaration
  private p = 0; // Private field
  public static y = 20; // Static public field
  private static sp = 30; // Static private field

  bar() {
    this.p = 10; // private 필드 참조
    // this.x = 10; // 새로운 public x 필드를 동적 추가한다.
    return this.p;
  }
}

const foo = new Foo();
console.log(foo); // Foo {p: 10, x: 1}

console.log(foo.x); // 1
// console.log(foo.p); // SyntaxError: Undefined private field p: must be declared in an enclosing class
console.log(Foo.y); // 20
// console.log(Foo.sp); // SyntaxError: Undefined private field sp: must be declared in an enclosing class
console.log(foo.bar()); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/161</guid>
      <comments>https://msm1307.tistory.com/161#entry161comment</comments>
      <pubDate>Tue, 2 Apr 2024 22:36:04 +0900</pubDate>
    </item>
    <item>
      <title>http &amp;rarr; http 크로스 도메인 쿠키 전송</title>
      <link>https://msm1307.tistory.com/159</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;http &amp;rarr; http로 서로 다른 도메인에서 쿠키를 심었을 경우&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sameSite 기본값(Lax)일 경우&lt;/h3&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;크롬에서 크로스 사이트를 사용 가능하도록 sameSite를 None 옵션으로 설정해주라고 메세지를 내뱉음. (서버에서 설정해줘야함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.14.45.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBWaus/btsFRbHRERk/rc1qXl9mdJDBhOGg97FvZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBWaus/btsFRbHRERk/rc1qXl9mdJDBhOGg97FvZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBWaus/btsFRbHRERk/rc1qXl9mdJDBhOGg97FvZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBWaus%2FbtsFRbHRERk%2Frc1qXl9mdJDBhOGg97FvZK%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;1668&quot; height=&quot;314&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.14.45.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;314&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;client 코드 - svelte (주소 : localhost:5173)&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  import axios from 'axios';

  const API = axios.create({
    baseURL: `http://localhost:8080`,
  });

  const getCookie = async () =&amp;gt; {
    // 의미없는 데이터임
    const data = {
      id: 'id',
      pw: 'pw',
    };

    // withCredentials 옵션은 단어의 의미에서 알 수 있듯이, 서로 다른 도메인(크로스 도메인)에 요청을 보낼 때 요청에 credential 정보를 담아서 보낼 지를 결정하는 항목입니다.
    // 여기서, credential 정보가 포함되어 있는 요청은 아래 두 가지 경우를 의미합니다.

    // 1. 쿠키를 첨부해서 보내는 요청
    // 2. 헤더에 Authorization 항목이 있는 요청
    const config = {
      withCredentials: true,
    };

    await API.post('/login', data, config);
  };
  
  const postCookie = async () =&amp;gt; {
    const data = {
      id: 'haha',
      pw: 'bb',
    };
    const config = {
      withCredentials: true,
    };
    await API.post('/cookie', data, config);
  };

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

&amp;lt;main&amp;gt;
  &amp;lt;button on:click={getCookie}&amp;gt;쿠키 심기&amp;lt;/button&amp;gt;
  &amp;lt;button on:click={postCookie}&amp;gt;쿠키 보내기&amp;lt;/button&amp;gt;
&amp;lt;/main&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;server 코드 - node express (주소 : 172.~~~~~:8080)&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const PORT = 8080;
const app = express();

app.use(cookieParser());
app.use(express.json());

app.use(
  cors({
    origin: true, // 클라이언트의 Origin
    credentials: true, // 요청에 인증 정보를 포함할 것임을 허용
  })
);

app.get('/', function (req, res) {
  res.send('ㅎㅇㅎㅇ');
});

app.post('/login', (req, res) =&amp;gt; {
  console.log('요청옴');
  // 가정: 로그인이 성공했을 때 사용자 정보를 생성하고 쿠키에 저장한다.
  const userInfo = { username: 'exampleUser', id: 123456 };

  // 쿠키 만료 시간 설정 (1시간)
  const oneHour = 60 * 60 * 1000; // milliseconds
  const expiryDate = new Date(Date.now() + oneHour);

  // 쿠키 생성
  res.cookie('userInfo', userInfo, {
    httpOnly: true, // HTTP Only 설정
    expires: expiryDate, // 만료 시간 설정
  });

  res.send('쿠키 심기');
});

app.post('/cookie', (req, res) =&amp;gt; {
  console.log(req.cookies['userInfo']);
  res.send('쿠키 가져오기');
});

// 서버가 실행할 PORT를 지정하고, 실행했을 때 콘솔로그를 찍음
app.listen(PORT, function () {
  console.log(`Listening on port ${PORT}! &amp;lt;http://localhost&amp;gt;:${PORT}`);
});&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;쿠키를 심고 쿠키를 보내기 했을 경우 서버에서 undefined로 뜸&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.27.42.png&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;36&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTC2iS%2FbtsFTfJw6aK%2FRWv4bG4S4czlbkk1gN0ZJ1%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;540&quot; height=&quot;36&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.27.42.png&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;36&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sameSite를 none 으로 설정할 경우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sameSite none 을 적용 할 경우 &lt;b&gt;secure: true&lt;/b&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;&lt;b&gt;서드 파티 쿠키 제한 확대&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.google.com/privacy-sandbox/3pcd?hl=ko#report-issues&quot;&gt;https://developers.google.com/privacy-sandbox/3pcd?hl=ko#report-issues&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;client 코드 (주소 : localhost:5173) 위와 동일&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  import axios from 'axios';

  const API = axios.create({
    baseURL: `http://localhost:8080`,
  });

  const getCookie = async () =&amp;gt; {
    // 의미없는 데이터임
    const data = {
      id: 'id',
      pw: 'pw',
    };

    // withCredentials 옵션은 단어의 의미에서 알 수 있듯이, 서로 다른 도메인(크로스 도메인)에 요청을 보낼 때 요청에 credential 정보를 담아서 보낼 지를 결정하는 항목입니다.
    // 여기서, credential 정보가 포함되어 있는 요청은 아래 두 가지 경우를 의미합니다.

    // 1. 쿠키를 첨부해서 보내는 요청
    // 2. 헤더에 Authorization 항목이 있는 요청
    const config = {
      withCredentials: true,
    };

    await API.post('/login', data, config);
  };

  const postCookie = async () =&amp;gt; {
    const data = {
      id: 'haha',
      pw: 'bb',
    };
    const config = {
      withCredentials: true,
    };
    await API.post('/cookie', data, config);
  };
&amp;lt;/script&amp;gt;

&amp;lt;main&amp;gt;
  &amp;lt;button on:click={getCookie}&amp;gt;쿠키 심기&amp;lt;/button&amp;gt;
  &amp;lt;button on:click={postCookie}&amp;gt;쿠키 보내기&amp;lt;/button&amp;gt;
&amp;lt;/main&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;server 코드 (주소 : 172.~~~~~:8080)&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const PORT = 8080;
const app = express();

app.use(cookieParser());
app.use(express.json());

app.use(
  cors({
    origin: true, // 클라이언트의 Origin
    credentials: true, // 요청에 인증 정보를 포함할 것임을 허용
  })
);

app.get('/', function (req, res) {
  res.send('ㅎㅇㅎㅇ');
});

app.post('/login', (req, res) =&amp;gt; {
  console.log('요청옴');
  // 가정: 로그인이 성공했을 때 사용자 정보를 생성하고 쿠키에 저장한다.
  const userInfo = { username: 'exampleUser', id: 123456 };

  // 쿠키 만료 시간 설정 (1시간)
  const oneHour = 60 * 60 * 1000; // milliseconds
  const expiryDate = new Date(Date.now() + oneHour);

  // 쿠키 생성
  res.cookie('userInfo', userInfo, {
    httpOnly: true, // HTTP Only 설정
    expires: expiryDate, // 만료 시간 설정
    sameSite: 'none',
    secure: true, // Secure 설정
  });

  res.send('쿠키 심기');
});

app.post('/cookie', (req, res) =&amp;gt; {
  console.log(&quot;req.cookies['userInfo'] = &quot;, req.cookies['userInfo']);
  res.send('쿠키 가져오기');
});

// 서버가 실행할 PORT를 지정하고, 실행했을 때 콘솔로그를 찍음
app.listen(PORT, function () {
  console.log(`Listening on port ${PORT}! &amp;lt;http://localhost&amp;gt;:${PORT}`);
});&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.27.42.png&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;36&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TC2iS/btsFTfJw6aK/RWv4bG4S4czlbkk1gN0ZJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTC2iS%2FbtsFTfJw6aK%2FRWv4bG4S4czlbkk1gN0ZJ1%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;540&quot; height=&quot;36&quot; data-filename=&quot;스크린샷 2024-03-18 오후 10.27.42.png&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;36&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;sameSite 옵션이 뭘까?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키의 속성 중 하나로, 보안 및 개인 정보 보호 측면에서 중요한 역할을 합니다. SameSite 속성은 웹 브라우저가 쿠키를 어떻게 처리해야 하는지를 지정합니다.&lt;br /&gt;즉, 쿠키에는 이 쿠키가 어떤 도메인에서만 사용할 수 있는지 설정할 수 있는 옵션&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SameSite은 크게 세 가지 값으로 설정할 수 있습니다. (기본값은 Lax)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Strict&lt;/b&gt;: 이 옵션을 사용하면 브라우저는 SameSite를 엄격하게 적용하여, 쿠키가 해당 사이트의 페이지로만 전송될 수 있도록 합니다. 즉, 외부 사이트로의 요청에서는 쿠키가 전송되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lax&lt;/b&gt;: 이 옵션은 엄격한 제약을 완화시키는 데 사용됩니다. 외부 도메인으로의 GET 요청에 대해서는 쿠키를 전송하지 않지만, POST 요청이나 외부 도메인에서 자동으로 시작되는 요청(ex: 링크를 클릭하여 이동하는 경우)에는 쿠키가 전송됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;None&lt;/b&gt;: 이 옵션은 SameSite를 사용하지 않음을 나타냅니다. 따라서 쿠키는 모든 요청에 대해 전송됩니다. 이 옵션을 사용할 때는 Secure 속성이 함께 설정되어야 하며, HTTPS 프로토콜을 사용하는 환경에서만 적용됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SameSite 속성은 주로 &lt;a href=&quot;https://nordvpn.com/ko/blog/csrf/&quot;&gt;CSRF&lt;/a&gt; (Cross-Site Request Forgery) 공격과 관련이 있습니다. 이를 통해 외부 사이트에서 해당 사이트로 요청을 보내는 공격을 막기 위해 SameSite 속성을 설정할 수 있습니다. 또한 SameSite는 쿠키를 통한 사용자 추적을 제한하고 개인 정보 보호를 강화하는 데 도움이 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;크롬의 SameSite 기본값 변화(None &amp;rarr; Lax)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 SameSite를 명시하지 않은 쿠키는 None으로 동작했지만, &lt;b&gt;2020년 2월 4일 크롬 80 버전&lt;/b&gt;이 배포되면서 SameSite의 기본값이 Lax로 변경되었다. 이에 따라 위에서 언급했던 것처럼 예외사항에 포함되지 않으면 다른 도메인 간의 요청에서 쿠키를 담아주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해선 SameSite 속성을 None으로 변경하고 쿠키를 secure 쿠키로 만들어 주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(SameSite를 None으로 하려면 무조건 secure를 true로 설정해야만 정상적으로 전송된다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;secure: 쿠키가 &lt;b&gt;SSL이나 HTTPS 연결을 통해서만&lt;/b&gt; 반횐될지 여부를 명시하는 값&lt;/li&gt;
&lt;li&gt;SameSite: 쿠키가 같은 도메인에서만 접근할 수 있어야 하는지 여부를 결정하는 값&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로스 도메인 쿠키를 제대로 사용하려면 HTTPS 를 적용하고 sameSite 설정을 none로 바꿔주자 !!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 사이트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@wiostz98kr/다른-도메인간-쿠키-전송하기&quot;&gt;https://velog.io/@wiostz98kr/다른-도메인간-쿠키-전송하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS지식</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/159</guid>
      <comments>https://msm1307.tistory.com/159#entry159comment</comments>
      <pubDate>Mon, 18 Mar 2024 23:01:18 +0900</pubDate>
    </item>
    <item>
      <title>TailwindCSS 재사용 컴포넌트 만들기 - feat: TypeScript</title>
      <link>https://msm1307.tistory.com/156</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TailwindCSS로 스타일링 할 때 재사용 컴포넌트를 만드려면 className 복사해서 사용해왔는데 여간 불편한 일이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 재사용 컴포넌트를 만들어서 코드의 중복을 줄이고, 디자인을 일관되게 유지하도록 만들어 보려 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TypeScript + TailwindCSS를 이용한 재사용 컴포넌트 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트를 사용하는 곳에 타입을 지정한 뒤 props를 통해 이벤트 헨들러, 컬러, 색상 등을 받을 수 있게 제작하였다.&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;components/common/Button.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1706269780297&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ReactNode } from 'react';

type Color = 'default' | 'white';
type Size = 'sm' | 'md' | 'full';
type Type = 'button' | 'submit';

interface ButtonProps {
  children: ReactNode;
  onClick?: () =&amp;gt; void;
  color?: Color;
  size?: Size;
  type?: Type;
}

export function Button({ children, onClick, color = 'default', type = 'button', size = 'md' }: ButtonProps) {
  return (
    &amp;lt;button
      className={`${buttonTheme.color[color]} ${buttonTheme.size[size]} text-center rounded-md font-semibold border`}
      type={type}
      onClick={onClick}
    &amp;gt;
      {children}
    &amp;lt;/button&amp;gt;
  );
}

const buttonTheme = {
  color: {
    default: 'text-white bg-green-400 border-green-400',
    white: 'text-green-400 bg-white border-green-400',
  },

  size: {
    sm: 'px-2 py-1.5 text-sm',
    md: 'px-3 py-2 text-base',
    full: 'py-3 w-full text-base',
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;공통으로 사용되는 css는 button의 className에 미리 정의해두고 중복을 제거하였다.&lt;br /&gt;Default 값을 사용하여 일반적으로 많이 쓰이는 설정을 미리 지정함으로써 불필요한 props 설정을 제거하였다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1706274195065&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import { Button } from './components/common/Button';

export default function App() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Button&amp;gt;안녕&amp;lt;/Button&amp;gt;
      &amp;lt;Button color=&quot;white&quot;&amp;gt;안녕&amp;lt;/Button&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;h3 data-ke-size=&quot;size23&quot;&gt;아쉬운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 살짝 아쉬운 부분이 있다. buttonTheme.color에 색상을 추가하면 type Color에서도 해당 키값을 추가해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 neutral 색상을 추가하려면 buttonTheme.color와 type Color를 직접 맞춰줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 buttonTheme.color에 값을 추가하면 동적으로 Color 타입도 추가하고 싶었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개선된 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components/common/Button.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1706275216371&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ReactNode } from 'react';

type Color = keyof typeof buttonTheme.color;
// type Color = 'default' | 'white';
type Size = keyof typeof buttonTheme.size;
// type Size = type Size = 'sm' | 'md' | 'full';
type Type = 'button' | 'submit';

//...

const buttonTheme = {
  color: {
    default: 'text-white bg-green-400 border-green-400',
    white: 'text-green-400 bg-white border-green-400',
  },

  size: {
    sm: 'px-2 py-1.5 text-sm',
    md: 'px-3 py-2 text-base',
    full: 'py-3 w-full text-base',
  },
};&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;TypeScript의 keyof typeof을 활용하면 객체의 key들만 가져와 상수 타입으로 만들 수 있다.&lt;/p&gt;</description>
      <category>라이브러리</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/156</guid>
      <comments>https://msm1307.tistory.com/156#entry156comment</comments>
      <pubDate>Fri, 26 Jan 2024 21:00:42 +0900</pubDate>
    </item>
    <item>
      <title>prisma 명령어 모음</title>
      <link>https://msm1307.tistory.com/155</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;현재 프로젝트에 prisma에 필요한 파일 생성&lt;/h2&gt;
&lt;pre id=&quot;code_1705855347273&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;npx prisma init&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;&quot; data-ke-size=&quot;size26&quot;&gt;데이터베이스 생성&lt;/h2&gt;
&lt;pre id=&quot;code_1705855347274&quot; class=&quot;ada&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;npx prisma migrate dev --name init&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;&quot; data-ke-size=&quot;size26&quot;&gt;웹에서 데이터베이스 보기&lt;/h2&gt;
&lt;pre id=&quot;code_1705855347274&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;npx prisma studio&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;&quot; data-ke-size=&quot;size26&quot;&gt;데이터베이스 초기화&lt;/h2&gt;
&lt;pre id=&quot;code_1705855347274&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;npx prisma migrate reset&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;</description>
      <category>라이브러리</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/155</guid>
      <comments>https://msm1307.tistory.com/155#entry155comment</comments>
      <pubDate>Mon, 22 Jan 2024 01:42:43 +0900</pubDate>
    </item>
    <item>
      <title>NestJS - dto</title>
      <link>https://msm1307.tistory.com/146</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;dto 란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;DTO는 Data Transfer Object의 약자이며, 주로 클라이언트와 서버 간의 데이터 전송을 위한 객체입니다.&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터&amp;nbsp;형식&amp;nbsp;지정&lt;/b&gt;:&amp;nbsp;DTO는&amp;nbsp;특정&amp;nbsp;데이터의&amp;nbsp;형식을&amp;nbsp;정의하고,&amp;nbsp;클라이언트와&amp;nbsp;서버&amp;nbsp;간에&amp;nbsp;데이터를&amp;nbsp;일관된&amp;nbsp;형식으로&amp;nbsp;주고받을&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유효성&amp;nbsp;검사&lt;/b&gt;:&amp;nbsp;서버에서는&amp;nbsp;클라이언트로부터&amp;nbsp;전달받은&amp;nbsp;데이터의&amp;nbsp;유효성을&amp;nbsp;검사하고&amp;nbsp;필요에&amp;nbsp;따라&amp;nbsp;오류를&amp;nbsp;처리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터&amp;nbsp;변환&lt;/b&gt;:&amp;nbsp;서버는&amp;nbsp;클라이언트로부터&amp;nbsp;받은&amp;nbsp;데이터를&amp;nbsp;필요한&amp;nbsp;형태로&amp;nbsp;가공하거나,&amp;nbsp;데이터베이스와&amp;nbsp;통신하기&amp;nbsp;전에&amp;nbsp;적절한&amp;nbsp;형식으로&amp;nbsp;변환합니다.&lt;/li&gt;
&lt;/ol&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;pre id=&quot;code_1703590012003&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i class-validator class-transformer&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;main.ts에서&amp;nbsp;ValidationPipe를&amp;nbsp;적용&lt;/h3&gt;
&lt;pre id=&quot;code_1703590422782&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true, // DTO에 정의되지 않은 속성이 들어오면 자동으로 제거
      forbidNonWhitelisted: true, // 허용되지 않은 속성이 DTO에 포함되면 요청을 거부
      transform: true, // DTO에 정의된 필드 유형이 일치하지 않는 경우 자동으로 타입 변환을 수행
    }),
  );
  await app.listen(3000);
}
bootstrap();&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;dto 파일 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/board/dto/create-board.dto.ts&lt;/p&gt;
&lt;pre id=&quot;code_1703592454817&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {
  IsEmail,
  IsNotEmpty,
  IsOptional,
  IsString,
  MaxLength,
} from 'class-validator';

export class CreateBoardDto {
  @MaxLength(20) // 최대 20글자 이하인지 확인
  @IsNotEmpty() // 빈 값이나 Null이 아닌지 확인
  @IsString() // 문자 타입인지 아닌지 확인
  title: string;

  @IsString()
  @IsOptional() // 있을 수도 있고 없을 수도 있음
  desc: string;

  @IsString()
  @IsEmail() // 이메일 양식이 맞는지 확인
  writer: string;
}&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;src/board/board.service.ts&lt;/p&gt;
&lt;pre id=&quot;code_1703592524424&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';
import { CreateBoardDto } from './dto/create-board.dto';

@Injectable()
export class BoardService {
  createBoard(boardData: CreateBoardDto) {
    return boardData;
  }
}&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;src/board/board.controller.ts&lt;/p&gt;
&lt;pre id=&quot;code_1703592548933&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Body, Controller, Post } from '@nestjs/common';
import { BoardService } from './board.service';
import { CreateBoardDto } from './dto/create-board.dto';

@Controller('board')
export class BoardController {
  constructor(private boardService: BoardService) {}

  @Post()
  create(@Body() boardData: CreateBoardDto) {
    return this.boardService.createBoard(boardData);
  }
}&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;API 요청&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-26 오후 9.07.12.png&quot; data-origin-width=&quot;1493&quot; data-origin-height=&quot;713&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJHTgC/btsCzDuhJG4/nSSxY4Qg9f4LNPnDyAaCF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJHTgC/btsCzDuhJG4/nSSxY4Qg9f4LNPnDyAaCF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJHTgC/btsCzDuhJG4/nSSxY4Qg9f4LNPnDyAaCF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJHTgC%2FbtsCzDuhJG4%2FnSSxY4Qg9f4LNPnDyAaCF0%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;1493&quot; height=&quot;713&quot; data-filename=&quot;스크린샷 2023-12-26 오후 9.07.12.png&quot; data-origin-width=&quot;1493&quot; data-origin-height=&quot;713&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에 설정된 타입과 다르면 에러 메세지를 반환한다.&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;class-validator 공식 사이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/typestack/class-validator&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/typestack/class-validator&lt;/a&gt;&lt;/p&gt;</description>
      <category>프레임워크/NestJS</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/146</guid>
      <comments>https://msm1307.tistory.com/146#entry146comment</comments>
      <pubDate>Thu, 9 Nov 2023 20:48:20 +0900</pubDate>
    </item>
    <item>
      <title>Socket.io 사용법</title>
      <link>https://msm1307.tistory.com/145</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Socket.io란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Socket.io는 실시간 웹 어플리케이션을 개발하기 위한 JavaScript 라이브러리로, &lt;b&gt;웹 소켓(WebSocket) 프로토콜을 기반으로 동작&lt;br /&gt;&lt;/b&gt;Socket.IO는&amp;nbsp;클라이언트와&amp;nbsp;서버&amp;nbsp;간의&amp;nbsp;실시간&amp;nbsp;통신을&amp;nbsp;위한&amp;nbsp;사용하기&amp;nbsp;&lt;b&gt;쉬운 인터페이스를 제공&lt;br /&gt;이벤트 기반&lt;/b&gt;으로 동작&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/blockquote&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;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;private&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;private은 1:1 통신을 말한다. 메신저를 예로 들면 1:1 채팅 같은 개념이다.&lt;/p&gt;
&lt;pre id=&quot;code_1701962988865&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;io.to(소켓 id).emit();&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;public&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송자를 포함한 모두에게 메세지를 전송한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701963425309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;io.emit();&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;broadcast&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송자를 제외한 모든 사용자에게 메세지를 전송한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701963537826&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.broadcast.emit();&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;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;server&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const { createServer } = require('http');
const express = require('express');
const { Server } = require('socket.io');

const app = express();
const httpServer = createServer(app);

const io = new Server(httpServer, {
  cors: {
    origin: 'http://localhost:3000',
  },
});

io.on('connection', (socket) =&amp;gt; {
  console.log('connection', socket.id); // 클라이언트가 서버에 연결되었을 때 발생

  socket.on('disconnect', () =&amp;gt; {
    console.log('연결 끊김'); // 클라이언트에서 소켓 연결 해제시 발생
  });
});

httpServer.listen(8000, () =&amp;gt; {
  console.log('server running at http://localhost:8000');
});&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;clinet&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701964710027&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useEffect, useState } from 'react';
import { io } from 'socket.io-client';

export default function ConnectionPage() {
  const [socket, setSocket] = useState();

  useEffect(() =&amp;gt; {
    const newSocket = io('http://localhost:8000');
    setSocket(newSocket);

    return () =&amp;gt; {
      newSocket.disconnect();
    };
  }, []);

  useEffect(() =&amp;gt; {
    if (!socket) return;
    socket.on('connect', () =&amp;gt; {
      // 소켓 연결되었을 때 발생
      console.log('소켓 연결 완료');
    });
    socket.on('disconnect', () =&amp;gt; {
      // 소켓 연결이 끊겼을 때 발생
      console.log('소켓 연결 끊김');
    });
  }, [socket]);

  return &amp;lt;div&amp;gt;ConnectionPage&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;h2 data-ke-size=&quot;size26&quot;&gt;예약이 되어 있는 이벤트 모음&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;server&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;connection&lt;/b&gt; : 클라이언트가 서버에 연결되었을 때 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;disconnecting&lt;/b&gt; : 클라이언트가 연결을 해제하려는 경우에 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;disconnect&lt;/b&gt; : 클라이언트가 연결을 해제했을 때 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;error&lt;/b&gt; : 연결중에 오류가 발생했을 때 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;client&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;connect&lt;/b&gt; : 서버와 소켓이 연결 되었을 때 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;disconnect&lt;/b&gt;&amp;nbsp;: 서버와 소켓이 해제되었을 때 발생&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;/h2&gt;
&lt;pre id=&quot;code_1701967209873&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 클라이언트를 &quot;roomA&quot; 방으로 추가
socket.join(&quot;roomA&quot;);

// 클라이언트를 &quot;roomA&quot; 방에서 제거
socket.leave(&quot;roomA&quot;);

// 특정 방에 속한 모든 클라이언트에게 특정 이벤트와 데이터를 발송
io.to(&quot;roomA&quot;).emit(&quot;message&quot;, &quot;Hello, Room A&quot;);

// 송신자를 제외한 특정 방에 속한 클라이언트에게 특정 이벤트와 데이터를 발송
socket.to(&quot;roomA&quot;).emit(&quot;message&quot;, &quot;Hello, Room A&quot;);
socket.broadcast.to(&quot;roomA&quot;).emit(&quot;message&quot;, &quot;Hello, Room A&quot;);

// 송신자를 제외한 서버에 연결된 모든 클라이언트에게 이벤트와 데이터를 발송
socket.broadcast.emit(&quot;message&quot;, &quot;Hello, Room A&quot;);

// 송신자를 포함하여 모든 클라이언트에게 이벤트와 데이터를 전송
io.sockets.emit(&quot;message&quot;, &quot;Hello, Room A&quot;);

// 특정 방에 속한 클라이언트들의 정보를 확인
const roomInfo = io.sockets.adapter.rooms.get(room);
console.log(roomInfo); // 방에 속한 클라이언트 id정보가 출력&lt;/code&gt;&lt;/pre&gt;</description>
      <category>라이브러리</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/145</guid>
      <comments>https://msm1307.tistory.com/145#entry145comment</comments>
      <pubDate>Sun, 5 Nov 2023 02:39:07 +0900</pubDate>
    </item>
    <item>
      <title>[새싹x코딩온] 프로젝트 회고 (열줌쉬어) - 프로젝트 소개 및 폴더 구조 세팅</title>
      <link>https://msm1307.tistory.com/143</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;스탑워치 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;/ &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;타이머&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;기능을 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;통해 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;실시간으로 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;공부시간을 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;기록하고&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;가입한 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;그룹 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;내에 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;공부량을 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;시각화하여 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;보여주는 웹사이트&lt;/span&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;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;23. 10. 23 ~ 23. 11. 10 (약 2주)&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;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프론트 엔드 - 2명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;ReactJS&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Redux-Toolkit&lt;/li&gt;
&lt;li&gt;TailwindCSS&lt;/li&gt;
&lt;li&gt;Socket.IO-client&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;백엔드 - 3명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Express&lt;/li&gt;
&lt;li&gt;Mongoose&lt;/li&gt;
&lt;li&gt;JWT (jsonwebtoken)&lt;/li&gt;
&lt;li&gt;Socket.IO&lt;/li&gt;
&lt;li&gt;MongoDB, AWS EC2, NGINX&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;협업 툴&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.notion.so/2-D-78a2d14c6765450d8a5aea0deb165f88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;노션&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/WebDeViper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;깃허브&lt;/a&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;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Vite&amp;nbsp; VS&amp;nbsp; create-react-app&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 create-react-app으로만 했었는데 vite가 &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;기존의 번들러와 비교하여 개발 속도가 월등히 빠르다고 하고, &lt;/span&gt;요즘 Vite를 사용하여 프로젝트 하는 곳이 많아 이번 기회에 써보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은&amp;nbsp;프로젝트에는&amp;nbsp;별&amp;nbsp;차이가&amp;nbsp;없겠지만&amp;nbsp;react&amp;nbsp;설치부터&amp;nbsp;시작해서&amp;nbsp;개발환경을&amp;nbsp;구축하는&amp;nbsp;과정이&amp;nbsp;create-react-app보다&amp;nbsp;간단하고&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;size18&quot;&gt;&lt;b&gt;Redux-Toolkit&amp;nbsp; VS&amp;nbsp; Zustand&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zustand가 상태관리 라이브러리 중 사용이 간편하고 진입장벽이 낮다고 해서 사용할까 말까 많이 망설였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Redux-Toolkit을 사용한 이유는 아직 채용 공고를 보면 Redux-Toolkit을 사용하는 곳이&amp;nbsp; 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Redux-Toolkit을 먼저 사용해봐야 Zustand를 나중에 배웠을 때 장점이 보일 것 같아 일단은 Redux-Toolkit 상태관리 라이브러리를 선택했다.&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;b&gt;TypeScript&amp;nbsp; VS&amp;nbsp; JavaScript&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 현업에서 많이 쓰는 TypeScript로 시작했었으나, 사용 중간에 타입 에러 잡는다고 시간을 많이 쏟아 프로젝트 기간 내에 못 맞출 거 같아 JavaScript로 전향했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 끝나면 TypeScript로 리팩토링을 꼭 하고 싶다.&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;b&gt;TailwindCSS&amp;nbsp; VS&amp;nbsp; Emotion&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 Emotion을 써봤고, 나는 클래스명과 변수명을 짓는데 시간을 꽤 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TailwindCSS는 클래스명 생각할 시간에 개발에 더 집중할 수 있기 때문에 이번 기회에 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;하지만 처음 사용해 봐서 class명 찾는다고 시간을 더 쓴 거 같다...&lt;/s&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;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-12 오후 6.43.17.png&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cszUAz/btsz82QM5yB/U7S6s9OcztZ2dmkcDKG61K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cszUAz/btsz82QM5yB/U7S6s9OcztZ2dmkcDKG61K/img.png&quot; data-alt=&quot;리액트 폴더 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cszUAz/btsz82QM5yB/U7S6s9OcztZ2dmkcDKG61K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcszUAz%2Fbtsz82QM5yB%2FU7S6s9OcztZ2dmkcDKG61K%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;590&quot; height=&quot;1006&quot; data-filename=&quot;스크린샷 2023-11-12 오후 6.43.17.png&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;1006&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리액트 폴더 구조&lt;/figcaption&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;components
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;common - 여러 페이지에서 사용되는 공통 컴포넌트 모음&lt;/li&gt;
&lt;li&gt;layout - 전체 화면을 담당하는 컴포넌트 (Header, main, Footer)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;data : 공통으로 사용되는 data 모음 (카테고리 등등)&lt;/li&gt;
&lt;li&gt;hooks : 공통으로 사용되는 hooks 모음&lt;/li&gt;
&lt;li&gt;pages : 페이지를 담당하는 폴더 - 각 페이지마다 한번씩 쓰는 컴포넌트는 여기서 관리&lt;/li&gt;
&lt;li&gt;reducers : redux slice 모음&lt;/li&gt;
&lt;li&gt;store : 리덕스 세팅&lt;/li&gt;
&lt;li&gt;utils : 공통으로 사용되는 axios나 함수 모음&lt;/li&gt;
&lt;li&gt;가독성을&amp;nbsp;유지하기&amp;nbsp;위해,&amp;nbsp;React&amp;nbsp;컴포넌트는&amp;nbsp;.jsx&amp;nbsp;확장자를&amp;nbsp;사용하고,&amp;nbsp;일반적인&amp;nbsp;JavaScript&amp;nbsp;함수를&amp;nbsp;모아둔&amp;nbsp;파일은&amp;nbsp;.js&amp;nbsp;확장자를&amp;nbsp;사용&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;초기 세팅 (공통 로직) - 라이브러리의&amp;nbsp;도움을&amp;nbsp;받아&amp;nbsp;효율적으로&amp;nbsp;구현&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;레이아웃&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;공통적인 컴포넌트를 처리&lt;/u&gt;하기 위해 React-Router-Dom에 있는 &amp;lt;Outlet /&amp;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;components/layout/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1699803959047&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Outlet } from 'react-router-dom';
import Footer from './Footer';
import Header from './Header';

export default function Layout() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Header /&amp;gt;
      &amp;lt;main&amp;gt;
        &amp;lt;Outlet /&amp;gt;
      &amp;lt;/main&amp;gt;
      &amp;lt;Footer /&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;p data-ke-size=&quot;size16&quot;&gt;App.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1699804008619&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Route, Routes } from 'react-router-dom';
import Layout from './components/layout';
import MainPage from './pages/MainPage';
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';

function App() {
  return (
    &amp;lt;Routes&amp;gt;
      &amp;lt;Route path=&quot;/&quot; element={&amp;lt;Layout /&amp;gt;}&amp;gt;
        &amp;lt;Route index element={&amp;lt;MainPage /&amp;gt;} /&amp;gt;
        &amp;lt;Route path=&quot;/login&quot; element={&amp;lt;LoginPage /&amp;gt;} /&amp;gt;
      &amp;lt;/Route&amp;gt;
    &amp;lt;/Routes&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&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;lt;Route path=&quot;/&quot; element={&amp;lt;Layout /&amp;gt;}&amp;gt; 로 감싸주면 children와 같은 효과를 내어 내부 로직이 Layout 컴포넌트의 main 태그 안에 들어가게 된다.&lt;br /&gt;이렇게 감싸주면 내부의 MainPage와 LoginPage의 컴포넌트에 매번 Layout 컴포넌트로 감싸주는 중복 로직을 제거 할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React-Router-Dom 공식 사이트 (Outlet)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://reactrouter.com/en/main/components/outlet&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://reactrouter.com/en/main/components/outlet&lt;/a&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;CSS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 사용하는 색상 추가 및 tailwindcss 속성 커스텀을 위해 tailwind config 파일에 옵션을 추가하고, 공통으로 사용되는 &lt;u&gt;heading 태그나 section 태그 통일성을 위해&lt;/u&gt; tailwindcss에서 지원하는 @layer base 를 사용하여 기본 스타일을 지정해 주었다.&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;tailwind.config.js&lt;/p&gt;
&lt;pre id=&quot;code_1699821490543&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', 'node_modules/flowbite-react/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {
      colors: {
        primary: '#22a3cc',
        semi_primary: '#bce3ef',
        secondary: '#bfd9ff',
        danger: '#e74c3c',
      },
      container: {
        screens: {
          lg: '1024px',
          md: '768px',
          sm: '640px',
          xs: '390px',
        },
        padding: {
          DEFAULT: '1rem',
          sm: '0',
        },
      },
    },
  },
  plugins: [require('flowbite/plugin')],
};&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;src/index.css&lt;/p&gt;
&lt;pre id=&quot;code_1699804984683&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;

@layer base {
  html {
    font-family: 'Roboto', system-ui, sans-serif;
  }

  textarea {
    resize: none;
  }

  section + section {
    @apply mt-12;
  }

  h2 {
    @apply text-2xl font-bold mb-8;
  }

  h3 {
    @apply text-lg font-semibold mb-5;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;@layer base 속성 안에다가 기본 스타일을 지정하는 이유&lt;br /&gt;&lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;CSS 우선 순위 때문이다.&lt;/span&gt;&lt;/u&gt; @layer 밖에다 적으면 h2 태그를 커스텀 할 일이 생길 때 CSS 우선 순위 때문에 해당 클래스명이 안 먹을 수 있다. @layer 종류에는 base, components, utilities 등등 있다.&lt;br /&gt;@apply 속성은 css 파일 내에서도 tailwindcss 클래스명을 사용할 수 있게 해준다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tailwindcss 공식 사이트 (base&amp;nbsp;styles)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tailwindcss.com/docs/adding-custom-styles#adding-base-styles&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tailwindcss.com/docs/adding-custom-styles#adding-base-styles&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;&lt;a href=&quot;https://leesangwondev.vercel.app/tailwind-css-%EB%98%91%EB%98%91%ED%95%98%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leesangwondev.vercel.app/tailwind-css-%EB%98%91%EB%98%91%ED%95%98%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&lt;/a&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;axios 요청&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios 인스턴스로 매번 백엔드 똑같은 주소(http://localhost:8000)를 적어야 하는 중복을 없앴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;인터셉터 메소드&lt;/b&gt;를 이용하여 매번 &lt;u&gt;headers에 토큰값을 넣어야 하는 사용자 인증 로직&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;&lt;b&gt;인터셉터 메소드 &lt;/b&gt;: then&amp;nbsp;또는&amp;nbsp;catch로&amp;nbsp;처리되기&amp;nbsp;전에&amp;nbsp;요청과&amp;nbsp;응답을&amp;nbsp;가로챌수&amp;nbsp;있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;request에서는 요청을 보내기 전에 하는 작업이 가능하다.&lt;/li&gt;
&lt;li&gt;response에서는&amp;nbsp;서버에서&amp;nbsp;받은&amp;nbsp;응답이&amp;nbsp;then과&amp;nbsp;catch로&amp;nbsp;처리되기&amp;nbsp;전에&amp;nbsp;인터셉터로&amp;nbsp;가로채서&amp;nbsp;원하는&amp;nbsp;작업들을&amp;nbsp;추가할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Interceptor.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F08Yu/btsAeCCQOKm/aJW2BKV5Ek4gsRZ6hrbSu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F08Yu/btsAeCCQOKm/aJW2BKV5Ek4gsRZ6hrbSu0/img.png&quot; data-alt=&quot;Interceptor을 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F08Yu/btsAeCCQOKm/aJW2BKV5Ek4gsRZ6hrbSu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF08Yu%2FbtsAeCCQOKm%2FaJW2BKV5Ek4gsRZ6hrbSu0%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;793&quot; height=&quot;166&quot; data-filename=&quot;Interceptor.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Interceptor을 설명한 이미지&lt;/figcaption&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;utils/axios.js&lt;/p&gt;
&lt;pre id=&quot;code_1699806093687&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios';

export const API = axios.create({
  baseURL: import.meta.env.VITE_APP_API_URL,
});

API.interceptors.request.use(
  function (config) {
    config.headers.Authorization = 'Bearer ' + localStorage.getItem('accessToken');
    return config;
  },
  function (error) {
    return Promise.reject(error);
  }
);

API.interceptors.response.use(
  function (response) {
    return response;
  },
  function (error) {
    if (error.response.data.msg === '토큰 만료') {
      window.location.reload();
    }

    return Promise.reject(error);
  }
);&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;pages/Notice/NoticePage/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1699808169249&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { API } from '../../../utils/axios';

export default function NoticePage() {
  const [notice, setNotice] = useState([]);

  useEffect(() =&amp;gt; {
    const fetchNotices = async () =&amp;gt; {
      try {
        const response = await API.get('/notices');
        const data = await response.data;
        setNotice(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetchNotices();
  }, []);


  return (
    &amp;lt;div className=&quot;container&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;blockquote data-ke-style=&quot;style2&quot;&gt;위 코드를 실행하면 매번 요청때마다 http://localhost:8001/api 가 기본주소로 등록이 되고, 매 요청마다 따로 설정 안해도 Request Headers Authorization 에 토큰값을 실어서 보낼 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;axios.png&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btof67/btsAfDO94x9/dWwMpN5DfsQuRn1A85Rwfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btof67/btsAfDO94x9/dWwMpN5DfsQuRn1A85Rwfk/img.png&quot; data-alt=&quot;axios 요청 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btof67/btsAfDO94x9/dWwMpN5DfsQuRn1A85Rwfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbtof67%2FbtsAfDO94x9%2FdWwMpN5DfsQuRn1A85Rwfk%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;1460&quot; height=&quot;494&quot; data-filename=&quot;axios.png&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;axios 요청 이미지&lt;/figcaption&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;axios 공식 사이트 (인스턴스)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://axios-http.com/kr/docs/instance&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://axios-http.com/kr/docs/instance&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;axios 공식 사이트 (인터셉터)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://axios-http.com/kr/docs/interceptors&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://axios-http.com/kr/docs/interceptors&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 블로그에서는 redux 세팅과 로그인&amp;nbsp;여부에&amp;nbsp;따른&amp;nbsp;제한&amp;nbsp;접근&amp;nbsp;라우팅&amp;nbsp;구현에 대해 적어야 겠다.&lt;/p&gt;</description>
      <category>Project/열줌쉬어</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/143</guid>
      <comments>https://msm1307.tistory.com/143#entry143comment</comments>
      <pubDate>Tue, 24 Oct 2023 10:33:12 +0900</pubDate>
    </item>
    <item>
      <title>버블 정렬, 선택 정렬, 이진 탐색</title>
      <link>https://msm1307.tistory.com/140</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;선택 정렬이란?&lt;/h2&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;최솟값을 찾아서 가장 왼쪽 자리부터 스왑하며 정렬&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;그림 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;선택정렬.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpl65c/btsxvGB92Eo/9KIVsDgd9SwhU8y88jAHfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpl65c/btsxvGB92Eo/9KIVsDgd9SwhU8y88jAHfk/img.png&quot; data-alt=&quot;선택 정렬을 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpl65c/btsxvGB92Eo/9KIVsDgd9SwhU8y88jAHfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcpl65c%2FbtsxvGB92Eo%2F9KIVsDgd9SwhU8y88jAHfk%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;781&quot; height=&quot;836&quot; data-filename=&quot;선택정렬.png&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;선택 정렬을 설명한 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;유튜브 설명&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=yXE9kFLHSOs&quot;&gt;https://www.youtube.com/watch?v=yXE9kFLHSOs&lt;/a&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;N개이&amp;nbsp;숫자가&amp;nbsp;입력되면&amp;nbsp;오름차순으로&amp;nbsp;정렬하여&amp;nbsp;출력하는&amp;nbsp;프로그램을&amp;nbsp;작성하세요.&amp;nbsp;정렬하는&amp;nbsp;방법은&amp;nbsp;선택정렬입니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력설명&lt;br /&gt;첫&amp;nbsp;번째&amp;nbsp;줄에&amp;nbsp;자연수&amp;nbsp;N(1&amp;lt;=N&amp;lt;=100)이&amp;nbsp;주어집니다.&lt;br /&gt;두&amp;nbsp;번째&amp;nbsp;줄에&amp;nbsp;N개의&amp;nbsp;자연수가&amp;nbsp;공백을&amp;nbsp;사이에&amp;nbsp;두고&amp;nbsp;입력됩니다.&amp;nbsp;각&amp;nbsp;자연수는&amp;nbsp;정수형&amp;nbsp;범위&amp;nbsp;안에&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력설명&lt;br /&gt;오름차순으로&amp;nbsp;정렬된&amp;nbsp;수열을&amp;nbsp;출력합니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력예제&amp;nbsp;1&lt;br /&gt;6&lt;br /&gt;13&amp;nbsp;5&amp;nbsp;11&amp;nbsp;7&amp;nbsp;23&amp;nbsp;15&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력예제&amp;nbsp;1&lt;br /&gt;5&amp;nbsp;7&amp;nbsp;11&amp;nbsp;13&amp;nbsp;15&amp;nbsp;23&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;코드&lt;/h3&gt;
&lt;pre id=&quot;code_1696987530427&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(arr) {
  const answer = arr;
  for (let i = 0; i &amp;lt; arr.length; i++) {
    let minIdx = i;
    for (let j = i + 1; j &amp;lt; arr.length; j++) {
      if (arr[j] &amp;lt; arr[minIdx]) minIdx = j;
    }
    [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
  }
  return answer;
}

const arr = [13, 5, 11, 7, 23, 15];
console.log(solution(arr));&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;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;서로 인접한 두 원소를 검사하여 정렬하는 알고리즘&lt;br /&gt;왼쪽부터 두 숫자를 비교하면서 큰 숫자를 오른쪽으로 스왑하며 정렬&lt;/blockquote&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;버블정렬.png&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lmpo7/btsxtmXCKSb/R7qdWPkHQpFhhdd18hXPe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lmpo7/btsxtmXCKSb/R7qdWPkHQpFhhdd18hXPe0/img.png&quot; data-alt=&quot;버블 정렬을 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lmpo7/btsxtmXCKSb/R7qdWPkHQpFhhdd18hXPe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flmpo7%2FbtsxtmXCKSb%2FR7qdWPkHQpFhhdd18hXPe0%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;639&quot; height=&quot;637&quot; data-filename=&quot;버블정렬.png&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;버블 정렬을 설명한 이미지&lt;/figcaption&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;&lt;a href=&quot;https://www.youtube.com/watch?v=fxuhgRRqYsY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=fxuhgRRqYsY&lt;/a&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;N개이&amp;nbsp;숫자가&amp;nbsp;입력되면&amp;nbsp;오름차순으로&amp;nbsp;정렬하여&amp;nbsp;출력하는&amp;nbsp;프로그램을&amp;nbsp;작성하세요.&amp;nbsp;정렬하는&amp;nbsp;방법은&amp;nbsp;버블정렬입니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력설명&lt;br /&gt;첫&amp;nbsp;번째&amp;nbsp;줄에&amp;nbsp;자연수&amp;nbsp;N(1&amp;lt;=N&amp;lt;=100)이&amp;nbsp;주어집니다.&lt;br /&gt;두&amp;nbsp;번째&amp;nbsp;줄에&amp;nbsp;N개의&amp;nbsp;자연수가&amp;nbsp;공백을&amp;nbsp;사이에&amp;nbsp;두고&amp;nbsp;입력됩니다.&amp;nbsp;각&amp;nbsp;자연수는&amp;nbsp;정수형&amp;nbsp;범위&amp;nbsp;안에&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력설명&lt;br /&gt;오름차순으로&amp;nbsp;정렬된&amp;nbsp;수열을&amp;nbsp;출력합니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력예제&amp;nbsp;1&lt;br /&gt;6&lt;br /&gt;13&amp;nbsp;5&amp;nbsp;11&amp;nbsp;7&amp;nbsp;23&amp;nbsp;15&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력예제&amp;nbsp;1&lt;br /&gt;5&amp;nbsp;7&amp;nbsp;11&amp;nbsp;13&amp;nbsp;15&amp;nbsp;23&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;pre id=&quot;code_1696865338958&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(arr) {
  const answer = arr;
  for (let i = 0; i &amp;lt; arr.length - 1; i++) {
    // arr.length - 1 한 이유는 어짜피 마지막에 제일 큰 수를 집어 넣을거라서 마지막은 제외
    for (let j = 0; j &amp;lt; arr.length - i - 1; j++) {
      if (arr[j] &amp;gt; arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
      console.log(i);
    }
  }
  return answer;
}

const arr = [13, 5, 11, 7, 23, 15];
console.log(solution(arr));&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;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;u&gt;정렬되어 있는 리스트&lt;/u&gt;에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 방법&lt;/blockquote&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이진검색.png&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d6J6mF/btsx2wyegkx/xgGxUfGmzAIltchln2YlZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d6J6mF/btsx2wyegkx/xgGxUfGmzAIltchln2YlZ0/img.png&quot; data-alt=&quot;이진 탐색을 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d6J6mF/btsx2wyegkx/xgGxUfGmzAIltchln2YlZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd6J6mF%2Fbtsx2wyegkx%2FxgGxUfGmzAIltchln2YlZ0%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;555&quot; height=&quot;608&quot; data-filename=&quot;이진검색.png&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이진 탐색을 설명한 이미지&lt;/figcaption&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;&lt;a href=&quot;https://www.youtube.com/watch?v=IfIuG95RH0o&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=IfIuG95RH0o&lt;/a&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;임의의&amp;nbsp;N개의&amp;nbsp;숫자가&amp;nbsp;입력으로&amp;nbsp;주어집니다.&amp;nbsp;N개의&amp;nbsp;수를&amp;nbsp;오름차순으로&amp;nbsp;정렬한&amp;nbsp;다음&amp;nbsp;N개의&amp;nbsp;수&amp;nbsp;중&amp;nbsp;한&amp;nbsp;개의&amp;nbsp;수인&amp;nbsp;M이&amp;nbsp;주어지면&amp;nbsp;이분검색으로&amp;nbsp;M이&amp;nbsp;정렬된&amp;nbsp;상태에서&amp;nbsp;몇&amp;nbsp;번째에&amp;nbsp;있는지&amp;nbsp;구하는&amp;nbsp;프로그램을&amp;nbsp;작성하세요.&amp;nbsp;단&amp;nbsp;중복값은&amp;nbsp;존재하지&amp;nbsp;않습니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력설명&lt;br /&gt;첫&amp;nbsp;줄에&amp;nbsp;한&amp;nbsp;줄에&amp;nbsp;자연수&amp;nbsp;N(3&amp;lt;=N&amp;lt;=1,000,000)과&amp;nbsp;M이&amp;nbsp;주어집니다.&amp;nbsp;두&amp;nbsp;번째&amp;nbsp;줄에&amp;nbsp;N개의&amp;nbsp;수가&amp;nbsp;공백을&amp;nbsp;사이에&amp;nbsp;두고&amp;nbsp;주어집니다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력설명&lt;br /&gt;첫&amp;nbsp;줄에&amp;nbsp;정렬&amp;nbsp;후&amp;nbsp;M의&amp;nbsp;값의&amp;nbsp;위치&amp;nbsp;번호를&amp;nbsp;출력한다.&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;입력예제&amp;nbsp;1&lt;br /&gt;8&amp;nbsp;32&lt;br /&gt;23&amp;nbsp;87&amp;nbsp;65&amp;nbsp;12&amp;nbsp;57&amp;nbsp;32&amp;nbsp;99&amp;nbsp;81&lt;br /&gt;&lt;br /&gt;▣&amp;nbsp;출력예제&amp;nbsp;1&lt;br /&gt;3&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;pre id=&quot;code_1696987103094&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(target, arr) {
  let answer;
  arr.sort((a, b) =&amp;gt; a - b);
  let lt = 0,
    rt = arr.length - 1;
  while (lt &amp;lt;= rt) {
    let mid = parseInt((lt + rt) / 2);
    if (arr[mid] === target) {
      answer = mid + 1;
      break;
    } else if (arr[mid] &amp;gt; target) rt = mid - 1;
    else lt = mid + 1;
  }

  return answer;
}

const arr = [23, 87, 65, 12, 57, 32, 99, 81];
console.log(solution(32, arr));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/140</guid>
      <comments>https://msm1307.tistory.com/140#entry140comment</comments>
      <pubDate>Mon, 9 Oct 2023 06:01:31 +0900</pubDate>
    </item>
    <item>
      <title>React의 state와 props</title>
      <link>https://msm1307.tistory.com/139</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;State란?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React 컴포넌트 내에서 관리되는 &lt;b&gt;데이터의 현재 상태&lt;/b&gt;를 나타낸다.&lt;br /&gt;각 컴포넌트는 자체적인 state를 가질 수 있으며, 이 데이터는 &lt;u&gt;해당 컴포넌트 내에서 변경&lt;/u&gt;될 수 있다.&lt;/blockquote&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동적인&amp;nbsp;데이터&amp;nbsp;관리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;state를&amp;nbsp;사용하여&amp;nbsp;애플리케이션의&amp;nbsp;상태를&amp;nbsp;저장하고&amp;nbsp;관리할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;이는&amp;nbsp;사용자와의&amp;nbsp;상호작용,&amp;nbsp;서버에서&amp;nbsp;받은&amp;nbsp;데이터,&amp;nbsp;현재&amp;nbsp;애플리케이션&amp;nbsp;상태&amp;nbsp;등과&amp;nbsp;같이&amp;nbsp;변할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;데이터를&amp;nbsp;처리하는&amp;nbsp;데&amp;nbsp;유용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI&amp;nbsp;업데이트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;state의&amp;nbsp;값이&amp;nbsp;변경되면&amp;nbsp;React는&amp;nbsp;해당&amp;nbsp;컴포넌트와&amp;nbsp;그&amp;nbsp;자식&amp;nbsp;컴포넌트의&amp;nbsp;렌더링을&amp;nbsp;다시&amp;nbsp;실행&lt;/u&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;이를&amp;nbsp;통해&amp;nbsp;UI가&amp;nbsp;업데이트되어&amp;nbsp;사용자에게&amp;nbsp;실시간으로&amp;nbsp;변경된&amp;nbsp;정보를&amp;nbsp;보여줄&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건부&amp;nbsp;렌더링&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;state의 값에 따라 다른 UI나 동작을 구현할 수 있다.&lt;/li&gt;
&lt;li&gt;예를&amp;nbsp;들어,&amp;nbsp;사용자의&amp;nbsp;인증&amp;nbsp;상태에&amp;nbsp;따라&amp;nbsp;로그인&amp;nbsp;폼이나&amp;nbsp;사용자&amp;nbsp;정보를&amp;nbsp;표시하는&amp;nbsp;등의&amp;nbsp;조건부&amp;nbsp;렌더링이&amp;nbsp;가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포넌트&amp;nbsp;간&amp;nbsp;데이터&amp;nbsp;전달&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;state를&amp;nbsp;통해&amp;nbsp;부모&amp;nbsp;컴포넌트에서&amp;nbsp;자식&amp;nbsp;컴포넌트로&amp;nbsp;데이터를&amp;nbsp;전달할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;부모&amp;nbsp;컴포넌트의&amp;nbsp;state&amp;nbsp;값을&amp;nbsp;자식&amp;nbsp;컴포넌트의&amp;nbsp;props로&amp;nbsp;전달하여&amp;nbsp;데이터를&amp;nbsp;공유할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;setState()&amp;nbsp;메서드&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태를&amp;nbsp;관리할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해주는&amp;nbsp;메서드&lt;/li&gt;
&lt;li&gt;useState&amp;nbsp;함수는&amp;nbsp;&lt;u&gt;배열을&amp;nbsp;반환&lt;/u&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;두&amp;nbsp;번째&amp;nbsp;요소는&amp;nbsp;상태를&amp;nbsp;업데이트하는&amp;nbsp;함수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;setState 호출은 비동기적으로 동작&lt;/u&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;/h3&gt;
&lt;pre id=&quot;code_1696758786071&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from 'react';
import './style.css';

export default function App() {
  const [number, setNumber] = useState(0);
  const add = () =&amp;gt; {
    setNumber(number + 1);
    console.log(number);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;div&amp;gt;{number}&amp;lt;/div&amp;gt;
      &amp;lt;button onClick={add}&amp;gt;+ 1&amp;lt;/button&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;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://stackblitz.com/edit/stackblitz-starters-ju7hzt?file=src%2FApp.js,src%2Findex.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/stackblitz-starters-ju7hzt?file=src%2FApp.js,src%2Findex.js&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;해당 코드는 문제 없이 잘 작동한다.&lt;br /&gt;하지만 개발자 도구에서 콘솔을 찍어보면 number 값이 한박자 늦게 찍히는 것을 볼 수 있다.&lt;br /&gt;즉, setNumber 함수는 비동기적으로 작동한다는 말이다.&lt;/blockquote&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI를 그리는 작업(렌더링)은 계산적 비용이 많이 드는 작업 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setState를 호출하면 React는 &lt;u&gt;즉시 컴포넌트 상태를 업데이트하거나 렌더링하지 않는다.&lt;/u&gt; React는 상태 업데이트를 예약하고, &lt;u&gt;여러 상태 업데이트를 모아서 &lt;span style=&quot;color: #ee2323;&quot;&gt;일괄&lt;/span&gt; 처리한 후, &lt;span style=&quot;color: #ee2323;&quot;&gt;단일 렌더링&lt;/span&gt;을 수행&lt;/u&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;setState는&amp;nbsp;성능&amp;nbsp;최적화를&amp;nbsp;위해&amp;nbsp;&lt;b&gt;&lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;상태&amp;nbsp;업데이트를&amp;nbsp;일괄&amp;nbsp;처리&lt;/span&gt;하여&amp;nbsp;비동기적으로&amp;nbsp;동작&lt;/u&gt;&lt;/b&gt;하며, 이러한 방식으로 호출된 setState가 바로 상태를 업데이트하지 않는 것이다.&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;</description>
      <category>프레임워크/React</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/139</guid>
      <comments>https://msm1307.tistory.com/139#entry139comment</comments>
      <pubDate>Sun, 8 Oct 2023 17:21:34 +0900</pubDate>
    </item>
    <item>
      <title>hombrew를 이용한 mysql 설치</title>
      <link>https://msm1307.tistory.com/138</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 설치&lt;/p&gt;
&lt;pre id=&quot;code_1696699474307&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install mysql&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;2. 서비스 실행&lt;/p&gt;
&lt;pre id=&quot;code_1696699506250&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew services start mysql&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;3. 접속&lt;/p&gt;
&lt;pre id=&quot;code_1696699517989&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -uroot&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;4. 서비스 종료&lt;/p&gt;
&lt;pre id=&quot;code_1696699542349&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew services stop mysql&lt;/code&gt;&lt;/pre&gt;</description>
      <category>database/Mysql</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/138</guid>
      <comments>https://msm1307.tistory.com/138#entry138comment</comments>
      <pubDate>Sun, 8 Oct 2023 02:26:19 +0900</pubDate>
    </item>
    <item>
      <title>react-router-dom v6 사용법</title>
      <link>https://msm1307.tistory.com/134</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;라우팅이란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가&amp;nbsp;요청한&amp;nbsp;URL&amp;nbsp;에&amp;nbsp;따라&amp;nbsp;해당&amp;nbsp;URL&amp;nbsp;에&amp;nbsp;맞는&amp;nbsp;페이지를&amp;nbsp;보여주는&amp;nbsp;것&lt;/li&gt;
&lt;li&gt;가장&amp;nbsp;많이&amp;nbsp;쓰이는&amp;nbsp;라이브러리?&amp;nbsp;React&amp;nbsp;Router&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;리액트 라우터(React Router)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자가&amp;nbsp;주소별로&amp;nbsp;다른컴포넌트를&amp;nbsp;보여주기&amp;nbsp;위해&amp;nbsp;사용하는&amp;nbsp;라이브러리&lt;/li&gt;
&lt;li&gt;여러&amp;nbsp;환경에서&amp;nbsp;동작할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;여러&amp;nbsp;종류의&amp;nbsp;라우터&amp;nbsp;컴포넌트&amp;nbsp;제공&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;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;BrowserRouter&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로고침을&amp;nbsp;하지&amp;nbsp;않아도&amp;nbsp;새로운&amp;nbsp;컴포넌트를&amp;nbsp;렌더링&amp;nbsp;해주는&amp;nbsp;기능&amp;nbsp;담당&lt;/li&gt;
&lt;li&gt;URL마다&amp;nbsp;컴포넌트가&amp;nbsp;바뀔&amp;nbsp;때&amp;nbsp;이때&amp;nbsp;바뀌는&amp;nbsp;부분의&amp;nbsp;최상단에&amp;nbsp;위치&amp;nbsp;해야&amp;nbsp;함&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;src/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1697462392239&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;BrowserRouter&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/BrowserRouter&amp;gt;
  &amp;lt;/React.StrictMode&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프레임워크/React</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/134</guid>
      <comments>https://msm1307.tistory.com/134#entry134comment</comments>
      <pubDate>Tue, 3 Oct 2023 03:41:10 +0900</pubDate>
    </item>
    <item>
      <title>[mysql] 'Your password does not satisfy the current policy requirements' 오류 해결 방법</title>
      <link>https://msm1307.tistory.com/131</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;오류가 뜨는 이유&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;비밀번호가 쉬워서&lt;/blockquote&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;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql 접속 후 아래 명령어 실행&lt;/p&gt;
&lt;pre id=&quot;code_1693280634178&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW VARIABLES LIKE 'validate_password%';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-29 12.39.43.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z0WH3/btssgonjJAD/odkKYFaclbBTuYNCtI9gZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z0WH3/btssgonjJAD/odkKYFaclbBTuYNCtI9gZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z0WH3/btssgonjJAD/odkKYFaclbBTuYNCtI9gZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ0WH3%2FbtssgonjJAD%2FodkKYFaclbBTuYNCtI9gZk%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;1212&quot; height=&quot;652&quot; data-filename=&quot;스크린샷 2023-08-29 12.39.43.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;652&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;u&gt;validate_password.policy&lt;/u&gt;가 &lt;b&gt;MEDIUM&lt;/b&gt; 인 경우 &lt;u&gt;숫자, 대문자, 소문자, 특수문자가 모두 포함된 validate_password.length 길이 만큼&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;u&gt;validate_password.policy&lt;/u&gt; 가 &lt;b&gt;LOW&lt;/b&gt; 인 경우는 &lt;u&gt;validate_password.length 길이만&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;pre id=&quot;code_1693280634179&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET GLOBAL validate_password.length=4;
SET GLOBAL validate_password.policy=LOW;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어 입력 후 다시 보안 규칙을 보면 아래처럼 바껴져있다.&lt;/p&gt;
&lt;pre id=&quot;code_1693280634180&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW VARIABLES LIKE 'validate_password%';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-29 12.40.38.png&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEwzCP/btssvZzaar3/hkiLIdniz3oQdgfKyXQNrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEwzCP/btssvZzaar3/hkiLIdniz3oQdgfKyXQNrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEwzCP/btssvZzaar3/hkiLIdniz3oQdgfKyXQNrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEwzCP%2FbtssvZzaar3%2FhkiLIdniz3oQdgfKyXQNrK%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;1174&quot; height=&quot;622&quot; data-filename=&quot;스크린샷 2023-08-29 12.40.38.png&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;622&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;이후에 아래 명령어를 입력해서 mysql 계정을 생성하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1693281303571&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password by '1234';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>database/Mysql</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/131</guid>
      <comments>https://msm1307.tistory.com/131#entry131comment</comments>
      <pubDate>Tue, 29 Aug 2023 12:55:20 +0900</pubDate>
    </item>
    <item>
      <title>[mysql] 계정 생성, 비밀번호 변경, 권한 부여</title>
      <link>https://msm1307.tistory.com/130</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;계정 생성&lt;/h2&gt;
&lt;pre id=&quot;code_1693279846596&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password by '1234';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://msm1307.tistory.com/entry/Your-password-does-not-satisfy-the-current-policy-requirements-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Your password does not satisfy the current policy requirements 오류 발생시&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;/h2&gt;
&lt;pre id=&quot;code_1693279931139&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password by '1234';&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;/h2&gt;
&lt;pre id=&quot;code_1693281546802&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>database/Mysql</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/130</guid>
      <comments>https://msm1307.tistory.com/130#entry130comment</comments>
      <pubDate>Tue, 29 Aug 2023 12:43:42 +0900</pubDate>
    </item>
    <item>
      <title>multer 사용법 (파일 업로드 미들웨어)</title>
      <link>https://msm1307.tistory.com/128</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;multer 란?&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;Node.js에서&amp;nbsp;파일&amp;nbsp;업로드를&amp;nbsp;처리하기&amp;nbsp;위해&amp;nbsp;사용되는&amp;nbsp;미들웨어&lt;/li&gt;
&lt;li&gt;express로&amp;nbsp;서버를&amp;nbsp;구축할&amp;nbsp;때&amp;nbsp;가장&amp;nbsp;많이&amp;nbsp;사용되는&amp;nbsp;미들웨어&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_1692880425667&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install multer express&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;사용법 - Form 태그&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;하나의&amp;nbsp;인풋에&amp;nbsp;하나의&amp;nbsp;파일을&amp;nbsp;업로드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693466093910&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;Single file upload&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;하나의 인풋에 하나의 파일을 업로드&amp;lt;/p&amp;gt;
  &amp;lt;!-- multer는 multipart가 아닌 폼에서는 동작하지 않음! 따라서 enctype=&quot;multipart/form-data&quot; 속성 필수~ --&amp;gt;
  &amp;lt;form action=&quot;/upload&quot; method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;userfile&quot; /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;button type=&quot;submit&quot;&amp;gt;업로드&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1692880571087&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const multer = require('multer');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

// multer 관련 설정
const upload = multer({
  // storage: 저장할 공간에 대한 정보
  // done(null, xx) 여기서 null은 error를 의미하는 매개변수
  // 에러가 없으므로 &quot;null&quot;이라고 전달하여 콜백 함수를 호출!
  storage: multer.diskStorage({
    destination(req, file, done) {
      // done: callback
      done(null, 'uploads/'); // 파일을 업로드할 경로 설정
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname); // 파일 &quot;확장자&quot;를 추출
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  // limits: 파일 제한 정보
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
});

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// 'userfile' = 클라이언트 &amp;lt;input type=&quot;file&quot; name=&quot;userfile&quot; /&amp;gt; 태그 name 값
app.post('/upload', upload.single('userfile'), (req, res) =&amp;gt; {
  console.log(req.body); // 파일 외의 정보들
  console.log(req.file); // 파일 업로드 정보
  // 파일 업로드 처리 후 응답
  res.send('파일 업로드 완료!');
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;하나의&amp;nbsp;인풋에&amp;nbsp;여러&amp;nbsp;개의&amp;nbsp;파일을&amp;nbsp;업로드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693468172532&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;Multi file upload v1&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;하나의 인풋에 여러 개의 파일을 업로드&amp;lt;/p&amp;gt;
  &amp;lt;form action=&quot;/upload/array&quot; method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;&amp;gt;
    &amp;lt;!-- 하나의 인풋에 여러 파일을 입력받고 싶다면 multiple 속성을 추가 --&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;userfiles&quot; multiple /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;button type=&quot;submit&quot;&amp;gt;업로드&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693468146033&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const multer = require('multer');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

// multer 관련 설정
const upload = multer({
  // storage: 저장할 공간에 대한 정보
  // done(null, xx) 여기서 null은 error를 의미하는 매개변수
  // 에러가 없으므로 &quot;null&quot;이라고 전달하여 콜백 함수를 호출!
  storage: multer.diskStorage({
    destination(req, file, done) {
      // done: callback
      done(null, 'uploads/'); // 파일을 업로드할 경로 설정
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname); // 파일 &quot;확장자&quot;를 추출
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  // limits: 파일 제한 정보
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
});

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

app.post('/upload/array', upload.array('userfiles'), (req, res) =&amp;gt; {
  console.log(req.files); // [ { 파일1_정보 }, { 파일2_정보 }, .. ] : 배열 형태로 각 파일 정보를 출력
  console.log(req.body);
  res.send('하나의 인풋에 여러 파일 업로드 완료!');
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;여러&amp;nbsp;인풋에&amp;nbsp;각각의&amp;nbsp;파일을&amp;nbsp;업로드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693468405353&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;Multi file upload v2&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;여러 인풋에 각각의 파일을 업로드&amp;lt;/p&amp;gt;
  &amp;lt;form action=&quot;/upload/fields&quot; method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;userfile1&quot; /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;userfile2&quot; /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;button type=&quot;submit&quot;&amp;gt;업로드&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693468432653&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const multer = require('multer');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

// multer 관련 설정
const upload = multer({
  // storage: 저장할 공간에 대한 정보
  // done(null, xx) 여기서 null은 error를 의미하는 매개변수
  // 에러가 없으므로 &quot;null&quot;이라고 전달하여 콜백 함수를 호출!
  storage: multer.diskStorage({
    destination(req, file, done) {
      // done: callback
      done(null, 'uploads/'); // 파일을 업로드할 경로 설정
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname); // 파일 &quot;확장자&quot;를 추출
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  // limits: 파일 제한 정보
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
});

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// fields() 매개 변수로 input 태그의 name을 각각 넣기
app.post('/upload/fields', upload.fields([{ name: 'userfile1' }, { name: 'userfile2' }]), (req, res) =&amp;gt; {
  console.log(req.files); // { userfile1: [ {파일_정보} ], userfile2: [ {파일_정보} ]} 객체 안에 배열 형태로 각 파일 정보
  console.log(req.body);
  res.send('하나의 인풋에 여러 파일 업로드 완료!');
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;사용법 - fetch API&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693469490320&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;동적 파일 업로드&amp;lt;/h1&amp;gt;
  &amp;lt;form&amp;gt;
    &amp;lt;input type=&quot;file&quot; name=&quot;dynamicUserfile&quot; id=&quot;dynamic-file&quot; /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;button type=&quot;submit&quot; class=&quot;btn&quot;&amp;gt;업로드&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
  &amp;lt;!-- 업로드한 이미지를 보여줄 img 태그 요소 --&amp;gt;
  &amp;lt;img src=&quot;&quot; alt=&quot;&quot; width=&quot;400&quot; /&amp;gt;
  &amp;lt;script&amp;gt;
    const btn = document.querySelector('.btn');

    btn.addEventListener('click', (e) =&amp;gt; {
      e.preventDefault();
      console.log('동적 파일 업로드');
      // js 만으로 폼을 전송 (파일데이터를 서버로 전송해야 하는 케이스)
      // FormData 객체를 활용하면 쉽게 전송 가능!
      const formData = new FormData();
      const file = document.querySelector('#dynamic-file');
      console.dir(file);
      console.dir(file.files); // 업로드한 파일 객체
      console.dir(file.files[0]); // 업로드한 첫 파일

      // append(key, value)
      formData.append('dynamicUserfile', file.files[0]);

      fetch('/dynamicFile', {
        method: 'post',
        header: {
          'Content-Type': 'multipart/form-data', // enctype=&quot;multipart/form-data&quot;
        },
        body: formData
      }).then((response) =&amp;gt; {
        return response.json();
      }).then((data) =&amp;gt; {
        console.log(data);
        document.querySelector('img').src = '/' + data.path;
      });
    });

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

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693469509501&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const multer = require('multer');
const app = express();
const PORT = 3000;
const path = require('path');

app.use('/uploads', express.static(__dirname + '/uploads'));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());

// multer 관련 설정
const upload = multer({
  // storage: 저장할 공간에 대한 정보
  // done(null, xx) 여기서 null은 error를 의미하는 매개변수
  // 에러가 없으므로 &quot;null&quot;이라고 전달하여 콜백 함수를 호출!
  storage: multer.diskStorage({
    destination(req, file, done) {
      // done: callback
      done(null, 'uploads/'); // 파일을 업로드할 경로 설정
    },
    filename(req, file, done) {
      const ext = path.extname(file.originalname); // 파일 &quot;확장자&quot;를 추출
      done(null, path.basename(file.originalname, ext) + Date.now() + ext);
    },
  }),
  // limits: 파일 제한 정보
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
});

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// 동적 폼 전송
app.post('/dynamicFile', upload.single('dynamicUserfile'), (req, res) =&amp;gt; {
  console.log(req.file);
  res.send(req.file);
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프레임워크/Express</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/128</guid>
      <comments>https://msm1307.tistory.com/128#entry128comment</comments>
      <pubDate>Thu, 24 Aug 2023 14:29:46 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript fetch와 axios 사용법</title>
      <link>https://msm1307.tistory.com/127</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Fetch&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;비동기 HTTP 통신으로 클라이언트에서 서버로 네트워크 요청을 보내고 응답을 받을 수 있도록 해주는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Web API&lt;/a&gt;&lt;/blockquote&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;브라우저에서 기본적으로 제공되는 API&lt;/u&gt;이므로 추가적인 라이브러리나 의존성 없이 사용 가능&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://msm1307.tistory.com/entry/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC#Promise-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Promise&lt;/a&gt; 기반&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저&amp;nbsp;호환성&amp;nbsp;문제&lt;/li&gt;
&lt;li&gt;axios에 비해 기능 부족
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;HTTP&amp;nbsp;에러&amp;nbsp;처리,&amp;nbsp;요청&amp;nbsp;취소&amp;nbsp;기능&amp;nbsp;등등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;nodejs 환경에서 사용 불가&lt;/u&gt;&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;size18&quot;&gt;&lt;b&gt;기본 구조&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692934746087&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(url, options)
	.then((response) =&amp;gt; console.log(response));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션(options)에 들어갈 중요 속성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;method : HTTP 요청 메서드 (GET,&amp;nbsp;POST,&amp;nbsp;PUT,&amp;nbsp;DELETE&amp;nbsp;등)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기본값은 GET&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;headers : HTTP&amp;nbsp;요청&amp;nbsp;헤더
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;객체나&amp;nbsp;String&amp;nbsp;값들을&amp;nbsp;가진&amp;nbsp;객체&amp;nbsp;리터럴로&amp;nbsp;제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;body : HTTP 요청에&amp;nbsp;추가하고자&amp;nbsp;하는&amp;nbsp;본문&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;fetch는 api 요청 시 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Response&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Response&lt;/a&gt; 객체를 반환한다.&lt;/blockquote&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;response 중요 속성 및 메서드&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;response.status&amp;nbsp;&amp;ndash;&amp;nbsp;HTTP&amp;nbsp;상태&amp;nbsp;코드&lt;/li&gt;
&lt;li&gt;response.ok - 응답의 성공 여부를 boolean값으로 나타냄
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;HTTP&amp;nbsp;상태&amp;nbsp;코드가&amp;nbsp;200과&amp;nbsp;299&amp;nbsp;사이일&amp;nbsp;경우&amp;nbsp;true&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;response.text()&amp;nbsp;&amp;ndash;&amp;nbsp;응답을&amp;nbsp;텍스트를&amp;nbsp;반환&lt;/li&gt;
&lt;li&gt;response.json()&amp;nbsp;&amp;ndash;&amp;nbsp;응답을&amp;nbsp;JSON&amp;nbsp;형태로&amp;nbsp;파싱한&amp;nbsp;결과로&amp;nbsp;반환&lt;/li&gt;
&lt;li&gt;response.formData()&amp;nbsp;&amp;ndash;&amp;nbsp;응답을&amp;nbsp;FormData&amp;nbsp;객체&amp;nbsp;형태로&amp;nbsp;반환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;get 방식&lt;/b&gt;&lt;/h3&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_1693099709536&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(url) // fetch는 get 방식이 기본으로 작동, options 생략 가능
  .then((response) =&amp;gt; {
    return response.json(); // 응답을 JSON 형태로 파싱한 결과로 반환
  })
  .then((data) =&amp;gt; {
    console.log(data); // 결과 출력
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', error);
  });&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;b&gt;post 방식&lt;/b&gt;&lt;/h3&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_1692875534958&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 보낼 데이터
const dataToSend = {
  title: '제목',
  body: '내용',
  userId: 1,
};

// POST 요청 보내기
fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(dataToSend),
  // js 객체를 json으로 변경
  // body의 데이터 유형은 반드시 &quot;Content-Type&quot; 헤더와 일치해야 함
})
  .then((response) =&amp;gt; {
    return response.json(); // 응답을 JSON 형태로 파싱한 결과로 반환
  })
  .then((data) =&amp;gt; {
    console.log(data); // 결과 출력
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', 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;Axios&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;비동기 HTTP 통신으로 클라이언트에서 서버로 네트워크 요청을 보내고 응답을 받을 수 있도록 해주는 라이브러리&lt;/blockquote&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;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;a href=&quot;https://msm1307.tistory.com/entry/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC#Promise-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Promise&lt;/a&gt; 기반&lt;/li&gt;
&lt;li&gt;브라우저와 nodejs 환경에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모듈 설치 or 호출을 해줘야 사용이 가능&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;axios 설치&lt;/p&gt;
&lt;pre id=&quot;code_1693107149828&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install axios&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios CDN&lt;/p&gt;
&lt;pre id=&quot;code_1693107282233&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 src=&quot;https://unpkg.com/axios/dist/axios.min.js&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;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;기본 구조&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1693112792132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios({
  url: '/user?ID=12345',
  method: 'get',
}).then((response) =&amp;gt; {
  console.log(response.data); // 서버가 제공하는 응답(데이터)
  console.log(response.status); // HTTP 상태 코드
  console.log(response.statusText); // HTTP 상태 메시지
  console.log(response.headers); // HTTP 헤더
  console.log(response.config); // 요청을 위해 'Axios'가 제공하는 구성
});&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;b&gt;get 방식&lt;/b&gt;&lt;/h3&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_1693112136406&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 방법 1
axios({
  url: '', // 통신하고자 하는 주소
  method: 'get', // HTTP 요청 메서드
  params: { query: '검색어' },
  // URL 파라미터
  // {key: value, key: value}로 작성
  // params 객체 대신 URL에 쿼리스트링과 함께 보낼 수 있음
})
  .then((response) =&amp;gt; {
    return response.data;
  })
  .then((data) =&amp;gt; {
    console.log(data);
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', error);
  });


// 방법 2
const options = {
  params: {
    query: '검색어',
  },
};

axios
  .get('url', options)
  .then((response) =&amp;gt; {
    return response.data;
  })
  .then((data) =&amp;gt; {
    console.log(data);
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', error);
  });&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;b&gt;post 방식&lt;/b&gt;&lt;/h3&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_1693113757650&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 방법 1
axios({
  url: '', // 통신하고자 하는 주소
  method: 'post', // HTTP 요청 메서드
  data: { userId: 'id', userPw: 'pw' },
  // {key: value, key: value}로 작성
  // method가 put, post, patch 일 때 사용
})
  .then((response) =&amp;gt; {
    return response.data;
  })
  .then((data) =&amp;gt; {
    console.log(data);
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', error);
  });


// 방법 2
const data = {
  userId: 'id',
  userPw: 'pw',
};

axios
  .post('url', data)
  .then((response) =&amp;gt; {
    return response.data;
  })
  .then((data) =&amp;gt; {
    console.log(data);
  })
  .catch((error) =&amp;gt; {
    console.error('오류 발생:', 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;실습&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;카카오 책 검색 Open API 사용해보기&lt;/b&gt;&lt;/h3&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://developers.kakao.com/docs/latest/ko/daum-search/dev-guide#search-book&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.kakao.com/docs/latest/ko/daum-search/dev-guide#search-book&lt;/a&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-27 14.41.21.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;1124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZKarf/btssfvzsN1A/jugie9wzDGD4zqXkrJCBzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZKarf/btssfvzsN1A/jugie9wzDGD4zqXkrJCBzK/img.png&quot; data-alt=&quot;카카오 책 검색 Open API 공식문서 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZKarf/btssfvzsN1A/jugie9wzDGD4zqXkrJCBzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZKarf%2FbtssfvzsN1A%2Fjugie9wzDGD4zqXkrJCBzK%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;926&quot; height=&quot;1124&quot; data-filename=&quot;스크린샷 2023-08-27 14.41.21.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;1124&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;카카오 책 검색 Open API 공식문서 이미지&lt;/figcaption&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch 버전&lt;/p&gt;
&lt;pre id=&quot;code_1693116838885&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const REST_API_KEY = '발급받은 REST_API_KEY';
const query = `?query=검색어`; // 검색어란에 원하는 값을 넣으면 됨

fetch(`https://dapi.kakao.com/v3/search/book${query}`, {
  method: 'get', // get method는 생략 가능
  headers: {
    Authorization: `KakaoAK ${REST_API_KEY}`,
  },
})
  .then((response) =&amp;gt; {
    return response.json();
  })
  .then((data) =&amp;gt; {
    console.log(data);
  });&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;axios 버전&lt;/p&gt;
&lt;pre id=&quot;code_1693117197691&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const REST_API_KEY = '발급받은 REST_API_KEY';
const options = {
  headers: {
    Authorization: `KakaoAK ${REST_API_KEY}`,
  },
  params: {
    query: '검색어',
  },
};

axios
  .get('https://dapi.kakao.com/v3/search/book', options)
  .then((response) =&amp;gt; {
    return response.data;
  })
  .then((data) =&amp;gt; {
    console.log(data);
  });&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;API_KEY 때문에 헷갈리는 경우가 있는데 헤더에 담아서 보내는 경우도 있고, URL 파라미터에 API 키를 같이 담아서 보내는 경우도 있다. 사이트마다 차이가 있는데 해당 사이트 공식문서에서 시키는 대로 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/127</guid>
      <comments>https://msm1307.tistory.com/127#entry127comment</comments>
      <pubDate>Tue, 22 Aug 2023 17:59:15 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript 비동기 처리</title>
      <link>https://msm1307.tistory.com/123</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;비동기 처리란?&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;특정&amp;nbsp;코드의&amp;nbsp;연산이&amp;nbsp;끝날&amp;nbsp;때까지&amp;nbsp;코드의&amp;nbsp;실행을&amp;nbsp;멈추지&amp;nbsp;않고&amp;nbsp;다음&amp;nbsp;코드를&amp;nbsp;먼저&amp;nbsp;실행하는&amp;nbsp;것을&amp;nbsp;비동기&amp;nbsp;처리라고&amp;nbsp;한다.&lt;/blockquote&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;i&gt;왜&amp;nbsp;비동기&amp;nbsp;처리일까?&lt;/i&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;/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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;비동기 코드를 처리하기 위한 3가지 방법&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;callback 함수&lt;/li&gt;
&lt;li&gt;promise&lt;/li&gt;
&lt;li&gt;async / await&lt;/li&gt;
&lt;/ol&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;callback(콜백) 함수&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;JavaScript는 함수를 인자로 받고 다른 함수를 통해 반환될 수 있는데, &lt;b&gt;인자(매개변수)로 대입되는 함수&lt;/b&gt;를 콜백함수라고 한다.&lt;/li&gt;
&lt;li&gt;즉, &lt;b&gt;다른 함수가 실행을 끝낸 뒤 실행되는 함수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;함수를 선언할 때는 parameter(인자, 매개변수)로 함수를 받아서 쓸 수 있다.&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;size18&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;/p&gt;
&lt;pre id=&quot;code_1692245373176&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const button = document.querySelector('button');
function sayHello() {
  console.log('hello~~~~');
}
button.addEventListener('click', sayHello);&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;독립적으로 수행되는 작업도 있는 반면 &lt;b&gt;응답을 받은 이후 처리되어야 하는 종속적인 작업&lt;/b&gt;도 있을 수 있으므로 그에 대한 대응 방법이 필요&lt;/blockquote&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;b&gt;callback 함수 사용 방법&lt;/b&gt;&lt;/h3&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;/p&gt;
&lt;pre id=&quot;code_1692247304861&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sum(x, y, callback) {
  const add = x + y;
  callback(add); // 콜백함수 호출
}

function print(result) {
  console.log(result); // sum 함수에서 넘어온 매개변수 출력
}

sum(1, 2, print); // 3&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;콜백함수.png&quot; data-origin-width=&quot;3338&quot; data-origin-height=&quot;1746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccJ7j0/btsrxplilje/Pi3JGH0Xo3BidHf8rKZ1UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccJ7j0/btsrxplilje/Pi3JGH0Xo3BidHf8rKZ1UK/img.png&quot; data-alt=&quot;콜백 함수 이해를 돕기 위한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccJ7j0/btsrxplilje/Pi3JGH0Xo3BidHf8rKZ1UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccJ7j0%2Fbtsrxplilje%2FPi3JGH0Xo3BidHf8rKZ1UK%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;3338&quot; height=&quot;1746&quot; data-filename=&quot;콜백함수.png&quot; data-origin-width=&quot;3338&quot; data-origin-height=&quot;1746&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;콜백 함수 이해를 돕기 위한 이미지&lt;/figcaption&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;Promise&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;비동기&amp;nbsp;방식으로&amp;nbsp;작성된&amp;nbsp;함수를&amp;nbsp;동기&amp;nbsp;방식처럼&amp;nbsp;순서대로&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;(하지만,&amp;nbsp;코드는&amp;nbsp;여전히&amp;nbsp;비동기&amp;nbsp;적으로&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Promise 사용 방법&lt;/b&gt;&lt;/h3&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;color: #8a3db6;&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #f89009;&quot;&gt;Promise&lt;/span&gt; 로 만들어서 사용!
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #f89009;&quot;&gt;Promise&lt;/span&gt;가 만들어질 때, &lt;u&gt;executor(실행 함수)가 자동&lt;/u&gt;으로 실행&lt;/li&gt;
&lt;li&gt;executor의 인수인 reject 와 resolve&lt;/li&gt;
&lt;li&gt;Promise가 생성되면 작업을 실행하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;작업의 완료 여부를 executor의 매개변수를 통해서 전달&lt;/u&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;executor 매개변수 (resolve와 reject 모두 callback)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;resolve&lt;/b&gt; : 비동기 작업이 성공했을 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;reject&lt;/b&gt; : 비동기 작업이 실패했을 때&lt;/li&gt;
&lt;/ul&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;b&gt;Promise의 상태&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Pending(대기)&lt;/b&gt; : Promise를 &lt;u&gt;수행 중인 상태&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fulfilled(이행)&lt;/b&gt; : Promise가 Resolve 된 상태 (&lt;u&gt;성공&lt;/u&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rejected(거부)&lt;/b&gt; : Promise가 지켜지지 못한 상태. Reject 된 상태 (&lt;u&gt;실패&lt;/u&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Settled&lt;/b&gt; : fulfilled 혹은 rejected로 &lt;u&gt;결론이 난 상태&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2023-08-16-1343.png&quot; data-origin-width=&quot;1631&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFVbpM/btsrsSBdxZM/Z63wzBdVKj0NxFgE4iZR81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFVbpM/btsrsSBdxZM/Z63wzBdVKj0NxFgE4iZR81/img.png&quot; data-alt=&quot;Promise의 상태를 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFVbpM/btsrsSBdxZM/Z63wzBdVKj0NxFgE4iZR81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFVbpM%2FbtsrsSBdxZM%2FZ63wzBdVKj0NxFgE4iZR81%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;1631&quot; height=&quot;873&quot; data-filename=&quot;제목 없음-2023-08-16-1343.png&quot; data-origin-width=&quot;1631&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Promise의 상태를 설명한 이미지&lt;/figcaption&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;b&gt;Promise 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;then&lt;/b&gt; : Promise가&amp;nbsp;&lt;u&gt;성공적으로&amp;nbsp;해결될&amp;nbsp;때&amp;nbsp;실행&lt;/u&gt;되는&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;등록하는&amp;nbsp;데&amp;nbsp;사용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이&amp;nbsp;메서드는&amp;nbsp;Promise가&amp;nbsp;해결될&amp;nbsp;때&amp;nbsp;그&amp;nbsp;결과값을&amp;nbsp;콜백&amp;nbsp;함수의&amp;nbsp;인자로&amp;nbsp;받아&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있음&lt;/li&gt;
&lt;li&gt;여러 개의 then 메서드를 체이닝하여 순차적으로 작업을 수행할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;앞에서 return 한 값을 다음 then에서 매개변수로 이어 받을 수 있음&lt;/u&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;catch&lt;/b&gt; : Promise에서&amp;nbsp;발생한&amp;nbsp;&lt;u&gt;오류를&amp;nbsp;처리&lt;/u&gt;하기&amp;nbsp;위한&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;등록하는&amp;nbsp;데&amp;nbsp;사용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Promise&amp;nbsp;체인에서&amp;nbsp;어떤&amp;nbsp;위치에서든&amp;nbsp;오류가&amp;nbsp;발생하면&amp;nbsp;해당&amp;nbsp;오류를&amp;nbsp;처리하고&amp;nbsp;계속&amp;nbsp;체인을&amp;nbsp;이어나갈&amp;nbsp;수&amp;nbsp;있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;finally&lt;/b&gt; : Promise가&amp;nbsp;&lt;u&gt;성공&amp;nbsp;또는&amp;nbsp;실패와&amp;nbsp;관계없이&amp;nbsp;마지막으로&amp;nbsp;실행&lt;/u&gt;되는&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;등록하는&amp;nbsp;데&amp;nbsp;사용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;네트워크&amp;nbsp;요청을&amp;nbsp;보낸&amp;nbsp;후에&amp;nbsp;무조건&amp;nbsp;수행되어야&amp;nbsp;하는&amp;nbsp;정리&amp;nbsp;작업이나&amp;nbsp;리소스&amp;nbsp;해제&amp;nbsp;작업을&amp;nbsp;처리할&amp;nbsp;때&amp;nbsp;유용&lt;/li&gt;
&lt;li&gt;Ex) loading... 여부 등등&lt;/li&gt;
&lt;/ul&gt;
&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_1692418300332&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function promise1(flag) {
  return new Promise(function (resolve, reject) {
    if (flag) {
      resolve('promise 상태는 fulfilled!! then으로 연결됩니다. \n 이때의 flag가 true입니다.');
    } else {
      reject('promise 상태는 rejected!! catch로 연결됩니다. \n 이때의 flag는 false입니다.');
    }
  });
}

promise1(true)
  .then((result) =&amp;gt; {
    console.log(result);
  })
  .catch((err) =&amp;gt; {
    console.log(err);
  })
  .finally(() =&amp;gt; {
    console.log('끝');
  });

// 결과
/*
  promise 상태는 fulfilled!! then으로 연결됩니다.
   이때의 flag가 true입니다.
  끝
*/

promise1(false)
  .then((result) =&amp;gt; {
    console.log(result);
  })
  .catch((err) =&amp;gt; {
    console.log(err);
  })
  .finally(() =&amp;gt; {
    console.log('끝');
  });

// 결과
/*
  promise 상태는 rejected!! catch로 연결됩니다.
   이때의 flag가 false입니다.
  끝
*/


/** 여러 개의 then 메서드를 체이닝 */
function promise2() {
  return new Promise(function (resolve, reject) {
    resolve(1);
  });
}

promise2()
  .then((result) =&amp;gt; {
    console.log(result); // 1
    return result * 2;
  })
  .then((result) =&amp;gt; {
    console.log(result); // 2
    return result * 2;
  })
  .then((result) =&amp;gt; {
    console.log(result); // 4
  });&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;Async&amp;nbsp;/&amp;nbsp;Await&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;프로미스&amp;nbsp;기반&amp;nbsp;코드를&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;쓰기&amp;nbsp;쉽고&amp;nbsp;읽기&amp;nbsp;쉽게&amp;nbsp;하기&amp;nbsp;위해&amp;nbsp;등장&lt;/li&gt;
&lt;li&gt;기능이&amp;nbsp;추가된&amp;nbsp;것이&amp;nbsp;아닌,&amp;nbsp;Promise를&amp;nbsp;다르게&amp;nbsp;사용하는&amp;nbsp;것&lt;/li&gt;
&lt;li&gt;에러는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;try...catch&lt;/a&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;b&gt;async&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 앞에 붙여 Promise를 반환&lt;/li&gt;
&lt;li&gt;프로미스가 아닌 값을 반환해도 프로미스로 감싸서 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;await&lt;/b&gt;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1692426329470&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function delay(ms) {
  return new Promise((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(ms);
    }, ms);
  });
}

async function print() {
  console.log('1'); // 1
  try {
    const result = await delay(1000); // 1초를 기다리고 반환값을 result라는 변수에 저장
    console.log(result); // 1000
  } catch (err) {
    console.log('Error!', err);
  }
  console.log('2'); // 2
}

print();

// 출력
/*
  1
  1000
  2
*/&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;b&gt;언제 어디서 어떻게 써야 할까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영화&amp;nbsp;API를&amp;nbsp;가지고&amp;nbsp;박스&amp;nbsp;오피스&amp;nbsp;영화&amp;nbsp;순위,&amp;nbsp;순위에&amp;nbsp;맞는&amp;nbsp;영화&amp;nbsp;정보와&amp;nbsp;영화&amp;nbsp;예고편을&amp;nbsp;보여주는&amp;nbsp;사이트를&amp;nbsp;만든다고&amp;nbsp;가정해보자.&lt;br /&gt;하지만 1개의 사이트에서 모든 정보를 제공하지 않는다. 찾아보니 3개의 API를 합치면 만들 수 있을 거 같다.&lt;br /&gt;A 사이트에서 박스 오피스 영화 순위를 제공, B 사이트는 영화 정보를 제공, C 사이트는 영화 예고편을 제공해 주는 API가 있다고 해보자.&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;A&amp;nbsp;사이트에서&amp;nbsp;박스&amp;nbsp;오피스&amp;nbsp;순위&amp;nbsp;정보를&amp;nbsp;가지고&amp;nbsp;와서&amp;nbsp;B와&amp;nbsp;C&amp;nbsp;사이트에&amp;nbsp;해당&amp;nbsp;영화&amp;nbsp;순위에&amp;nbsp;맞는&amp;nbsp;정보와&amp;nbsp;예고편을&amp;nbsp;API&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A&amp;nbsp;사이트에서&amp;nbsp;현재&amp;nbsp;박스&amp;nbsp;오피스&amp;nbsp;순위&amp;nbsp;정보를&amp;nbsp;가져온다.&lt;/li&gt;
&lt;li&gt;가져온&amp;nbsp;순위&amp;nbsp;정보에&amp;nbsp;따라&amp;nbsp;B&amp;nbsp;사이트와&amp;nbsp;C&amp;nbsp;사이트에&amp;nbsp;영화&amp;nbsp;정보와&amp;nbsp;예고편을&amp;nbsp;요청한다.&lt;/li&gt;
&lt;li&gt;B&amp;nbsp;사이트에서&amp;nbsp;해당&amp;nbsp;순위의&amp;nbsp;영화&amp;nbsp;정보를&amp;nbsp;받아오고,&amp;nbsp;C&amp;nbsp;사이트에서&amp;nbsp;해당&amp;nbsp;순위의&amp;nbsp;영화&amp;nbsp;예고편을&amp;nbsp;받아온다.&lt;/li&gt;
&lt;li&gt;받아온 영화 정보와 예고편을 화면에 그린다.&lt;/li&gt;
&lt;/ol&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;예시.png&quot; data-origin-width=&quot;1677&quot; data-origin-height=&quot;1531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qmfLd/btsryp01WA0/bm0eJX866ze1NL8r9lX6a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qmfLd/btsryp01WA0/bm0eJX866ze1NL8r9lX6a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qmfLd/btsryp01WA0/bm0eJX866ze1NL8r9lX6a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqmfLd%2Fbtsryp01WA0%2Fbm0eJX866ze1NL8r9lX6a1%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;1677&quot; height=&quot;1531&quot; data-filename=&quot;예시.png&quot; data-origin-width=&quot;1677&quot; data-origin-height=&quot;1531&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_1692514892193&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function getFromSiteA() {
  const url = '해당 사이트 url';
  const params = '가져올 정보';
  const response = await fetch(url + params);
  const data = await response.json();
  return data;
}

async function getFromSiteB(movieRankings) {
  const url = '해당 사이트 url';
  const dataList = [];
  for (const params of movieRankings) {
    const response = await fetch(url + params);
    const data = await response.json();
    dataList.push(data);
  }
  return dataList;
}

async function getFromSiteC(movieRankings) {
  const url = '해당 사이트 url';
  const dataList = [];
  for (const params of movieRankings) {
    const response = await fetch(url + params);
    const data = await response.json();
    dataList.push(data);
  }
  return dataList;
}

function displayMovieInfo(movieInfoList) {
  // 영화 정보를 그려주는 코드
}

function displayMovieTrailer(movieTrailerList) {
  // 영화 예고편을 그려주는 코드
}

async function main() {
  try {
    const movieRankings = await getFromSiteA(); // A 사이트에서 가져온 오피스 박스 순위를 movieRankings에 저장
    const movieInfoList = await getFromSiteB(movieRankings); // movieRankings 정보를 가지고 B 사이트에 정보 요청
    const movieTrailerList = await getFromSiteC(movieRankings); // movieRankings 정보를 가지고 C 사이트애 정보 요청

    displayMovieInfo(movieInfoList); // B 사이트에서 가져온 결과 값을 화면에 그려줌
    displayMovieTrailer(movieTrailerList); // C 사이트에서 가져온 결과 값을 화면에 그려줌
  } catch (err) {
    console.log('Error!', err);
  }
}

main();&lt;/code&gt;&lt;/pre&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;A 사이트에 정보를 요청하고 끝날 때까지 기다린다.&lt;/li&gt;
&lt;li&gt;A 사이트 응답이 끝나면 A 정보를 가지고 B 사이트에 정보를 요청하고 끝날 때까지 기다린다.&lt;/li&gt;
&lt;li&gt;B 사이트 응답이 끝나면 A 정보를 가지고 C 사이트에 정보를 요청하고 끝날 때까지 기다린다.&lt;/li&gt;
&lt;li&gt;C 사이트 응답이 끝나면 화면에 그려준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 정상 동작은 하는데 약간 아쉬움이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;B와 C는 서로 무관한데 getFromSiteC 함수를 쓰기 위해서는 getFromSiteB 함수가 끝날 때까지 기다려야 한다.&lt;br /&gt;즉, getFromSiteB 함수 요청 시간이 2초, getFromSiteC 함수 요청 시간이 5초 이면 총 7초를 기다려야 한다.&lt;/blockquote&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_1692516940275&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function getFromSiteA() {
  const url = '해당 사이트 url';
  const params = '가져올 정보';
  const response = await fetch(url + params);
  const data = await response.json();
  return data;
}

async function getFromSiteB(movieRankings) {
  const url = '해당 사이트 url';
  const dataList = [];
  for (const params of movieRankings) {
    const response = await fetch(url + params);
    const data = await response.json();
    dataList.push(data);
  }
  return dataList;
}

async function getFromSiteC(movieRankings) {
  const url = '해당 사이트 url';
  const dataList = [];
  for (const params of movieRankings) {
    const response = await fetch(url + params);
    const data = await response.json();
    dataList.push(data);
  }
  return dataList;
}

function displayMovieInfo(movieInfoList) {
  // 영화 정보를 그려주는 코드
}

function displayMovieTrailer(movieTrailerList) {
  // 영화 예고편을 그려주는 코드
}

async function main() {
  try {
    const movieRankings = await getFromSiteA(); // A 사이트에서 가져온 오피스 박스 순위를 movieRankings에 저장

    const [movieInfoList, movieTrailerList] = await Promise.all([
      getFromSiteB(movieRankings),
      getFromSiteC(movieRankings),
    ]);
    // movieRankings 정보를 가지고 B 사이트와 C 사이트에 동시에 요청을 한다. 두개 함수 중 늦게 끝나는 함수 기준으로 결과값을 반환
    // await Promise.all에서 리턴값으로 배열이 반환되는데 구조 분해를 통해 movieInfoList와 movieTrailerList 변수에 결과값을 대입한다.

    displayMovieInfo(movieInfoList); // B 사이트에서 가져온 결과 값을 화면에 그려줌
    displayMovieTrailer(movieTrailerList); // C 사이트에서 가져온 결과 값을 화면에 그려줌
  } catch (err) {
    console.log('Error!', err);
  }
}

main();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all&lt;/b&gt; 메서드를 사용하면 getFromSiteB 함수와 getFromSiteC 함수를 &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;위 코드를 순서대로 설명하면 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 사이트에 정보를 요청하고 끝날 때까지 기다린다.&lt;/li&gt;
&lt;li&gt;A 사이트 응답이 끝나면 A 정보를 가지고 B 사이트와 C 사이트에 &lt;u&gt;동시에 정보를 요청&lt;/u&gt;한다.&lt;/li&gt;
&lt;li&gt;B, C 사이트 중 응답이 늦게 끝나는 함수 기준으로 결과값을 반환한다.&lt;/li&gt;
&lt;li&gt;B, C 사이트 응답이 끝나면 화면에 그려준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, getFromSiteB 함수 요청시간이 2초, getFromSiteC 함수 요청 시간이 5초 이면 총 5초만 기다리면 된다.&lt;br /&gt;개선 이전 코드보다 2초를 더 줄일 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise.all 메서드 예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1692536050181&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function delay(ms, message) {
  return new Promise((resolve) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(message);
    }, ms);
  });
}

async function sequentialExecution() {
  console.time('순차적 실행');
  const result1 = await delay(2000, '첫번째');
  const result2 = await delay(5000, '두번째');
  console.log(result1, result2, '&amp;lt;&amp;lt;=== 순차적 실행');
  console.timeEnd('순차적 실행');
}

async function parallelExecutionWithPromiseAll() {
  console.time('Promise.all');
  const [result1, result2] = await Promise.all([delay(2000, '첫번째'), delay(5000, '두번째')]);
  console.log(result1, result2, '&amp;lt;&amp;lt;=== Promise.all');
  console.timeEnd('Promise.all');
}

sequentialExecution(); // 걸리는 시간 7초
parallelExecutionWithPromiseAll(); // 걸리는 시간 5초&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;span style=&quot;color: #ee2323;&quot;&gt;Promise.all 메서드를 사용 할 때에는, 등록한 프로미스 중 하나라도 실패하면, 모든게 실패 한 것으로 간주한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결 하려면 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Promise.allSettled&lt;/a&gt; 메서드를 참고하면 되겠다.&lt;/p&gt;</description>
      <category>JavaScript</category>
      <category>async/await</category>
      <category>javascript promise</category>
      <category>js promise</category>
      <category>Promise</category>
      <category>Promise all</category>
      <category>비동기 함수</category>
      <category>콜백 함수</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/123</guid>
      <comments>https://msm1307.tistory.com/123#entry123comment</comments>
      <pubDate>Thu, 17 Aug 2023 12:04:06 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript 배열 메서드 정리</title>
      <link>https://msm1307.tistory.com/122</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원본 배열 수정하는 메서드&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;push&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 끝에 하나 이상의 요소를 추가&lt;/p&gt;
&lt;pre id=&quot;code_1692077986578&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3];
originalArray.push(4, 5);
console.log(originalArray); // [1, 2, 3, 4, 5]&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;b&gt;pop&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의 마지막 요소를 제거하고 해당 요소를 반환&lt;/p&gt;
&lt;pre id=&quot;code_1692078346281&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3];
const removedElement = originalArray.pop(); // 3
console.log(removedElement); // 3
console.log(originalArray); // [1, 2]&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;b&gt;unshift&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의&amp;nbsp;시작&amp;nbsp;부분에&amp;nbsp;하나&amp;nbsp;이상의&amp;nbsp;요소를&amp;nbsp;추가&lt;/p&gt;
&lt;pre id=&quot;code_1692078468532&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [2, 3];
originalArray.unshift(1);
console.log(originalArray); // [1, 2, 3]&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;b&gt;shift&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;요소를&amp;nbsp;제거하고&amp;nbsp;해당&amp;nbsp;요소를&amp;nbsp;반환&lt;/p&gt;
&lt;pre id=&quot;code_1692078549143&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3];
const removedElement = originalArray.shift();
console.log(removedElement); // 1
console.log(originalArray); // [2, 3]&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;b&gt;splice&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열에서&amp;nbsp;요소를&amp;nbsp;제거하거나&amp;nbsp;새로운&amp;nbsp;요소를&amp;nbsp;삽입하여&amp;nbsp;배열을&amp;nbsp;수정&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;array.splice(start[, deleteCount[, addItem1[, addItem2[, ...]]]])&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;start : 배열의&amp;nbsp;변경을&amp;nbsp;시작할&amp;nbsp;인덱스
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;음수인&amp;nbsp;경우&amp;nbsp;배열의&amp;nbsp;끝에서부터&amp;nbsp;요소를&amp;nbsp;세어나감&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;deleteCount : 배열에서&amp;nbsp;제거할&amp;nbsp;요소의&amp;nbsp;수
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;0&amp;nbsp;이하라면&amp;nbsp;어떤&amp;nbsp;요소도&amp;nbsp;제거하지&amp;nbsp;않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;addItem : 배열에&amp;nbsp;추가할&amp;nbsp;요소
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;아무 요소도 지정하지 않으면 splice()는 요소를 제거하기만 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692079146463&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3, 4, 5];
originalArray.splice(1, 2); // [2, 3] 제거
console.log(originalArray); // [1, 4, 5]

originalArray.splice(1, 0, 6, 7); // 인덱스 1에 6과 7 삽입
console.log(originalArray); // [1, 6, 7, 4, 5]&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;b&gt;reverse&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의&amp;nbsp;요소&amp;nbsp;순서를&amp;nbsp;역순으로&amp;nbsp;변경&lt;/p&gt;
&lt;pre id=&quot;code_1692083010433&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 3, 2, 4];
originalArray.reverse();
console.log(originalArray); // [4, 2, 3, 1]&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;b&gt;sort&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열의&amp;nbsp;요소를&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;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 사이트&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;비교&amp;nbsp;함수를&amp;nbsp;제공하여&amp;nbsp;사용자&amp;nbsp;정의&amp;nbsp;정렬&amp;nbsp;기준을&amp;nbsp;설정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692083654765&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [3, 1, 2];
originalArray.sort((a, b) =&amp;gt; a - b);
console.log(originalArray); // [1, 2, 3] # 오름차순 정렬하기

originalArray.sort((a, b) =&amp;gt; b - a);
console.log(originalArray); // [3, 2, 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;원본&amp;nbsp;배열의&amp;nbsp;일부를&amp;nbsp;복사하여&amp;nbsp;새로운&amp;nbsp;배열을&amp;nbsp;반환하는 메서드&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;원본 배열은 변경되지 않는다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;slice&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본&amp;nbsp;배열의&amp;nbsp;일부를&amp;nbsp;추출하여&amp;nbsp;새&amp;nbsp;배열을&amp;nbsp;반환&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;arr.slice([begin[, end]])&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;begin : 시작점에 대한 인덱스
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;음수인 경우 배열의 끝에서부터 길이를&amp;nbsp;나타냄&lt;/li&gt;
&lt;li&gt;undefined인&amp;nbsp;경우에는,&amp;nbsp;0번&amp;nbsp;인덱스부터&amp;nbsp;시작&lt;/li&gt;
&lt;li&gt;배열의&amp;nbsp;길이보다&amp;nbsp;큰&amp;nbsp;경우에는,&amp;nbsp;빈&amp;nbsp;배열을&amp;nbsp;반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;end : 종료점에 대한 인덱스
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;u&gt;end&amp;nbsp;인덱스를&amp;nbsp;제외하고&amp;nbsp;추출&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;음수&amp;nbsp;인덱스는&amp;nbsp;배열의&amp;nbsp;끝에서부터의&amp;nbsp;길이를&amp;nbsp;나타냄&lt;/li&gt;
&lt;li&gt;end가&amp;nbsp;생략되면&amp;nbsp;배열의&amp;nbsp;끝까지&amp;nbsp;추출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1692088341489&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3, 4, 5];
const newArray = originalArray.slice(1, 4);
console.log(newArray); // [2, 3, 4]
console.log(originalArray); // [1, 2, 3, 4, 5]&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;b&gt;concat&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두&amp;nbsp;개&amp;nbsp;이상의&amp;nbsp;배열을&amp;nbsp;결합하여&amp;nbsp;새로운&amp;nbsp;배열을&amp;nbsp;반환&lt;/p&gt;
&lt;pre id=&quot;code_1692088556992&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const array1 = [1, 2];
const array2 = [3, 4];
const newArray = array1.concat(array2);
console.log(newArray); // [1, 2, 3, 4]
console.log(array1); // [1, 2]
console.log(array2); // [3, 4]&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;b&gt;filter&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에&amp;nbsp;따라&amp;nbsp;원본&amp;nbsp;배열의&amp;nbsp;일부&amp;nbsp;요소를&amp;nbsp;선택하여&amp;nbsp;새로운&amp;nbsp;배열을&amp;nbsp;반환&lt;/p&gt;
&lt;pre id=&quot;code_1692088943665&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3, 4, 5];
const filteredArray = originalArray.filter(item =&amp;gt; item &amp;gt; 2);
console.log(newArray); // [3, 4, 5]
console.log(originalArray); // [1, 2, 3, 4, 5]&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;b&gt;map&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본&amp;nbsp;배열의&amp;nbsp;각&amp;nbsp;요소를&amp;nbsp;변환하여&amp;nbsp;새로운&amp;nbsp;배열을&amp;nbsp;생성&lt;/p&gt;
&lt;pre id=&quot;code_1692089040469&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const originalArray = [1, 2, 3];
const newArray = originalArray.map(item =&amp;gt; item * 2);
console.log(newArray); // [2, 4, 6]
console.log(originalArray); // [1, 2, 3]&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 data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692156836870&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;Array - JavaScript | MDN&quot; data-og-description=&quot;JavaScript Array 클래스는 리스트 형태의 고수준 객체인 배열을 생성할 때 사용하는 전역 객체입니다.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ntjQO/hyTFkiq7ok/kVBoxNammTacefHtHjEl60/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ntjQO/hyTFkiq7ok/kVBoxNammTacefHtHjEl60/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;Array - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript Array 클래스는 리스트 형태의 고수준 객체인 배열을 생성할 때 사용하는 전역 객체입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&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;</description>
      <category>JavaScript</category>
      <category>javascript 배열</category>
      <category>javascript 배열 메서드</category>
      <category>js 배열 메서드</category>
      <category>js 배열 함수</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/122</guid>
      <comments>https://msm1307.tistory.com/122#entry122comment</comments>
      <pubDate>Tue, 15 Aug 2023 13:11:37 +0900</pubDate>
    </item>
    <item>
      <title>맥북 에어(M1) 듀얼 모니터 사용하기</title>
      <link>https://msm1307.tistory.com/121</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;맥북 에어(M1 칩) 듀얼 모니터 사용하기 (클램쉘 모드)&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;원래 M1 Pro 칩 이상부터 외장 모니터 수를 2대씩 지원하는데 M1 칩으로 듀얼 모니터를 사용하기 위해선 여러 방법이 있는데 그 중 한가지 방법을 소개함&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-15-09-21-45.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p4Luf/btsrhFayMc9/E41tR9mN9fihJyD6KS8Ak1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p4Luf/btsrhFayMc9/E41tR9mN9fihJyD6KS8Ak1/img.jpg&quot; data-alt=&quot;맥북 에어 듀얼모니터 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p4Luf/btsrhFayMc9/E41tR9mN9fihJyD6KS8Ak1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp4Luf%2FbtsrhFayMc9%2FE41tR9mN9fihJyD6KS8Ak1%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;4032&quot; height=&quot;3024&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-15-09-21-45.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;맥북 에어 듀얼모니터 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;준비물&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;USB 3.0 이상 지원이 되고 HDMI가 있는&amp;nbsp; 멀티 허브&lt;/li&gt;
&lt;li&gt;외장 모니터 2대&lt;/li&gt;
&lt;li&gt;HDMI 디스플레이 아댑터 변환젠더 (NEXT-JUA354)&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;b&gt;NEXT-JUA354&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_KakaoTalk_Photo_2023-08-15-10-48-40 001.jpeg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1071&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c020UN/btsrdiHsgVR/Oqw9LfXGzTSpexYD6pCKzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c020UN/btsrdiHsgVR/Oqw9LfXGzTSpexYD6pCKzk/img.png&quot; data-alt=&quot;NEXT-JUA354 제품 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c020UN/btsrdiHsgVR/Oqw9LfXGzTSpexYD6pCKzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc020UN%2FbtsrdiHsgVR%2FOqw9LfXGzTSpexYD6pCKzk%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;1000&quot; height=&quot;1071&quot; data-filename=&quot;edited_edited_KakaoTalk_Photo_2023-08-15-10-48-40 001.jpeg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1071&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NEXT-JUA354 제품 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;해당 제품은 4K 30Hz 또는 1080p 60Hz를 지원한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 모니터는 QHD(1440p) 한대와 1080 모니터 한대여서 4K는 체험해보지 못했다.&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;USB 3.0 포트에 JUA354 연결하기&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sU9vp/btsrcuA9Stc/vHvM3EatVOqDsfeVNaFXd1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sU9vp/btsrcuA9Stc/vHvM3EatVOqDsfeVNaFXd1/img.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-15-10-48-41 004.jpeg&quot; data-is-animation=&quot;false&quot; style=&quot;width: 63.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sU9vp/btsrcuA9Stc/vHvM3EatVOqDsfeVNaFXd1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsU9vp%2FbtsrcuA9Stc%2FvHvM3EatVOqDsfeVNaFXd1%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;4032&quot; height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FjG8J/btsrfhBx2xK/OOgyPZ57kqFTlRQ4ASRDG1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FjG8J/btsrfhBx2xK/OOgyPZ57kqFTlRQ4ASRDG1/img.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;KakaoTalk_Photo_2023-08-15-10-48-42 007.jpeg&quot; style=&quot;width: 35.5814%;&quot; data-widthpercent=&quot;36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FjG8J/btsrfhBx2xK/OOgyPZ57kqFTlRQ4ASRDG1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFjG8J%2FbtsrfhBx2xK%2FOOgyPZ57kqFTlRQ4ASRDG1%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;3024&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;USB 3.0 포트에 JUA354 제품을 연결한 이미지&lt;/figcaption&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;JUA354&amp;nbsp;드라이버&amp;nbsp;다운로드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.j5create.com/pages/drivers/#jua354-show&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.j5create.com/pages/drivers/#jua354-show&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692064757874&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;Drivers &amp;amp; Downloads - j5create&quot; data-og-description=&quot;Download the latest drivers, manuals, quick install guides, and view important updates for your j5create products.&quot; data-og-host=&quot;en.j5create.com&quot; data-og-source-url=&quot;https://en.j5create.com/pages/drivers/#jua354-show&quot; data-og-url=&quot;https://en.j5create.com/pages/drivers&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/i0XKA/hyTCHMTKWi/ZqfC5HQec9DnnAIjLu4Rk0/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bxgf4s/hyTFbr1LKC/KLWWhFDBHRYlU7RLfDIQq0/img.jpg?width=900&amp;amp;height=912&amp;amp;face=0_0_900_912,https://scrap.kakaocdn.net/dn/bJBNrV/hyTFnMLFwl/lDQrDVNZzK7d5NtgDPupp0/img.jpg?width=900&amp;amp;height=900&amp;amp;face=0_0_900_900&quot;&gt;&lt;a href=&quot;https://en.j5create.com/pages/drivers/#jua354-show&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.j5create.com/pages/drivers/#jua354-show&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/i0XKA/hyTCHMTKWi/ZqfC5HQec9DnnAIjLu4Rk0/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bxgf4s/hyTFbr1LKC/KLWWhFDBHRYlU7RLfDIQq0/img.jpg?width=900&amp;amp;height=912&amp;amp;face=0_0_900_912,https://scrap.kakaocdn.net/dn/bJBNrV/hyTFnMLFwl/lDQrDVNZzK7d5NtgDPupp0/img.jpg?width=900&amp;amp;height=900&amp;amp;face=0_0_900_900');&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;Drivers &amp;amp; Downloads - j5create&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Download the latest drivers, manuals, quick install guides, and view important updates for your j5create products.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.j5create.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-15 11.00.02.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;865&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzOkD4/btsrgnnYZKO/QTD5sBVJXOchZkrgkCM5u0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzOkD4/btsrgnnYZKO/QTD5sBVJXOchZkrgkCM5u0/img.png&quot; data-alt=&quot;JUA354 드라이버 다운로드 사이트 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzOkD4/btsrgnnYZKO/QTD5sBVJXOchZkrgkCM5u0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzOkD4%2FbtsrgnnYZKO%2FQTD5sBVJXOchZkrgkCM5u0%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;970&quot; height=&quot;865&quot; data-filename=&quot;스크린샷 2023-08-15 11.00.02.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;865&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JUA354 드라이버 다운로드 사이트 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;위 링크에 들어가서 해당 맥북 버전에 맞는 드라이버 다운로드 후 맥북 재실행&lt;br /&gt;&lt;u&gt;&lt;/u&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kS0Lm/btsq7cVg4zJ/SHZnXKI4396O4kPoDfqISK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kS0Lm/btsq7cVg4zJ/SHZnXKI4396O4kPoDfqISK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;917&quot; data-origin-height=&quot;432&quot; data-filename=&quot;스크린샷 2023-08-15 11.38.15.png&quot; style=&quot;width: 59.4802%; margin-right: 10px;&quot; data-widthpercent=&quot;60.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kS0Lm/btsq7cVg4zJ/SHZnXKI4396O4kPoDfqISK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkS0Lm%2Fbtsq7cVg4zJ%2FSHZnXKI4396O4kPoDfqISK%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;917&quot; height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSwtVP/btsrawlDtPv/zueSKEdnkRR4XUzxCqMNe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSwtVP/btsrawlDtPv/zueSKEdnkRR4XUzxCqMNe1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;440&quot; data-filename=&quot;스크린샷 2023-08-15 11.38.31.png&quot; style=&quot;width: 39.357%;&quot; data-widthpercent=&quot;39.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSwtVP/btsrawlDtPv/zueSKEdnkRR4XUzxCqMNe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSwtVP%2FbtsrawlDtPv%2FzueSKEdnkRR4XUzxCqMNe1%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;618&quot; height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;드라이브 설치 과정 이미지&lt;/figcaption&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;i&gt;맥북 버전 확인 방법&lt;/i&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;/li&gt;
&lt;li&gt;이 Mac에 관하여(About This Mac) 클릭&lt;/li&gt;
&lt;li&gt;macOS 버전 확인&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;설치 후 시스템 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 설치 후 맥북을 재실행하고, 응용프로그램에 USB Display Device 라는 프로그램을 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE5dzZ/btsq5Z2RLEP/ULsIjIVykzFVkL5CHDsAtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE5dzZ/btsq5Z2RLEP/ULsIjIVykzFVkL5CHDsAtK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;229&quot; data-filename=&quot;스크린샷 2023-08-15 11.39.44.png&quot; data-widthpercent=&quot;8.57&quot; style=&quot;width: 8.46643%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE5dzZ/btsq5Z2RLEP/ULsIjIVykzFVkL5CHDsAtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE5dzZ%2Fbtsq5Z2RLEP%2FULsIjIVykzFVkL5CHDsAtK%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;269&quot; height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k2vsY/btsrf5gKPro/NJvlZG2dneHS4Q4I5MMgJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k2vsY/btsrf5gKPro/NJvlZG2dneHS4Q4I5MMgJK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;326&quot; data-origin-height=&quot;26&quot; data-filename=&quot;스크린샷 2023-08-15 11.53.41.png&quot; style=&quot;width: 90.3708%;&quot; data-widthpercent=&quot;91.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k2vsY/btsrf5gKPro/NJvlZG2dneHS4Q4I5MMgJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk2vsY%2Fbtsrf5gKPro%2FNJvlZG2dneHS4Q4I5MMgJK%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;326&quot; height=&quot;26&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;JUA354 프로그램 이미지&lt;/figcaption&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;위 이미지에서 빨간색 동그라미를 친 부분을 클릭하고 Show Diagnostics... 버튼을 클릭&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-15 12.19.03.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buJN95/btsq5Zhr1Tm/kKYKPp5UKaJX1ft4nLzZ3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buJN95/btsq5Zhr1Tm/kKYKPp5UKaJX1ft4nLzZ3K/img.png&quot; data-alt=&quot;JUA354 프로그램 실행 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buJN95/btsq5Zhr1Tm/kKYKPp5UKaJX1ft4nLzZ3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuJN95%2Fbtsq5Zhr1Tm%2FkKYKPp5UKaJX1ft4nLzZ3K%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;1002&quot; height=&quot;501&quot; data-filename=&quot;스크린샷 2023-08-15 12.19.03.png&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JUA354 프로그램 실행 이미지&lt;/figcaption&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tym1Q/btsrf3pI7p0/CcElSwq3lM28D3MGeIkUPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tym1Q/btsrf3pI7p0/CcElSwq3lM28D3MGeIkUPK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;628&quot; data-filename=&quot;스크린샷 2023-08-15 11.47.46.png&quot; data-widthpercent=&quot;42.02&quot; style=&quot;width: 41.5351%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tym1Q/btsrf3pI7p0/CcElSwq3lM28D3MGeIkUPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftym1Q%2Fbtsrf3pI7p0%2FCcElSwq3lM28D3MGeIkUPK%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;718&quot; height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGr5u6/btsrgnuKopa/nBK2fPwaOFp3NIpT6s2kUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGr5u6/btsrgnuKopa/nBK2fPwaOFp3NIpT6s2kUk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;291&quot; data-filename=&quot;스크린샷 2023-08-15 12.20.01.png&quot; style=&quot;width: 57.3021%;&quot; data-widthpercent=&quot;57.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGr5u6/btsrgnuKopa/nBK2fPwaOFp3NIpT6s2kUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGr5u6%2FbtsrgnuKopa%2FnBK2fPwaOFp3NIpT6s2kUk%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;459&quot; height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CLH6n/btsraweV0sl/22Q4TejKZ4Vo8SoZbSZKQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CLH6n/btsraweV0sl/22Q4TejKZ4Vo8SoZbSZKQK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;167&quot; data-filename=&quot;스크린샷 2023-08-15 12.20.12.png&quot; style=&quot;width: 69.6497%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;70.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CLH6n/btsraweV0sl/22Q4TejKZ4Vo8SoZbSZKQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCLH6n%2FbtsraweV0sl%2F22Q4TejKZ4Vo8SoZbSZKQK%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;457&quot; height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTSlO3/btsq8Jk6Ay9/5QQI28vscDk88qocygiJbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTSlO3/btsq8Jk6Ay9/5QQI28vscDk88qocygiJbK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;620&quot; data-filename=&quot;스크린샷 2023-08-15 11.48.24.png&quot; style=&quot;width: 29.1875%; margin-top: 10px;&quot; data-widthpercent=&quot;29.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTSlO3/btsq8Jk6Ay9/5QQI28vscDk88qocygiJbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTSlO3%2Fbtsq8Jk6Ay9%2F5QQI28vscDk88qocygiJbK%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;711&quot; height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;프로그램 설정에 관한 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&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;좌측 상단 애플로고 - &lt;b&gt;시스템 설정&lt;/b&gt; - &lt;b&gt;개인정보 보호 및 보안&lt;/b&gt; (밑으로 쭉 스크롤 후 &lt;b&gt;세부사항...&lt;/b&gt; 클릭)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;USB Display Device 버튼 활성화&lt;/b&gt;하고 확인&lt;/li&gt;
&lt;li&gt;화면 기록 알람창이 뜨면 &lt;b&gt;시스템 설정 열기&lt;/b&gt; 버튼 클릭&lt;/li&gt;
&lt;li&gt;화면 기록에서 &lt;b&gt;DJTVirtualDisplayAgent 버튼 활성화&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;맥북 &lt;b&gt;재실행&lt;/b&gt;&lt;/li&gt;
&lt;/ol&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;&lt;b&gt;맥북 에어(M1 칩) 듀얼 모니터 &lt;/b&gt;연결 후 장,&amp;nbsp; 단점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저렴한 가격으로 외장 모니터 2대 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;넷플릭스나 쿠팡 플레이 시청시 소리만 나옴 (외장 모니터 1개 빼야 볼 수 있음) | 유튜브는 잘나옴&lt;/li&gt;
&lt;li&gt;보조 모니터로 쓰기엔 적합하나 주 모니터로 쓰기에는 약간 버벅임? 현상이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결론 : 맥북을 클램쉘 모드 사용해서 2개의 모니터를 쓸거면 맥 미니가 낫지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;제품&amp;nbsp; 링크&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;USB 3.0 지원 가능한 멀티 허브&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/6QCkN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://link.coupang.com/a/6QCkN&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692072148276&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;애니포트 5포트 C타입 맥북 삼성 덱스 미러링 멀티포트 USB 허브 AP-TC51PH&quot; data-og-description=&quot;COUPANG&quot; data-og-host=&quot;www.coupang.com&quot; data-og-source-url=&quot;https://link.coupang.com/a/6QCkN&quot; data-og-url=&quot;https://www.coupang.com/vp/products/6427397919&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iLtTp/hyTFevxNFP/v3vHUa0o9aSAdQKHskp0Tk/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230,https://scrap.kakaocdn.net/dn/daJuqh/hyTFebewzh/Xj8KWswAG0TU1WVqczUs1k/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/6QCkN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://link.coupang.com/a/6QCkN&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iLtTp/hyTFevxNFP/v3vHUa0o9aSAdQKHskp0Tk/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230,https://scrap.kakaocdn.net/dn/daJuqh/hyTFebewzh/Xj8KWswAG0TU1WVqczUs1k/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230');&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;애니포트 5포트 C타입 맥북 삼성 덱스 미러링 멀티포트 USB 허브 AP-TC51PH&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;COUPANG&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.coupang.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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NEXT-JUA354&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/6QDDr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://link.coupang.com/a/6QDDr&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692072323073&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;넥스트 USB3.0 to 4K HDMI 디스플레이 아답터 변환젠더&quot; data-og-description=&quot;COUPANG&quot; data-og-host=&quot;www.coupang.com&quot; data-og-source-url=&quot;https://link.coupang.com/a/6QDDr&quot; data-og-url=&quot;https://www.coupang.com/vp/products/1767550159&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jWCSh/hyTCE3HWlj/kMrkq7JjAXGFKr1NB7D25K/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230,https://scrap.kakaocdn.net/dn/bcaDsq/hyTCF9oIAo/JRDdl9WgXYBzsUEGy7ytc1/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230&quot;&gt;&lt;a href=&quot;https://link.coupang.com/a/6QDDr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://link.coupang.com/a/6QDDr&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jWCSh/hyTCE3HWlj/kMrkq7JjAXGFKr1NB7D25K/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230,https://scrap.kakaocdn.net/dn/bcaDsq/hyTCF9oIAo/JRDdl9WgXYBzsUEGy7ytc1/img.jpg?width=230&amp;amp;height=230&amp;amp;face=0_0_230_230');&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;넥스트 USB3.0 to 4K HDMI 디스플레이 아답터 변환젠더&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;COUPANG&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.coupang.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;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;이&amp;nbsp;포스팅은&amp;nbsp;쿠팡&amp;nbsp;파트너스&amp;nbsp;활동의&amp;nbsp;일환으로,&amp;nbsp;이에&amp;nbsp;따른&amp;nbsp;일정액의&amp;nbsp;수수료를&amp;nbsp;제공받습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>JUA354</category>
      <category>M1 듀얼 모니터</category>
      <category>맥북 듀얼 모니터</category>
      <category>맥북 에어 듀얼 모니터</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/121</guid>
      <comments>https://msm1307.tistory.com/121#entry121comment</comments>
      <pubDate>Tue, 15 Aug 2023 10:51:25 +0900</pubDate>
    </item>
    <item>
      <title>[새싹x코딩온] 웹 개발자 부트캠프 4주차 | Express</title>
      <link>https://msm1307.tistory.com/120</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Express란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NodeJS를&amp;nbsp;사용하여&amp;nbsp;쉽게&lt;b&gt;&amp;nbsp;웹 서버를 생성&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;웹 애플리케이션을 만들기 위한 각종 메소드와 미들웨어 등이 내장되어 있다.&lt;/li&gt;
&lt;li&gt;라우팅,&amp;nbsp;인증,&amp;nbsp;데이터베이스&amp;nbsp;연결,&amp;nbsp;에러&amp;nbsp;처리&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;기능을&amp;nbsp;제공한다.&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;Express 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1691961225778&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install express&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;Express 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1691961515299&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
// Node.js의 CommonJS 모듈 시스템을 사용하여 'express' 모듈을 가져옴

const app = express();
// express() 함수를 호출하여 새로운 Express 애플리케이션 객체 app을 만듦

const PORT = 8000;
// 서버가 사용할 포트 번호를 8000으로 설정

app.get('/', function (req, res) {
// '/' 경로로 들어오는 GET 요청을 처리
  res.send('hello express');
  // 응답 객체의 send 메서드를 사용하여 클라이언트로 'hello express' 문자열을 보냄
});


app.listen(PORT, function () {
// 서버를 시작하고 포트 8000에서 수신 대기하도록 설정
  console.log(`Listening on port ${PORT}! http://localhost:${PORT}`);
});&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;/p&gt;
&lt;pre id=&quot;code_1691984079500&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node app.js&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;b&gt;Express 미들웨어&lt;/b&gt;&lt;/h3&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;b&gt;중간 과정을 함수로 분리&lt;/b&gt;한 것&lt;/li&gt;
&lt;li&gt;&lt;u&gt;서버와 클라이언트를 이어주는&lt;/u&gt; 중간 작업&lt;/li&gt;
&lt;li&gt;&lt;b&gt;use() 를 이용해 등록&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;middleware.png&quot; data-origin-width=&quot;2403&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOS7eS/btssht8Bwua/xp0ysEzcqddZ76EZLW8pD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOS7eS/btssht8Bwua/xp0ysEzcqddZ76EZLW8pD1/img.png&quot; data-alt=&quot;미들웨어를 설명하는 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOS7eS/btssht8Bwua/xp0ysEzcqddZ76EZLW8pD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOS7eS%2Fbtssht8Bwua%2Fxp0ysEzcqddZ76EZLW8pD1%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;2403&quot; height=&quot;724&quot; data-filename=&quot;middleware.png&quot; data-origin-width=&quot;2403&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미들웨어를 설명하는 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;쉽게 말해 클라이언트와 서버 사이에서 통역사 역할을 해준다고 보면 된다.&lt;/blockquote&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;클라이언트로부터&amp;nbsp;오는&amp;nbsp;요청&amp;nbsp;데이터를&amp;nbsp;서버에서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;형식으로&amp;nbsp;파싱하는&amp;nbsp;역할&lt;/p&gt;
&lt;pre id=&quot;code_1693460456304&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use(express.urlencoded({ extended: true })); // URL 인코딩된 데이터 파싱
app.use(express.json()); // JSON 데이터 파싱&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;파일을&amp;nbsp;제공하기&amp;nbsp;위해&amp;nbsp;사용&lt;/p&gt;
&lt;pre id=&quot;code_1693460926622&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use('/public', express.static(__dirname + '/static'));
// /public 경로로 들어오는 요청을 현재 파일의 디렉토리에 위치한 'static' 디렉토리 안의 정적 파일로 제공하도록 설정합니다.
// 이렇게 함으로써 예를 들어 이미지 파일이나 다른 정적 파일들을 웹 브라우저에서 직접 접근할 수 있게 됩니다.&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;b&gt;클라이언트와 서버 데이터 전송 방법&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;form 태그 이용 방법&lt;/b&gt;&lt;/h4&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;b&gt;GET 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693461782905&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;GET 방식&amp;lt;/h1&amp;gt;
  &amp;lt;form action=&quot;/getForm&quot; method=&quot;get&quot;&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;id&quot; placeholder=&quot;ID&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;password&quot; name=&quot;pw&quot; placeholder=&quot;PW&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;제출&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693461825461&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// GET 방식은 클라이언트에서 보낸 데이터가 req.query에 저장
app.get('/getForm', (req, res) =&amp;gt; {
  console.log(req.query);
  res.send(req.query);
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;b&gt;POST 방식&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;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693462557814&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;POST 방식&amp;lt;/h1&amp;gt;
  &amp;lt;form action=&quot;/postForm&quot; method=&quot;post&quot;&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;id&quot; placeholder=&quot;ID&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;password&quot; name=&quot;pw&quot; placeholder=&quot;PW&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;제출&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693462574889&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// POST 방식은 클라이언트에서 보낸 데이터가 req.body에 저장
app.post('/postForm', (req, res) =&amp;gt; {
  console.log(req.body);
  res.send(req.body);
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;fetch API 이용 방법&lt;/h4&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;b&gt;GET 방식&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;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693463871549&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;GET 방식&amp;lt;/h1&amp;gt;
  &amp;lt;form class=&quot;form&quot;&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;id&quot; placeholder=&quot;ID&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;password&quot; name=&quot;pw&quot; placeholder=&quot;PW&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;button type=&quot;submit&quot; class=&quot;btn&quot;&amp;gt;제출&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;

  &amp;lt;script&amp;gt;
    const btn = document.querySelector('.btn');

    btn.addEventListener('click', (e) =&amp;gt; {
      e.preventDefault();
      const form = document.querySelector('.form');
      const id = form.id.value;
      const pw = form.pw.value;
      const query = `?id=${id}&amp;amp;pw=${pw}`;

      fetch(`/getFetch${query}`).then((response) =&amp;gt; {
        return response.json();
      }).then((data) =&amp;gt; {
        console.log(data);
      })
    })
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693463914411&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// GET 방식은 클라이언트에서 보낸 데이터가 req.query에 저장
app.get('/getFetch', (req, res) =&amp;gt; {
  console.log(req.query);
  res.send(req.query);
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;b&gt;POST 방식&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;views/index.html&lt;/p&gt;
&lt;pre id=&quot;code_1693464198476&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
  &amp;lt;title&amp;gt;폼 전송&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;POST 방식&amp;lt;/h1&amp;gt;
  &amp;lt;form class=&quot;form&quot;&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;id&quot; placeholder=&quot;ID&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;password&quot; name=&quot;pw&quot; placeholder=&quot;PW&quot; required /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;button type=&quot;submit&quot; class=&quot;btn&quot;&amp;gt;제출&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;

  &amp;lt;script&amp;gt;
    const btn = document.querySelector('.btn');

    btn.addEventListener('click', (e) =&amp;gt; {
      e.preventDefault();
      const form = document.querySelector('.form');
      const id = form.id.value;
      const pw = form.pw.value;

      const data = {
        id,
        pw,
      };

      fetch(`/postFetch`, {
        method: 'post',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
      }).then((response) =&amp;gt; {
        return response.json();
      }).then((data) =&amp;gt; {
        console.log(data);
      })
    })
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&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;app.js&lt;/p&gt;
&lt;pre id=&quot;code_1693464218024&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const app = express();
const PORT = 3000;
const path = require('path');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname + '/views/index.html'));
});

// post 방식은 클라이언트에서 보낸 데이터가 req.body에 저장
app.post('/postFetch', (req, res) =&amp;gt; {
  console.log(req.body);
  res.send(req.body);
});

app.listen(PORT, () =&amp;gt; {
  console.log('연결 성공');
});&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-31 오후 3.10.56.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxry6E/btsswVkVuRo/ktqYkv6yrOf9K59xJ6pNHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxry6E/btsswVkVuRo/ktqYkv6yrOf9K59xJ6pNHk/img.png&quot; data-alt=&quot;요청 성공 결과 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxry6E/btsswVkVuRo/ktqYkv6yrOf9K59xJ6pNHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcxry6E%2FbtsswVkVuRo%2FktqYkv6yrOf9K59xJ6pNHk%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;1214&quot; height=&quot;190&quot; data-filename=&quot;스크린샷 2023-08-31 오후 3.10.56.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요청 성공 결과 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>새싹x코딩온 웹 개발자 부트캠프</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/120</guid>
      <comments>https://msm1307.tistory.com/120#entry120comment</comments>
      <pubDate>Mon, 14 Aug 2023 06:26:17 +0900</pubDate>
    </item>
    <item>
      <title>Git 대용량 파일 저장 방법</title>
      <link>https://msm1307.tistory.com/118</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Git에 대용량 파일 저장하는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#&amp;nbsp;Git&amp;nbsp;LFS&amp;nbsp;설치&lt;/p&gt;
&lt;pre id=&quot;code_1691377174753&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install git-lfs&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691377137326&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git lfs install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;#&amp;nbsp;대용량&amp;nbsp;파일&amp;nbsp;LFS로&amp;nbsp;추적&lt;/p&gt;
&lt;pre id=&quot;code_1691377185193&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git lfs track &quot;assets/video/iphone77.mp4&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&quot;*.확장자명&quot; 해주면 모든 확장자 파일을 추가 할 수 있다.&lt;/blockquote&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;/p&gt;
&lt;pre id=&quot;code_1691377270019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git add .gitattributes
git commit -m &quot;Track large video file with LFS&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;#&amp;nbsp;변경사항&amp;nbsp;푸시&lt;/p&gt;
&lt;pre id=&quot;code_1691377276677&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git push origin main&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;Git에 대용량 파일 다운로드하는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#&amp;nbsp;Git&amp;nbsp;LFS&amp;nbsp;설치&lt;/p&gt;
&lt;pre id=&quot;code_1691377339362&quot; class=&quot;mipsasm&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install git-lfs&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691377339363&quot; class=&quot;cmake&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git lfs install&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;파일&amp;nbsp;받아오기&lt;/p&gt;
&lt;pre id=&quot;code_1691377374450&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git lfs fetch
git lfs checkout&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Git</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/118</guid>
      <comments>https://msm1307.tistory.com/118#entry118comment</comments>
      <pubDate>Mon, 7 Aug 2023 00:11:45 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] display: flex (flexbox) 정리</title>
      <link>https://msm1307.tistory.com/116</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;flexbox의 등장 배경&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;기존의&amp;nbsp;CSS&amp;nbsp;레이아웃&amp;nbsp;방법은&amp;nbsp;복잡하고&amp;nbsp;어려움&lt;/li&gt;
&lt;li&gt;기존의&amp;nbsp;CSS&amp;nbsp;레이아웃&amp;nbsp;방법은&amp;nbsp;유연성이&amp;nbsp;부족&lt;/li&gt;
&lt;li&gt;모바일&amp;nbsp;웹의&amp;nbsp;등장으로&amp;nbsp;유동적인&amp;nbsp;레이아웃이&amp;nbsp;필요&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;flexbox를 제외한 속성들로 아래 이미지 레이아웃을 코드로 작성해보자&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-29 03.41.39.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/upIgO/btspk8zKeBW/G70YtUYyB3o06RKUyLpz0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/upIgO/btspk8zKeBW/G70YtUYyB3o06RKUyLpz0k/img.png&quot; data-alt=&quot;header 레이아웃 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/upIgO/btspk8zKeBW/G70YtUYyB3o06RKUyLpz0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FupIgO%2Fbtspk8zKeBW%2FG70YtUYyB3o06RKUyLpz0k%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;1113&quot; height=&quot;67&quot; data-filename=&quot;스크린샷 2023-07-29 03.41.39.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;67&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;header 레이아웃 이미지&lt;/figcaption&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_1690573823037&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;style&amp;gt;
      * {
        list-style: none;
        padding: 0;
        margin: 0;
      }
      header {
        background-color: gainsboro;
        padding: 0px 20px;
      }
      header .wrap {
        position: relative;
        line-height: 50px;
        text-align: center;
      }
      header .wrap .logo,
      header .wrap .login {
        position: absolute;
        top: 0;
        bottom: 0;
      }
      header .wrap .logo {
        left: 0;
      }
      header .wrap .login {
        right: 0;
      }
      header .wrap nav {
        display: inline-block;
      }
      header .wrap .menus li {
        display: inline-block;
        margin: 0 10px;
      }
      header a {
        color: #000;
        text-decoration: none;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;div class=&quot;wrap&quot;&amp;gt;
        &amp;lt;div class=&quot;logo&quot;&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;로고&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;nav&amp;gt;
          &amp;lt;ul class=&quot;menus&quot;&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU3&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;/ul&amp;gt;
        &amp;lt;/nav&amp;gt;
        &amp;lt;div class=&quot;login&quot;&amp;gt;
          &amp;lt;a href=&quot;#&quot;&amp;gt;로그인&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/header&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;위 코드가 정답은 아니지만 이렇게 간단한 레이아웃을 짜는데도 복잡해진다.&lt;br /&gt;&lt;u&gt;나중 flexbox를 배우고 난 이후에 해당 코드와 비교해보자.&lt;/u&gt;&lt;br /&gt;TMI&lt;br /&gt;나는 이전 회사가 지방자치단체, 교육기관 홈페이지 개발 위주였는데 퍼블리싱 할 때마다 flex를 못쓰게 해서(IE9까지 맞춰야 됨) 눈물 흘리면서 코드를 짰다. 반응형 들어갈 때는 콧물까지 흐른 기억이 난다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;flexbox의 기본 용어&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;flex-container&lt;/b&gt;: flex&amp;nbsp;속성을&amp;nbsp;갖는&amp;nbsp;요소로&amp;nbsp;flex&amp;nbsp;부모&amp;nbsp;요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;flex-items&lt;/b&gt;: flex&amp;nbsp;속성을&amp;nbsp;갖는&amp;nbsp;요소의&amp;nbsp;자식&amp;nbsp;요소들로&amp;nbsp;flex&amp;nbsp;자식&amp;nbsp;요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;container1.png&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;963&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z9GDM/btspsUAT76y/S2o30bwknMyQQtLizSM4Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z9GDM/btspsUAT76y/S2o30bwknMyQQtLizSM4Bk/img.png&quot; data-alt=&quot;flex-container와 flex-items를 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z9GDM/btspsUAT76y/S2o30bwknMyQQtLizSM4Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ9GDM%2FbtspsUAT76y%2FS2o30bwknMyQQtLizSM4Bk%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;1382&quot; height=&quot;963&quot; data-filename=&quot;container1.png&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;963&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flex-container와 flex-items를 설명한 이미지&lt;/figcaption&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;size18&quot;&gt;&lt;b&gt;주축 (main axis)&lt;/b&gt;: 아이템의&amp;nbsp;배치&amp;nbsp;방향의&amp;nbsp;축&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;교차축&amp;nbsp;(cross&amp;nbsp;axis)&lt;/b&gt;: 주축의 수직축&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 이미지는 아이템들이 &lt;b&gt;수평&lt;/b&gt;으로 있을 때 주축과 교차축&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;axis1-1.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnMG1C/btspsUHC0TG/vGVR6htDy6qR7epfeXoBfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnMG1C/btspsUHC0TG/vGVR6htDy6qR7epfeXoBfk/img.png&quot; data-alt=&quot;아이템들이 수평으로 있을 때 주축과 교차축 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnMG1C/btspsUHC0TG/vGVR6htDy6qR7epfeXoBfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnMG1C%2FbtspsUHC0TG%2FvGVR6htDy6qR7epfeXoBfk%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;1668&quot; height=&quot;733&quot; data-filename=&quot;axis1-1.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아이템들이 수평으로 있을 때 주축과 교차축 설명한 이미지&lt;/figcaption&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;아래 이미지는 아이템들이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;수직&lt;/b&gt;으로 있을 때 주축과 교차축&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;axis1-2.png&quot; data-origin-width=&quot;1287&quot; data-origin-height=&quot;1005&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo7EI3/btspBzplU39/2mWIErKM4sRZ4tCGNrWo50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo7EI3/btspBzplU39/2mWIErKM4sRZ4tCGNrWo50/img.png&quot; data-alt=&quot;아이템들이 수직으로 있을 때 주축과 교차축을 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo7EI3/btspBzplU39/2mWIErKM4sRZ4tCGNrWo50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo7EI3%2FbtspBzplU39%2F2mWIErKM4sRZ4tCGNrWo50%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;1287&quot; height=&quot;1005&quot; data-filename=&quot;axis1-2.png&quot; data-origin-width=&quot;1287&quot; data-origin-height=&quot;1005&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아이템들이 수직으로 있을 때 주축과 교차축을 설명한 이미지&lt;/figcaption&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;flexbox의 속성&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;flexbox 컨테이너에 적용하는 속성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;flexbox 속성을 사용하기 위해선 우선 컨테이너에 display: flex를 설정해 주셔야 아래 속성들을 사용 가능합나다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690704721948&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        height: 100vh;
        display: flex;
        /* 여기에 아래 속성들 들어갈 자리 */
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
      }
      .container .item2 {
        background-color: orange;
      }
      .container .item3 {
        background-color: yellow;
      }
      .container .item4 {
        background-color: green;
      }
      .container .item5 {
        background-color: blueviolet;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item4&quot;&amp;gt;4&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item5&quot;&amp;gt;5&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;flex-direction&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이템들이&amp;nbsp;배치되는&amp;nbsp;방향을&amp;nbsp;설정&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;b&gt;row&lt;/b&gt;(default): 수평&amp;nbsp;정렬&amp;nbsp;(좌&amp;nbsp;&amp;rarr;&amp;nbsp;우)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;row-reverse&lt;/b&gt;: 수평&amp;nbsp;정렬&amp;nbsp;(우&amp;nbsp;&amp;rarr;&amp;nbsp;좌)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;column&lt;/b&gt;:&amp;nbsp;수직&amp;nbsp;정렬(위&amp;nbsp;&amp;rarr;&amp;nbsp;아래)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;column-reverse&lt;/b&gt;:&amp;nbsp;수직&amp;nbsp;정렬&amp;nbsp;(아래&amp;nbsp;&amp;rarr;&amp;nbsp;위)&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
  .custom .container {
    width: 100%;
    height: 500px;
    background-color: skyblue;
  }
  .custom .item {
    width: 80px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    color: #000;
  }
  .custom .item1 {
    background-color: red;
  }
  .custom .item2 {
    background-color: orange;
  }
  .custom .item3 {
    background-color: yellow;
  }
  .custom .item4 {
    background-color: green;
  }
  .custom .item5 {
    background-color: blueviolet;
  }

  @media (max-width: 800px) {
    div.custom .container {
      height: 400px;
    }
    div.custom .item {
      width: 60px;
      height: 60px;
      line-height: 60px;
    }
  }
  @media (max-width: 640px) {
    div.custom .container {
      height: 300px;
    }
    div.custom .item {
      width: 40px;
      height: 40px;
      line-height: 40px;
    }
  }

  .custom [type='radio']:checked,
  .custom [type='radio']:not(:checked) {
    position: absolute;
    left: -9999px;
  }
  .custom [type='radio']:checked + label,
  .custom [type='radio']:not(:checked) + label {
    position: relative;
    padding-left: 28px;
    cursor: pointer;
    line-height: 20px;
    display: inline-block;
  }
  .custom [type='radio']:checked + label:before,
  .custom [type='radio']:not(:checked) + label:before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    width: 18px;
    height: 18px;
    border: 1px solid #ddd;
    border-radius: 100%;
    background: #fff;
  }
  .custom [type='radio']:checked + label:after,
  .custom [type='radio']:not(:checked) + label:after {
    content: '';
    width: 12px;
    height: 12px;
    background: rgb(93, 176, 215);
    position: absolute;
    top: 3px;
    left: 3px;
    border-radius: 100%;
    -webkit-transition: all 0.2s ease;
    transition: all 0.2s ease;
  }
  .custom [type='radio']:not(:checked) + label:after {
    opacity: 0;
    -webkit-transform: scale(0);
    transform: scale(0);
  }
  .custom [type='radio']:checked + label:after {
    opacity: 1;
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  .custom [type='radio']:not(:checked) + label {
    color: rgb(189, 189, 189);
  }

  .custom .style {
    margin-bottom: 20px;
  }
  .custom .style span + span {
    margin-left: 5px;
  }
  .custom.ex2 .container {
    display: flex;
  }
  .custom.ex2 .style {
    position: relative;
  }
  .custom.ex2 .style .value {
    margin-left: 115px;
  }
  .custom.ex2 .style .attr {
    position: absolute;
  }

  .custom.ex2 .wrap {
    position: relative;
    padding: 40px;
  }

  .custom.ex2 .axis {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
  .custom.ex2 .axis .arrow,
  .custom.ex2 .axis .arrow {
    background-color: #1971c2;
    position: relative;
  }
  .custom.ex2 .axis .main-axis {
    color: #1971c2;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: absolute;
    top: -8px;
    left: 40px;
  }
  .custom.ex2 .axis .main-axis .arrow {
    width: 200px;
    height: 2px;
  }
  .custom.ex2 .axis .main-axis span {
    display: block;
  }

  .custom.ex2 .axis .main-axis .arrow::after {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    content: '';
    width: 10px; /* 사이즈 */
    height: 10px; /* 사이즈 */
    border-top: 2px solid #1971c2; /* 선 두께 */
    border-right: 2px solid #1971c2; /* 선 두께 */
    transform: rotate(45deg); /* 각도 */
  }

  .custom.ex2 .axis .cross-axis {
    color: #1971c2;
    display: flex;
    align-items: center;
    position: absolute;
    top: 40px;
    left: -6px;
  }

  .custom.ex2 .axis .cross-axis .arrow {
    width: 2px;
    height: 200px;
  }

  .custom.ex2 .axis .cross-axis span {
    display: block;
    writing-mode: vertical-lr;
    text-orientation: sideways;
    transform: scale(-1);
  }

  .custom.ex2 .axis .cross-axis .arrow::after {
    position: absolute;
    bottom: 0;
    left: -4px;
    content: '';
    width: 10px;
    height: 10px;
    border-top: 2px solid #1971c2;
    border-right: 2px solid #1971c2;
    transform: rotate(135deg);
  }

  /* row-reverse 방향 */
  .custom.ex2 .row-reverse .axis .main-axis {
    left: auto;
    right: 40px;
  }
  .custom.ex2 .row-reverse .axis .main-axis .arrow {
    transform: scaleX(-1);
  }
  .custom.ex2 .row-reverse .axis .cross-axis {
    left: auto;
    right: -6px;
    transform: scaleX(-1);
  }
  .custom.ex2 .row-reverse .axis .cross-axis span {
    transform: scaleX(-1);
  }

  /* column 방향 */
  .custom.ex2 .column .axis .main-axis {
    flex-direction: row;
    top: 40px;
    left: -6px;
  }
  .custom.ex2 .column .axis .main-axis .arrow {
    width: 2px;
    height: 200px;
  }

  .custom.ex2 .column .axis .main-axis span {
    display: block;
    writing-mode: vertical-lr;
    text-orientation: sideways;
    transform: scale(-1);
  }

  .custom.ex2 .column .axis .main-axis .arrow::after {
    top: auto;
    bottom: 0;
    left: -4px;
    transform: rotate(135deg);
  }

  .custom.ex2 .column .axis .cross-axis {
    flex-direction: column;
    top: -8px;
    left: 40px;
  }

  .custom.ex2 .column .axis .cross-axis .arrow {
    width: 200px;
    height: 2px;
  }

  .custom.ex2 .column .axis .cross-axis span {
    writing-mode: initial;
    text-orientation: sideways;
    transform: initial;
  }

  .custom.ex2 .column .axis .cross-axis .arrow::after {
    transform: rotate(45deg);
    top: 0;
    left: auto;
    right: 0;
    bottom: 0;
    margin: auto;
  }
  /* column-reverse 방향 */
  .custom.ex2 .column-reverse .axis .main-axis {
    flex-direction: row;
    top: auto;
    bottom: 40px;
    left: -6px;
    transform: scaleY(-1);
  }
  .custom.ex2 .column-reverse .axis .main-axis .arrow {
    width: 2px;
    height: 200px;
  }

  .custom.ex2 .column-reverse .axis .main-axis span {
    display: block;
    writing-mode: vertical-lr;
    text-orientation: sideways;
    transform: scaleX(-1);
  }

  .custom.ex2 .column-reverse .axis .main-axis .arrow::after {
    top: auto;
    bottom: 0;
    left: -4px;
    transform: rotate(135deg);
  }

  .custom.ex2 .column-reverse .axis .cross-axis {
    flex-direction: column;
    top: auto;
    bottom: -8px;
    left: 40px;
    row-gap: 4px;
  }

  .custom.ex2 .column-reverse .axis .cross-axis .arrow {
    width: 200px;
    height: 2px;
  }

  .custom.ex2 .column-reverse .axis .cross-axis span {
    writing-mode: initial;
    text-orientation: sideways;
    transform: initial;
    order: 1;
  }

  .custom.ex2 .column-reverse .axis .cross-axis .arrow::after {
    transform: rotate(45deg);
    top: 0;
    left: auto;
    right: 0;
    bottom: 0;
    margin: auto;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex2&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;flex-direction:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;row&quot; name=&quot;flex-direction&quot; value=&quot;row&quot; checked /&gt;
        &lt;label for=&quot;row&quot;&gt;row;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;row-reverse&quot; name=&quot;flex-direction&quot; value=&quot;row-reverse&quot; /&gt;
        &lt;label for=&quot;row-reverse&quot;&gt;row-reverse;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;column&quot; name=&quot;flex-direction&quot; value=&quot;column&quot; /&gt;
        &lt;label for=&quot;column&quot;&gt;column;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;column-reverse&quot; name=&quot;flex-direction&quot; value=&quot;column-reverse&quot; /&gt;
        &lt;label for=&quot;column-reverse&quot;&gt;column-reverse;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;wrap row&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
      &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
      &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
      &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
      &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
      &lt;div class=&quot;axis&quot;&gt;
        &lt;div class=&quot;main-axis&quot;&gt;
          &lt;span&gt;주축 (main axis)&lt;/span&gt;
          &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&quot;cross-axis&quot;&gt;
          &lt;span&gt;교차축 (cross axis)&lt;/span&gt;
          &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom2 = document.querySelector('.custom.ex2');
  const container2 = custom2.querySelector('.container');
  const radioBtn2 = custom2.querySelectorAll('input');
  const wrap = custom2.querySelector('.wrap');
  radioBtn2.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom2.querySelector('input[name=&quot;flex-direction&quot;]:checked').value;
      container2.style.flexDirection = value;
      wrap.className = `wrap ${value}`;
    });
  });
&lt;/script&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;justify-content&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;flex-start&lt;/b&gt;(default): 아이템들을 시작점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction 속성이 row(수평)일 때는 왼쪽, column(수직)일 때는 위&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-end&lt;/b&gt;: 아이템들을 끝점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction이&amp;nbsp;row(수평)일&amp;nbsp;때는&amp;nbsp;오른쪽,&amp;nbsp;column(수직)일&amp;nbsp;때는&amp;nbsp;아래&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;center&lt;/b&gt;: 아이템들을 가운데로 정렬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-between&lt;/b&gt;: 양쪽 여백을 없애고 나머지 아이템들이 공간을 나누어 갖는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-around&lt;/b&gt;: 아이템들의 여백을 모두 공평하게 나누어 갖는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-evenly&lt;/b&gt;: 모든 아이템들의 간격이 일정&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
  .custom.ex3 .container {
    display: flex;
    height: 150px;
  }
  .custom.ex3 .style {
    position: relative;
  }
  .custom.ex3 .style .value {
    margin-left: 125px;
  }
  .custom.ex3 .style .attr {
    position: absolute;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex3&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;justify-content:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;flex-start&quot; name=&quot;justify-content&quot; value=&quot;flex-start&quot; checked /&gt;
        &lt;label for=&quot;flex-start&quot;&gt;flex-start;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;flex-end&quot; name=&quot;justify-content&quot; value=&quot;flex-end&quot; /&gt;
        &lt;label for=&quot;flex-end&quot;&gt;flex-end;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;center&quot; name=&quot;justify-content&quot; value=&quot;center&quot; /&gt;
        &lt;label for=&quot;center&quot;&gt;center;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;space-between&quot; name=&quot;justify-content&quot; value=&quot;space-between&quot; /&gt;
        &lt;label for=&quot;space-between&quot;&gt;space-between;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;space-around&quot; name=&quot;justify-content&quot; value=&quot;space-around&quot; /&gt;
        &lt;label for=&quot;space-around&quot;&gt;space-around;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;space-evenly&quot; name=&quot;justify-content&quot; value=&quot;space-evenly&quot; /&gt;
        &lt;label for=&quot;space-evenly&quot;&gt;space-evenly;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
    &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom3 = document.querySelector('.custom.ex3');
  const container3 = custom3.querySelector('.container');
  const radioBtn3 = custom3.querySelectorAll('input');
  radioBtn3.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom3.querySelector('input[name=&quot;justify-content&quot;]:checked').value;
      container3.style.justifyContent = value;
    });
  });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;space-around와 space-evenly의 차이점&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLP4h7/btspmhcwZSp/jDG3FaSBfFQQJadI4eWnL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLP4h7/btspmhcwZSp/jDG3FaSBfFQQJadI4eWnL1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1636&quot; data-origin-height=&quot;416&quot; data-filename=&quot;space-around.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLP4h7/btspmhcwZSp/jDG3FaSBfFQQJadI4eWnL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLP4h7%2FbtspmhcwZSp%2FjDG3FaSBfFQQJadI4eWnL1%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;1636&quot; height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPUVjC/btsplpWJb4p/VlmNFcnSlwqw87twlNhB4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPUVjC/btsplpWJb4p/VlmNFcnSlwqw87twlNhB4k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1636&quot; data-origin-height=&quot;416&quot; data-filename=&quot;space-evenly.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPUVjC/btsplpWJb4p/VlmNFcnSlwqw87twlNhB4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPUVjC%2FbtsplpWJb4p%2FVlmNFcnSlwqw87twlNhB4k%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;1636&quot; height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;space-around와 space-evenly의 차이를 설명한 이미지&lt;/figcaption&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;align-items&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교차&amp;nbsp;축을&amp;nbsp;따라&amp;nbsp;아이템들을&amp;nbsp;어떻게&amp;nbsp;정렬할지&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;b&gt;stretch&lt;/b&gt;(default): &lt;u&gt;아이템 크기 설정이 없으면&lt;/u&gt; 부모 요소의 세로 크기를 따라 확장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-start&lt;/b&gt;: 아이템들을 시작점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction 속성이 row(수평)일 때는 위, column(수직)일 때는 왼쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-end&lt;/b&gt;: 아이템들을 끝점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction이 row(수평)일 때는 아래, column(수직)일 때는 오른쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;center&lt;/b&gt;: 아이템들을 가운데로 정렬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;baseline&lt;/b&gt;: 아이템 텍스트 baseline 기준으로 정렬&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
  .custom.ex4 .container {
    display: flex;
    height: 300px;
  }
  .custom.ex4 .item {
    padding: 30px;
    width: auto;
    height: auto;
  }
  @media (max-width: 800px) {
    div.custom.ex4 .item {
      padding: 20px;
    }
  }
  .custom.ex4 .item3 {
    font-size: 40px;
  }
  .custom.ex4 .item5 {
    font-size: 30px;
  }

  .custom.ex4 .style {
    position: relative;
  }
  .custom.ex4 .style .value {
    margin-left: 100px;
  }
  .custom.ex4 .style .attr {
    position: absolute;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex4&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;align-items:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ai-stretch&quot; name=&quot;align-items&quot; value=&quot;stretch&quot; checked /&gt;
        &lt;label for=&quot;ai-stretch&quot;&gt;stretch;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ai-flex-start&quot; name=&quot;align-items&quot; value=&quot;flex-start&quot; /&gt;
        &lt;label for=&quot;ai-flex-start&quot;&gt;flex-start;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ai-flex-end&quot; name=&quot;align-items&quot; value=&quot;flex-end&quot; /&gt;
        &lt;label for=&quot;ai-flex-end&quot;&gt;flex-end;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ai-center&quot; name=&quot;align-items&quot; value=&quot;center&quot; /&gt;
        &lt;label for=&quot;ai-center&quot;&gt;center;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ai-baseline&quot; name=&quot;align-items&quot; value=&quot;baseline&quot; /&gt;
        &lt;label for=&quot;ai-baseline&quot;&gt;baseline;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
    &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom4 = document.querySelector('.custom.ex4');
  const container4 = custom4.querySelector('.container');
  const radioBtn4 = custom4.querySelectorAll('input');
  radioBtn4.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom4.querySelector('input[name=&quot;align-items&quot;]:checked').value;
      container4.style.alignItems = value;
    });
  });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;baseline 이해하기 쉬운 이미지&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_baseline.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7TeTd/btsppHIzJif/k2OHfwhCYdN1OuE3rXYDZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7TeTd/btsppHIzJif/k2OHfwhCYdN1OuE3rXYDZ1/img.png&quot; data-alt=&quot;baseline 설명 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7TeTd/btsppHIzJif/k2OHfwhCYdN1OuE3rXYDZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7TeTd%2FbtsppHIzJif%2Fk2OHfwhCYdN1OuE3rXYDZ1%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;884&quot; height=&quot;438&quot; data-filename=&quot;edited_baseline.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;baseline 설명 이미지&lt;/figcaption&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;flex-wrap&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너(부모)가&amp;nbsp;한&amp;nbsp;줄에&amp;nbsp;아이템을&amp;nbsp;다&amp;nbsp;수용하지&amp;nbsp;못할&amp;nbsp;때,&amp;nbsp;줄바꿈&amp;nbsp;관련&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;b&gt;nowrap&lt;/b&gt;(default): 줄 바꿈 하지 않고 넘치면 삐져 나감&lt;/li&gt;
&lt;li&gt;&lt;b&gt;wrap&lt;/b&gt;: 넘치면 줄 바꿈함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;wrap-reverse&lt;/b&gt;: 넘치면 역순으로 줄 바꿈&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;wrap, wrap-reverse에서 드래그바를 움직여 보세요.&lt;/blockquote&gt;
&lt;style&gt;
  .custom.ex5 .container {
    display: flex;
    position: relative;
    max-width: 100%;
  }
  .custom.ex5 .container .resize {
    position: absolute;
    top: 0;
    right: 0;
    width: 4px;
    height: 100%;
    background-color: #000;
  }
  .custom.ex5 .container .resize::before {
    position: absolute;
    top: -27px;
    right: -5px;
    content: '드래그바 ↓';
    z-index: -1;
    width: max-content;
    color: #874747;
  }
  .custom.ex5 .container .resize:hover {
    cursor: col-resize;
  }

  .custom.ex5 .style {
    position: relative;
  }
  .custom.ex5 .style .value {
    margin-left: 85px;
  }
  .custom.ex5 .style .attr {
    position: absolute;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex5&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;flex-wrap:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;nowrap&quot; name=&quot;flex-wrap&quot; value=&quot;nowrap&quot; checked /&gt;
        &lt;label for=&quot;nowrap&quot;&gt;nowrap;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;wrap&quot; name=&quot;flex-wrap&quot; value=&quot;wrap&quot; /&gt;
        &lt;label for=&quot;wrap&quot;&gt;wrap;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;wrap-reverse&quot; name=&quot;flex-wrap&quot; value=&quot;wrap-reverse&quot; /&gt;
        &lt;label for=&quot;wrap-reverse&quot;&gt;wrap-reverse;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
    &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
    &lt;div class=&quot;resize&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom5 = document.querySelector('.custom.ex5');
  const resize = custom5.querySelector('.resize');
  const container5 = custom5.querySelector('.container');
  const radioBtn5 = custom5.querySelectorAll('input');
  let isTouch = false;
  let sX = 0;
  let cX = 0;
  let diffX = 0;

  container5.addEventListener('mousedown', (e) =&gt; {
    e.preventDefault();
  });

  resize.addEventListener('mousedown', (e) =&gt; {
    sX = e.clientX + diffX;
    isTouch = true;
  });

  custom5.addEventListener('mousemove', (e) =&gt; {
    if (isTouch === true) {
      cX = e.clientX;
      diffX = sX - cX;
      if (diffX &lt; 0) return (diffX = 0);
      container5.style.width = `calc(100% - ${diffX}px)`;
    }
  });

  document.addEventListener('mouseup', (e) =&gt; {
    isTouch = false;
  });

  container5.addEventListener('touchstart', (e) =&gt; {
    e.preventDefault();
  });

  resize.addEventListener('touchstart', (e) =&gt; {
    const touch = e.touches[0];
    sX = touch.clientX + diffX;
    isTouch = true;
  });

  custom5.addEventListener('touchmove', (e) =&gt; {
    if (isTouch === true) {
      const touch = e.touches[0];
      cX = touch.clientX;
      diffX = sX - cX;
      if (diffX &lt; 0) return (diffX = 0);
      container5.style.width = `calc(100% - ${diffX}px)`;
    }
  });

  document.addEventListener('touchend', (e) =&gt; {
    isTouch = false;
  });

  radioBtn5.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom5.querySelector('input[name=&quot;flex-wrap&quot;]:checked').value;
      container5.style.flexWrap = value;
    });
  });
&lt;/script&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;align-content&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 줄이 있을 때 교차 축을 따라 줄들을 어떻게 정렬할지 설정 (&lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;두 줄 이상 이루어진 플렉스 컨테이너에만 적용&lt;/span&gt;&lt;/u&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ &lt;u&gt;여러 줄일 경우 align-items 속성 대신 align-content 속성이 적용된다.&lt;/u&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;b&gt;stretch&lt;/b&gt;(default): &lt;u&gt;아이템&amp;nbsp;크기&amp;nbsp;설정이&amp;nbsp;없으면&lt;/u&gt;&amp;nbsp;부모&amp;nbsp;요소의&amp;nbsp;세로&amp;nbsp;크기를&amp;nbsp;따라&amp;nbsp;확장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-start&lt;/b&gt;: 아이템들을&amp;nbsp;시작점으로&amp;nbsp;정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction&amp;nbsp;속성이&amp;nbsp;row(수평)일&amp;nbsp;때는&amp;nbsp;위,&amp;nbsp;column(수직)일&amp;nbsp;때는&amp;nbsp;왼쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-end&lt;/b&gt;: 아이템들을&amp;nbsp;끝점으로&amp;nbsp;정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;flex-direction이&amp;nbsp;row(수평)일&amp;nbsp;때는&amp;nbsp;아래,&amp;nbsp;column(수직)일&amp;nbsp;때는&amp;nbsp;오른쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;center&lt;/b&gt;: 아이템들을&amp;nbsp;가운데로&amp;nbsp;정렬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-between&lt;/b&gt;: 양쪽&amp;nbsp;여백을&amp;nbsp;없애고&amp;nbsp;나머지&amp;nbsp;아이템들이&amp;nbsp;공간을&amp;nbsp;나누어&amp;nbsp;갖는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-around&lt;/b&gt;: 아이템들의&amp;nbsp;여백을&amp;nbsp;모두&amp;nbsp;공평하게&amp;nbsp;나누어&amp;nbsp;갖는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;space-evenly&lt;/b&gt;:&amp;nbsp;모든&amp;nbsp;아이템들의&amp;nbsp;간격이&amp;nbsp;일정&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
  .custom.ex6 .container {
    display: flex;
    flex-wrap: wrap;
    position: relative;
    max-width: 100%;
  }
  .custom.ex6 .container .resize {
    position: absolute;
    top: 0;
    right: 0;
    width: 4px;
    height: 100%;
    background-color: #000;
  }
  .custom.ex6 .container .resize::before {
    position: absolute;
    top: -27px;
    right: -5px;
    content: '드래그바 ↓';
    z-index: -1;
    width: max-content;
    color: #874747;
  }
  .custom.ex6 .container .resize:hover {
    cursor: col-resize;
  }
  .custom.ex6 .item {
    padding: 30px;
    width: auto;
    height: auto;
  }
  @media (max-width: 640px) {
    div.custom.ex6 .item {
      padding: 20px;
    }
  }

  .custom.ex6 .style {
    position: relative;
  }
  .custom.ex6 .style .value {
    margin-left: 115px;
  }
  .custom.ex6 .style .attr {
    position: absolute;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex6&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div&gt;&lt;b&gt;flex-wrap:&lt;/b&gt; wrap;&lt;/div&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;align-content:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-stretch&quot; name=&quot;align-content&quot; value=&quot;stretch&quot; checked /&gt;
        &lt;label for=&quot;ac-stretch&quot;&gt;stretch;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-flex-start&quot; name=&quot;align-content&quot; value=&quot;flex-start&quot; /&gt;
        &lt;label for=&quot;ac-flex-start&quot;&gt;flex-start;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-flex-end&quot; name=&quot;align-content&quot; value=&quot;flex-end&quot; /&gt;
        &lt;label for=&quot;ac-flex-end&quot;&gt;flex-end;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-center&quot; name=&quot;align-content&quot; value=&quot;center&quot; /&gt;
        &lt;label for=&quot;ac-center&quot;&gt;center;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-space-between&quot; name=&quot;align-content&quot; value=&quot;space-between&quot; /&gt;
        &lt;label for=&quot;ac-space-between&quot;&gt;space-between;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-space-around&quot; name=&quot;align-content&quot; value=&quot;space-around&quot; /&gt;
        &lt;label for=&quot;ac-space-around&quot;&gt;space-around;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;ac-space-evenly&quot; name=&quot;align-content&quot; value=&quot;space-evenly&quot; /&gt;
        &lt;label for=&quot;ac-space-evenly&quot;&gt;space-evenly;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
    &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
    &lt;div class=&quot;resize&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom6 = document.querySelector('.custom.ex6');
  const resize2 = custom6.querySelector('.resize');
  const container6 = custom6.querySelector('.container');
  const radioBtn6 = custom6.querySelectorAll('input');
  let isTouch2 = false;
  let sX2 = 0;
  let cX2 = 0;
  let diffX2 = 0;

  container6.addEventListener('mousedown', (e) =&gt; {
    e.preventDefault();
  });

  resize2.addEventListener('mousedown', (e) =&gt; {
    sX2 = e.clientX + diffX2;
    isTouch2 = true;
  });

  custom6.addEventListener('mousemove', (e) =&gt; {
    if (isTouch2 === true) {
      cX2 = e.clientX;
      diffX2 = sX2 - cX2;
      if (diffX2 &lt; 0) return (diffX2 = 0);
      container6.style.width = `calc(100% - ${diffX2}px)`;
    }
  });

  document.addEventListener('mouseup', (e) =&gt; {
    isTouch2 = false;
  });

  container6.addEventListener('touchstart', (e) =&gt; {
    e.preventDefault();
  });

  resize2.addEventListener('touchstart', (e) =&gt; {
    const touch = e.touches[0];
    sX2 = touch.clientX + diffX2;
    isTouch2 = true;
  });

  custom6.addEventListener('touchmove', (e) =&gt; {
    if (isTouch2 === true) {
      const touch = e.touches[0];
      cX2 = touch.clientX;
      diffX2 = sX2 - cX2;
      if (diffX2 &lt; 0) return (diffX2 = 0);
      container6.style.width = `calc(100% - ${diffX2}px)`;
    }
  });

  document.addEventListener('touchend', (e) =&gt; {
    isTouch2 = false;
  });

  radioBtn6.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom6.querySelector('input[name=&quot;align-content&quot;]:checked').value;
      container6.style.alignContent = value;
    });
  });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;space-around와 space-evenly의 차이점&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MX1Yt/btspmKFOMmu/hsKfvEVfZLKRNEFQirs1b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MX1Yt/btspmKFOMmu/hsKfvEVfZLKRNEFQirs1b0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;758&quot; data-filename=&quot;align-content-around.png&quot; style=&quot;width: 49.7194%; margin-right: 10px;&quot; data-widthpercent=&quot;50.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MX1Yt/btspmKFOMmu/hsKfvEVfZLKRNEFQirs1b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMX1Yt%2FbtspmKFOMmu%2FhsKfvEVfZLKRNEFQirs1b0%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;909&quot; height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwvYHg/btspBAu3P16/ZXnAqvM7borKu6KtGHFz2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwvYHg/btspBAu3P16/ZXnAqvM7borKu6KtGHFz2k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;758&quot; data-filename=&quot;align-content-evenly.png&quot; style=&quot;width: 49.1178%;&quot; data-widthpercent=&quot;49.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwvYHg/btspBAu3P16/ZXnAqvM7borKu6KtGHFz2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwvYHg%2FbtspBAu3P16%2FZXnAqvM7borKu6KtGHFz2k%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;898&quot; height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;space-around와 space-evenly의 차이를 설명한 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Tip. flex에서 아이템 사이 간격 주는 방법&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;column-gap&lt;/b&gt;: 수평일 때 아이템 사이 여백 사이즈를 줄 수 있다.&lt;br /&gt;&lt;b&gt;row-gap&lt;/b&gt;: 수직일 때 아이템 사이 여백 사이즈를 줄 수 있다.&lt;br /&gt;※ &lt;u&gt;margin처럼 아이템 양끝 여백을 신경 안 써도 된다.&lt;/u&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690867756834&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        display: flex;
        background-color: skyblue;
        height: 300px;
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
      }
      .container .item1 {
        background-color: blue;
      }
      .container .item2 {
        background-color: green;
      }
      .container .item3 {
        background-color: red;
      }
      .container1 {
        flex-direction: row;
        column-gap: 20px;
      }
      .container2 {
        flex-direction: column;
        row-gap: 20px;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;p&amp;gt;flex-direction: row;&amp;lt;/p&amp;gt;
    &amp;lt;div class=&quot;container container1&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;flex-direction: column;&amp;lt;/p&amp;gt;
    &amp;lt;div class=&quot;container container2&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;아래는 연습을 위해 flexbox 컨테이너 속성을 모아놓았습니다.&lt;br /&gt;stretch 효과를 보기위해 아이템들 사이즈는 설정을 안했습니다.&lt;br /&gt;&lt;u&gt;헷갈리시면 아이템 사이즈 설정을 체크해 주세요 !&lt;/u&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;style&gt;
  .custom.ex7 .container {
    height: 600px;
    min-height: 600px;
    background: transparent;
    margin-bottom: 25px;
  }
  .custom.ex7 .container .wrap {
    display: flex;
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    position: relative;
    background-color: skyblue;
  }
  .custom.ex7 .container .item {
    width: auto;
    height: auto;
    line-height: normal;
    padding: 20px 30px;
  }
  .custom.ex7 .container .wrap.size .item {
    width: 80px;
    height: 80px;
    line-height: 80px;
    padding: 0;
  }
  @media (max-width: 800px) {
    div.custom.ex7 .container .wrap.size .item {
      width: 60px;
      height: 60px;
      line-height: 60px;
    }
  }
  @media (max-width: 640px) {
    div.custom.ex7 .container {
      height: 400px;
      min-height: 400px;
    }
    div.custom.ex7 .container .item {
      padding: 15px 20px;
    }
    div.custom.ex7 .container .wrap.size .item {
      width: 40px;
      height: 40px;
      line-height: 40px;
    }
  }
  .custom.ex7 .container .resize-col {
    position: absolute;
    top: 0;
    right: 0;
    width: 4px;
    height: 100%;
    background-color: #000;
  }
  .custom.ex7 .container .resize-row {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 4px;
    background-color: #000;
  }
  .custom.ex7 .container .resize-col::before {
    position: absolute;
    top: -27px;
    right: -5px;
    content: '드래그바 ↓';
    z-index: -1;
    width: max-content;
    color: #874747;
  }
  .custom.ex7 .container .resize-row::before {
    position: absolute;
    bottom: -27px;
    left: -5px;
    content: '↑ 드래그바';
    z-index: -1;
    width: max-content;
    color: #874747;
  }
  .custom.ex7 .container .resize-col:hover {
    cursor: col-resize;
  }
  .custom.ex7 .container .resize-row:hover {
    cursor: row-resize;
  }
  .custom.ex7 [type='radio']:not(:checked) + label {
    color: rgb(170, 170, 170);
  }
  .custom.ex7 .style {
    position: relative;
    font-size: 14px;
  }
  .custom.ex7 .style li {
    display: flex;
    column-gap: 10px;
    border-top: 1px solid #a2a2a2;
    padding: 0 5px;
  }
  .custom.ex7 .style li:hover {
    background-color: #ffd6d6;
  }
  .custom.ex7 .style .value {
    flex: 1;
  }
  .custom.ex7 .style .attr {
    font-weight: bold;
  }
&lt;/style&gt;

&lt;div class=&quot;custom ex7&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div&gt;
      &lt;label for=&quot;is-size&quot; style=&quot;padding-right: 5px; color: red&quot;&gt;아이템 사이즈 설정&lt;/label
      &gt;&lt;input type=&quot;checkbox&quot; id=&quot;is-size&quot; /&gt;
    &lt;/div&gt;
    &lt;div style=&quot;padding-left: 5px&quot;&gt;&lt;b&gt;display:&lt;/b&gt; flex;&lt;/div&gt;
    &lt;ul&gt;
      &lt;li&gt;
        &lt;div class=&quot;attr&quot;&gt;flex-direction:&lt;/div&gt;
        &lt;div class=&quot;value&quot;&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;row2&quot; name=&quot;flex-direction2&quot; value=&quot;row&quot; checked /&gt;
            &lt;label for=&quot;row2&quot;&gt;row;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;row-reverse2&quot; name=&quot;flex-direction2&quot; value=&quot;row-reverse&quot; /&gt;
            &lt;label for=&quot;row-reverse2&quot;&gt;row-reverse;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;column2&quot; name=&quot;flex-direction2&quot; value=&quot;column&quot; /&gt;
            &lt;label for=&quot;column2&quot;&gt;column;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;column-reverse2&quot; name=&quot;flex-direction2&quot; value=&quot;column-reverse&quot; /&gt;
            &lt;label for=&quot;column-reverse2&quot;&gt;column-reverse;&lt;/label&gt;
          &lt;/span&gt;
        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;div class=&quot;attr&quot;&gt;justify-content:&lt;/div&gt;
        &lt;div class=&quot;value&quot;&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;flex-start2&quot; name=&quot;justify-content2&quot; value=&quot;flex-start&quot; checked /&gt;
            &lt;label for=&quot;flex-start2&quot;&gt;flex-start;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;flex-end2&quot; name=&quot;justify-content2&quot; value=&quot;flex-end&quot; /&gt;
            &lt;label for=&quot;flex-end2&quot;&gt;flex-end;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;center2&quot; name=&quot;justify-content2&quot; value=&quot;center&quot; /&gt;
            &lt;label for=&quot;center2&quot;&gt;center;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;space-between2&quot; name=&quot;justify-content2&quot; value=&quot;space-between&quot; /&gt;
            &lt;label for=&quot;space-between2&quot;&gt;space-between;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;space-around2&quot; name=&quot;justify-content2&quot; value=&quot;space-around&quot; /&gt;
            &lt;label for=&quot;space-around2&quot;&gt;space-around;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;space-evenly2&quot; name=&quot;justify-content2&quot; value=&quot;space-evenly&quot; /&gt;
            &lt;label for=&quot;space-evenly2&quot;&gt;space-evenly;&lt;/label&gt;
          &lt;/span&gt;
        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;div class=&quot;attr&quot;&gt;align-items:&lt;/div&gt;
        &lt;div class=&quot;value&quot;&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ai-stretch2&quot; name=&quot;align-items2&quot; value=&quot;stretch&quot; checked /&gt;
            &lt;label for=&quot;ai-stretch2&quot;&gt;stretch;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ai-flex-start2&quot; name=&quot;align-items2&quot; value=&quot;flex-start&quot; /&gt;
            &lt;label for=&quot;ai-flex-start2&quot;&gt;flex-start;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ai-flex-end2&quot; name=&quot;align-items2&quot; value=&quot;flex-end&quot; /&gt;
            &lt;label for=&quot;ai-flex-end2&quot;&gt;flex-end;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ai-center2&quot; name=&quot;align-items2&quot; value=&quot;center&quot; /&gt;
            &lt;label for=&quot;ai-center2&quot;&gt;center;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ai-baseline2&quot; name=&quot;align-items2&quot; value=&quot;baseline&quot; /&gt;
            &lt;label for=&quot;ai-baseline2&quot;&gt;baseline;&lt;/label&gt;
          &lt;/span&gt;
        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;div class=&quot;attr&quot;&gt;flex-wrap:&lt;/div&gt;
        &lt;div class=&quot;value&quot;&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;nowrap2&quot; name=&quot;flex-wrap2&quot; value=&quot;nowrap&quot; checked /&gt;
            &lt;label for=&quot;nowrap2&quot;&gt;nowrap;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;wrap2&quot; name=&quot;flex-wrap2&quot; value=&quot;wrap&quot; /&gt;
            &lt;label for=&quot;wrap2&quot;&gt;wrap;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;wrap-reverse2&quot; name=&quot;flex-wrap2&quot; value=&quot;wrap-reverse&quot; /&gt;
            &lt;label for=&quot;wrap-reverse2&quot;&gt;wrap-reverse;&lt;/label&gt;
          &lt;/span&gt;
        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;div class=&quot;attr&quot;&gt;align-content:&lt;/div&gt;
        &lt;div class=&quot;value&quot;&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-stretch2&quot; name=&quot;align-content2&quot; value=&quot;stretch&quot; checked /&gt;
            &lt;label for=&quot;ac-stretch2&quot;&gt;stretch;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-flex-start2&quot; name=&quot;align-content2&quot; value=&quot;flex-start&quot; /&gt;
            &lt;label for=&quot;ac-flex-start2&quot;&gt;flex-start;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-flex-end2&quot; name=&quot;align-content2&quot; value=&quot;flex-end&quot; /&gt;
            &lt;label for=&quot;ac-flex-end2&quot;&gt;flex-end;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-center2&quot; name=&quot;align-content2&quot; value=&quot;center&quot; /&gt;
            &lt;label for=&quot;ac-center2&quot;&gt;center;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-space-between2&quot; name=&quot;align-content2&quot; value=&quot;space-between&quot; /&gt;
            &lt;label for=&quot;ac-space-between2&quot;&gt;space-between;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-space-around2&quot; name=&quot;align-content2&quot; value=&quot;space-around&quot; /&gt;
            &lt;label for=&quot;ac-space-around2&quot;&gt;space-around;&lt;/label&gt;
          &lt;/span&gt;
          &lt;span&gt;
            &lt;input type=&quot;radio&quot; id=&quot;ac-space-evenly2&quot; name=&quot;align-content2&quot; value=&quot;space-evenly&quot; /&gt;
            &lt;label for=&quot;ac-space-evenly2&quot;&gt;space-evenly;&lt;/label&gt;
          &lt;/span&gt;
        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;wrap&quot;&gt;
      &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
      &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
      &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
      &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
      &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
      &lt;div class=&quot;resize-col&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;resize-row&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom7 = document.querySelector('.custom.ex7');
  const isSize = custom7.querySelector('#is-size');
  const container7 = custom7.querySelector('.container .wrap');
  const radioBtn7 = custom7.querySelectorAll('input');

  const resizeCol = custom7.querySelector('.resize-col');
  const resizeRow = custom7.querySelector('.resize-row');

  const RESIZE_COL = 'col';
  const RESIZE_ROW = 'row';
  const RESIZE_NONE = 'none';

  let touchMode = RESIZE_NONE;
  let sX3 = 0;
  let cX3 = 0;
  let sY3 = 0;
  let cY3 = 0;
  let diffX3 = 0;
  let diffY3 = 0;

  container7.addEventListener('mousedown', (e) =&gt; {
    e.preventDefault();
  });

  resizeCol.addEventListener('mousedown', (e) =&gt; {
    sX3 = e.clientX + diffX3;
    touchMode = RESIZE_COL;
  });
  resizeRow.addEventListener('mousedown', (e) =&gt; {
    sY3 = e.clientY - diffY3;
    touchMode = RESIZE_ROW;
  });

  custom7.addEventListener('mousemove', (e) =&gt; {
    if (touchMode === RESIZE_COL) {
      cX3 = e.clientX;
      diffX3 = sX3 - cX3;
      if (diffX3 &lt; 0) return (diffX3 = 0);
      container7.style.width = `calc(100% - ${diffX3}px)`;
    } else if (touchMode === RESIZE_ROW) {
      cY3 = e.clientY;
      diffY3 = cY3 - sY3;
      if (diffY3 &gt; 0) return (diffY3 = 0);
      container7.style.height = `calc(100% + ${diffY3}px)`;
    }
  });

  document.addEventListener('mouseup', (e) =&gt; {
    touchMode = RESIZE_NONE;
  });

  container7.addEventListener('touchstart', (e) =&gt; {
    e.preventDefault();
  });

  resizeCol.addEventListener('touchstart', (e) =&gt; {
    const touch = e.touches[0];
    sX3 = touch.clientX + diffX3;
    touchMode = RESIZE_COL;
  });

  resizeRow.addEventListener('touchstart', (e) =&gt; {
    const touch = e.touches[0];
    sY3 = touch.clientY - diffY3;
    touchMode = RESIZE_ROW;
  });

  custom7.addEventListener('touchmove', (e) =&gt; {
    const touch = e.touches[0];
    if (touchMode === RESIZE_COL) {
      cX3 = touch.clientX;
      diffX3 = sX3 - cX3;
      if (diffX3 &lt; 0) return (diffX3 = 0);
      container7.style.width = `calc(100% - ${diffX3}px)`;
    } else if (touchMode === RESIZE_ROW) {
      cY3 = touch.clientY;
      diffY3 = cY3 - sY3;
      if (diffY3 &gt; 0) return (diffY3 = 0);
      container7.style.height = `calc(100% + ${diffY3}px)`;
    }
  });

  document.addEventListener('touchend', (e) =&gt; {
    touchMode = RESIZE_NONE;
  });

  isSize.addEventListener('click', () =&gt; {
    container7.classList.toggle('size');
  });

  radioBtn7.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom7.querySelector('input[name=&quot;flex-direction2&quot;]:checked').value;
      const value2 = custom7.querySelector('input[name=&quot;justify-content2&quot;]:checked').value;
      const value3 = custom7.querySelector('input[name=&quot;align-items2&quot;]:checked').value;
      const value4 = custom7.querySelector('input[name=&quot;flex-wrap2&quot;]:checked').value;
      const value5 = custom7.querySelector('input[name=&quot;align-content2&quot;]:checked').value;

      container7.style.flexDirection = value;
      container7.style.justifyContent = value2;
      container7.style.alignItems = value3;
      container7.style.flexWrap = value4;
      container7.style.alignContent = value5;
    });
  });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;flexbox 아이템에 적용하는 속성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;아이템에 적용하는 속성은 아이템 전체로 주거나 아이템 한 개씩 컨트롤을 할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690767109277&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        height: 100vh;
        display: flex;
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
        /* 여기에 아래 속성들 들어갈 자리 */
      }
      .container .item1 {
        background-color: red;
      }
      .container .item2 {
        background-color: orange;
      }
      .container .item3 {
        background-color: yellow;
      }
      .container .item4 {
        background-color: green;
      }
      .container .item5 {
        background-color: blueviolet;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item4&quot;&amp;gt;4&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item5&quot;&amp;gt;5&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;flex-basis&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flex 아이템의 기본 크기를 설정 (flex-direction이 row일 때는 너비, column일 때는 높이)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;auto&lt;/b&gt;(default): 아이템의 원래 너비 적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;content&lt;/b&gt;: 아이템의&amp;nbsp;크기는&amp;nbsp;내부&amp;nbsp;콘텐츠의&amp;nbsp;크기에&amp;nbsp;따라&amp;nbsp;결정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;px, %, em&lt;/b&gt; 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690775755216&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        display: flex;
        height: 300px;
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
        flex-basis: 400px;
      }
      .container .item2 {
        background-color: orange;
        flex-basis: 200px;
      }
      .container .item3 {
        background-color: yellow;
        flex-basis: auto;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;style&gt;
  .container.ex8 {
    background-color: skyblue;
    display: flex;
    height: 300px;
  }
  .container.ex8 .item {
    width: 80px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    color: #000;
  }
  .container.ex8 .item1 {
    background-color: red;
    flex-basis: 400px;
  }
  .container.ex8 .item2 {
    background-color: orange;
    flex-basis: 200px;
  }
  .container.ex8 .item3 {
    background-color: yellow;
    flex-basis: auto;
  }
&lt;/style&gt;

&lt;div class=&quot;container ex8&quot;&gt;
  &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
  &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
  &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
&lt;/div&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;flex-grow&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 요소가 적거나 크기가 작아 컨테이너에 공간이 남을 때 빈&amp;nbsp;공간을&amp;nbsp;메울만큼&amp;nbsp;늘어나도록&amp;nbsp;설정하는&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;b&gt;0&lt;/b&gt;(default): 아이템의&amp;nbsp;원래&amp;nbsp;너비&amp;nbsp;적용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;양수&lt;/b&gt;: 해당&amp;nbsp;아이템이&amp;nbsp;유연한(Flexible)&amp;nbsp;박스로&amp;nbsp;변하고&amp;nbsp;원래의&amp;nbsp;크기보다&amp;nbsp;커지며&amp;nbsp;빈&amp;nbsp;공간을&amp;nbsp;메우게&amp;nbsp;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
  .custom.ex9 .container {
    display: flex;
    height: 150px;
  }
  .custom.ex9 .style {
    position: relative;
  }
  .custom.ex9 .style .value {
    margin-left: 100px;
  }
  .custom.ex9 .style .attr {
    position: absolute;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex9&quot;&gt;
  &lt;div class=&quot;style&quot;&gt;
    &lt;div class=&quot;attr&quot;&gt;&lt;b&gt;flex-grow:&lt;/b&gt;&lt;/div&gt;
    &lt;div class=&quot;value&quot;&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;item-grow-0&quot; name=&quot;flex-grow&quot; value=&quot;0&quot; checked /&gt;
        &lt;label for=&quot;item-grow-0&quot;&gt;0;&lt;/label&gt;
      &lt;/span&gt;
      &lt;span&gt;
        &lt;input type=&quot;radio&quot; id=&quot;item-grow-1&quot; name=&quot;flex-grow&quot; value=&quot;1&quot; /&gt;
        &lt;label for=&quot;item-grow-1&quot;&gt;1;&lt;/label&gt;
      &lt;/span&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;item item4&quot;&gt;4&lt;/div&gt;
    &lt;div class=&quot;item item5&quot;&gt;5&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom8 = document.querySelector('.custom.ex9');
  const items = custom8.querySelectorAll('.container .item');
  const radioBtn8 = custom8.querySelectorAll('input');
  radioBtn8.forEach((el) =&gt; {
    el.addEventListener('click', () =&gt; {
      const value = custom8.querySelector('input[name=&quot;flex-grow&quot;]:checked').value;
      items.forEach((item) =&gt; {
        item.style.flexGrow = value;
      });
    });
  });
&lt;/script&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_1690774311926&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        height: 300px;
        display: flex;
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
        flex-grow: 1;
      }
      .container .item2 {
        background-color: orange;
        flex-grow: 2;
      }
      .container .item3 {
        background-color: yellow;
        flex-grow: 3;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;결과 화면 (1:2:3 비율로 커짐)&lt;/p&gt;
&lt;style&gt;
  .custom.ex10 .container {
    background-color: skyblue;
    height: 300px;
    display: flex;
  }
  .custom.ex10 .container .item {
    width: 80px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    color: #000;
  }
  .custom.ex10 .container .item1 {
    background-color: red;
    flex-grow: 1;
  }
  .custom.ex10 .container .item2 {
    background-color: orange;
    flex-grow: 2;
  }
  .custom.ex10 .container .item3 {
    background-color: yellow;
    flex-grow: 3;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex10&quot;&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&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;flex-shrink&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이템들이&amp;nbsp;컨테이너&amp;nbsp;내에서&amp;nbsp;사용&amp;nbsp;가능한&amp;nbsp;공간보다&amp;nbsp;작을&amp;nbsp;때&amp;nbsp;어떻게&amp;nbsp;줄어들지를&amp;nbsp;결정하는&amp;nbsp;데&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;b&gt;1&lt;/b&gt;(default): 모든&amp;nbsp;아이템들이&amp;nbsp;동등하게&amp;nbsp;줄어든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;0&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;양수&lt;/b&gt;: 아이템이&amp;nbsp;줄어드는&amp;nbsp;비율&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690782590587&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        display: flex;
        height: 300px;
      }
      .container .item {
        flex-basis: 100px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
        flex-shrink: 1;
      }
      .container .item2 {
        background-color: orange;
        flex-shrink: 2;
      }
      .container .item3 {
        background-color: yellow;
        flex-shrink: 0;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;style&gt;
  .custom.ex11 {
    padding-top: 30px;
  }
  .custom.ex11 .container {
    display: flex;
    position: relative;
    max-width: 100%;
    height: 300px;
  }
  .custom.ex11 .container .item {
    flex-basis: 100px;
    height: 80px;
    line-height: 80px;
  }
  .custom.ex11 .container .item1 {
    background-color: red;
    flex-shrink: 1;
  }
  .custom.ex11 .container .item2 {
    background-color: orange;
    flex-shrink: 2;
  }
  .custom.ex11 .container .item3 {
    background-color: yellow;
    flex-shrink: 0;
  }
  .custom.ex11 .container .resize {
    position: absolute;
    top: 0;
    right: 0;
    width: 4px;
    height: 100%;
    background-color: #000;
  }
  .custom.ex11 .container .resize::before {
    position: absolute;
    top: -27px;
    right: -5px;
    content: '드래그바 ↓';
    z-index: -1;
    width: max-content;
    color: #874747;
  }
  .custom.ex11 .container .resize:hover {
    cursor: col-resize;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex11&quot;&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
    &lt;div class=&quot;resize&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const custom11 = document.querySelector('.custom.ex11');
  const resize11 = custom11.querySelector('.resize');
  const container11 = custom11.querySelector('.container');
  let isTouch11 = false;
  let sX11 = 0;
  let cX11 = 0;
  let diffX11 = 0;

  container11.addEventListener('mousedown', (e) =&gt; {
    e.preventDefault();
  });

  resize11.addEventListener('mousedown', (e) =&gt; {
    sX11 = e.clientX + diffX11;
    isTouch11 = true;
  });

  custom11.addEventListener('mousemove', (e) =&gt; {
    if (isTouch11 === true) {
      cX11 = e.clientX;
      diffX11 = sX11 - cX11;
      if (diffX11 &lt; 0) return (diffX11 = 0);
      container11.style.width = `calc(100% - ${diffX11}px)`;
    }
  });

  document.addEventListener('mouseup', (e) =&gt; {
    isTouch11 = false;
  });

  container11.addEventListener('touchstart', (e) =&gt; {
    e.preventDefault();
  });

  resize11.addEventListener('touchstart', (e) =&gt; {
    const touch = e.touches[0];
    sX11 = touch.clientX + diffX11;
    isTouch11 = true;
  });

  custom11.addEventListener('touchmove', (e) =&gt; {
    if (isTouch11 === true) {
      const touch = e.touches[0];
      cX11 = touch.clientX;
      diffX11 = sX11 - cX11;
      if (diffX11 &lt; 0) return (diffX11 = 0);
      container11.style.width = `calc(100% - ${diffX11}px)`;
    }
  });

  document.addEventListener('touchend', (e) =&gt; {
    isTouch11 = false;
  });
&lt;/script&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;flex&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flex-grow, flex-shrink, flex-basis 속성을 한 줄에 축약해서 사용할 수 있도록 해주는 단축 속성 (순서 지켜야 함)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;flex-grow&amp;nbsp;flex-shrink&amp;nbsp;flex-basis&lt;/b&gt;;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Ex) flex: 1 0 100px;&lt;/li&gt;
&lt;li&gt;/*&amp;nbsp;flex-grow:&amp;nbsp;1,&amp;nbsp;flex-shrink:&amp;nbsp;0,&amp;nbsp;flex-basis:&amp;nbsp;100px;&amp;nbsp;*/&lt;/li&gt;
&lt;/ul&gt;
&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;flex-basis, flex-grow, flex-shrink 속성은 저도 잘 써보지 않아서 설명이 좀 미흡하네요 ㅠ&lt;br /&gt;나중에 개념이 좀 더 잡히면 내용을 추가하도록 하겠습니다~!&lt;/blockquote&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;order&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;&lt;b&gt;※&lt;/b&gt; &lt;b&gt;참고&lt;/b&gt; : order&amp;nbsp;속성을&amp;nbsp;사용하면&amp;nbsp;실제&amp;nbsp;DOM&amp;nbsp;순서와&amp;nbsp;화면에&amp;nbsp;보여지는&amp;nbsp;콘텐츠의&amp;nbsp;순서가&amp;nbsp;서로&amp;nbsp;연결되지&amp;nbsp;않기&amp;nbsp;때문에,&amp;nbsp;시각으로&amp;nbsp;스크린&amp;nbsp;리더&amp;nbsp;등&amp;nbsp;보조&amp;nbsp;기술을&amp;nbsp;사용해&amp;nbsp;이동하는&amp;nbsp;사용자의&amp;nbsp;경험에&amp;nbsp;부정적인&amp;nbsp;영향을&amp;nbsp;줄&amp;nbsp;수&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;b&gt;0&lt;/b&gt;(default): 순서를 바꾸지 않음&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690851964674&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        display: flex;
        height: 300px;
      }
      .container .item {
        width: 80px;
        height: 80px;
        line-height: 80px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
        order: 1;
      }
      .container .item2 {
        background-color: orange;
        order: 0;
      }
      .container .item3 {
        background-color: yellow;
        order: -1;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;style&gt;
  .custom.ex12 .container {
    background-color: skyblue;
    display: flex;
    height: 300px;
  }
  .custom.ex12 .container .item {
    width: 80px;
    height: 80px;
    line-height: 80px;
    text-align: center;
    color: #000;
  }
  .custom.ex12 .container .item1 {
    background-color: red;
    order: 1;
  }
  .custom.ex12 .container .item2 {
    background-color: orange;
    order: 0;
  }
  .custom.ex12 .container .item3 {
    background-color: yellow;
    order: -1;
  }
&lt;/style&gt;

&lt;div class=&quot;custom ex12&quot;&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&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;align-self&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;b&gt;auto&lt;/b&gt;(default): align-items&amp;nbsp;설정을&amp;nbsp;상속&lt;/li&gt;
&lt;li&gt;&lt;b&gt;stretch&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;아이템 크기 설정이 없으면&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;부모 요소의 세로 크기를 따라 확장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-start&lt;/b&gt;: 아이템을 시작점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex-direction 속성이 row(수평)일 때는 위, column(수직)일 때는 왼쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;flex-end&lt;/b&gt;: 아이템을 끝점으로 정렬
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex-direction이 row(수평)일 때는 아래, column(수직)일 때는 오른쪽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;center&lt;/b&gt;: 아이템을 가운데로 정렬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;baseline&lt;/b&gt;: 아이템 텍스트 baseline 기준으로 정렬&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690865839348&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Flex&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
      .container {
        background-color: skyblue;
        display: flex;
        height: 300px;
      }
      .container .item {
        padding: 30px;
        text-align: center;
        color: #000;
      }
      .container .item1 {
        background-color: red;
      }
      .container .item2 {
        background-color: orange;
        align-self: center;
      }
      .container .item3 {
        background-color: yellow;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;container&quot;&amp;gt;
      &amp;lt;div class=&quot;item item1&quot;&amp;gt;1&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item2&quot;&amp;gt;2&amp;lt;/div&amp;gt;
      &amp;lt;div class=&quot;item item3&quot;&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;style&gt;
  .custom.ex13 .container {
    background-color: skyblue;
    display: flex;
    height: 300px;
  }
  .custom.ex13 .container .item {
    padding: 30px;
    text-align: center;
    color: #000;
    width: auto;
    height: auto;
  }
  .custom.ex13 .container .item1 {
    background-color: red;
  }
  .custom.ex13 .container .item2 {
    background-color: orange;
    align-self: center;
  }
  .custom.ex13 .container .item3 {
    background-color: yellow;
  }
&lt;/style&gt;

&lt;div class=&quot;custom ex13&quot;&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;item item1&quot;&gt;1&lt;/div&gt;
    &lt;div class=&quot;item item2&quot;&gt;2&lt;/div&gt;
    &lt;div class=&quot;item item3&quot;&gt;3&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 처음에 보았던 이미지를 flex를 이용하여 만들어 보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-29 03.41.39.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz6Mhh/btspK2SHkDd/i9XYI024kayFB3QRH4yto1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz6Mhh/btspK2SHkDd/i9XYI024kayFB3QRH4yto1/img.png&quot; data-alt=&quot;header 레이아웃 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz6Mhh/btspK2SHkDd/i9XYI024kayFB3QRH4yto1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz6Mhh%2FbtspK2SHkDd%2Fi9XYI024kayFB3QRH4yto1%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;1113&quot; height=&quot;67&quot; data-filename=&quot;스크린샷 2023-07-29 03.41.39.png&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;67&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;header 레이아웃 이미지&lt;/figcaption&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_1690866408432&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;style&amp;gt;
      * {
        list-style: none;
        padding: 0;
        margin: 0;
      }
      header {
        background-color: gainsboro;
        padding: 0px 20px;
        height: 50px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
      header .menus {
        display: flex;
        column-gap: 20px;
      }
      header a {
        color: #000;
        text-decoration: none;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;div class=&quot;logo&quot;&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;로고&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;nav&amp;gt;
        &amp;lt;ul class=&quot;menus&quot;&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;MENU3&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/nav&amp;gt;
      &amp;lt;div class=&quot;login&quot;&amp;gt;
        &amp;lt;a href=&quot;#&quot;&amp;gt;로그인&amp;lt;/a&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/header&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2023-07-28-0200.png&quot; data-origin-width=&quot;1529&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bchGs4/btspxaLj6qc/WlEwC6fk0Myfs51k8fTCz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bchGs4/btspxaLj6qc/WlEwC6fk0Myfs51k8fTCz0/img.png&quot; data-alt=&quot;flex 쓰고 난 후 코드를 비교한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bchGs4/btspxaLj6qc/WlEwC6fk0Myfs51k8fTCz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbchGs4%2FbtspxaLj6qc%2FWlEwC6fk0Myfs51k8fTCz0%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;1529&quot; height=&quot;1024&quot; data-filename=&quot;제목 없음-2023-07-28-0200.png&quot; data-origin-width=&quot;1529&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flex 쓰고 난 후 코드를 비교한 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;코드가 잘 보이진 않는데 얼핏 봐도 코드가 훨씬 짧아지고 가독성도 좋아진다.&lt;/blockquote&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;b&gt;결론 :&amp;nbsp;&lt;/b&gt;flex, grid는 필수로 배우도록 하자 !!&lt;/p&gt;</description>
      <category>CSS</category>
      <category>css display flex</category>
      <category>css flexbox</category>
      <category>display flex</category>
      <category>display flex 정리</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/116</guid>
      <comments>https://msm1307.tistory.com/116#entry116comment</comments>
      <pubDate>Sat, 29 Jul 2023 04:50:27 +0900</pubDate>
    </item>
    <item>
      <title>[새싹x코딩온] 웹 개발자 부트캠프 2주차 | CSS</title>
      <link>https://msm1307.tistory.com/111</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CSS란 무엇일까?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CSS는 Cascading Style Sheets의 약자이다.&lt;/li&gt;
&lt;li&gt;HTML로&amp;nbsp;문서(웹&amp;nbsp;페이지)의&amp;nbsp;뼈대를&amp;nbsp;만들면,&amp;nbsp;CSS는&amp;nbsp;문서(웹&amp;nbsp;페이지)를&amp;nbsp;디자인하기&amp;nbsp;위해&amp;nbsp;사용하는&amp;nbsp;언어&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CSS 참조 방식&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;인라인 방식&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태그에 직접 CSS를 정의해주는 기법&lt;/li&gt;
&lt;li&gt;스타일을 공통 CSS로 수정할 수 없음&lt;/li&gt;
&lt;li&gt;재사용 불가능&lt;/li&gt;
&lt;li&gt;&lt;u&gt;우선순위가 절대적으로 높아야 할 경우&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드 예시를 보자&lt;/p&gt;
&lt;pre id=&quot;code_1690341805184&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hello HTML !&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Hello CSS !&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 태그에서 p 태그 두개에 똑같은 스타일을 한다면 각각의 p태그에 style 속성에 스타일을 두번씩 적어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1690341919814&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p style=&quot;color: blue; background-color: yellow;&quot;&amp;gt;Hello HTML !&amp;lt;/p&amp;gt;
&amp;lt;p style=&quot;color: blue; background-color: yellow;&quot;&amp;gt;Hello CSS !&amp;lt;/p&amp;gt;&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;b&gt;내장 방식&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML의 &amp;lt;head&amp;gt; 태그 내부에 사용할 Style을 &amp;lt;style&amp;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;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690342373576&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;style&amp;gt;
    p {
      color: blue;
      background-color: yellow;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;p&amp;gt;Hello HTML !&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;Hello CSS !&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 방식과는 다르게 p태그는 재활용이 가능해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p태그를 쓸 때마다 같은 스타일의 태그를 가지게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;링크 방식&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 Style을 하나의 CSS 파일에 넣고, 필요한 HTML 파일에서 해당 파일을 링크해서 사용하는 방식&lt;/li&gt;
&lt;li&gt;html 파일에 &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;css 파일 경로&quot; /&amp;gt; 형식으로 사용&lt;/li&gt;
&lt;li&gt;HTML 문서와 분리가 되어 코드가 깔끔해진다.&lt;/li&gt;
&lt;li&gt;가장 많이 사용하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-26 오후 12.56.58.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mWbQ2/btsoY88ugIs/JB9NTncK2OjSvcZyNX5zM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mWbQ2/btsoY88ugIs/JB9NTncK2OjSvcZyNX5zM1/img.png&quot; data-alt=&quot;링크 방식을 설명하기 위한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mWbQ2/btsoY88ugIs/JB9NTncK2OjSvcZyNX5zM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmWbQ2%2FbtsoY88ugIs%2FJB9NTncK2OjSvcZyNX5zM1%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;1814&quot; height=&quot;600&quot; data-filename=&quot;스크린샷 2023-07-26 오후 12.56.58.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;링크 방식을 설명하기 위한 이미지&lt;/figcaption&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;index.html&lt;/p&gt;
&lt;pre id=&quot;code_1690343039288&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./style.css&quot; /&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;p&amp;gt;Hello HTML !&amp;lt;/p&amp;gt;
        &amp;lt;p&amp;gt;Hello CSS !&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;style.css&lt;/p&gt;
&lt;pre id=&quot;code_1690343076805&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;p {
    color: blue;
    background-color: yellow;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면 (인라인 방식, 내장 방식, 링크 방식 동일)&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
  &lt;p style=&quot;color: blue; background-color: yellow;&quot;&gt;Hello HTML !&lt;/p&gt;
  &lt;p style=&quot;color: blue; background-color: yellow;&quot;&gt;Hello CSS !&lt;/p&gt;
&lt;/div&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;CSS 선택자&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-27 09.13.25.png&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDkR5m/btso6Mcy7lk/vsE54Qo7hXbl0FkClyT1R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDkR5m/btso6Mcy7lk/vsE54Qo7hXbl0FkClyT1R0/img.png&quot; data-alt=&quot;CSS 선택자를 설명하는 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDkR5m/btso6Mcy7lk/vsE54Qo7hXbl0FkClyT1R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDkR5m%2Fbtso6Mcy7lk%2FvsE54Qo7hXbl0FkClyT1R0%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;1296&quot; height=&quot;356&quot; data-filename=&quot;스크린샷 2023-07-27 09.13.25.png&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CSS 선택자를 설명하는 이미지&lt;/figcaption&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;선택자로&amp;nbsp;HTML&amp;nbsp;요소를&amp;nbsp;선택하고&amp;nbsp;{&amp;nbsp;}&amp;nbsp;내에&amp;nbsp;속성&amp;nbsp;값을&amp;nbsp;지정하여&amp;nbsp;다양한&amp;nbsp;style을&amp;nbsp;정의&lt;/li&gt;
&lt;li&gt;여러 개의 프로퍼티를 연속해서 지정할 수 있으며 세미콜론(;)으로 구분&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/span&gt;은&amp;nbsp;표준스펙으로&amp;nbsp;이미&amp;nbsp;지정되어&amp;nbsp;있는&amp;nbsp;것을&amp;nbsp;사용,&amp;nbsp;사용자가&amp;nbsp;임의로&amp;nbsp;정의할&amp;nbsp;수&amp;nbsp;없다&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/span&gt;은&amp;nbsp;해당&amp;nbsp;속성에&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;값을&amp;nbsp;키워드나&amp;nbsp;크기&amp;nbsp;단위&amp;nbsp;또는&amp;nbsp;색상&amp;nbsp;단위등의&amp;nbsp;특정&amp;nbsp;단위로&amp;nbsp;지정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CSS 선택자 종류&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;id 선택자&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;id 이름을 선택자로 사용&lt;/li&gt;
&lt;li&gt;CSS에서 id 선택자 앞에 &quot;#&quot;을 붙여서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;class 선택자&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;class 이름을 선택자로 사용&lt;/li&gt;
&lt;li&gt;CSS에서 class 선택자 앞에 &quot;.&quot;을 붙여서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;&quot;*&quot;로 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690432412221&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;style&amp;gt;
      /* 전체 선택자 */
      * {
        background-color: skyblue;
      }
      /* 태그 선택자 */
      p {
        border: 1px solid blue;
        margin-bottom: 5px;
      }
      /* id 선택자 */
      #atxt {
        color: green;
      }
      /* class 선택자 */
      .btxt {
        color: red;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;p&amp;gt;태그 입니다.&amp;lt;/p&amp;gt;
    &amp;lt;p id=&quot;atxt&quot;&amp;gt;id 선택자&amp;lt;/p&amp;gt;
    &amp;lt;p class=&quot;btxt&quot;&amp;gt;class 선택자&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;style&gt;
  /* 전체 선택자 */
  .custom.ex1 {
    background-color: skyblue;
  }
  /* 태그 선택자 */
  .custom.ex1 p {
    border: 1px solid blue;
    margin-bottom: 5px !important;
  }
  /* id 선택자 */
  .custom.ex1 #atxt {
    color: green;
  }
  /* class 선택자 */
  .custom.ex1 .btxt {
    color: red;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex1&quot;&gt;
  &lt;p&gt;태그 입니다.&lt;/p&gt;
  &lt;p id=&quot;atxt&quot;&gt;id 선택자&lt;/p&gt;
  &lt;p class=&quot;btxt&quot;&gt;class 선택자&lt;/p&gt;
&lt;/div&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;/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;요소 내부에 있는 모든 해당 요소&lt;/u&gt;를 가리키며, 선택자 사이를 &quot; &quot;(공백)으로 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690433574574&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;style&amp;gt;
      /* 하위 선택자 */
      .box p {
        color: red;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;box&quot;&amp;gt;
      &amp;lt;p&amp;gt;.box의 자식&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;.box의 자식&amp;lt;/p&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;p&amp;gt;.box의 자손&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;p&amp;gt;.box의 자손&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;.box의 형제&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;style&gt;
  #content .custom.ex2 .box p {
    color: red;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex2&quot;&gt;
  &lt;div class=&quot;box&quot;&gt;
    &lt;p&gt;.box의 자식&lt;/p&gt;
    &lt;p&gt;.box의 자식&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;.box의 자손&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;.box의 자손&lt;/p&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
  &lt;p&gt;.box의 형제&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;.box의 하위 요소 p 태그가 전체 선택이 된다. (&lt;span style=&quot;color: #ee2323;&quot;&gt;자식 선택자와 헷갈림 주의&lt;/span&gt;)&lt;/blockquote&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;/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;요소 내부에 있는 바로 하위 요소만&lt;/u&gt; 가르키고, 선택자 사이를 &quot;&amp;gt;&quot;으로 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690434795525&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;style&amp;gt;
      /* 자식 선택자 */
      .box &amp;gt; p {
        color: red;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;box&quot;&amp;gt;
      &amp;lt;p&amp;gt;.box의 자식&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;.box의 자식&amp;lt;/p&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;p&amp;gt;.box의 자손&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;p&amp;gt;.box의 자손&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;.box의 형제&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;style&gt;
  #content .custom.ex3 .box &gt; p {
    color: red;
  }
&lt;/style&gt;
&lt;div class=&quot;custom ex3&quot;&gt;
  &lt;div class=&quot;box&quot;&gt;
    &lt;p&gt;.box의 자식&lt;/p&gt;
    &lt;p&gt;.box의 자식&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;p&gt;.box의 자손&lt;/p&gt;&lt;/li&gt;
      &lt;li&gt;&lt;p&gt;.box의 자손&lt;/p&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
  &lt;p&gt;.box의 형제&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;.box 하위 요소 중 .box의 자식 p태그만 선택이 된다.&lt;/blockquote&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;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;:link = 방문한 적이 없는 링크 선택 (a 태그에 해당)&lt;/li&gt;
&lt;li&gt;:visited = 방문한 적이 있는 링크 선택 (a 태그에 해당)&lt;/li&gt;
&lt;li&gt;:hover = 요소에 마우스 커서가 올라가 있는 동안 선택&lt;/li&gt;
&lt;li&gt;:active = 요소에 마우스를 클릭하고 있는 동안 선택&lt;/li&gt;
&lt;li&gt;:focus = 요소가 포커스되면 선택 (input 태그 등)&lt;/li&gt;
&lt;li&gt;:checked = 라디오 버튼이나 체크박스가 체크되었을 때 선택&lt;/li&gt;
&lt;li&gt;:first-child = 형제 요소 중 첫 번째 요소 선택&lt;/li&gt;
&lt;li&gt;:last-chlid = 형제 요소 중 마지막 요소 선택&lt;/li&gt;
&lt;li&gt;:nth-child(n) = 형제 요소 중 (n)번째라면 선택
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;:nth-child(odd) = 형제 요소 중 홀수 선택&lt;/li&gt;
&lt;li&gt;:nth-child(even) = 같은 요소 중 짝수 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;:not(x) = 부정 선택자 (x 요소 아닌 요소 선택)&lt;/li&gt;
&lt;li&gt;:has = 해당 요소 중 자손 선택자를 가지고 있는 경우 선택 (css의 if문)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최신 스펙이라 지원 안되는 브라우저도 있음 (&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://caniuse.com/?search=css%20has&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;확인하러 가기&lt;/a&gt;&lt;/span&gt;)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Ex) div:has(img) = div 요소 중 자손으로 img를 가지고 있을 경우&lt;/li&gt;
&lt;li&gt;Ex) div:has(+ p) = div 요소 중 형제로 p를 가지고 있을 경우&lt;/li&gt;
&lt;li&gt;Ex) div:has(p, img) = div 요소 중 자손으로 p, img를 가지고 있을 경우 (and 연산자)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690439001325&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
      body &amp;gt; * {
        border: 1px solid black;
        margin-bottom: 10px;
        padding: 5px;
      }
      /* hover */
      .hover:hover {
        background-color: skyblue;
      }
      /* active */
      .active:active {
        background-color: blue;
        color: #fff;
      }
      /* focus */
      .focus:focus {
        background-color: pink;
      }
      /* checked */
      .checked .radio input:checked + label {
        color: blueviolet;
      }
      .checked .checkbox input:checked + label {
        color: green;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;p class=&quot;hover&quot;&amp;gt;hover : 여기에 마우스 커서 올려보세요.&amp;lt;/p&amp;gt;
    &amp;lt;p class=&quot;active&quot;&amp;gt;active : 여기에 마우스 클릭해 보세요.&amp;lt;/p&amp;gt;
    &amp;lt;input type=&quot;text&quot; class=&quot;focus&quot; /&amp;gt; focus : input 태그를 클릭해 보세요.
    &amp;lt;div class=&quot;checked&quot;&amp;gt;
      &amp;lt;div class=&quot;radio&quot;&amp;gt;
        &amp;lt;input type=&quot;radio&quot; id=&quot;contactChoice1&quot; name=&quot;contact&quot; value=&quot;email&quot; checked /&amp;gt;
        &amp;lt;label for=&quot;contactChoice1&quot;&amp;gt;Email&amp;lt;/label&amp;gt;

        &amp;lt;input type=&quot;radio&quot; id=&quot;contactChoice2&quot; name=&quot;contact&quot; value=&quot;phone&quot; /&amp;gt;
        &amp;lt;label for=&quot;contactChoice2&quot;&amp;gt;Phone&amp;lt;/label&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;checked&quot;&amp;gt;
      &amp;lt;div class=&quot;checkbox&quot;&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;input type=&quot;checkbox&quot; id=&quot;coding&quot; name=&quot;interest&quot; value=&quot;coding&quot; /&amp;gt;
          &amp;lt;label for=&quot;coding&quot;&amp;gt;코딩&amp;lt;/label&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;input type=&quot;checkbox&quot; id=&quot;music&quot; name=&quot;interest&quot; value=&quot;music&quot; /&amp;gt;
          &amp;lt;label for=&quot;music&quot;&amp;gt;음악&amp;lt;/label&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;style&gt;
  #content .contents_style .custom.ex4 &gt; * {
    border: 1px solid black;
    margin-bottom: 10px !important;
    padding: 5px;
  }
  /* hover */
  #content .contents_style .custom.ex4 .hover:hover {
    background-color: skyblue;
  }
  /* active */
  #content .contents_style .custom.ex4 .active:active {
    background-color: blue;
    color: #fff;
  }
  /* focus */
  #content .contents_style .custom.ex4 .focus:focus {
    background-color: pink;
  }
  /* checked */
  #content .contents_style .custom.ex4 .checked .radio input:checked + label {
    color: blueviolet;
  }
  #content .contents_style .custom.ex4 .checked .checkbox input:checked + label {
    color: green;
  }
&lt;/style&gt;

&lt;div class=&quot;custom ex4&quot;&gt;
  &lt;p class=&quot;hover&quot;&gt;hover : 여기에 마우스 커서 올려보세요.&lt;/p&gt;
  &lt;p class=&quot;active&quot;&gt;active : 여기에 마우스 클릭해 보세요.&lt;/p&gt;
  &lt;input type=&quot;text&quot; class=&quot;focus&quot; /&gt; focus : input 태그를 클릭해 보세요.
  &lt;div class=&quot;checked&quot;&gt;
    &lt;div class=&quot;radio&quot;&gt;
      &lt;input type=&quot;radio&quot; id=&quot;contactChoice1&quot; name=&quot;contact&quot; value=&quot;email&quot; checked /&gt;
      &lt;label for=&quot;contactChoice1&quot;&gt;Email&lt;/label&gt;

      &lt;input type=&quot;radio&quot; id=&quot;contactChoice2&quot; name=&quot;contact&quot; value=&quot;phone&quot; /&gt;
      &lt;label for=&quot;contactChoice2&quot;&gt;Phone&lt;/label&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;checked&quot;&gt;
    &lt;div class=&quot;checkbox&quot;&gt;
      &lt;div&gt;
        &lt;input type=&quot;checkbox&quot; id=&quot;coding&quot; name=&quot;interest&quot; value=&quot;coding&quot; /&gt;
        &lt;label for=&quot;coding&quot;&gt;코딩&lt;/label&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;input type=&quot;checkbox&quot; id=&quot;music&quot; name=&quot;interest&quot; value=&quot;music&quot; /&gt;
        &lt;label for=&quot;music&quot;&gt;음악&lt;/label&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선택 된 요소의 앞, 뒤로 별도의 Content를 삽입하는 선택자&lt;/li&gt;
&lt;li&gt;실제로 의미 없는 HTML 태그를 만들지 않고 요소 삽입이 가능하여 자주 사용 !
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ex) 쇼핑몰 페이지 메뉴에 Hot, 추천 등(가상 요소 선택자를 활용하여 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반드시 content 라는 속성을 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 값(&quot;&quot;) 이라도 넣어야 적용이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;::after = 요소의 뒤에 내용 삽입&lt;/li&gt;
&lt;li&gt;::before = 요소의 앞에 내용 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690440464291&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
      .box::before {
        content: '택시';
      }
      .box::after {
        content: '빨리';
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;box&quot;&amp;gt;요기요&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;style&gt;
  .custom.ex5 .box::before {
    content: '택시';
  }
  .custom.ex5 .box::after {
    content: '빨리';
  }
&lt;/style&gt;

&lt;div class=&quot;custom ex5&quot;&gt;
  &lt;div class=&quot;box&quot;&gt;요기요&lt;/div&gt;
&lt;/div&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;b&gt;선택자 우선순위&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 112px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;선택자&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;우선순위(점수)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;전체 선택자( * )&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;태그 선택자 ( p, div, h1, ul, ... )&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;class 선택자 ( .box, ... )&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;가상클래스 선택자( :first-child, ... )&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;id 선택자 ( #box, ... )&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;!important, inline style을 제외한 우선순위 수치를 모두 합한 값으로 우선순위가 결정&lt;/li&gt;
&lt;li&gt;같은 요소라도 값이 높은 선택자가 부여한 속성이 우선으로 적용&lt;/li&gt;
&lt;li&gt;부여한 속성이 적용되지 않는다면 이전에 작성한 CSS 중 더 높은 순위를 갖는 선택자가 있는지 의심해봐야 됨&lt;/li&gt;
&lt;li&gt;동일한 값이라면 나중에 기술한 것이 먼저 기술한 것보다 우선순위가 높다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;※ 전체 우선순위&lt;br /&gt;태그 선택자 &amp;lt; class 선택자, 가상클래스 선택자 &amp;lt; id 선택자 &amp;lt; inline style &amp;lt; !important&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690441808012&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;box&quot;&amp;gt;
  &amp;lt;ul class=&quot;list&quot;&amp;gt;
    &amp;lt;li&amp;gt;
      &amp;lt;p&amp;gt;우선 순위를 알아보자&amp;lt;/p&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 순위 값 계산&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 128px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;선택자&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;우선순위 계산&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;ul&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;.list&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;ul.list&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;1 + 10 = 11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;#box ul&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;100 + 1 = 101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;#box .list&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;100 + 10 = 110&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;#box ul.list&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;100 + 1 + 10 = 111&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;아래 코드 중 p 태그의 색상은 무슨 색일까?&lt;/blockquote&gt;
&lt;pre id=&quot;code_1690442503965&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
      ul.list li p {
        color: red;
      }
      ul li p {
        color: orange;
      }
      #box ul.list li p {
        color: yellow;
      }
      #box .list li p {
        color: green;
      }
    &amp;lt;/style&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;box&quot;&amp;gt;
      &amp;lt;ul class=&quot;list&quot;&amp;gt;
        &amp;lt;li&amp;gt;
          &amp;lt;p&amp;gt;우선 순위를 맞혀보자&amp;lt;/p&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
  &lt;p&gt;정답을 선택하세요.&lt;/p&gt;
  &lt;div class=&quot;test&quot;&gt;
    &lt;ul&gt;
      &lt;li&gt;
        &lt;input type=&quot;radio&quot; id=&quot;red&quot; name=&quot;quiz&quot; value=&quot;red&quot; /&gt;
        &lt;label for=&quot;red&quot;&gt;red&lt;/label&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;input type=&quot;radio&quot; id=&quot;orange&quot; name=&quot;quiz&quot; value=&quot;orange&quot; /&gt;
        &lt;label for=&quot;orange&quot;&gt;orange&lt;/label&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;input type=&quot;radio&quot; id=&quot;yellow&quot; name=&quot;quiz&quot; value=&quot;yellow&quot; /&gt;
        &lt;label for=&quot;yellow&quot;&gt;yellow&lt;/label&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;input type=&quot;radio&quot; id=&quot;green&quot; name=&quot;quiz&quot; value=&quot;green&quot; /&gt;
        &lt;label for=&quot;green&quot;&gt;green&lt;/label&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;button
      id=&quot;quiz_submit&quot;
      style=&quot;border: 1px solid; padding: 2px 7px; background: #d5e4d5; border-radius: 5px; margin: 10px 0&quot;
    &gt;
      정답 제출
    &lt;/button&gt;

    &lt;div class=&quot;result&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
  const test = document.querySelector('.custom .test');
  const submit = document.querySelector('#quiz_submit');
  submit.addEventListener('click', () =&gt; {
    if (document.querySelector('input[name=&quot;quiz&quot;]:checked')) {
      const value = test.querySelector('input[name=&quot;quiz&quot;]:checked').value;
      const result = test.querySelector('.result');
      if (value === 'yellow') {
        result.innerHTML =
          '&lt;hr /&gt;&lt;p&gt;정답 입니다.&lt;/p&gt;&lt;p&gt;해설&lt;/p&gt;&lt;ul&gt;&lt;li&gt;red = 1 (ul) + 10 (.list) + 1 (li) + 1 (p) = 13점&lt;/li&gt;&lt;li&gt;orange = 1 (ul) + 1 (li) + 1 (p) = 3점&lt;/li&gt;&lt;li&gt;yellow = 100 (#box) + 1 (ul) + 10 (.list) + 1 (li) + 1 (p) = 113점&lt;/li&gt;&lt;li&gt;green = 100 (#box) + 10 (.list) + 1 (li) + 1 (p) = 112점&lt;/li&gt;&lt;/ul&gt;';
      } else {
        result.innerHTML = '&lt;hr /&gt;&lt;p&gt;땡 !&lt;/p&gt;';
      }
    } else {
      return alert('정답을 선택하세요 !');
    }
  });
&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>새싹x코딩온 웹 개발자 부트캠프/CSS</category>
      <category>CSS 선택자</category>
      <category>CSS 선택자 종류</category>
      <category>CSS 우선순위</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/111</guid>
      <comments>https://msm1307.tistory.com/111#entry111comment</comments>
      <pubDate>Wed, 26 Jul 2023 12:36:04 +0900</pubDate>
    </item>
    <item>
      <title>HTML table 태그</title>
      <link>https://msm1307.tistory.com/110</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;table 태그 (표 관련 태그) : 블록 요소&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;table 태그의 기본 구성&lt;/p&gt;
&lt;pre id=&quot;code_1690305716146&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;table border=&quot;1&quot; width=&quot;100%&quot;&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;6&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;7&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;8&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;9&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
    &lt;table style=&quot;width: 100%;&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;1&lt;/td&gt;
            &lt;td&gt;2&lt;/td&gt;
            &lt;td&gt;3&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;4&lt;/td&gt;
            &lt;td&gt;5&lt;/td&gt;
            &lt;td&gt;6&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;7&lt;/td&gt;
            &lt;td&gt;8&lt;/td&gt;
            &lt;td&gt;9&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;결과 화면을 보면 우리가 아는 table과 약간 다를 것이다.&lt;br /&gt;HTML에서 table에 border=&quot;1&quot; 이라는 속성을 주면 두 줄로 생성이 된다.&lt;br /&gt;이거는 css 편에서 알아보도록 하자.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-22 07.29.35.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1suWE/btso21NsyuE/QAjDiK2ptfvm29Ahqb8oa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1suWE/btso21NsyuE/QAjDiK2ptfvm29Ahqb8oa0/img.png&quot; data-alt=&quot;table 태그의 구성 요소를 쉽게 설명한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1suWE/btso21NsyuE/QAjDiK2ptfvm29Ahqb8oa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1suWE%2Fbtso21NsyuE%2FQAjDiK2ptfvm29Ahqb8oa0%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;1270&quot; height=&quot;640&quot; data-filename=&quot;스크린샷 2023-07-22 07.29.35.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;table 태그의 구성 요소를 쉽게 설명한 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;table&amp;gt;&amp;lt;/table&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의미 및 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표를 정의 할 때 사용하는 태그이며, 행 (Row)과 열(Column)의 2차원 정보로 구성&lt;/li&gt;
&lt;li&gt;자식 요소로 반드시 tr 태그를 정의해 주어야 하며 table -&amp;gt; tr -&amp;gt; td 순으로 마크업해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;border : 테두리 두께&lt;/li&gt;
&lt;li&gt;cellspacing : 테두리 간격 사이의 너비&lt;/li&gt;
&lt;li&gt;cellpadding : 셀 내부의 간격&lt;/li&gt;
&lt;li&gt;align : 테이블의 정렬 속성&lt;/li&gt;
&lt;li&gt;width 와 height : 테이블의 너비와 높이&lt;/li&gt;
&lt;li&gt;bgcolor 와 bordercolor : 테이블 배경색과, 테두리 색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;tr&amp;gt;&amp;lt;/tr&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의미 및 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;table 태그의 자식 요소로 표에서 행 (Row)을 정의할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의미 및 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tr 태그의 자식 요소로 표에서 열 (Column)을 정의할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;colspan : 해당 칸이 점유하는 열의 수 지정&lt;/li&gt;
&lt;li&gt;rowspan : 해당 칸의 점유하는 행의 수 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690305716151&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;colspan&amp;lt;/p&amp;gt;
&amp;lt;table border=&quot;1&quot; width=&quot;100%&quot;&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td colspan=&quot;3&quot;&amp;gt;1&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;p&amp;gt;rowspan&amp;lt;/p&amp;gt;
&amp;lt;table border=&quot;1&quot; width=&quot;100%&quot;&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td rowspan=&quot;3&quot;&amp;gt;1&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;3&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;4&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
    &lt;p&gt;colspan&lt;/p&gt;
    &lt;table border=&quot;1&quot; width=&quot;100%&quot;&gt;
        &lt;tr&gt;
            &lt;td colspan=&quot;3&quot;&gt;1&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;2&lt;/td&gt;
            &lt;td&gt;3&lt;/td&gt;
            &lt;td&gt;4&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
    
    &lt;p&gt;rowspan&lt;/p&gt;
    &lt;table border=&quot;1&quot; width=&quot;100%&quot;&gt;
        &lt;tr&gt;
            &lt;td rowspan=&quot;3&quot;&gt;1&lt;/td&gt;
            &lt;td&gt;2&lt;/td&gt;
            &lt;td&gt;3&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;4&lt;/td&gt;
            &lt;td&gt;5&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;th&amp;gt;&amp;lt;/th&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;td 태그와는 달리 글씨가 굵고 가운데 정렬이 기본 스타일 속성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;colspan : 해당 칸이 점유하는 열의 수 지정&lt;/li&gt;
&lt;li&gt;rowspan : 해당 칸의 점유하는 행의 수 지정&lt;/li&gt;
&lt;li&gt;scope : 열 (Column) 제목이나 행 (Row) 제목 셀&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;th&lt;/b&gt;에 정의&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저에서는 th 요소에 scope 속성을 명시해도 아무런 시각적 효과도 나타나지 않지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;스크린 리더기와 같은 장치에서는 유용하게 사용&lt;/u&gt;될 수 있다.&lt;/li&gt;
&lt;li&gt;열 (Column)의 제목일 경우 &amp;lt;th scope=&quot;col&quot;&amp;gt;로 정의&lt;/li&gt;
&lt;li&gt;행 (Row)의 제목일 경우 &amp;lt;th scope=&quot;row&quot;&amp;gt;로 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690305716157&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;table border=&quot;1&quot; width=&quot;100%&quot;&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th scope=&quot;col&quot;&amp;gt;교과목&amp;lt;/th&amp;gt;
        &amp;lt;th scope=&quot;col&quot;&amp;gt;점수&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th scope=&quot;row&quot;&amp;gt;수학&amp;lt;/th&amp;gt;
        &amp;lt;td&amp;gt;95&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th scope=&quot;row&quot;&amp;gt;영어&amp;lt;/th&amp;gt;
        &amp;lt;td&amp;gt;45&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
    &lt;table border=&quot;1&quot; width=&quot;100%&quot;&gt;
        &lt;tr&gt;
            &lt;th scope=&quot;col&quot;&gt;교과목&lt;/th&gt;
            &lt;th scope=&quot;col&quot;&gt;점수&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th scope=&quot;row&quot;&gt;수학&lt;/th&gt;
            &lt;td&gt;95&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;th scope=&quot;row&quot;&gt;영어&lt;/th&gt;
            &lt;td&gt;45&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;thead&amp;gt;&amp;lt;/thead&amp;gt;, &amp;lt;tbody&amp;gt;&amp;lt;/tbody&amp;gt;, &amp;lt;tfoot&amp;gt;&amp;lt;/tfoot&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의미 및 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML table에서 콘텐츠들을 그룹으로 묶을 때 사용&lt;/li&gt;
&lt;li&gt;thead,&amp;nbsp;tbody,&amp;nbsp;tfoot&amp;nbsp;요소는&amp;nbsp;기본적으로&amp;nbsp;웹&amp;nbsp;페이지의&amp;nbsp;레이아웃에&amp;nbsp;전혀&amp;nbsp;영향을&amp;nbsp;주지&amp;nbsp;않지만,&amp;nbsp;이&amp;nbsp;요소들의&amp;nbsp;스타일을&amp;nbsp;CSS를&amp;nbsp;사용하여&amp;nbsp;변경할&amp;nbsp;수는&amp;nbsp;있다.&lt;/li&gt;
&lt;li&gt;thead와 tfoot는 없는 경우도 있다.&lt;br /&gt;- table 태그를 사용시 브라우저가 자동으로 tbody는 삽입을 해주는 거 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;colgroup&amp;gt;&amp;lt;/colgroup&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의미 및 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;table의 열을 그룹으로 묶을 때 사용&lt;/li&gt;
&lt;li&gt;자식 요소&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;lt;col&amp;gt;&amp;lt;/col&amp;gt; 태그&lt;/b&gt;와 함께 사용할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt;caption&amp;gt;&amp;lt;/caption&amp;gt; 태그&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/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;table의 모든 태그를 활용한 코드&lt;/p&gt;
&lt;pre id=&quot;code_1690305716164&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;table width=&quot;100%&quot; border=&quot;1&quot;&amp;gt;
    &amp;lt;caption&amp;gt;
        학교 성적에 대한 표
    &amp;lt;/caption&amp;gt;
    &amp;lt;colgroup&amp;gt;
        &amp;lt;col style=&quot;width: 30%; background: skyblue&quot; /&amp;gt;
        &amp;lt;col /&amp;gt;
    &amp;lt;/colgroup&amp;gt;
    &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th scope=&quot;col&quot;&amp;gt;교과목&amp;lt;/th&amp;gt;
            &amp;lt;th scope=&quot;col&quot;&amp;gt;점수&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
    &amp;lt;tbody&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th scope=&quot;row&quot;&amp;gt;수학&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;90&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th scope=&quot;row&quot;&amp;gt;영어&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;70&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/tbody&amp;gt;
    &amp;lt;tfoot&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;평균&amp;lt;/th&amp;gt;
            &amp;lt;td&amp;gt;80&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/tfoot&amp;gt;
&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
    &lt;table width=&quot;100%&quot; border=&quot;1&quot;&gt;
        &lt;caption&gt;
            학교 성적에 대한 표
        &lt;/caption&gt;
        &lt;colgroup&gt;
            &lt;col style=&quot;width: 30%; background: skyblue&quot; /&gt;
            &lt;col /&gt;
        &lt;/colgroup&gt;
        &lt;thead&gt;
            &lt;tr&gt;
                &lt;th scope=&quot;col&quot;&gt;교과목&lt;/th&gt;
                &lt;th scope=&quot;col&quot;&gt;점수&lt;/th&gt;
            &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
            &lt;tr&gt;
                &lt;th scope=&quot;row&quot;&gt;수학&lt;/th&gt;
                &lt;td&gt;90&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;th scope=&quot;row&quot;&gt;영어&lt;/th&gt;
                &lt;td&gt;70&lt;/td&gt;
            &lt;/tr&gt;
        &lt;/tbody&gt;
        &lt;tfoot&gt;
            &lt;tr&gt;
                &lt;th&gt;평균&lt;/th&gt;
                &lt;td&gt;80&lt;/td&gt;
            &lt;/tr&gt;
        &lt;/tfoot&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>HTML</category>
      <category>HTML caption 태그</category>
      <category>HTML colgroup</category>
      <category>html table</category>
      <category>HTML table scope</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/110</guid>
      <comments>https://msm1307.tistory.com/110#entry110comment</comments>
      <pubDate>Wed, 26 Jul 2023 02:23:48 +0900</pubDate>
    </item>
    <item>
      <title>[새싹x코딩온] 웹 개발자 부트캠프 1주차 | HTML</title>
      <link>https://msm1307.tistory.com/104</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTML이란 무엇일까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;HTML은 &lt;span style=&quot;color: #333333;&quot;&gt;Hypertext Markup&lt;/span&gt; Language의 약자이다.&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;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Hypertext&lt;/span&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;: &lt;span style=&quot;color: #333333;&quot;&gt;웹 페이지를 다른 페이지로 연결하는 링크&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Markup&lt;/span&gt; &lt;span style=&quot;color: #333333;&quot;&gt;Language&lt;/span&gt; &lt;span style=&quot;color: #333333;&quot;&gt;: &lt;span style=&quot;background-color: #ffffff; color: #202122; text-align: left;&quot;&gt;태그 등을 이용하여 문서나 데이터의 구조를 명기하는 언어의 한 가지&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여기서 &lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Hypertext&lt;/b&gt;는 이해가 가는데 &lt;b&gt;Markup&lt;/b&gt;이 이해가 안가서 검색을 해보았다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&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;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 아래와 같은 텍스트가 있는데 텍스트에서 &quot;HTML&quot; 이라는 단어를 강조하고 싶다고 가정해보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;오늘은 HTML에 대해서 배웠다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;만약 블로그에서 &quot;HTML&quot; 단어를 강조하고 싶다면 강조하고 싶은 글자를 드래그해서 에디터를 활용하면 되겠지만 이거는 인간이 입장에서의 얘기고, 브라우저에서 저 글자를 강조해!라고 지시를 내린다면 어떻게 내릴 것인가?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;브라우저에서 &quot;HTML&quot;을&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;강조하기 위해서 앞뒤로 특수한 의미를 갖고 있다고 구분 지어야 하는데, &lt;/span&gt;&lt;span style=&quot;color: #ee2323; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이럴 때 필요한 게 태그이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;오늘은 &amp;lt;b&amp;gt;HTML&amp;lt;/b&amp;gt;에 대해서 배웠다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아직 &amp;lt;b&amp;gt;&amp;lt;/b&amp;gt;태그에 대해서는 안 배웠지만 이렇게 태그로 강조하고 싶은 범위를 표시(Mark)하는 게 &lt;b&gt;마크업&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTML 기본 구조&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689959904997&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;여기에는 문서의 제목을 입력해주세요&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    여기에 웹페이지에 표시할 콘텐츠(태그)를 입력해주세요
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/b&gt; : 문서의 형식 선언
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;DOCTYPE은&amp;nbsp;문서의&amp;nbsp;내용이&amp;nbsp;시작되기&amp;nbsp;전에&amp;nbsp;해당&amp;nbsp;문서가&amp;nbsp;어떤&amp;nbsp;마크업&amp;nbsp;언어&amp;nbsp;형식으로&amp;nbsp;작성되었는지를&amp;nbsp;명시하는&amp;nbsp;역할&lt;/li&gt;
&lt;li&gt;DOCTYPE의&amp;nbsp;뒤에&amp;nbsp;html이라고&amp;nbsp;쓰여&amp;nbsp;있는&amp;nbsp;것은&amp;nbsp;'이&amp;nbsp;문서는&amp;nbsp;HTML5로&amp;nbsp;작성되었습니다'라는&amp;nbsp;뜻&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;html&amp;gt;&lt;/b&gt;&amp;nbsp;:&amp;nbsp;문서의&amp;nbsp;시작과&amp;nbsp;끝
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;문서&amp;nbsp;형식&amp;nbsp;선언&amp;nbsp;이후&amp;nbsp;실제&amp;nbsp;문서의&amp;nbsp;내용을&amp;nbsp;표시하는&amp;nbsp;태그가&amp;nbsp;바로&amp;nbsp;&amp;lt;html&amp;gt;&amp;nbsp;태그&amp;nbsp;(여는&amp;nbsp;태그가&amp;nbsp;문서의&amp;nbsp;시작을,&amp;nbsp;닫는&amp;nbsp;태그가&amp;nbsp;문서의&amp;nbsp;끝을&amp;nbsp;의미)&lt;/li&gt;
&lt;li&gt;이&amp;nbsp;태그에는&amp;nbsp;선택적으로&amp;nbsp;lang이라는&amp;nbsp;속성을&amp;nbsp;추가할&amp;nbsp;수&amp;nbsp;있는데,&amp;nbsp;이는&amp;nbsp;문서의&amp;nbsp;주요&amp;nbsp;언어를&amp;nbsp;표기하기&amp;nbsp;위해&amp;nbsp;추가하는&amp;nbsp;속성&lt;br /&gt;ex)&amp;nbsp;한국어를&amp;nbsp;사용한&amp;nbsp;경우&amp;nbsp;&quot;ko&quot;,&amp;nbsp;영어를&amp;nbsp;사용한&amp;nbsp;경우&amp;nbsp;&quot;en&quot;&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;언어&amp;nbsp;코드를&amp;nbsp;속성값으로&amp;nbsp;입력할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;head&amp;gt;&lt;/b&gt;&amp;nbsp;:&amp;nbsp;문서의&amp;nbsp;정보
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;브라우저에게&amp;nbsp;문서의&amp;nbsp;정보를&amp;nbsp;전달&lt;/li&gt;
&lt;li&gt;&amp;lt;head&amp;gt;의&amp;nbsp;안에&amp;nbsp;작성되는&amp;nbsp;태그들은&amp;nbsp;웹&amp;nbsp;브라우저&amp;nbsp;화면에&amp;nbsp;표시될&amp;nbsp;콘텐츠를&amp;nbsp;나타내는&amp;nbsp;것은&amp;nbsp;아니지만,&amp;nbsp;웹페이지의&amp;nbsp;품질에&amp;nbsp;영향을&amp;nbsp;주는&amp;nbsp;중요한&amp;nbsp;정보들이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;meta&amp;gt;&lt;/b&gt;&amp;nbsp;:&amp;nbsp;문서의&amp;nbsp;키워드,&amp;nbsp;설정&amp;nbsp;등&amp;nbsp;문서와&amp;nbsp;관련된&amp;nbsp;항목들을&amp;nbsp;지정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;페이지&amp;nbsp;설명,&amp;nbsp;키워드,&amp;nbsp;저자,&amp;nbsp;화면&amp;nbsp;크기&amp;nbsp;등의&amp;nbsp;정보&lt;/li&gt;
&lt;li&gt;주로&amp;nbsp;브라우저&amp;nbsp;또는&amp;nbsp;검색&amp;nbsp;엔진에서&amp;nbsp;사용&lt;/li&gt;
&lt;li&gt;charset=&quot;utf-8&quot;&amp;nbsp;은&amp;nbsp;하단&amp;nbsp;설명&amp;nbsp;참조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;title&amp;gt;&lt;/b&gt;&amp;nbsp;:&amp;nbsp;문서의&amp;nbsp;제목
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;문서의&amp;nbsp;제목을&amp;nbsp;입력하는&amp;nbsp;태그,&amp;nbsp;웹&amp;nbsp;브라우저의&amp;nbsp;탭&amp;nbsp;메뉴에&amp;nbsp;표시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;body&amp;gt;&lt;/b&gt;&amp;nbsp;:&amp;nbsp;화면에&amp;nbsp;표시될&amp;nbsp;콘텐츠
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;웹&amp;nbsp;브라우저&amp;nbsp;화면에&amp;nbsp;표시될&amp;nbsp;콘텐츠를&amp;nbsp;입력하는&amp;nbsp;태그&lt;/li&gt;
&lt;li&gt;다양한&amp;nbsp;태그를&amp;nbsp;사용하여&amp;nbsp;웹&amp;nbsp;페이지의&amp;nbsp;구조를&amp;nbsp;설계할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;meta 태그에 charset=&quot;utf-8&quot; 을 설정하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;utf.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFRBLs/btsoysejQNY/vAfBsO9Wfso7he8LG1h4k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFRBLs/btsoysejQNY/vAfBsO9Wfso7he8LG1h4k0/img.png&quot; data-alt=&quot;한글이 깨진 메모장 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFRBLs/btsoysejQNY/vAfBsO9Wfso7he8LG1h4k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFRBLs%2FbtsoysejQNY%2FvAfBsO9Wfso7he8LG1h4k0%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;924&quot; height=&quot;163&quot; data-filename=&quot;utf.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한글이 깨진 메모장 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&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;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;세상에는 한국어, 영어, 일본어 등 다양한 언어 및 문자가 존재한다. 그리고 컴퓨터가 이를 해석하기 위해서는 각 문자에 맞는 인코딩 방식을 사용해야 한다. 가장 흔히 사용되는 인코딩 방식 중 하나는 utf-8이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;b&gt;utf-8&lt;/b&gt;&amp;nbsp;방식으로&amp;nbsp;설정하면,&amp;nbsp;한글을&amp;nbsp;비롯한&amp;nbsp;세상의&amp;nbsp;모든&amp;nbsp;언어를&amp;nbsp;표시할&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;HTML 태그 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-22 04.28.35.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tUdAH/btso09SDwAH/1lUEY0E91N1AomDImr8IX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tUdAH/btso09SDwAH/1lUEY0E91N1AomDImr8IX1/img.png&quot; data-alt=&quot;HTML 태그 기본 구조 (출처 : 새싹x코딩온)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tUdAH/btso09SDwAH/1lUEY0E91N1AomDImr8IX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtUdAH%2Fbtso09SDwAH%2F1lUEY0E91N1AomDImr8IX1%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;982&quot; height=&quot;295&quot; data-filename=&quot;스크린샷 2023-07-22 04.28.35.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTML 태그 기본 구조 (출처 : 새싹x코딩온)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTML 구성요소&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;HTML 구성요소에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;태그&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;요소&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Tag(태그)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690318599989&quot; class=&quot;xml&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;태그의이름&amp;gt;콘텐츠&amp;lt;/태그의이름&amp;gt;
&amp;lt;!-- &amp;lt;&amp;gt; 기호로 묶인 부분이 바로 태그이다. --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 태그는 HTML 문서를 작성하는 데 사용되는 기본 요소이다.&lt;/li&gt;
&lt;li&gt;HTML 태그는 시작 태그와 종료 태그로 구성된다. 시작 태그는 콘텐츠의 시작을 나타내고 종료 태그는 콘텐츠의 끝을 나타낸다.&lt;/li&gt;
&lt;li&gt;시작 태그와 종료 태그가 짝을 이루기 위해서는 태그의 이름이 같아야 하며, 종료 태그에는 &amp;lt; 기호 바로 뒤에 / 기호를 붙여 시작 태그와 구별해야 한다.&lt;/li&gt;
&lt;li&gt;태그의&amp;nbsp;이름은&amp;nbsp;해당&amp;nbsp;태그가&amp;nbsp;웹페이지에&amp;nbsp;어떤&amp;nbsp;콘텐츠를&amp;nbsp;표시하는지를&amp;nbsp;의미한다.&lt;br /&gt;예를 들어 텍스트&amp;nbsp;문단을&amp;nbsp;표시할&amp;nbsp;때는&amp;nbsp;'paragraph'의&amp;nbsp;약자인&amp;nbsp;'p'를&amp;nbsp;태그의&amp;nbsp;이름으로&amp;nbsp;사용하고,&amp;nbsp;이미지를&amp;nbsp;표시할&amp;nbsp;때는&amp;nbsp;'image'의&amp;nbsp;약자인&amp;nbsp;'img'를&amp;nbsp;태그의&amp;nbsp;이름으로&amp;nbsp;사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;단일 태그&lt;/h4&gt;
&lt;pre id=&quot;code_1690318599990&quot; class=&quot;apache&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;태그의이름&amp;gt;&lt;/code&gt;&lt;/pre&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;단일&amp;nbsp;태그는&amp;nbsp;태그&amp;nbsp;이름만으로&amp;nbsp;작성되며&amp;nbsp;닫는&amp;nbsp;태그가&amp;nbsp;없다.&lt;br /&gt;Ex) &amp;lt;br&amp;gt; : 줄 바꿈, &amp;lt;hr&amp;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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Element(요소)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;요소의 유형은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;블록 요소&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;인라인 요소&lt;/span&gt;로 나뉜다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;블록 요소(Block Element)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 부모 요소의 전체 너비(100%)를 차지한다.&lt;/li&gt;
&lt;li&gt;태그가 시작되면 무조건 개행(줄바꿈)이 일어난다.&lt;/li&gt;
&lt;li&gt;모든 인라인 요소를 포함하거나 다른 블록 요소를 포함한다.&lt;br /&gt;※ 블록 요소를 자식 요소로 포함 할 수 있는 요소와 포함할 수 없는 요소가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;인라인 요소(Inline Element)&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Attribute(속성)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태그를 보조하는 명령어로 태그 안쪽에서 작동&lt;br /&gt;Ex) id, class, style, width, height 등등&lt;/li&gt;
&lt;li&gt;태그마다 사용 가능한 속성이 정해져 있음&lt;br /&gt;Ex) &amp;lt;a href=&quot;&quot; style=&quot;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/li&gt;
&lt;li&gt;※&amp;nbsp;id, class, style은 모든 요소가 사용할 수 있는 속성&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;❗️ id 속성과 class 속성의 차이점&lt;/b&gt;&lt;br /&gt;id : 문서 전체에서 유일한 고유식별자(ID)를 정의, 즉 &quot;exciting&quot; 이라는 id 값을 사용했으면 한 HTML 문서에 &quot;exciting&quot; 라는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;id 값은 더 이상 사용 할 수 없다.&lt;/u&gt;&lt;br /&gt;&lt;/span&gt;class : id 속성과 달리 여러번 사용이 가능하다. (주로 css를 작성할 때 사용된다.)&lt;/blockquote&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_1690318599991&quot; class=&quot;applescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;p class=&quot;foo&quot; style=&quot;color: green&quot;&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 화면&lt;/p&gt;
&lt;div class=&quot;custom&quot;&gt;
	&lt;p class=&quot;foo&quot; style=&quot;color: green&quot;&gt;This is a paragraph.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>새싹x코딩온 웹 개발자 부트캠프/HTML</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/104</guid>
      <comments>https://msm1307.tistory.com/104#entry104comment</comments>
      <pubDate>Sat, 22 Jul 2023 01:41:51 +0900</pubDate>
    </item>
    <item>
      <title>[새싹x코딩온] 웹 개발자 부트캠프 1주차 | Git 설치 및 환경설정</title>
      <link>https://msm1307.tistory.com/98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;깃 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃 주소 : &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; href=&quot;https://git-scm.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://git-scm.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1689693178021&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;Git&quot; data-og-description=&quot;&quot; data-og-host=&quot;git-scm.com&quot; data-og-source-url=&quot;https://git-scm.com/&quot; data-og-url=&quot;https://git-scm.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5LAKI/hyTmsgW6c9/9fMFPbkZTTxdpWV0hRZMpk/img.png?width=778&amp;amp;height=502&amp;amp;face=0_0_778_502&quot;&gt;&lt;a href=&quot;https://git-scm.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://git-scm.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5LAKI/hyTmsgW6c9/9fMFPbkZTTxdpWV0hRZMpk/img.png?width=778&amp;amp;height=502&amp;amp;face=0_0_778_502');&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;Git&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;git-scm.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사이트에 들어가서 운영체제에 맞게 설치를 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ git 홈페이지에서 유저 운영체제를 인식해서 운영체제에 맞는 download url을 제공해주는 거 같다. Tip : &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; title=&quot;NavigatorUAData&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/platform&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NavigatorUAData&lt;/a&gt;&lt;/span&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;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;window : 시작 프로그램 - Git - Git Bash 실행 후 아래 명령어 입력&lt;/li&gt;
&lt;li&gt;mac : 응용 프로그램 - 유틸리티 or 기타 - 터미널 실행 후 아래 명령어 입력&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;display: flex; align-items: center; justify-content: flex-start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border: 1px solid; display: inline-block; align-items: center; width: 5px; height: 5px; border-radius: 100%; margin: 0 5px;&quot;&gt;&lt;/span&gt;Step1 : 유저 이름&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;설정&lt;/p&gt;
&lt;pre id=&quot;code_1689695123914&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global user.name &quot;your_name&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-19 00.52.33.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pEP1A/btsn9a56a0R/CxHrWf3eexuMXp7AwoOQkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pEP1A/btsn9a56a0R/CxHrWf3eexuMXp7AwoOQkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pEP1A/btsn9a56a0R/CxHrWf3eexuMXp7AwoOQkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpEP1A%2Fbtsn9a56a0R%2FCxHrWf3eexuMXp7AwoOQkk%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;980&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2023-07-19 00.52.33.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&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 style=&quot;display: flex; align-items: center; justify-content: flex-start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border: 1px solid; display: inline-block; align-items: center; width: 5px; height: 5px; border-radius: 100%; margin: 0 5px;&quot;&gt;&lt;/span&gt;Step2 : 유저 이메일&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_1689695705510&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global user.email &quot;your_email&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-19 00.56.26.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8F7ne/btsobIBcSP8/jX8UAKOL1ys5jJK99qOh6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8F7ne/btsobIBcSP8/jX8UAKOL1ys5jJK99qOh6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8F7ne/btsobIBcSP8/jX8UAKOL1ys5jJK99qOh6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8F7ne%2FbtsobIBcSP8%2FjX8UAKOL1ys5jJK99qOh6k%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;980&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2023-07-19 00.56.26.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&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 style=&quot;display: flex; align-items: center; justify-content: flex-start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border: 1px solid; display: inline-block; align-items: center; width: 5px; height: 5px; border-radius: 100%; margin: 0 5px;&quot;&gt;&lt;/span&gt;Step3 : 기본 브랜치명 main으로 설정하기&lt;/p&gt;
&lt;pre id=&quot;code_1689695975839&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global init.defaultBranch main&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-19 01.00.19.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdhWtq/btsn6NjKOcN/1vBeywge0bJwDIESPr4Tr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdhWtq/btsn6NjKOcN/1vBeywge0bJwDIESPr4Tr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdhWtq/btsn6NjKOcN/1vBeywge0bJwDIESPr4Tr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdhWtq%2Fbtsn6NjKOcN%2F1vBeywge0bJwDIESPr4Tr1%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;980&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2023-07-19 01.00.19.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ &lt;span&gt;git&lt;/span&gt;의&lt;span&gt; &lt;/span&gt;기본&lt;span&gt; &lt;/span&gt;브랜치명인&lt;span&gt; master&lt;/span&gt;가&lt;span&gt; &lt;/span&gt;노예제를&lt;span&gt; &lt;/span&gt;연상시킨다는&lt;span&gt; &lt;/span&gt;이유로&lt;span&gt; main &lt;/span&gt;으로&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 style=&quot;display: flex; align-items: center; justify-content: flex-start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border: 1px solid; display: inline-block; align-items: center; width: 5px; height: 5px; border-radius: 100%; margin: 0 5px;&quot;&gt;&lt;/span&gt;Step4 : 정보 확인하기&lt;/p&gt;
&lt;pre id=&quot;code_1689696120499&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global --list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-19 01.02.42.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/noIq2/btsn3jJ4rhg/XUXwZuK0DCw2DchTXAijLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/noIq2/btsn3jJ4rhg/XUXwZuK0DCw2DchTXAijLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/noIq2/btsn3jJ4rhg/XUXwZuK0DCw2DchTXAijLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnoIq2%2Fbtsn3jJ4rhg%2FXUXwZuK0DCw2DchTXAijLK%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;979&quot; height=&quot;135&quot; data-filename=&quot;스크린샷 2023-07-19 01.02.42.png&quot; data-origin-width=&quot;979&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;※ 정보 확인 후 q를 누르면 빠져나갈 수 있다.&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;</description>
      <category>Git</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/98</guid>
      <comments>https://msm1307.tistory.com/98#entry98comment</comments>
      <pubDate>Wed, 19 Jul 2023 01:15:18 +0900</pubDate>
    </item>
    <item>
      <title>VSCode 자동완성 세팅(code snippets)</title>
      <link>https://msm1307.tistory.com/94</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;snippets 파일 생성&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. &lt;span style=&quot;text-align: left;&quot;&gt;Cmd + Shift + P&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;키를 누르고, 검색창에 &lt;/span&gt;Configure User Snippets&lt;span style=&quot;text-align: left;&quot;&gt;을 입력합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682202331048&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;Snippets: Configure User snippets&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;span style=&quot;color: #333333;&quot;&gt;2. Enter 키를 누르면, 스니펫 설정 관련 메뉴가 나타납니다. 처음 설정하는 경우, New Global Snippets file... 항목을 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682202495376&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;New Global Snippets file...&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;span style=&quot;color: #333333;&quot;&gt;3. 파일 이름을 입력하고 Enter 키를 누릅니다. 파일 이름은 [fileName].code-snippets로 설정해주는 것이 일반적입니다.&lt;/span&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;snippets 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;파일이 열리면, 스니펫을 작성합니다. 스니펫은 JSON 형식으로 작성하며, &lt;/span&gt;prefix&lt;span style=&quot;text-align: left;&quot;&gt;와 &lt;/span&gt;body&lt;span style=&quot;text-align: left;&quot;&gt; 속성이 필요합니다.&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;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;▼ 예시 코드&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1682203053406&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;Console log&quot;: {
    &quot;prefix&quot;: &quot;cl&quot;,
    &quot;body&quot;: &quot;console.log($1);&quot;
  },
  &quot;Console log with string template&quot;: {
    &quot;prefix&quot;: &quot;clt&quot;,
    &quot;body&quot;: &quot;console.log(`$1 ${$2}`);&quot;
  },
  &quot;Function&quot;: {
    &quot;prefix&quot;: &quot;fc&quot;,
    &quot;body&quot;: [&quot;function $1(){&quot;, &quot;  $2&quot;, &quot;}&quot;]
  },
  &quot;Arrow Function&quot;: {
    &quot;prefix&quot;: &quot;afc&quot;,
    &quot;body&quot;: [&quot;const $1 = () =&amp;gt; {&quot;, &quot;  $2&quot;, &quot;};&quot;]
  },

  // react
  &quot;Arrow Function Callback&quot;: {
    &quot;prefix&quot;: &quot;ucb&quot;,
    &quot;body&quot;: [&quot;const $1 = useCallback(() =&amp;gt; {&quot;, &quot;  $2&quot;, &quot;}, []);&quot;]
  },
  &quot;useState&quot;: {
    &quot;prefix&quot;: &quot;us&quot;,
    &quot;body&quot;: [&quot;const [$1, set${1/(.*)/${1:/capitalize}/}] = useState($2);&quot;]
  },
  &quot;useEffect&quot;: {
    &quot;prefix&quot;: &quot;ue&quot;,
    &quot;body&quot;: [&quot;useEffect(() =&amp;gt; {&quot;, &quot;  $1&quot;, &quot;}, []);&quot;]
  },
  &quot;useEffect return&quot;: {
    &quot;prefix&quot;: &quot;uer&quot;,
    &quot;body&quot;: [&quot;useEffect(() =&amp;gt; {&quot;, &quot;  $1&quot;, &quot;&quot;, &quot;return () =&amp;gt; {&quot;, &quot;$2&quot;, &quot;}&quot;, &quot;}, []);&quot;]
  },
  &quot;React Functional Component&quot;: {
    &quot;prefix&quot;: &quot;rfc&quot;,
    &quot;body&quot;: [
      // 단일 정규식으로 변환: 첫 글자 또는 하이픈(-) 뒤 글자를 대문자로 변경
      &quot;export default function ${1:${TM_FILENAME_BASE/^(.)|-(.)/${1:/upcase}${2:/upcase}/g}}() {&quot;,
      &quot;  return (&quot;,
      &quot;    &amp;lt;div&amp;gt;&quot;,
      &quot;      ${2:$TM_FILENAME_BASE}&quot;, // 원본 파일명 표시
      &quot;    &amp;lt;/div&amp;gt;&quot;,
      &quot;  );&quot;,
      &quot;}&quot;,
      &quot;&quot;
    ],
    &quot;description&quot;: &quot;Creates a React functional component, converting kebab-case filename to PascalCase component name.&quot;
  },
  &quot;React Custom Hook&quot;: { // 새로 추가된 스니펫
    &quot;prefix&quot;: &quot;uhook&quot;, // 또는 uhook (use custom hook) 등 원하는 prefix 사용
    &quot;body&quot;: [
      // 파일명을 useCamelCase 형태로 변환 (예: data-fetcher -&amp;gt; useDataFetcher)
      &quot;export default function ${1:${TM_FILENAME_BASE/-(.)/${1:/upcase}/g}}($2) {&quot;,
      &quot;  $0&quot;, // 최종 커서 위치
      &quot;}&quot;,
      &quot;&quot;
    ],
    &quot;description&quot;: &quot;Creates a default exported React custom hook function, deriving the name from the filename (kebab-case to usePascalCase).&quot;
  },
  
  // storybook
  &quot;Storybook Meta&quot;: {
    &quot;prefix&quot;: &quot;sm&quot;,
    &quot;body&quot;: [
      &quot;import type { Meta, StoryObj } from '@storybook/react';&quot;,
      &quot;import { fn } from '@storybook/test';&quot;,
      &quot;&quot;,
      &quot;const meta = {&quot;,
      &quot;  title: '$1',&quot;,
      &quot;  component: ${2:Component},&quot;,
      &quot;  tags: ['autodocs'],&quot;,
      &quot;  parameters: {&quot;,
      &quot;    layout: 'centered',&quot;,
      &quot;  },&quot;,
      &quot;  argTypes: {&quot;,
      &quot;    children: { control: 'text' },&quot;,
      &quot;  },&quot;,
      &quot;  args: { ${3:event}: fn() },&quot;,
      &quot;} satisfies Meta&amp;lt;typeof ${2:Component}&amp;gt;;&quot;,
      &quot;&quot;,
      &quot;export default meta;&quot;,
      &quot;type Story = StoryObj&amp;lt;typeof meta&amp;gt;;&quot;,
      &quot;&quot;,
      &quot;export const Primary: Story = {&quot;,
      &quot;  args: {&quot;,
      &quot;    children: 'Button',&quot;,
      &quot;  },&quot;,
      &quot;};&quot;,
      &quot;&quot;
    ]
  },
  &quot;Storybook Meta Render&quot;: {
    &quot;prefix&quot;: &quot;smr&quot;,
    &quot;body&quot;: [
      &quot;import type { Meta, StoryObj } from '@storybook/react';&quot;,
      &quot;import { fn } from '@storybook/test';&quot;,
      &quot;import { useArgs } from '@storybook/preview-api';&quot;,
      &quot;&quot;,
      &quot;const meta = {&quot;,
      &quot;  title: '$1',&quot;,
      &quot;  component: ${2:Component},&quot;,
      &quot;  tags: ['autodocs'],&quot;,
      &quot;  parameters: {&quot;,
      &quot;    layout: 'centered',&quot;,
      &quot;  },&quot;,
      &quot;  argTypes: {&quot;,
      &quot;    children: { control: 'text' },&quot;,
      &quot;  },&quot;,
      &quot;  args: { ${3:event}: fn() },&quot;,
      &quot;} satisfies Meta&amp;lt;typeof ${2:Component}&amp;gt;;&quot;,
      &quot;&quot;,
      &quot;export default meta;&quot;,
      &quot;type Story = StoryObj&amp;lt;typeof meta&amp;gt;;&quot;,
      &quot;export const Primary: Story = {&quot;,
      &quot;  args: {&quot;,
      &quot;    children: 'Button',&quot;,
      &quot;  },&quot;,
      &quot;  render: (args) =&amp;gt; {&quot;,
      &quot;    const [{ isOpen }, updateArgs] = useArgs();&quot;,
      &quot;&quot;,
      &quot;    function onChange() {&quot;,
      &quot;      updateArgs({ isOpen: !isOpen });&quot;,
      &quot;    }&quot;,
      &quot;&quot;,
      &quot;    return &amp;lt;Checkbox {...args} onChange={onChange} isChecked={isChecked} /&amp;gt;;&quot;,
      &quot;  },&quot;,
      &quot;};&quot;,
      &quot;&quot;
    ]
  },

}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;us의 경우 변수명을 입력하고 tab을 누르면 set 다음 바로 나오는 첫번째 글자가 대문자로 바뀐다.&lt;/blockquote&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: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.youtube.com/watch?v=umeqCopb96w&quot;&gt;https://www.youtube.com/watch?v=umeqCopb96w&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;유튜브 강의&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://snippet-generator.app/&quot;&gt;https://snippet-generator.app/&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 사이트에 접속해서 편리하게 세팅해서 복사해와도 됨&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://code.visualstudio.com/docs/editor/userdefinedsnippets&quot;&gt;https://code.visualstudio.com/docs/editor/userdefinedsnippets&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;관련 문서&lt;/span&gt;&lt;/p&gt;</description>
      <category>IDE/VSCode</category>
      <category>vscode snippet</category>
      <category>vscode 스니펫</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/94</guid>
      <comments>https://msm1307.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 23 Apr 2023 07:40:13 +0900</pubDate>
    </item>
    <item>
      <title>제네릭(Generic) 타입</title>
      <link>https://msm1307.tistory.com/93</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;제네릭은 TypeScript에서 &lt;u&gt;&lt;b&gt;타입을 추상화하여 재사용 가능한 코드&lt;/b&gt;&lt;/u&gt;를 작성하는 방법 중 하나입니다. 함수, 클래스, 인터페이스 등 여러 곳에서 사용될 수 있으며, 특정 타입 대신 &lt;u&gt;코드가 실행될 때 타입이 결정&lt;/u&gt;되도록 합니다. 제네릭을 사용하면 코드의 재사용성과 유지 보수성이 향상되며, 코드의 유연성과 확장성이 높아집니다.&lt;/blockquote&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;pre id=&quot;code_1682198441560&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getFirstNumber(numbers: number[]): number | undefined {
  return numbers[0];
}

function getFirstString(strings: string[]): string | undefined {
  return strings[0];
}

const numbers = [1, 2, 3];
const firstNumber = getFirstNumber(numbers);
console.log(firstNumber); // 1

const strings = ['a', 'b', 'c'];
const firstString = getFirstString(strings);
console.log(firstString); // a&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;위의 코드에서 getFirstNumber 함수와 getFirstString 함수가 각각 숫자와 문자열 배열에 대해 작동하도록 구현되어 있습니다. 이 경우 함수 구현이 중복되기 때문에 코드의 가독성과 유지보수성이 저하될 수 있습니다. 또한, 새로운 유형의 데이터에 대해 함수를 작성할 때마다 새로운 함수를 구현해야 하는 문제점이 있습니다.&lt;/blockquote&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;pre id=&quot;code_1682201316982&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getFirstItem&amp;lt;T&amp;gt;(items: T[]): T | undefined {
  return items[0];
}

const numbers = [1, 2, 3];
const firstNumber = getFirstItem(numbers);
console.log(firstNumber); // 1

const strings = ['a', 'b', 'c'];
const firstString = getFirstItem(strings);
console.log(firstString); // a&lt;/code&gt;&lt;/pre&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;lt;T&amp;gt;는 제네릭 타입 매개변수로 사용됩니다. 함수의 items 매개변수는 T 배열입니다. 따라서 함수의 반환 유형은 T 또는 undefined 입니다. getFirstItem 함수는 numbers 배열과 strings 배열 모두에 대해 작동합니다. 제네릭은 타입스크립트의 강력한 기능 중 하나이며, 타입 안정성을 유지하면서 다양한 유형의 데이터를 다룰 수 있도록 도와줍니다.&lt;/blockquote&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: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://www.typescriptlang.org/docs/handbook/2/generics.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.typescriptlang.org/docs/handbook/2/generics.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>TypeScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/93</guid>
      <comments>https://msm1307.tistory.com/93#entry93comment</comments>
      <pubDate>Fri, 21 Apr 2023 12:53:24 +0900</pubDate>
    </item>
    <item>
      <title>Tiptab font-size 기능 구현</title>
      <link>https://msm1307.tistory.com/92</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 라이브러리 설치&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;background-color: #333333; color: #dddddd;&quot;&gt;npm install @tiptap/react @tiptap/pm @tiptap/starter-kit @tiptap/extension-text-style&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 폰트 사이즈 수정 라이브러리 만들기&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위 라이브러리에는 font-size 수정하는 내장함수가 포함이 안 되어 있다.&lt;br /&gt;&lt;s&gt;♧ Tiptab 라이브러리 자체가 필요한 것들을 따로 설치해서 사용해야 되는 거 같다.(리액트 같은 느낌)&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;직접 커스텀 해서 만들거나 &lt;span style=&quot;background-color: #333333; color: #dddddd;&quot;&gt;npm install tiptap-extension-font-size&lt;/span&gt; 라이브러리를 설치해서 사용하여야 한다.&lt;br /&gt;나는 필요시 수정도 할 수 있을 거 같아 &lt;a href=&quot;https://stackoverflow.com/questions/70564092/tiptap-font-size-react&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;스택오버플로우&lt;/span&gt;&lt;/a&gt;를 참고해 라이브러리를 따로 만들었다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/lib/font-size.js&lt;/p&gt;
&lt;pre id=&quot;code_1681897237520&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Extension } from '@tiptap/react';

export const FontSize = Extension.create({
  name: 'fontSize',
  addOptions() {
    return {
      types: ['textStyle'],
    };
  },
  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          fontSize: {
            default: null,
            parseHTML: (element) =&amp;gt;
              element.style.fontSize.replace(/['&quot;]+/g, ''),
            renderHTML: (attributes) =&amp;gt; {
              if (!attributes.fontSize) {
                return {};
              }
              return {
                style: `font-size: ${attributes.fontSize}`,
              };
            },
          },
        },
      },
    ];
  },
  addCommands() {
    return {
      setFontSize:
        (fontSize) =&amp;gt;
        ({ chain }) =&amp;gt; {
          return chain().setMark('textStyle', { fontSize: fontSize }).run();
        },
      unsetFontSize:
        () =&amp;gt;
        ({ chain }) =&amp;gt; {
          return chain()
            .setMark('textStyle', { fontSize: null })
            .removeEmptyTextStyle()
            .run();
        },
    };
  },
});&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;커스텀 만드는 방법 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://tiptap.dev/guide/custom-extensions/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tiptap.dev/guide/custom-extensions/&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;s&gt;나도 위 사이트 보고 이해 안되서 다른 코드를 보고 참고했음&lt;/s&gt; &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt; &lt;br /&gt;이미 만들어진 익스텐션들 : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://tiptap.dev/api/extensions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tiptap.dev/api/extensions&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 라이브러리를 불러와 사용해보자&lt;/h3&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681897584846&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState, useCallback } from 'react';
import { useEditor, EditorContent } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import TextStyle from '@tiptap/extension-text-style';
import { FontSize } from './lib/font-size';
import Toolbar from './Toolbar.jsx';
import { StyledEditor } from './styledEditor.js';

export default function Editor() {
  const [fontSize, setFontSize] = useState('16px');

  const editor = useEditor({
    extensions: [StarterKit, TextStyle, FontSize],
    content: '',
  });

  const handleFontSizeChange = useCallback(
    (event) =&amp;gt; {
      if (!editor) return null;
      const button = event.target;
      const fontSize = button.innerText;
      setFontSize(`${fontSize}px`);
      editor.chain().focus().setFontSize(`${fontSize}px`).run();
    },
    [editor]
  );

  return (
    &amp;lt;StyledEditor&amp;gt;
      &amp;lt;Toolbar editor={editor} onFontSizeChange={handleFontSizeChange} /&amp;gt;
      &amp;lt;EditorContent editor={editor} /&amp;gt;
    &amp;lt;/StyledEditor&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/Toolbar.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681898267504&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';

const fontSize = ['14', '16', '18', '24', '28', '30', '34', '38'];

export default function Toolbar({ editor, onFontSizeChange }) {
  if (!editor) {
    return null;
  }
  return (
    &amp;lt;div className=&quot;toolbar&quot;&amp;gt;
      {fontSize.map((value) =&amp;gt; (
        &amp;lt;button
          key={value}
          onClick={onFontSizeChange}
          className={
            editor.isActive('textStyle', { fontSize: `${value}px` })
              ? 'is-active'
              : ''
          }
        &amp;gt;
          {value}
        &amp;lt;/button&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;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;background-color: #333333; color: #dddddd;&quot;&gt;npm i @emotion/styled @emotion/react&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;에디터를 스타일링 하기위해 emotion을 택했다.&lt;br /&gt;&lt;s&gt;처음엔 .css 파일로 작성하려 했는데 나중에 props로 state를 전달 받아 사용해야 될 거 같아 설치하게 되었다.&lt;br /&gt;&lt;/s&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/styledEditor.js&lt;/p&gt;
&lt;pre id=&quot;code_1681899453872&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import styled from '@emotion/styled';

export const StyledEditor = styled.div`
    .toolbar {
        margin-bottom: 10px;
        display: flex;

        button {
            cursor: pointer;
            background-color: #fff;
            font-size: 16px;
            border-radius: 5px;
            margin: 0 1px;
            display: flex;
            justify-content: center;
            align-items: center;
            border: 1px solid black;

            &amp;amp;:hover {
                background-color: rgba(0, 0, 0, 0.07);
            }

            &amp;amp;.is-active {
                background-color: #333;
                color: #fff;
            }
        }

    }

    /* 에디터 */
    .ProseMirror {
        padding: 20px;
        height: 400px;
        border: 1px solid;
        overflow-y: auto;
        overflow-x: hidden;

        &amp;amp;:focus {
            outline: none;
        }

        p {
            margin: 10px 0;
        }

        ol {
            padding-left: 30px;
        }
    }
`;&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;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://stackblitz.com/edit/react-8fcue8?file=src/editor/styledEditor.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-8fcue8?file=src/editor/styledEditor.js&lt;/a&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;size16&quot;&gt;위 주소로 들어가면 font-size 수정이 가능하다. 하지만 보통 에디터들처럼 버그? 투성이다.&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;color: #ee2323;&quot;&gt;커서 사이즈 버그(빈&lt;span style=&quot;text-align: left;&quot;&gt;&amp;nbsp;에디터일 때 38px 폰트를 클릭해도 커서는 커지지 않고 그대로임&lt;/span&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;실행 시 첫 폰트 사이즈를 따로 지정해 줘야 됨&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;텍스트를 쳤다가 빈 에디터로 만들면(계속 삭제) 폰트 사이즈가 초기화됨&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 버그 수정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 커서 사이즈 버그 수정&lt;/h4&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/styledEditor.js&lt;/p&gt;
&lt;pre id=&quot;code_1681900732857&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // 기존 스타일 코드
    // ...

    /* 에디터 */
    .ProseMirror {
        padding: 20px;
        height: 400px;
        border: 1px solid;
        overflow-y: auto;
        overflow-x: hidden;

        &amp;amp;:focus {
            outline: none;
        }

        p {
            margin: 10px 0;

            /* 텍스트 없을 때 커서 사이즈 유지 */
            &amp;amp;:last-child:has(br) {
                font-size: ${(props) =&amp;gt; props.editorFontSize};
            }
        }

        ol {
            padding-left: 30px;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681901626270&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  // 기존 코드
  // ...
  return (
    &amp;lt;StyledEditor editorFontSize={fontSize}&amp;gt;
      &amp;lt;Toolbar editor={editor} onFontSizeChange={handleFontSizeChange} /&amp;gt;
      &amp;lt;EditorContent editor={editor} /&amp;gt;
    &amp;lt;/StyledEditor&amp;gt;
  );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;✔️ 해결 방법&lt;br /&gt;개발자 도구로 에디터 html을 까보면 빈 에디터일 때 &amp;lt;p&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;를 볼 수 있다.&lt;br /&gt;&amp;amp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/:has&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;:has&lt;/a&gt;&lt;/span&gt;(br) 이렇게 하면 p 태그 중 br 태그만 포함 된 p 태그를 선택할 수 있다. 하지만 모든 br 상위인 p 태그를 선택하게 되면 나중에 새로운 버그를 만들어 낼 거 같아 &lt;u&gt;&amp;amp;:last-child:has(br)&lt;/u&gt; 이렇게 마지막 br 상위인 p 태그를 선택하게 되었다.&lt;br /&gt;마지막으로 fontSize를 props으로 받아와 font-size를 지정해 주었다.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 실행시 첫 폰트사이즈 지정&lt;/h4&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681901839462&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  // 기존 코드
  // ...
  
  const editor = useEditor({
    extensions: [StarterKit, TextStyle, FontSize],
    content: '',
    onCreate({ editor }) {
      editor.chain().focus().setFontSize(`${fontSize}`).run();
    },
  });
  
  // 기존 코드
  // ...&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;✔️ 해결 방법&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://tiptap.dev/api/events#create&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tiptap.dev/api/events#create&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;위 주소에 보면 에디터의 이벤트에 대한 설명이 자세히 나와있다.&lt;br /&gt;create (에디터가 생성되고 난 후) 이벤트를 활용해&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;editor.chain().focus().setFontSize(`${fontSize}`).run();&lt;/span&gt; (폰트 사이즈를 결정짓는 함수)를 사용하였다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 텍스트를 쳤다가 빈 에디터로 만들면(계속 삭제 시킴) 폰트 사이즈가 초기화는 현상 수정&lt;/h4&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;src/editor/index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681902575634&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  // 기존 코드
  // ...
  
  const editor = useEditor({
    extensions: [StarterKit, TextStyle, FontSize],
    content: '',
    onCreate({ editor }) {
      editor.chain().focus().setFontSize(fontSize).run();
    },
    onUpdate({ editor }) {
      if (editor.isEmpty) {
        const currentFontSize = editor.getAttributes('textStyle').fontSize;
        const newFontSize = currentFontSize || fontSize;

        editor.chain().focus().setFontSize(newFontSize).run();
        setFontSize(newFontSize);
      }
    },
  });
  
  // 기존 코드
  // ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;✔️ 해결 방법&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://tiptap.dev/api/events#update&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tiptap.dev/api/events#update&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;마찬가지로 위 주소에 보면 에디터의 이벤트에 대한 설명이 자세히 나와있다.&lt;br /&gt;update(내용이 바뀌었을 때) 이벤트를 이용해 내용 바뀌는 것을  감지한다.&lt;br /&gt;&lt;br /&gt;if (editor.isEmpty) 이 부분은 에디터가 빈 값일 대 true를 반환해준다.&lt;br /&gt;(에디터가 빈 값일 때만 실행해 주면 되기 때문 아래 함수 호출을 최소화할 수 있다.)&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;const currentFontSize = editor.getAttributes('textStyle').fontSize;&lt;/span&gt; &amp;lt;- 현재 fontSize를 반환해준다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;const newFontSize = currentFontSize || fontSize;&lt;/span&gt;&lt;br /&gt;currentFontSize는 빈 텍스트일 때 null을 반환해서 or 연산자를 이용해 null일 경우 state 값인 fontSize를 지정해 주게 한다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;editor.chain().focus().setFontSize(newFontSize).run();&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;setFontSize(newFontSize);&lt;/span&gt;&lt;br /&gt;현재 폰트 사이즈를 newFontSize 값을 넣음으로 써 최신 값이 유지가 된다.&lt;br /&gt;마지막으로 fontSize는 css에서 커서 사이즈를 조절하기 때문 setFontSize을 써서 fontSize를 최신화해주었다.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&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;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://stackblitz.com/edit/react-1bqplt?file=src/editor/index.jsx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-1bqplt?file=src/editor/index.jsx&lt;/a&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프레임워크/React</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/92</guid>
      <comments>https://msm1307.tistory.com/92#entry92comment</comments>
      <pubDate>Wed, 19 Apr 2023 15:31:21 +0900</pubDate>
    </item>
    <item>
      <title>react-quill Custom</title>
      <link>https://msm1307.tistory.com/91</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;toolbar 기존 아이콘 변경&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1681730724430&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ReactQuill, { Quill } from &quot;react-quill&quot;;
import &quot;react-quill/dist/quill.snow.css&quot;;

const icons = Quill.import(&quot;ui/icons&quot;);
icons[&quot;bold&quot;] = &quot;&amp;lt;span&amp;gt;B&amp;lt;/span&amp;gt;&quot;;

export default function Editor() {
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;ReactQuill /&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;▼ 종류&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 324px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;종류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;설명 (아이콘)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 20px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;bold&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 20px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;굵기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;italic&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기울임&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;underline&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;밑줄&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;strike&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;취소선&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;blockquote&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;color&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;글자색&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;background&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;배경색&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;image&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이미지 첨부&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;link&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;링크&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;list&quot;][&quot;&lt;span style=&quot;text-align: center;&quot;&gt;ordered&lt;/span&gt;&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;순서 있는 리스트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;list&quot;][&quot;bullet&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: center;&quot;&gt;순서 없는 리스트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;list&quot;][&quot;check&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;체크 리스트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;align&quot;][&quot;&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;왼쪽 정렬&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;align&quot;][&quot;center&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가운데 정렬&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;align&quot;][&quot;right&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;오른쪽 정렬&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.8605%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;icons[&quot;align&quot;][&quot;justify&quot;]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.1395%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;양쪽 정렬&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;nbsp; 많은 종류는&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;node_modules &amp;gt; quill &amp;gt; ui &amp;gt; icons.js&lt;/b&gt;&lt;/span&gt; 파일 참고&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;toolbar 폰트 사이즈 변경&lt;/b&gt;&lt;/h2&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;default.js&lt;/p&gt;
&lt;pre id=&quot;code_1681743594952&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const fontSize = [&quot;14px&quot;, &quot;16px&quot;, &quot;18px&quot;, &quot;24px&quot;, &quot;28px&quot;, &quot;32px&quot;];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;Toolbar.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681743621374&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { fontSize } from &quot;./default&quot;;

export default function Toolbar() {
    return (
        &amp;lt;div id=&quot;toolbar&quot;&amp;gt;
            &amp;lt;span className=&quot;ql-formats&quot;&amp;gt;
                &amp;lt;select className=&quot;ql-size&quot;&amp;gt;
                    {fontSize.map((val) =&amp;gt; (
                        &amp;lt;option value={val} selected={val === &quot;16px&quot;}&amp;gt;
                            {val.replace(/[^0-9]/g, &quot;&quot;)}
                        &amp;lt;/option&amp;gt;
                    ))}
                &amp;lt;/select&amp;gt;
            &amp;lt;/span&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;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;index.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1681743503381&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ReactQuill, { Quill } from &quot;react-quill&quot;;
import &quot;react-quill/dist/quill.snow.css&quot;;
import Toolbar from &quot;./Toolbar&quot;;
import { fontSize } from &quot;./default&quot;;

var Size = Quill.import(&quot;attributors/style/size&quot;);
Size.whitelist = fontSize;
Quill.register(Size, true);

const modules = {
    toolbar: {
        container: &quot;#toolbar&quot;,
        handlers: {},
    },
};

export default function Editor() {
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;Toolbar /&amp;gt;
            &amp;lt;ReactQuill modules={modules} /&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackblitz.com/edit/react-vz6kkz?file=src%2Findex.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-vz6kkz?file=src%2Findex.js&lt;/a&gt;&lt;/p&gt;</description>
      <category>프레임워크/React</category>
      <category>react-quill</category>
      <category>react-quill Custom</category>
      <category>react-quill fontSize</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/91</guid>
      <comments>https://msm1307.tistory.com/91#entry91comment</comments>
      <pubDate>Mon, 17 Apr 2023 20:28:13 +0900</pubDate>
    </item>
    <item>
      <title>React에서 Tooltip 만들기</title>
      <link>https://msm1307.tistory.com/90</link>
      <description>&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;Tooltip.js&lt;/p&gt;
&lt;pre id=&quot;code_1681538626485&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from 'react';
import styled from 'styled-components';

function Tooltip({ children, text }) {
  const [show, setShow] = useState(false);

  return (
    &amp;lt;StyledWrap&amp;gt;
      &amp;lt;StyledBlock
        onMouseEnter={() =&amp;gt; setShow(true)}
        onMouseLeave={() =&amp;gt; setShow(false)}
      &amp;gt;
        {children}
      &amp;lt;/StyledBlock&amp;gt;
      &amp;lt;StyledTooltip isShow={show}&amp;gt;{text}&amp;lt;/StyledTooltip&amp;gt;
    &amp;lt;/StyledWrap&amp;gt;
  );
}

export default Tooltip;

const StyledWrap = styled.div`
    position: relative;
`;

const StyledTooltip = styled.span`
    display: flex;
    align-items: center;
    width: max-content;
    visibility: ${({ isShow }) =&amp;gt; (isShow ? 'visible' : 'hidden')};
    background: rgb(235, 236, 239);
    position: absolute;
    padding: 0 12px;
    font-size: 14px;
    border-radius: 5px;
    left: 55px;
    top: 0;
    bottom: 0;
    &amp;amp;:before {
        display: block;
        position: absolute;
        content: &quot;&quot;;
        left: -18px;
        border-top: 8px solid transparent;
        border-right: 12px solid rgb(235, 236, 239);
        border-bottom: 8px solid transparent;
        border-left: 8px solid transparent;
    }
`;

const StyledBlock = styled.div`
    width: max-content;
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;code-title&quot; data-ke-size=&quot;size16&quot;&gt;App.js&lt;/p&gt;
&lt;pre id=&quot;code_1681538678639&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import styled from 'styled-components';
import Tooltip from './Tooltip';

export default function App() {
  return (
    &amp;lt;StyledWrapper&amp;gt;
      &amp;lt;StyledBlock&amp;gt;
        &amp;lt;Tooltip text=&quot;확대하기 +&quot;&amp;gt;
          &amp;lt;StyledButton&amp;gt;
            &amp;lt;svg
              width=&quot;24&quot;
              height=&quot;24&quot;
              fill=&quot;rgba(26,26,26,0.8)&quot;
              fillOpacity=&quot;1&quot;
              xmlns=&quot;http://www.w3.org/2000/svg&quot;
              viewBox=&quot;0 0 96 96&quot;
            &amp;gt;
              &amp;lt;path
                fillRule=&quot;evenodd&quot;
                clipRule=&quot;evenodd&quot;
                d=&quot;M45 18c-14.912 0-27 12.088-27 27s12.088 27 27 27 27-12.088 27-27-12.088-27-27-27ZM12 45c0-18.225 14.775-33 33-33s33 14.775 33 33c0 8.032-2.87 15.395-7.64 21.117L83.12 78.88a3 3 0 1 1-4.242 4.242L66.117 70.36A32.866 32.866 0 0 1 45 78c-18.225 0-33-14.775-33-33Zm33-17a3 3 0 0 1 3 3v12h12a3 3 0 1 1 0 6H48v12a3 3 0 1 1-6 0V49H30a3 3 0 1 1 0-6h12V31a3 3 0 0 1 3-3Z&quot;
              &amp;gt;&amp;lt;/path&amp;gt;
            &amp;lt;/svg&amp;gt;
          &amp;lt;/StyledButton&amp;gt;
        &amp;lt;/Tooltip&amp;gt;
      &amp;lt;/StyledBlock&amp;gt;
      &amp;lt;StyledBlock&amp;gt;
        &amp;lt;Tooltip text=&quot;축소하기 -&quot;&amp;gt;
          &amp;lt;StyledButton&amp;gt;
            &amp;lt;svg
              width=&quot;24&quot;
              height=&quot;24&quot;
              fill=&quot;rgba(26,26,26,0.8)&quot;
              fillOpacity=&quot;1&quot;
              xmlns=&quot;http://www.w3.org/2000/svg&quot;
              viewBox=&quot;0 0 96 96&quot;
            &amp;gt;
              &amp;lt;path
                fillRule=&quot;evenodd&quot;
                clipRule=&quot;evenodd&quot;
                d=&quot;M45 18c-14.912 0-27 12.088-27 27s12.088 27 27 27 27-12.088 27-27-12.088-27-27-27ZM12 45c0-18.225 14.775-33 33-33s33 14.775 33 33c0 8.032-2.87 15.395-7.64 21.117L83.12 78.88a3 3 0 1 1-4.242 4.242L66.117 70.36A32.866 32.866 0 0 1 45 78c-18.225 0-33-14.775-33-33Zm14 1a3 3 0 0 1 3-3h32a3 3 0 1 1 0 6H29a3 3 0 0 1-3-3Z&quot;
              &amp;gt;&amp;lt;/path&amp;gt;
            &amp;lt;/svg&amp;gt;
          &amp;lt;/StyledButton&amp;gt;
        &amp;lt;/Tooltip&amp;gt;
      &amp;lt;/StyledBlock&amp;gt;
    &amp;lt;/StyledWrapper&amp;gt;
  );
}

const StyledButton = styled.button`
    width: 30px;
    height: 30px;
    display: flex;
    justify-content: center;
    align-items: center;
    border: none;
    border-radius: 4px;
`;

const StyledWrapper = styled.div`
    display: flex;
    flex-direction: column;
`;

const StyledBlock = styled.div`
    margin: 10px;
`;&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;a href=&quot;https://stackblitz.com/edit/react-tvv9mg?file=src/App.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-tvv9mg?file=src/App.js&lt;/a&gt;&lt;/p&gt;</description>
      <category>Project/bounding-box</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/90</guid>
      <comments>https://msm1307.tistory.com/90#entry90comment</comments>
      <pubDate>Sat, 15 Apr 2023 15:26:00 +0900</pubDate>
    </item>
    <item>
      <title>커스텀 훅(Custom Hook)</title>
      <link>https://msm1307.tistory.com/88</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React Hooks의 개념을 확장하여 &lt;b&gt;&lt;u&gt;재사용 가능한 로직&lt;/u&gt;&lt;/b&gt;을 만들 수 있는 기능입니다. 커스텀 훅을 사용하면 여러 &lt;u&gt;컴포넌트에서 공통으로 사용되는 로직을 쉽게 추출하고 관리&lt;/u&gt;할 수 있습니다. 기본적으로 커스텀 훅은 일반 JavaScript 함수이며, 내부에서 기존의 React Hooks를 사용할 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;커스텀 훅의 이름은 보통 &lt;b&gt;&lt;u&gt;use로 시작&lt;/u&gt;&lt;/b&gt;합니다. 이렇게 작명하는 이유는 훅 사용 규칙을 준수하고, 커스텀 훅이 일반 함수와 혼동되지 않게 하기 위함입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;훅-쓰기-전-로직&quot; style=&quot;background-color: #ffffff; color: #2c3e50; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;커스텀 훅 사용 전 로직&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #2c3e50; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681037934826&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from 'react';

const App = () =&amp;gt; {
  const [id, setId] = useState('');
  const [nick, setNick] = useState('');
  const [password, setPassword] = useState('');

  const onChangeId = (e) =&amp;gt; {
    setId(e.target.value);
  };
  const onChangeNick = (e) =&amp;gt; {
    setNick(e.target.value);
  };
  const onChangePassword = (e) =&amp;gt; {
    setPassword(e.target.value);
  };

  const onSubmit = (e) =&amp;gt; {
    e.preventDefault();
    console.log(`id : ${id}, nick : ${nick}, password : ${password}`);
  };

  return (
    &amp;lt;form onSubmit={onSubmit}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-id&quot;&amp;gt;아이디 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-id&quot;
          name=&quot;user-id&quot;
          value={id}
          required
          onChange={onChangeId}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-nick&quot;&amp;gt;닉네임 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-nick&quot;
          name=&quot;user-nick&quot;
          value={nick}
          required
          onChange={onChangeNick}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-password&quot;&amp;gt;비밀번호 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-password&quot;
          name=&quot;user-password&quot;
          type=&quot;password&quot;
          value={password}
          required
          onChange={onChangePassword}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;전송&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
};

export default App;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;커스텀 훅 사용 후 로직&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680911496107&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from 'react';

const useInput = (initialValue) =&amp;gt; {
  const [value, setValue] = useState(initialValue);

  const onChange = (e) =&amp;gt; {
    setValue(e.target.value);
  };

  return [value, onChange];
};


const App = () =&amp;gt; {
  const [id, onChangeId] = useInput('');
  const [nick, onChangeNick] = useInput('');
  const [password, onChangePassword] = useInput('');

  const onSubmit = (e) =&amp;gt; {
    e.preventDefault();
    console.log(`id : ${id}, nick : ${nick}, password : ${password}`);
  };

  return (
    &amp;lt;form onSubmit={onSubmit}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-id&quot;&amp;gt;아이디 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-id&quot;
          name=&quot;user-id&quot;
          value={id}
          required
          onChange={onChangeId}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-nick&quot;&amp;gt;닉네임 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-nick&quot;
          name=&quot;user-nick&quot;
          value={nick}
          required
          onChange={onChangeNick}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label htmlFor=&quot;user-password&quot;&amp;gt;비밀번호 : &amp;lt;/label&amp;gt;
        &amp;lt;input
          id=&quot;user-password&quot;
          name=&quot;user-password&quot;
          type=&quot;password&quot;
          value={password}
          required
          onChange={onChangePassword}
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;전송&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
};


export default App;&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;a href=&quot;https://stackblitz.com/edit/react-1vbvtx?file=src/App.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-1vbvtx?file=src/App.js&lt;/a&gt;&lt;/p&gt;</description>
      <category>프레임워크/React</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/88</guid>
      <comments>https://msm1307.tistory.com/88#entry88comment</comments>
      <pubDate>Sat, 8 Apr 2023 08:55:35 +0900</pubDate>
    </item>
    <item>
      <title>React에서 Canvas 이미지 줌, 이동 기능 만들기</title>
      <link>https://msm1307.tistory.com/87</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;canvas에서 이미지 줌, 이동&amp;nbsp; 기능을 구현 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1680861561738&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useRef, useEffect } from 'react';

const img = new Image();
const INITIAL_POSITION = { x: 0, y: 0 };
const MIN_SCALE = 0.1;
const MAX_SCALE = 10;

function App() {
  const zoomCanvasRef = useRef(null);
  const scaleRef = useRef(1);
  const panningRef = useRef(false);
  const viewPosRef = useRef(INITIAL_POSITION);
  const startPosRef = useRef(INITIAL_POSITION);

  const setTransform = () =&amp;gt; {
    const zoomCanvas = zoomCanvasRef.current;
    const context = zoomCanvas.getContext('2d');
    context.setTransform(
      scaleRef.current,
      0,
      0,
      scaleRef.current,
      viewPosRef.current.x,
      viewPosRef.current.y
    );
  };

  const draw = () =&amp;gt; {
    const zoomCanvas = zoomCanvasRef.current;
    const context = zoomCanvas.getContext('2d');
    zoomCanvas.width = zoomCanvas.width;
    setTransform();
    context.drawImage(img, 0, 0, zoomCanvas.width, zoomCanvas.height);
  };

  useEffect(() =&amp;gt; {
    img.src =
      'https://firebasestorage.googleapis.com/v0/b/storege-974dc.appspot.com/o/image%2Frabbit.jpeg?alt=media&amp;amp;token=cc501a63-0258-4aa3-809f-c45b743d2735';
    // Load image
    img.onload = function () {
      draw();
    };
  }, []);

  const handleMouseDown = (e) =&amp;gt; {
    const { offsetX, offsetY } = e.nativeEvent;
    e.preventDefault();
    startPosRef.current = {
      x: offsetX - viewPosRef.current.x,
      y: offsetY - viewPosRef.current.y,
    };
    panningRef.current = true;
  };

  const handleMouseUp = (e) =&amp;gt; {
    panningRef.current = false;
  };

  const handleMouseMove = (e) =&amp;gt; {
    const { offsetX, offsetY } = e.nativeEvent;
    e.preventDefault();
    if (!panningRef.current) {
      return;
    }
    viewPosRef.current = {
      x: offsetX - startPosRef.current.x,
      y: offsetY - startPosRef.current.y,
    };
    draw();
  };

  const handleWheel = (e) =&amp;gt; {
    const { offsetX, offsetY } = e.nativeEvent;
    e.preventDefault();
    const xs = (offsetX - viewPosRef.current.x) / scaleRef.current;
    const ys = (offsetY - viewPosRef.current.y) / scaleRef.current;
    const delta = -e.deltaY;
    const newScale =
      delta &amp;gt; 0 ? scaleRef.current * 1.2 : scaleRef.current / 1.2;

    if (newScale &amp;gt;= MIN_SCALE &amp;amp;&amp;amp; newScale &amp;lt;= MAX_SCALE) {
      scaleRef.current = newScale;
      viewPosRef.current = {
        x: offsetX - xs * scaleRef.current,
        y: offsetY - ys * scaleRef.current,
      };
    }
    draw();
  };

  return (
    &amp;lt;canvas
      ref={zoomCanvasRef}
      width=&quot;500&quot;
      height=&quot;500&quot;
      style={{ border: ' 1px solid' }}
      onMouseDown={handleMouseDown}
      onMouseMove={handleMouseMove}
      onMouseUp={handleMouseUp}
      onWheel={handleWheel}
    /&amp;gt;
  );
}
export default App;&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 style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;useState 대신 useRef를 사용한 이유는 상태를 변경할 때마다 컴포넌트가 다시 렌더링되는 것을 방지하기 위해서입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;마우스 이벤트에서 draw 함수를 호출해 다시 그려주기 때문에 useState 대신 useRef로 관리 하는 것이 낫다고 생각하여 useRef를 사용하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;const scaleRef&lt;/b&gt; : 현재 확대/축소 비율을 저장합니다.&lt;br /&gt;&lt;b&gt;&lt;b&gt;const&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;panningRef&lt;/b&gt; : 드래그 중인지 여부를 저장합니다.&lt;br /&gt;&lt;b&gt;&lt;b&gt;const&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;viewPosRef&lt;/b&gt; : 현재 이미지 위치를 저장합니다.&lt;br /&gt;&lt;b&gt;&lt;b&gt;const&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;startPosRef&lt;/b&gt; : 마우스 드래그 시작 위치를 저장합니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;setTransform&amp;nbsp;함수&lt;/b&gt;는 캔버스에 현재 확대/축소 비율과 화면 위치를 설정합니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;handleWheel&amp;nbsp;함수&lt;/b&gt;를 풀어보면 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;const xs = (offsetX - viewPosRef.current.x) / scaleRef.current;&lt;/b&gt;&lt;br /&gt;마우스 포인터의 X 좌표(offsetX)에서 현재 이미지 위치(viewPosRef.current.x)를 빼고, 이미지의 현재 스케일(scaleRef.current)로 나누어 xs 값을 계산합니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;const ys = (offsetY - viewPosRef.current.y) / scaleRef.current;&lt;/b&gt;&lt;br /&gt;마우스 포인터의 Y 좌표(offsetY)에서 현재 이미지 위치(viewPosRef.current.y)를 빼고, 이미지의 현재 스케일(scaleRef.current)로 나누어 ys 값을 계산합니다.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;u&gt;xs, ys 값은 이미지의 어느 부분이 확대/축소되는지를 결정하는 데 사용됩니다.&lt;/u&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;const delta = -e.deltaY;&lt;/b&gt;&lt;br /&gt;e.deltaY는 마우스 휠 이벤트의 수직 휠 위치 변경 값을 나타냅니다. 이 값을 -1을 곱하여 delta 변수에 저장합니다. 마우스 휠 이벤트에서 deltaY 값이 양수이면 축소, 음수이면 확대로 처리하기 위함입니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;const newScale = delta &amp;gt; 0 ? scaleRef.current * 1.2 : scaleRef.current / 1.2;&lt;/b&gt;&lt;br /&gt;delta 값이 양수일 경우, 이미지를 확대하려면 현재 스케일에 1.2를 곱하고, 음수일 경우 축소하려면 현재 스케일에 1.2로 나눕니다. 이렇게 계산된 결과를 newScale 변수에 저장합니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;if (newScale &amp;gt;= MIN_SCALE &amp;amp;&amp;amp; newScale &amp;lt;= MAX_SCALE) { ... }&lt;/b&gt;&lt;br /&gt;newScale 값이 MIN_SCALE과 MAX_SCALE 사이에 있는지 확인합니다. 그렇다면 이미지의 스케일을 갱신하고, 이미지 위치를 업데이트하여 확대/축소된 이미지가 마우스 포인터를 기준으로 정상적으로 보이게 합니다. 이렇게 함으로써 이미지가 설정한 최소 및 최대 스케일 범위를 벗어나지 않도록 제한할 수 있습니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; Canvas setTransform 함수&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이&amp;nbsp;함수의&amp;nbsp;주&amp;nbsp;목적은&amp;nbsp;canvas의&amp;nbsp;기본&amp;nbsp;확대,&amp;nbsp;경사도,&amp;nbsp;이동거리를&amp;nbsp;설정하기&amp;nbsp;위해&amp;nbsp;사용&lt;/p&gt;
&lt;pre id=&quot;code_1701370444632&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTransform(a, b, c, d, e, f)&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;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&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;a: 수평 방향 확대 또는 축소 비율&lt;/li&gt;
&lt;li&gt;b: 수직 방향 경사율&lt;/li&gt;
&lt;li&gt;c: 수평 방향 경사율&lt;/li&gt;
&lt;li&gt;d: 수직 방향 확대 또는 축소 비율&lt;/li&gt;
&lt;li&gt;e: 수평 방향 이동 거리&lt;/li&gt;
&lt;li&gt;f:&amp;nbsp;수직&amp;nbsp;방향&amp;nbsp;이동&amp;nbsp;거리&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;실행화면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;canvas id=&quot;zoomCanvas&quot; width=&quot;500&quot; height=&quot;500&quot; style=&quot;border: 1px solid;&quot;&gt;&lt;/canvas&gt;
&lt;script&gt;
const INITIAL_POSITION = { x: 0, y: 0 };
const MIN_SCALE = 0.1;
const MAX_SCALE = 10;

const zoomCanvas = document.getElementById(&quot;zoomCanvas&quot;);
const context = zoomCanvas.getContext(&quot;2d&quot;);

const img = new Image();

let scale = 1;
let panning = false;
let viewPos = INITIAL_POSITION;
let start = INITIAL_POSITION;

function setTransform() {
    context.setTransform(scale, 0, 0, scale, viewPos.x, viewPos.y);
}

function draw() {
    zoomCanvas.width = zoomCanvas.width;
    setTransform();
    context.drawImage(img, 0, 0, zoomCanvas.width, zoomCanvas.height);
}

img.src = &quot;https://firebasestorage.googleapis.com/v0/b/storege-974dc.appspot.com/o/image%2Frabbit.jpeg?alt=media&amp;token=cc501a63-0258-4aa3-809f-c45b743d2735&quot;;
img.onload = function () {
    draw();
};

zoomCanvas.addEventListener(&quot;mousedown&quot;, (e) =&gt; {
    e.preventDefault();
    start = {
        x: e.offsetX - viewPos.x,
        y: e.offsetY - viewPos.y,
    };
    panning = true;
});

zoomCanvas.addEventListener(&quot;mouseup&quot;, (e) =&gt; {
    panning = false;
});

zoomCanvas.addEventListener(&quot;mousemove&quot;, (e) =&gt; {
    e.preventDefault();
    if (!panning) {
        return;
    }
    viewPos = {
        x: e.offsetX - start.x,
        y: e.offsetY - start.y,
    };
    draw();
});

zoomCanvas.addEventListener(&quot;wheel&quot;, (e) =&gt; {
	e.preventDefault();
    const xs = (e.offsetX - viewPos.x) / scale;
    const ys = (e.offsetY - viewPos.y) / scale;
    const delta = -e.deltaY;
    const newScale = delta &gt; 0 ? scale * 1.2 : scale / 1.2;

    if (newScale &gt;= MIN_SCALE &amp;&amp; newScale &lt;= MAX_SCALE) {
        scale = newScale;
        viewPos = {
            x: e.offsetX - xs * scale,
            y: e.offsetY - ys * scale,
        };
    }
    draw();
});

&lt;/script&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://stackblitz.com/edit/react-eyyxfk?file=src/App.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackblitz.com/edit/react-eyyxfk?file=src/App.js&lt;/a&gt;&lt;/p&gt;</description>
      <category>Project/bounding-box</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/87</guid>
      <comments>https://msm1307.tistory.com/87#entry87comment</comments>
      <pubDate>Fri, 7 Apr 2023 19:06:37 +0900</pubDate>
    </item>
    <item>
      <title>useImperativeHandle</title>
      <link>https://msm1307.tistory.com/86</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React의 커스텀 훅(hook) 중 하나로,&amp;nbsp;&lt;b&gt;&lt;u&gt;부모 컴포넌트에서 자식 컴포넌트의 함수 또는 값을 직접 호출하거나 사용&lt;/u&gt;&lt;/b&gt;할 수 있도록&amp;nbsp;해줍니다. 일반적으로 컴포넌트 간의 상호작용을 위해 props를 사용하지만, 때때로 부모 컴포넌트가 자식 컴포넌트의 인스턴스를 직접 참조해야 하는 경우가 있습니다. 이때 useImperativeHandle을 사용할 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680857741658&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const CustomInput = (props, ref) =&amp;gt; {
  const inputRef = useRef();

  useImperativeHandle(ref, () =&amp;gt; ({
    focus: () =&amp;gt; {
      inputRef.current.focus();
    },
  }));

  return &amp;lt;input ref={inputRef} type=&quot;text&quot; /&amp;gt;;
};

const ForwardedCustomInput = forwardRef(CustomInput);

const ParentComponent = () =&amp;gt; {
  const inputRef = useRef();

  const handleClick = () =&amp;gt; {
    inputRef.current.focus();
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;Focus on input&amp;lt;/button&amp;gt;
      &amp;lt;ForwardedCustomInput ref={inputRef} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ParentComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;코드 설명&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;CustomInput 컴포넌트는 forwardRef 를 사용하여 ref를 전달받을 수 있게 하고 있습니다.&lt;br /&gt;ParentComponent는 inputRe를 통해 CustomInput 컴포넌트의 인스턴스를 참조하고, handleClick 함수에서 inputRef.current.focus()를 호출하여 자식 컴포넌트의&amp;nbsp; focus 함수를 실행합니다.&lt;br /&gt;이를 통해 input에 포커스가 이동하게 됩니다.&lt;/blockquote&gt;</description>
      <category>프레임워크/React</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/86</guid>
      <comments>https://msm1307.tistory.com/86#entry86comment</comments>
      <pubDate>Fri, 7 Apr 2023 17:57:31 +0900</pubDate>
    </item>
    <item>
      <title>마우스 이벤트(client, page, offset, screen)의 차이점</title>
      <link>https://msm1307.tistory.com/85</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;client&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&gt;브라우저 창 기준으로 마우스 클릭 위치의 x, y좌표를 나타냅니다. 스크롤바가 있어도 &lt;b&gt;&lt;u&gt;스크롤바를 제외&lt;/u&gt;&lt;/b&gt;한 브라우저의 좌측 상단을 원점으로 삼습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;page&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 전체를 기준으로 마우스 클릭 위치의 x, y좌표를 나타냅니다. &lt;b&gt;&lt;u&gt;스크롤바를 포함&lt;/u&gt;&lt;/b&gt;한 문서의 좌측 상단을 원점으로 삼습니다&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;offset&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 대상 엘리먼트를 기준으로 마우스 클릭 위치의 x, y좌표를 나타냅니다. 이벤트가 발생한 &lt;b&gt;&lt;u&gt;엘리먼트의 좌측 상단&lt;/u&gt;&lt;/b&gt;을 원점으로 삼습니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;screen&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;u&gt;모니터 화면 전체&lt;/u&gt;&lt;/b&gt;를 기준으로 마우스 클릭 위치의 x, y좌표를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680856080392&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div style=&quot;width: 300px; height: 300px; background-color: red; display:flex; align-items: center; justify-content: center;&quot; id=&quot;box&quot;&amp;gt;마우스 클릭&amp;lt;/div&amp;gt;
&amp;lt;div id=&quot;show&quot; style=&quot;margin-top: 20px;&quot;&amp;gt;
  clientX : 0, clientY : 0&amp;lt;br/&amp;gt;
  pageX : 0, pageY : 0&amp;lt;br/&amp;gt;
  offsetX : 0, offsetY : 0&amp;lt;br/&amp;gt;
  screenX : 0, screenY : 0
&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
  const box = document.getElementById('box');
  const show = document.getElementById('show');
  box.addEventListener('click', (e) =&amp;gt; {
    show.innerHTML = `
      clientX : ${e.clientX}, clientY : ${e.clientY}&amp;lt;br/&amp;gt;
      pageX : ${e.pageX}, pageY : ${e.pageY}&amp;lt;br/&amp;gt;
      offsetX : ${e.offsetX}, offsetY : ${e.offsetY}&amp;lt;br/&amp;gt;
      screenX : ${e.screenX}, screenY : ${e.screenY}
    `
  });
&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;div style=&quot;width: 300px; height: 300px; background-color: red; display:flex; align-items: center; justify-content: center;&quot; id=&quot;box&quot;&gt;마우스 클릭&lt;/div&gt;
&lt;div id=&quot;show&quot; style=&quot;margin-top: 20px;&quot;&gt;
  clientX : 0, clientY : 0&lt;br/&gt;&lt;br/&gt;
  pageX : 0, pageY : 0&lt;br/&gt;&lt;br/&gt;
  offsetX : 0, offsetY : 0&lt;br/&gt;&lt;br/&gt;
  screenX : 0, screenY : 0
&lt;/div&gt;
&lt;script&gt;
  const box = document.getElementById('box');
  const show = document.getElementById('show');
  box.addEventListener('click', (e) =&gt; {
    show.innerHTML = `
      clientX : ${e.clientX}, clientY : ${e.clientY}&lt;br/&gt;&lt;br/&gt;
      pageX : ${e.pageX}, pageY : ${e.pageY}&lt;br/&gt;&lt;br/&gt;
      offsetX : ${e.offsetX}, offsetY : ${e.offsetY}&lt;br/&gt;&lt;br/&gt;
      screenX : ${e.screenX}, screenY : ${e.screenY}
    `
  });
&lt;/script&gt;</description>
      <category>JavaScript</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/85</guid>
      <comments>https://msm1307.tistory.com/85#entry85comment</comments>
      <pubDate>Fri, 7 Apr 2023 17:29:25 +0900</pubDate>
    </item>
    <item>
      <title>CSS 효과 모음</title>
      <link>https://msm1307.tistory.com/83</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;원&amp;nbsp;튕기듯한&amp;nbsp;느낌&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1689699707548&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    .circle {
        display: block;
        width: 38px;
        height: 38px;
        margin: auto;
        border-radius: 50%;
        background-color: #a4ece1;
    }
    .circle:hover {
        animation: jello-vertical 0.8s both;
    }
    @keyframes jello-vertical {
        0% {
            transform: scale3d(0.9, 0.9, 1);
        }
        30% {
            transform: scale3d(0.85, 1.21, 1);
        }
        40% {
            transform: scale3d(1.15, 0.85, 1);
        }
        50% {
            transform: scale3d(0.92, 1.08, 1);
        }
        65% {
            transform: scale3d(1.03, 0.95, 1);
        }
        75% {
            transform: scale3d(0.95, 1.03, 1);
        }
        100% {
            transform: scale3d(1, 1, 1);
        }
    }
&amp;lt;/style&amp;gt;
&amp;lt;div class=&quot;circle&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;div class=&quot;circle&quot;&gt;&lt;/div&gt;
&lt;style&gt;
.circle{display:block; width:38px; height:38px; margin:auto; border-radius:50%; background-color:#a4ece1;}
.circle:hover{animation:jello-vertical .8s both;}
    @keyframes jello-vertical{
        0%{transform:scale3d(.9, .9, 1);}
        30%{transform:scale3d(0.85, 1.21, 1);}
        40%{transform:scale3d(1.15, 0.85, 1);}
        50%{transform:scale3d(0.92, 1.08, 1);}
        65%{transform:scale3d(1.03, 0.95, 1);}
        75%{transform:scale3d(0.95, 1.03, 1);}
        100%{transform:scale3d(1, 1, 1);}
    }
&lt;/style&gt;</description>
      <category>CSS</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/83</guid>
      <comments>https://msm1307.tistory.com/83#entry83comment</comments>
      <pubDate>Wed, 14 Sep 2022 12:30:06 +0900</pubDate>
    </item>
    <item>
      <title>VSCode 단축키 모음</title>
      <link>https://msm1307.tistory.com/79</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;VSCode 단축키 모음&lt;/b&gt;&lt;/h2&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;b&gt;커서&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Alt + Shift + I&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;선택 영역 다중 커서&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Shift + Alt + 마우스 드래그&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다중 커서&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Alt + Click&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다중 커서&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Alt + Ctrl + &amp;uarr;/&amp;darr;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다중 커서를 위/아래로 넓힌다&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Ctrl + &amp;larr;/&amp;rarr;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단어의 앞으로 커서 이동&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Ctrl + U&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이전 커서 위치로 이동&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;이동&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Alt&amp;nbsp;+&amp;nbsp;&amp;uarr;&amp;nbsp;/&amp;nbsp;&amp;darr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;현재&amp;nbsp;라인&amp;nbsp;위치&amp;nbsp;이동&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;&amp;uarr;/&amp;darr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;커서&amp;nbsp;위치는&amp;nbsp;그대로&amp;nbsp;두고&amp;nbsp;위&amp;nbsp;아래로&amp;nbsp;스크롤&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Home/End&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;파일의&amp;nbsp;맨&amp;nbsp;앞&amp;nbsp;혹은&amp;nbsp;맨&amp;nbsp;뒤로&amp;nbsp;이동&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Alt&amp;nbsp;+&amp;nbsp;PgUp/PgDn&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;커서&amp;nbsp;위치는&amp;nbsp;그대로&amp;nbsp;두고&amp;nbsp;Page&amp;nbsp;Up/&amp;nbsp;Page&amp;nbsp;Down&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;삭제 / 변경&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;shift&amp;nbsp;+&amp;nbsp;k&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;한&amp;nbsp;줄&amp;nbsp;삭제&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;BackSpace&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;단어&amp;nbsp;부분&amp;nbsp;삭제&amp;nbsp;(커서&amp;nbsp;위의&amp;nbsp;왼쪽)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Delete&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;단어&amp;nbsp;부분&amp;nbsp;삭제(커서&amp;nbsp;위치의&amp;nbsp;오른쪽)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;H&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;단어&amp;nbsp;변경&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;선택&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctl + &lt;b&gt;cmd &lt;b&gt;+ &lt;/b&gt;&lt;/b&gt;Shift + &amp;rarr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;태그&amp;nbsp;단위로&amp;nbsp;확장&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;&lt;b&gt;Ctl +&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;cmd&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;Shift +&lt;/b&gt;&amp;nbsp;&amp;larr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;태그&amp;nbsp;단위로&amp;nbsp;축소&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;cmd + F2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;같은&amp;nbsp;단어&amp;nbsp;전체&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;cmd + D&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;같은&amp;nbsp;단어&amp;nbsp;한&amp;nbsp;개씩&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;&amp;larr;&amp;nbsp;/&amp;nbsp;&amp;rarr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;단어&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;L&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;라인&amp;nbsp;단위&amp;nbsp;선택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;기타&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Enter&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;라인&amp;nbsp;중간에&amp;nbsp;커서&amp;nbsp;있어도&amp;nbsp;다음&amp;nbsp;라인&amp;nbsp;생성&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Alt&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;&amp;uarr;&amp;nbsp;/&amp;nbsp;&amp;darr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;현재&amp;nbsp;라인&amp;nbsp;아래로&amp;nbsp;복사&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;/&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;해당&amp;nbsp;라인&amp;nbsp;주석&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.6977%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;B&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%; height: 20px;&quot;&gt;&lt;b&gt;토글 슬라이드바&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;P,&amp;nbsp;F1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;커맨드&amp;nbsp;팔렛&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl + P&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;퀵&amp;nbsp;오픈&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;,&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;유저&amp;nbsp;셋팅&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.6977%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;J&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.3023%;&quot;&gt;&lt;b&gt;터미널&amp;nbsp;열고&amp;nbsp;/&amp;nbsp;닫기&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>IDE/VSCode</category>
      <category>vscode 단축키</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/79</guid>
      <comments>https://msm1307.tistory.com/79#entry79comment</comments>
      <pubDate>Sat, 23 Apr 2022 14:27:36 +0900</pubDate>
    </item>
    <item>
      <title>웹스톰 단축키 모음</title>
      <link>https://msm1307.tistory.com/78</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;웹스톰&amp;nbsp;단축키&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 280px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;단축키&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl + Alt + L&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;코드&amp;nbsp;정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;W&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;텍스트&amp;nbsp;확장&amp;nbsp;선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;D&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;선택된&amp;nbsp;블럭을&amp;nbsp;복제&amp;nbsp;/&amp;nbsp;라인&amp;nbsp;복제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Y&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;라인&amp;nbsp;삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Alt&amp;nbsp;+&amp;nbsp;J&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;같은 단어 차례선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;J&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;같은 단어 모두 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Alt + Shift + &amp;uarr;, &amp;darr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;라인&amp;nbsp;이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;G&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;라인번호&amp;nbsp;이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Shift&amp;nbsp;+&amp;nbsp;Enter&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;아래로&amp;nbsp;새로운&amp;nbsp;라인으로&amp;nbsp;줄바꿈하기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;Enter&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;윗줄로&amp;nbsp;새로운&amp;nbsp;라인으로&amp;nbsp;줄바꿈하기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl + Drag&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;드래그&amp;nbsp;한&amp;nbsp;코드를&amp;nbsp;마우스로&amp;nbsp;원하는&amp;nbsp;위치로&amp;nbsp;이동시키기&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;v&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;최근&amp;nbsp;복사했던&amp;nbsp;목록&amp;nbsp;보여주기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 30.814%; height: 20px;&quot;&gt;&lt;b&gt;파일/폴더 선택 후 Ctrl + Shift + R&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%; height: 20px;&quot;&gt;해당 파일에서 일치 단어 전체 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.814%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;M&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%;&quot;&gt;괄호이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.814%;&quot;&gt;&lt;b&gt;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;]&amp;nbsp;/&amp;nbsp;[&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%;&quot;&gt;가장&amp;nbsp;가까운&amp;nbsp;괄호&amp;nbsp;시작/종료로&amp;nbsp;이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.814%;&quot;&gt;&lt;b&gt;Ctrl + Alt + &amp;larr; , &amp;rarr;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292e;&quot;&gt;이전 커서가 있던 화면으로 이동&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.814%;&quot;&gt;&lt;b&gt;Ctrl + g&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%;&quot;&gt;특정 line 번호로 이동&lt;span style=&quot;background-color: #ffffff; color: #24292e;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.814%;&quot;&gt;&lt;b&gt;Ctrl + Shift + N&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.186%;&quot;&gt;파일 검색&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IDE/webstorm</category>
      <category>웹스톰 단축키</category>
      <author>석미니</author>
      <guid isPermaLink="true">https://msm1307.tistory.com/78</guid>
      <comments>https://msm1307.tistory.com/78#entry78comment</comments>
      <pubDate>Sat, 9 Apr 2022 12:58:52 +0900</pubDate>
    </item>
  </channel>
</rss>