Vue.js

Vue.js 3.0 STEP 6 - 단일 파일 컴포넌트

2024. 1. 25. 15:57
728x90

★ 단일 파일 컴포넌트 

  • 단일 파일 컴포넌트는 컴포넌트 하나를 .vue 파일 하나에 작성하기 때문에 붙여진 이름
  • 한 파일에 컴포넌트 구성을 위해 템플릿, 스크립트, 스타일 정보를 모두 포함하기 때문에 컴포넌트 단위로 분리 가능
  • Vue 애플리케이션을 개발하기 위해서는 Webpack, Rollup 과 같은 모듈 번들러 도구와 ES6, TypeScript와 같은 트랜스파일러를 함께 사용하도록 개발 프로젝트 환경을 설정해야 한다.

1. 프로젝트 설정 도구

  • 1.1 Vue CLI 도구
  • Webpack 기반의 Vue 공식 프로젝트 설정 도구였다.
  • 하지만,  이 방법은 프로젝트를 생성하고 구동하기까지 다소 긴 시간이 소요가 된다.
  • 또한, 번들링 과정을 거쳐야하기 때문에 작성한 코드를 테스트하기에 조금 긴 시간을 기다려야 한다.
  • 번들링 : 여러 모듈을 묶어서 하나 또는 몇개의 모듈 파일로 만드는 과정
  • 프로젝트 생성 방법
npx @vue/cli create [프로젝트명]
cd [프로젝트명]
npm run serve
  • 1.2 Vite 기반의 도구
  • vite(비트)는 프랑스어로 '빠르다' 라는 뜻을 가진 단어로, Vue의 창시자인 Evan You가 만든 차세대 프론트엔드 개발 도구이다.
  • webpack과 같은 빌드 도구는 자바스크립트 언어로 만들어져있지만, Vite의 ESBuild는  Go 라는 네이티브 언어로 만들어진 도구를 사용하기 때문에 빌드 속도가 아주 빠르다.
  • 프로젝트 생성 방법
 npm init vite [프로젝트명]
 npm init vue@latest
  • vite 기반 프로젝트가 생성되면 프로젝트 디렉터리로 이동하며, 관련 패키지를 설치하고 실행
cd [프로젝트명]
npm install
npm run dev
  • vite 기반 프로젝트의 폴더 구조
src JavaSciprt 코드, .vue 파일을 이곳에 작성한다. 시작진입(Entry) 파일은 src/main.js
public 이미지와 같은 정적 파일, 자원을 이곳에 작성한다.
dist 빌드 후 생성된 산출물이 저장되는 디렉터리이다.
index.html Vue 애플리케이션의 컴포넌트 트리는 index.html의 id가 app인 div 요소 내부에 렌더링된다.
  • 프로젝트 내에서 다음 명령어를 사용해 개발서버를 구동하거나 빌드할 수 있다.
빌드 명령어 npm run build
개발 서버 시작 명령어 npm run dev
미리보기 명령어 npm run preview

 

 

★  프로젝트 생성하기

  • vite 방법을 이용한 프로젝트 생성

 

 

2. 간단한 단일 파일 컴포넌트 작성과 사용

  • src/components 디렉터리의 모든 하위 디렉터리와 컴포넌트 파일을 삭제하고, CheckboxItem 컴포넌트를ㅈ추가
  • 작성할 때는, vue VSCode Snippets 도구를 이용하면 편리하다.
  • 간단한 파일 컴포넌트 작성
<template>
    <li>
        <input type="checkbox" v-model="checked" /> 옵션1
    </li>
</template>

<script>
    export default {
        name : "ChecboxItem",
        data() {
            return {
                checked: false
            };
        }
    }
</script>

 

■ 전역 컴포넌트

  • Vue 애플리케이션 인스턴스의 component() 메서드를 이용해 등록.
  • 전역 컴포넌트로 등록한 경우에는 루트 컴포넌트 하위의 모든 자식 컴포넌트 어디에서나 등록한 컴포넌트를 이용할 수 있다.
  • main.js에서 전역 컴포넌트를 등록
import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import CheckboxItem from './components/CheckboxItem.vue'

import './assets/main.css'

createApp(App)
    .component('CheckboxItem', CheckboxItem)
    .mount('#app')

 

■ 지역 컴포넌트

  • 특정 컴포넌트에서 컴포넌트를 직접 등록하여 사용하는 방법
  • 컴포넌트 객체 내에서 components라는 옵션을 만들고 그곳에 템플릿에서 사용할 태그명과 컴포넌트 객체를 등록하여 사용
import CheckboxItem from './components/CheckboxItem.vue'
export default {
    name : "App",
    components: { "CheckboxItem" : CheckboxItem },
}

 

■ 최적안 

  • 지역 컴포넌트의 사용을 추천. 전역 컴포넌트로 등록할 경우 컴포넌트를 더이상 사용하지 않아도 빌드되는 패키지에 포함되어 사용자에게 배포될 코드의 크기를 증가시키기 때문이다.
  • 전역 컴포넌트로 등록하는 경우는 여러 화면, 컴포넌트에서 공통적으로 자주 사용하는 컴포넌트일 때로 한정하는 편이 바람직하다.
  • src/App.vue 다시 작성
<template>
  <div>
    <h2> App 컴포넌트 </h2>
    <hr>
    <ul>
      <CheckboxItem />
      <CheckboxItem />
      <CheckboxItem />
      <CheckboxItem />
    </ul>
  </div>
</template>

<script>
  import CheckboxItem from './components/CheckboxItem.vue'
  export default {
    name: "App",
    components: { CheckboxItem },
  }
</script>

 

 

3. 컴포넌트의 조합

  • Vue 애플리케이션은 여러 컴포넌트들을 조합하여 개발한다.
  • 컴포넌트들은 속성(Props)을 통해서 자식 컴포넌트로 정보를 전달할 수 있다. 전당 방향은 부모에서 자식으로만 향한다.
  • 자식 컴포넌트는 부모 컴포넌트로 이벤트를 발신할 수 있다.
  • 자식 컴포넌트에서 사용자 정의 이벤트를 정의하고, 이벤트를 발생시키면 부모 컴포넌트에서 이벤트 핸들러 메소드를 호출하도록 작성한다.

 

4. 속성

  • 자식 컴포넌트는 props 옵션으로 속성을 정의하고 부모 컴포넌트는 v-bind 디렉티브를 이용해 자식 컴포넌트의 속성에 정보를 전달한다.
  • 속성으로 전달받은 데이터를 변경할 수 없다는 점, 속성으로 전달받은 값은 읽기 전용으로 다루어진다.
  • 부모 컴포넌트에서 데이터를 변경하면, 부모 컴포넌트가 렌더링되면서 다시 속성을 전달하기 때문에 부모 컴포넌트의 데이터만 변경하면 속성을 전달 받는 모든 자식 컴포넌트에서 변경된 속성을 확인할 수 있다.
  • Checkboxitem.vue
<template>
    <li>
        <input type="checkbox" :checked="checked" /> {{name}}
    </li>
</template>

<script>
    export default {
        name : "ChecboxItem",
        props : ["name", "checked"],
    }
</script>

<style lang="stylus" scoped>

</style>
  • App.vue
<template>
  <div>
    <h2> 관심있는 K-POP 가수 </h2>
    <hr>
    <ul>
      <CheckboxItem v-for="idol in idols" :key="idol.id"
        v-bind="idol" />
    </ul>
  </div>
</template>

<script>
  import CheckboxItem from './components/CheckboxItem.vue'
  export default {
    name: "App",
    components: { CheckboxItem },
    data() {
      return {
        idols : [
          { id:1, name:"BTS", checked:true},
          { id:2, name:"Blak Pink", checked:false},
          { id:3, name:"2NE1", checked:false},
          { id:4, name:"ITZY", checked:false},
        ]
      }
    }
  }
</script>

 

 

5. 사용자 정의 이벤트

  • 사용자 정의 이벤트를 이용한 정보 전달
  • $emit() 메소드 사용
this.$emit('event-name', eventArgs1, eventArgs2, ... )
  • InputName.vue -> 작성
<template>
    <div style="border: solid 1px gray; padding:5px;">
        이름 : <input type="text" v-model="name" />
        <button @click="$emit('nameChanged', { name })">이벤트 발신</button>
    </div>
</template>

<script>
    export default {
        name : "InputName",
        data() {
            return {
                name : ""
            };
        },
    }
</script>
  • App4.vue
<template>
    <div>
        <InputName @nameChanged="nameChangedHandler" />
        <br>
        <h3>App 데이터 : {{ parentName }}</h3>
    </div>
</template>

<script>
    import InputName from './components/InputName.vue'
    export default {
        name : "App4",
        components : { InputName },
        data() {
            return { parentName: "" }
        },
        methods: {
            nameChangedHandler(e) {
                this.parentName = e.name;
            }
        },
    }
</script>
  • 자식 컴포넌트 인스턴스의 $emit() 메서드를 이용해서 이벤트를 발신한다.
  • v-on 디렉티브로 자식 컴포넌트에서 발신한 이벤트명으로 이벤트를 수신해 등록한 핸들러 메서드를 호출한다.
  • 이벤트 발신을 위한 $emit() 내장 메서드는 직계 부모 컴포넌트로만 이벤트 정보를 전송한다.
  • 컴포넌트 계층 구조가 복잡할 때는 중간에 거쳐가는 컴포넌트에서 이벤트 정보를 받아서 다시 부모로 전달해야 한다.

 

6. 이벤트 유효성 검증

  • emits 옵션을 등록하여, 발신 하는 이벤트에 대한 유효성 검사를 수행한다.
const Component = {
    ....
    emits : ["이벤트명1", "이벤트명2"]
    ....
}
  • 또 다른 방법
  • 컴포넌트의 작동방식에 대한 명확한 문서화를 위해서도 emits 옵션을 정의할 것을 권장한다.
const Component = {
    ....
    emits : {
    	이벤트명1 : (e) => {
        	//true가 리턴되면 유효
            //false가 리턴되면 유효하지 않음
        },
        //유효성 검사 하지 않음
        이벤트명2 : null,
        ....
    },
    .....
}
  • 해당 방법을 사용하면 단순히 발신하는 이벤트명만 확인하는 것이 아니라 전달하는 이벤트 아규먼트의 유효성 여부까지 확인할 수 있다.
<script>
    export default {
        name : "InputName",
        //emits : ["nameChanged1"],
        emits: {
            nameChanged: (e) => {
                return e.name && typeof(e.name) === "string" && e.name.trim().length >= 3 ? true : false
            }
        },
        data() {
            return {
                name : ""
            };
        },
    }
</script>

 

 

7. 이벤트 에미터 사용

  • 부모-자식-손자와 같이 계층적으로 복잡하게 컴포넌트가 구성된 경우 속성과 이벤트를 조합하여 애플리케이션을 개발할 수 있다. 
  • 이벤트를 일일이 경로를 거슬러 올라가도록 전달해야 하는 측면 불편함, 형제 관계에 있는 컴포넌트는 개발하기 힘들 수 있다.
  • 이런 경우 사용하는 것이 에미터이다.
CTRL + C 를 눌러 Vue를 종료
npm install --save mitt

main.js
-> import mitt from 'mitt';

const emitter = mitt();
emitter.on('*', (type, e) => console.log(`## 이벤트 로그 : ${type} -> `, e))
const app = createApp(App)
app.config.globalProperties.emitter = emitter;
app.mount("#app");

 

■ Sender, Receiver 컴포넌트 작성

  • Sender.vue
<template>
    <div style="border: solid 1px gray; margin:5px; padding:5px;">
        <h2>Sender</h2><hr>
        <button @click="sendMessage">이벤트 발신</button>
    </div>
</template>

<script>
    export default {
        name : "Sender",
        methods: {
            sendMessage() {
                this.emitter.emit("message", Date.now() + "에 발신된 메시지");
            }
        },
    }
</script>
  • Receiver.vue
<template>
    <div style="border: solid 1px gray; margin:5px; padding:5px;">
        <h2>Receiver</h2>
        <hr>
        <h2>전송된 텍스트 : {{ textMessage }}</h2>
    </div>
</template>

<script>
    export default {
        name : "Receiver",
        created() {
            this.emitter.on("message", this.receiveHandler);
        },
        data() {
            return {
                textMessage: ""
            }
        },
        methods: {
            receiveHandler(msg) {
                this.textMessage = msg;
            }
        },
    }
</script>
  • App5.vue
<template>
    <div>
        <Sender />
        <hr>
        <Receiver />
    </div>
</template>

<script>
    import Receiver from './components/Receiver.vue'
    import Sender from './components/Sender.vue'
    export default {
        name : "App5",
        components : { Sender, Receiver }
    }
</script>
  • 결과

 

728x90
저작자표시 비영리 변경금지 (새창열림)

'Vue.js' 카테고리의 다른 글

Vue.js 3.0 STEP 7 - TodoList 리팩토링  (0) 2024.01.25
Vue.js 3.0 STEP 5 - TodoList  (0) 2024.01.25
Vue.js 3.0 STEP 4 - 스타일 적용  (0) 2024.01.25
Vue.js 3.0 STEP 3 - 이벤트 처리  (0) 2024.01.18
Vue.js 3.0 STEP 2 - Vue 인스턴스  (0) 2024.01.18
'Vue.js' 카테고리의 다른 글
  • Vue.js 3.0 STEP 7 - TodoList 리팩토링
  • Vue.js 3.0 STEP 5 - TodoList
  • Vue.js 3.0 STEP 4 - 스타일 적용
  • Vue.js 3.0 STEP 3 - 이벤트 처리
IT의 큰손
IT의 큰손
IT계의 큰손이 되고 싶은 개린이의 Log 일지
Developer Story HouseIT계의 큰손이 되고 싶은 개린이의 Log 일지
IT의 큰손
Developer Story House
IT의 큰손
전체
오늘
어제
  • 분류 전체보기 (457)
    • 정보처리기사 필기 (18)
    • 정보처리기사 실기 (12)
    • 정보처리기사 통합 QUIZ (12)
    • 빅데이터 (11)
    • 안드로이드 (11)
    • 웹페이지 (108)
    • 자바 (49)
    • SQLD (3)
    • 백준 알고리즘 (76)
    • 데이터베이스 (41)
    • 깃허브 (2)
    • Library (14)
    • Server (31)
    • 크롤링&스크래핑 (3)
    • Spring (23)
    • Vue.js (13)
    • React (27)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Developer Stroy House

인기 글

태그

  • 백엔드
  • 웹개발
  • 개발자
  • 정보보안전문가
  • DBA
  • 정보처리기사
  • 백준
  • 데이터베이스
  • IT개발자
  • 프론트엔드
  • ajax
  • 자바
  • 알고리즘
  • DB
  • React
  • css
  • 정보처리기사필기
  • 코딩테스트
  • it
  • IT자격증공부
  • 개발블로그
  • 웹개발자
  • jquery
  • java
  • html
  • 앱개발자
  • 웹페이지
  • JavaScript
  • jsp
  • IT자격증

최근 댓글

최근 글

Designed By hELLO
IT의 큰손
Vue.js 3.0 STEP 6 - 단일 파일 컴포넌트
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.