FrontEnd/Vue를 이용한 웹 게임 만들기

Chapter 02. 컴포넌트와 웹팩을 쓰는 이유

계란💕 2023. 3. 30. 11:53

컴포넌트의 필요성

  • 같은 코드의 중복을 없애고 간편하고 효율적으로 개발하기 위해 컴포넌트가 필요하다. 
  • 컴포넌트의 활용은 여러 번 사용하는 것을 전제로 한다. 
  • 지난 포스팅에서 살펴본 것과 다르게 여러 개의 끝말잇기를 한 페이지에 여러 개 진행하려면?

 

 

  Ex)  컴포넌트를 적용하지 않은 끝말잇기 게임

  • 복사해서 여러 개의 submit 메서드를 만든다. 
<hide/>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <div>{{word}}</div>
        <form v-on:submit="onSubmitForm">
            <input type="text" ref="answer" v-model="value">
            <button type="submit">입력!</button>
        </form>
        <div>{{result}}</div>
        <div>{{word1}}</div>
        <form v-on:submit="onSubmitForm1">
            <input type="text" ref="answer1" v-model="value1">
            <button type="submit">입력!</button>
        </form>
        <div>{{result1}}</div>
        <div>{{word2}}</div>
        <form v-on:submit="onSubmitForm2">
            <input type="text" ref="answer2" v-model="value2">
            <button type="submit">입력!</button>
        </form>
        <div>{{result2}}</div>
    </div>
    <script>
        const app = new Vue({
            el: '#root',
            data: {
                word: '제로초',
                word1: 'Vue',
                word2: '좋은 아침',
                result: '',
                result1: '',
                result2: '',
                value: '',
                value1: '',
                value2: ''
            },
            methods: {
                onSubmitForm(e) {
                    e.preventDefault();
                    if (this.word[this.word.length - 1] === this.value[0]) {
                        this.result = "딩동댕";
                        this.word = this.value;
                        this.value = '';
                        this.$refs.answer.focus();
                    } else {
                        this.result = "땡";
                        this.value = '';
                        this.$refs.answer.focus();
                    }
                },
                onSubmitForm1(e) {
                    e.preventDefault();
                    if (this.word1[this.word1.length - 1] === this.value1[0]) {
                        this.result1 = "딩동댕";
                        this.word1 = this.value1;
                        this.value1 = '';
                        this.$refs.answer1.focus();
                    } else {
                        this.result1 = "땡";
                        this.value1 = '';
                        this.$refs.answer1.focus();
                    }
                },
                onSubmitForm2(e) {
                    e.preventDefault();
                    if (this.word2[this.word2.length - 1] === this.value2[0]) {
                        this.result2 = "딩동댕";
                        this.word2 = this.value2;
                        this.value2 = '';
                        this.$refs.answer2.focus();
                    } else {
                        this.result2 = "땡";
                        this.value2 = '';
                        this.$refs.answer2.focus();
                    }
                }
            }
        })
    </script>
</body>
</html>

 

  Note) 실행 결과

  • 아래와 같이 세 개의 끝말잇기를 만들었으나 
  • 중복되는 부분이 너무 많다. 
  • 이런 비효율성을 해결할 수 있는 것이 "컴포넌트"이다.
  • 최소 단위를 재사용한다. 

 

입력 누른 후


컴포넌트 적용하기

  • component() 안에는 파스칼, 케밥 표기법을 쓴다. 
    • 카멜 표기법(camelCase), 파스칼 표기법(PascalCase), 케밥 표기법(kebab-case)
    • 카멜이랑 파스칼이랑 맨 앞문자가 대문자인지 소문자인지 여부만 다르다. 
  • data{} 안에는 수정사항이 있다. 
    • 기존 data{} 안에 객체 형식이었지만 컴포넌트 적용하는 경우는 함수로 만들어야한다. 
    • data 객체를 돌려주는 함수로 만든다. 
  • template: ``
    • cf) 백틱(`)을 쓰면 줄바꿈할 때 편리함
    • 아까 그 반복되는 코드를 템플릿 안에 넣어준다. 
    • 템플릿은 제약 조건 상 항상 하나로 감싸줘야한다. 
    • 템플릿 안에 형제 태그 3개가 있는데 이를 모두 하나로 감싸서 템플릿에 넣어줘야한다. 
  • root에 해당하는 Vue () 안에 있는 데이터를 모두 컴포넌트로 옮겨준다. 
    •  data, methods 영역의 내용을 컴포넌트로 이동한다. 
    • 기존 Vue () 인스턴스 안에 내용을 모두 지운다. 

 

 

 

  Ex) 컴포넌트 적용

<hide/>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <word-relay></word-relay>
        <word-relay></word-relay>
        <word-relay></word-relay>
    </div>
    <script>
        Vue.component('word-relay', {
            template: `
                <div>
                    <div>{{word}}</div>
                        <form v-on:submit="onSubmitForm">
                            <input type="text" ref="answer" v-model="value">
                            <button type="submit">입력!</button>
                        </form>
                    <div>{{result}}</div>        
                </div>
            `,
            data() {
                return {
                    word: '제로초',
                    result: '',
                    value: ''
                };
            },
            methods: {
                onSubmitForm(e) {
                    e.preventDefault();
                    if (this.word[this.word.length - 1] === this.value[0]) {
                        this.result = "딩동댕";
                        this.word = this.value;
                        this.value = '';
                        this.$refs.answer.focus();
                    } else {
                        this.result = "땡";
                        this.value = '';
                        this.$refs.answer.focus();
                    }
                }
            }
        })
    </script>
    <script>
        const app = new Vue({
            el: '#root'
        })
    </script>
</body>
</html>

 

  Note) 실행 결과 

 

 


  • 오류
    • vue.js:5108 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
  • 원인
    • data를 객체형이 아닌 함수형으로 만들어줘야한다. 
  • 해결
    • 위 코드를 아래와 같이 함수형으로 바꾼다. 
<hide/>
data: {
    word: '',
    result:  '',
    value: ''
}, 

data() {
    return{
        word: '',
        result:  '',
        value: ''
    }
}

컴포넌트의 특성

  • 컴포넌트는 렌더링(화면에 표시)하지만 중복을 제거한다. 
  • 데이터들은 따로 논다. 같은 컴포넌트라도 각각의 데이터를 가진다. 
  • 컴포넌트를 만드는 스크립트는 상단에 와야한다. 
  • 전역 컴포넌트(global component)라고도 한다. 

props와 웹팩의 필요성

  • 공통적으로 반복되는 부분이 있지만 조금씩 다른 부분이 있다면?
  • 예를 들어 아래 사진에서 동그라미 안에 숫자만 다르다. 

 

 

  Ex) props 적용, 전역 컴포넌트

  • 기존의 코드에서 각 끝말잇기의 첫 단어를 다르게 고정시키려면?
  • 컴포넌트를 쓰는 쪽에서 startWord 값을 넣어주고
  • 컴포넌트를 정의하는 부분에는 props를 받아준다. (startWord를 받겠다고 넣어주기. )
  • 다음과 같이 "start-word"를 케밥 표기법으로 넣어줘야한다. 
    • Vue의  html 에서는 케밥 표기법으로 넣고 JavsScript 에서는 카멜 표기법으로 받아준다. 
    • html: <word-relay start-word="고양이"></word-relay>
    • JavsScript: component 안 부분에  word: this.startWord 라고 넣는다. 
    • 이렇게 각각 넣어주면 Vue가 알아서 처리해준다. 
<hide>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>끝말잇기</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <word-relay start-word="고양이"></word-relay>
        <word-relay start-word="아메리카노"></word-relay>
        <word-relay start-word="침팬치"></word-relay>
    </div>
    <script>
        Vue.component('word-relay', {
            template: `
                <div>
                    <div>{{word}}</div>
                        <form v-on:submit="onSubmitForm">
                            <input type="text" ref="answer" v-model="value">
                            <button type="submit">입력!</button>
                        </form>
                    <div>{{result}}</div>        
                </div>
            `,
            props: ['startWord'],
            data() {
                return {
                    word: this.startWord,
                    result: '',
                    value: ''
                };
            },
            methods: {
                onSubmitForm(e) {
                    e.preventDefault();
                    if (this.word[this.word.length - 1] === this.value[0]) {
                        this.result = "딩동댕";
                        this.word = this.value;
                        this.value = '';
                        this.$refs.answer.focus();
                    } else {
                        this.result = "땡";
                        this.value = '';
                        this.$refs.answer.focus();
                    }
                }
            }
        })
    </script>
    <script>
        const app = new Vue({
            el: '#root'
        })
    </script>
</body>
</html>

 

  Note) 실행 결과

  • 전역 컴포넌트를 이용하면 공통적인 모양이 있지만 데이터를 따로 가지고 있다. 

 


웹팩을 배우는 이유

  • <script>를 많이 쓰게 되는 경우, 복잡함을 줄이기 위해 웹팩을 쓴다. 
  • 웹팩을 쓰면 여러 스크립트를 합칠 수 있다. 
  • 웹 사이트를 크게 만들려면 스크립트가 늘어나고 스크립트 관리에 대한 어려움이 생겨서  웹팩을 배우는 게 좋다. 

Note

  •  content

찾아보기

  •  content

 

 

출처 - https://www.inflearn.com/course/web-game-vue/dashboard