FE - Vue.js (CDN)

수현·2023년 9월 22일
0

Ucamp

목록 보기
8/19

📒 Vue.js

📕 Vue.js 기본

1. Vue.js

1) 개념

  • Evan You가 2013년에 발표한 Front-end JavaScript framework

  • Angular와 React 장점만 가진 프레임워크

  • SPA(Single Page Application) 목적의 프레임워크

  • Vue-CLI : Vuejs 프로젝트(코드, 디렉토리 구조)를 생성 해주는 라이브러리

  • CRA(Create Project App) : ReactJS 프로젝트(코드, 디렉토리 구조)를 생성 해주는 라이브러리

  • Vite : 다양한 JS(TS) 프로젝트를 생성해주는 라이브러리

2) 특징

  • JS 컴파일러가 필요함

    • Babel 은 javascript 컴파일러 변환하는 이유는 브라우저 호환성을 위해서 ES6 => ES5 로 transform (변환) 해서 배포
  • Bundling(번들링) 도구가 필요함

    • Webpack

2. MVVM 패턴

  • Vue 및 React, Angular 등 프레임워크가 지향하는 패턴
  • MVVM 패턴은 Model, View, ViewModel의 약자로 어플리케이션 로직과 UI 분리를 위한 패턴
  • ViewModel은 Model과 View를 연결하는데 Model의 데이터가 변경되면 View에 화면을 갱신하게 하고, 사용자가 화면에서 값을 변경하면 다시 그 값을 Model에 업데이트

3. Vue.js 개발 방법

1) CDN 이용

<script src="https://cdn/jsdelivr.net/npm/vue/dist/vue.js"></script>

2) CLI 이용

npm install -g @vue/cli

4. CDN 활용한 개발

1) 기본 구조

  • View (Template)

    • HTML과 CSS로 이루어진 요소
    • Vue.js의 디렉티브 또는 {{}} 같은 템플릿
    • 표현식으로는 HTML DOM에 데이터를 렌더링함
    • v-xxx 형식의 다양한 디렉티브 사용할 수 있음
  • Model

    • 데이터 요소
    • JSON 형태로 표현
  • ViewModel

    • Controller 역할을 하며 Vue 객체가 담당함

    • 가장 중요한 역할은 View와 Model의 연결

    • 📋 코드 📋

      <!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>vuejs 기본구조</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <!-- view -->
        <div id="app">
            {{ message }}
        </div>
        <script> 
          	// Model
          	let model = {
          		message : '안녕하세요 Vue!'
          	};
          	// ViewModel - Vue 객체
            var app = new Vue({
                el: '#app', // 연결할 View 선택
                data: { // 사용할 Model 설정
                    message: model.message
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>vuejs data종류</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <!-- data 종류 -->
            message:{{ message }}<br>
            age:{{ age }}<br>
            phones:{{ phones[0] }}&nbsp;{{ phones}}<br>
            author:{{ author.name }}&nbsp;{{author.age}}<br>
            isMarried:{{ isMarried }}<br>
            <hr>
            <!-- {{}}을 mustache(이중중괄호)라고 부른다.-->
            1) message:{{ message }}<br>
            2) age(산술연산):{{ age+1 }}<br>
            3) 30보다 적냐?(비교연산):{{age<30}}<br>
            4) 이름길이:{{ author.name.length}}<br>
            5) 결혼여부(3항연산자):{{ isMarried?"기혼":"미혼" }}<br>
      
            6) 문자열_대문자함수:{{message.toUpperCase()}}<br>
            7) 문자열_소문자함수:{{message.toLowerCase()}}<br>
            7-1) 문자열 대문자와 소문자 출력 함수:{{upper_lower_case()}}<br>
            8) 문자열_부분열함수:{{message.slice(0,3)}}<br>
            9) 문자열_치환함수:{{message.replace("Vue","vuex")}}<br>
            10) 수치_정수변환함수:{{Number.parseInt(height)}}<br>
            11) 배열_join함수:{{phones.join(":")}}
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!',
                    age: 20,
                    height: 178.535,
                    phones: [100, 200, 300],
                    author: { name: "홍길동", age: 20 },
                    isMarried: true
                }, // data
                methods: {
                    upper_lower_case() {
                        return this.message.toUpperCase() + ' || ' +this.message.toLowerCase()
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

2) Vue 객체

  • Vue 객체의 생성자는 옵션 객체를 통해서 필요한 속성들을 설정
  • 속성 종류
    • el : Vue로 만든 화면이 그려지는 인스턴스의 시작 지점 (CSS로 요소 지정)
    • data : 인스턴스의 데이터 속성으로 model을 나타냄
    • template : 화면에 표시할 HTML, CSS 등 마크업 요소를 정의하는 속성 (Vue의 데이터 및 기타 속성들도 함께 화면에 렌더링)
    • methods : 이벤트 및 화면 동작 메서드로 속성들은 function
    • created : 라이프 사이클 커스터마이징 로직
    • 📋 코드 📋
      <!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>vuejs template</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            This will be replaced !
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!'
                },
                template: `<div>{{message}}</div>`  //template 속성값에는 반드시 root태그 필요
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3) Vue 객체의 유효범위 (scope)

  • Vue 객체의 유효범위는 Vue 객체가 관리하는 HTML의 범위 (el 속성에 지정된 영역)

  • 해당 범위에서만 Vue가 동작하기 때문에 지정된 scope를 벗어나면 {{}} 표현식 등 단순한 문자열로 처리

  • Vue 객체 동작 과정

    • 📋 코드 📋
      <!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>vuejs app scope</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            scope범위포함:{{ message }}
        </div>
        scope범위 미포함:{{ message }}
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!'
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

📕 directive

1. directive 개념

  • 지시자(directive)
    • 지시자로서 Vue에서 template에 데이터를 표현하는 용도로 사용되는 속성
    • Vue의 디렉티브들은 v-를 접두어로 가짐
  • 지시자 종류
    • 텍스트 표현 : v-text, v-html, v-once
    • html 속성 바인딩 : v-bind
    • 양방향 데이터 바인딩 : v-model
    • 제어문 : v-show, v-if, v-else, v-else-if
    • 반복문 : v-for

1) 텍스트 표현

  • v-text
    • innerText 속성에 연결되며 문자열 그대로 화면에 표현
    • Model과의 반응성이 유지됨
  • v-html
    • innerHtml 속성에 연결되며 문자열 중 html 태그를 파싱해서 화면에 나타냄
    • Model과의 반응성이 유지됨
  • v-once
    • v-text, v-html에 부가적으로 사용
    • v-once는 1번 연동 후 반응성이 제거됨
    • 📋 코드 📋
      <!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>directive v-text, v-html, v-once</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <ul>
                <li>{{ message }}</li>
                <li><span v-text="message"></span></li>
                <li v-html="message"></li>
                <li v-once>{{message}}</li>
            </ul>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '<h1>안녕하세요 Vue!</h1>'
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

2) html 속성 바인딩 (단방향 바인딩)

  • v-bind

    • html의 속성인 id, class, style 등에 model 값을 연결할 때 사용하는 단방향 바인딩

    • 연동하려는 대상에 따라 v-bind:id, v-bind:class, v-bind:style 등 사용

    • 축약형으로 v-bind 생략 가능

    • html의 class 속성의 경우 여러 값 설정 가능

      • 객체 형태로 값을 전달하는데 boolean 타입의 model값을 이용해서 해당 class를 on/off 처리
    • 📋 코드 📋

      <!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>directive v-bind</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            .red-accent {
                color: red;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <ul v-bind:id="mid">
                <li v-bind:class="mclass">클래스바인딩</li>
                <li :style="mstyle">스타일바인딩</li>
                <li><a :href="link.mhref" :title="link.mtitle">go</a></li>
            </ul>
            <img v-bind:src="user_imgs[0]" /><br/>
            <img :src="user_imgs[1]" />
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    mid: "list",
                    mclass: "red-accent",
                    mstyle: "color:blue",
                    link: {
                        mhref: "http://vuejs.org",
                        mtitle: "Vuejs"
                    },
                    user_imgs :
                    ["https://reqres.in/img/faces/1-image.jpg", 
                     "https://reqres.in/img/faces/2-image.jpg"] ,
                    
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>directive v-bind 멀티 class속성</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            .set1 {
                color: red;
            }
      
            .set2 {
                background-color: blue
            }
      
            .set3 {
                font-style: italic;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <div :class="{set1:s1, set2:s2, set3:s3}">
                Hello
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    s1: true,
                    s2: false,
                    s3: false,
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>directive v-bind 동적 전달 인자</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            .set1 {
                color: red;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <div :[mid]="xxx" :[mclass]="s1">
                Hello
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    mid: "id",
                    mclass: "class",
                    xxx: "v1",
                    s1: "set1"
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3) 양방향 데이터 바인딩

  • v-model

    • view와 model 사이의 양방향 데이터 바인딩에 사용되는 디렉티브

    • 사용자로부터 값을 입력 받는 <input>, <select>, <textarea> 등에서 사용

      • 사용자가 입력한 값을 Model에 반영시킴
      • Model이 변경되면 입력 요소의 값도 변경됨
      • 다중 선택이 지원되는 <select>, checkbox의 경우의 값은 배열 객체와 연결되고 나머지 요소들은 단일 값과 연결됨
    • 기능 추가하기 위한 수식어 제공 ('.' 이용해서 설정, 여러 속성 chaining 가능)

      • lazy : 입력 폼에서 change 이벤트가 발생하면 데이터 동기화 (입력 후에 Enter치면 반영됨)
      • number : 입력 값을 parseInt 또는 parseDouble을 이용해 number 타입으로 저장 (첫 숫자 이후의 문자는 무시됨)
      • trim : 입력 문자열의 앞 뒤 공백을 자동으로 제거
    • 📋 코드 📋

      <!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>directive v-model</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div>
                이름1:<input v-model="username" /><br>
                <!-- 이름2(lazy):<input v-model.lazy="username" /><br> -->
                입력한 이름:{{username}}<br>
                <hr/>
                나이1:<input v-model="age" /><br>
                나이2(number):<input v-model.number="age" /><br>
                입력한 나이:{{age}}<br>
                <hr/>
                주소1:<input v-model="address" /><br>
                주소2(trim):<input v-model.trim="address" /><br>
                입력한 주소:{{address}}<br>
                입력한 주소:{{address.length}}<br>
                <hr/>
                출생연도(lazy.number):<input v-model.lazy.number="year"><br>
                입력연도:{{year}}<br>
                <hr/>
                배열1:<input type="checkbox" v-model="team" value="A">A<br>
                배열2:<input type="checkbox" v-model="team" value="B">B<br>
                배열3:<input type="checkbox" v-model="team" value="C">C<br>
                선택한 배열:{{team}}
                <hr/> 
                <input type="checkbox" v-model="isFlag">user Image변경 <br/>
                <img :src="isFlag?user_imgs[0]:user_imgs[1]" />
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    username: "",
                    age: '',
                    address: '',
                    year: '',
                    team: [],
                    user_imgs :
                    ["https://reqres.in/img/faces/1-image.jpg", 
                     "https://reqres.in/img/faces/2-image.jpg"],
                    isFlag: true 
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>directive v-model 2</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            .red-accent {
                color: red;
            }
        </style>
      </head>
      <body>
        <div id="select">
            <label>가장 좋아하는 캐릭터는?</label>
            <input type="text" v-model.trim="favorite"><br>
            <label>팀 멤버를 선택하세요</label>
            <input type="checkbox" value="1" v-model="team"><label>아이언맨</label>
            <input type="checkbox" value="2" v-model="team"><label>토르</label>
            <input type="checkbox" value="3" v-model="team"><label>헐크</label><br>
            <label>출생 연도는?</label>
            <input type="text" v-model.lazy.number="year"><br>
        </div>
        <hr>
        <div id="result">
            <p>당신의 선택은
            <ul>
                <li>캐릭터:{{favorite}}</li>
                <li>팀:{{team}}</li>
                <li>출생년도:{{year}}</li>
            </ul>
            </p>
        </div>
        <script>
            let model = { favorite: "", team: [], year: "" }
            var select = new Vue({
                el: '#select',
                data: model
            });
            var result = new Vue({
                el: '#result',
                data: model
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

4) 제어문

  • v-show

    • 조건 불일치시 렌더링 방식 : display=none으로 처리
    • 이에 따른 비용 : 초기 렌더링 비용이 큼
    • 유용한 경우 : 자주 바뀔 때
  • v-if

    • 조건 불일치시 렌더링 방식 : 렌더링하지 않음

    • 이에 따른 비용 : 토글 비용이 큼

    • 유용한 경우 : 자주 바뀌지 않을 때

    • 📋 코드 📋

      <!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>directive v-if, v-show</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <input type="checkbox" v-model="isShow" />Image 보여주기
            isShow 값은 {{isShow}} <br/>
            <img src="images/error.png" width="20" height="20" v-show="isShow" /><br/>
      
            나이:<input v-model.number="age" /> <br/>
            <img v-show="age < 0" src="images/error.png" width="20" height="20">
            <hr>
            당신은:
            <span v-if="age < 0">입력오류</span>
            <span v-else-if="age < 8">미취학</span>
            <span v-else-if="age < 19">미성년</span>
            <span v-else>성년</span>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    age: '',
                    isShow:false,
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

5) 반복문

  • v-for

    • 유니크한 속성명을 이용해서 :key 설정
    • 조건문과 연계 가능
    • 문법
      • v-for="항목 in 배열|객체" :key="값"
    • 배열
      • <v-for="contact in cotacts" :key="유일값">
      • <v-for="(contact, index) in contacts" :key="유일값">
    • 객체
      • v-for="(val, key) in regions"
      • v-for="(val, key, indexl) in regions"
  • template 태그

    • <template>는 여러 요소를 묶어서 반복 렌더링 할 때 요소를 묶어주는 태그

    • 실제 렌더링 내용에는 포함되지 않고, 단지 요소들을 그룹핑하는 용도로 사용

    • 📋 코드 📋

      <!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>directive v-for</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div>
                <h1>배열 반복1</h1>
                <ul>
                    <li v-for="(value) in heros">{{value}}</li>
                </ul>
                <h1>배열 반복2</h1>
                <ul>
                    <li v-for="(value,index) in heros" :key="index">{{index}}:{{value}}</li>
                </ul>
                <h1>객체 반복1</h1>
                <ul>
                    <li v-for="(value,key) in hero">{{key}}:{{value}}</li>
                </ul>
                <h1>객체 반복2</h1>
                <ul>
                    <li v-for="(value,key,index) in hero" :key="index">{{index}}:{{key}}:{{value}}</li>
                </ul>
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    heros: ["A", "B", "C"],
                    hero: {
                        name: "홍길동",
                        age: 20,
                        address: "서울"
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>directive v-for template</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <template v-for="(value, index) in heroes">
                <div>
                    <p>등장순서:{{index}}, 이름:{{value}}</p>
                </div>
                <hr v-if="index % 2==0">
            </template>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    heroes: ["아이언맨", "헐크", "토르", "캡틴아메리카", "비전"],
                    ironMan: {
                        name: "토니스타크",
                        nickName: "깡통"
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

📕 Vue 객체

1. Vue 객체

  • Vue 객체
    • MVVM 패턴에서 ViewModel을 담당하는 Vue.js의 핵심 객체
    • Vue 생성자 함수에 옵션 객체를 전달해서 생성함
    • 속성은 Vue 객체 외부에서 접근하기 위해서 $options 속성 이용

1) el

  • elment, View를 연결하는 속성
  • Vue로 만든 화면이 그려지는 인스턴스의 시작 지점
    • el 지정할 때는 CSS 선택자를 이용해서 HTML의 DOM 속성 지정
    • 반드시 하나만 지정
    • 여러 개가 선택되더라도 맨 처음 요소만 사용됨 (ID기반 접근 필요)
  • Vue 객체 외부에서 el요소에 접근하기 위해서는 $el 속성 이용

2) data

  • Model을 연결하는 속성으로 JSON 객체
  • 인스턴스의 데이터 속성으로 객체를 이용해 여러 값 저장
  • Vue 객체 외부에서 data에 접근하기 위한 내장옵션으로 $data 사용
    • data 속성들은 모두 Vue 객체의 속성으로 관리

3) template

  • 화면에 표시할 HTML, CSS 등 마크업 요소를 정의하는 속성
  • Vue의 데이터 및 기타 속성들도 함께 렌더링

4) created

  • 라이프 사이클 커스터마이징 로직

    • 📋 코드 📋
      <!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>vue 객체</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            {{ message }}
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!'
                }
            });
            console.log("Vue객체:", app)
            console.log("el접근:", app.$el)
            console.log("message 접근1:", app.$data.message)
            console.log("message 접근2:", app.message)
        </script>
      </body>
      </html>
    • 📋 실행 📋

2. Methods, computed, watch 속성

1) methods

  • 이벤트 및 화면 동작 메서드
  • Vue 객체에서 사용할 메서드들을 객체로 등록하는 속성
    • 등록된 메서드는 Vue 객체에서 직접 호출하거나 디렉티브 표현식 등에서 data 처럼 사용 가능
  • 호출할 때 반드시 () 사용
    • 화면이 다시 렌더린 될 때마다 화면에서 사용되고 있는 methods들은 모두 다시 실행됨
    • 호출 시점에 메서드가 실행되어 값을 반환하기 때문에 캐시 기능이 없음

2) computed

  • 함수를 속성으로 갖는 객체

  • methods 속성과 달리 생성 시점에 계산된 값을 반환하고, 이후에는 캐시값을 사용

  • 호출시 반드시 함수명만 사용

    • 📋 코드 📋

      <!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>vue 객체 methods, computed</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
          <input type="number" v-model="num" /><br />
          num : {{num}}<br />
          message : <input type="text" v-model="message" />
          <p>원본 메시지: "{{ message }}"</p>
          <p>역순으로 표시한 메시지: "{{ reversedMessage }}"</p> 
        </div>
        <script>
          var app = new Vue({
            el: "#app",
            data: {
              message: "Hello",
              num: 0,
            },
            // methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
            // 반드시 () 이용
            // message 아닌 num 변경해도 계속 수행됨 (불필요한 렌더링 계속 발생)
            methods: {
              // reversedMessage() {
      
              // 위와 동일
              // reversedMessage: function () {
              //   console.log("methods reverseMessage");
              //   return this.message.split("").reverse().join(""); // olleH
              // }, 
            }, // methods
            // computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
            // () 사용안함
            computed: {
                reversedMessage: function () {
                  console.log("computed reverseMessage")
                  return this.message.split("").reverse().join("");
                },
            },
          }); // computed
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>vue 객체 methods, computed 화면 재렌더링시</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <input type="number" v-model="num">
            값:{{num}}<br>
            {{xxx()}}{{xxx()}}
            {{yyy}}{{yyy}}
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    num: 0
                },
                // methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
                // 반드시 () 이용
                // 화면이 다시 랜더링 될때마다 화면에서 사용되고 있는 methods들이 모두 다시 실행된다
                methods: {
                    xxx() {
                        console.log("xxx");
                    }
                },
                // computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
                // () 사용안함
                // 화면이 다시 랜더링 여부와 상관없이 실행 안됨.
                computed: {
                    yyy() {
                        console.log("yyy");
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Dvue 객체 methods, computed Data 변경시</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <input type="number" v-model="num">
            값:{{num}}<br>
            {{xxx()}}{{xxx()}}
            {{yyy}}{{yyy}}
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    num: 0
                },
                // methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
                // 반드시 () 이용
                // 화면이 다시 랜더링 될때마다 화면에서 사용되고 있는 methods들이 모두 다시 실행된다
                methods: {
                    xxx() {
                        console.log("xxx", this.num);
                    }
                },
                // computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
                // () 사용안함
                // 화면이 다시 랜덩링 여부와 상관없이 실행 안됨.
                // 함수안에서 data 접근코드 지정하고 data가 변경되면 호출된다.
                computed: {
                    yyy() {
                        console.log("yyy", this.num);
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3) watch

  • methods, computed와 유사하게 함수를 관리하는 객체
    • 기능은 데이터 변경시 특정 동작 처릭 가능한 함수들을 관리함
  • watch함수를 등록할 때 함수의 이름은 반드시 변경할 모니터링할 객체의 속성명과 같아야함
  • 함수 파라미터 값으로 old값과 new값을 전달 받을 수 있음
  • 긴 시간이 필요로하는 비동기 처리에 적합함

  • 📋 코드 📋
    <!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>vue 객체 watch/title>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    <body>
      <div id="app">
          <input type="number" v-model='v1'>+<input type="number" v-model='v2'>={{sum}}
      </div>
      <script>
          var app = new Vue({
              el: '#app',
              data: {
                  v1: 0,
                  v2: 0,
                  sum: 0
              },
              // 1. watch 속성의 함수명은 반드시 data 속성명과 일치해야 된다.
              // 2. methods 및 computed 함수도 data 속성이 변경되면 자동으로 호출되지만,
              //  반드시 명시적으로 함수명을 지정한 경우에만 해당된다.
              //  하지만 watch는 명시적으로 호출하지 않아도 자동으로 호출된다.
              watch: {
                  v1(newValue, oldValue) {
                      console.log("v1값 변경됨", oldValue, newValue);
                      this.sum = Number.parseInt(newValue) + Number.parseInt(this.v2);
                  },
                  v2(newValue, oldValue) {
                      console.log("v2값 변경됨", oldValue, newValue);
                      this.sum = Number.parseInt(this.v1) + Number.parseInt(newValue);
                  }
              }
          });
           bookList = [
              {title: "java", price:100},
              {title: "java2", price:200},
              {title: "java3", price:300}
          ]
      </script>
    </body>
    </html>
  • 📋 실행 📋

3. filters

  • {{}} 표현식 또는 v-bind에서 텍스트 형식화하는 기능 제공

    • 📋 코드 📋

      <!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>vue 객체 filter 지역적 </title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <span>원본:{{name}}</span><br>
            <span>대문자로:{{name|toCap}}</span><br>
            <span>첫 4글자만 대문자:{{name|subStr(0,4)|toCap}}</span>
        </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    name: 'HongKilDong',
                    price: 1000000000
                },
                filters: {
                    toCap(param) {
                        return param.toUpperCase();
                    },
                    subStr(param, start, end) {
                        console.log(start, end);
                        return param.substr(start, end);
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>vue 객체 filter 전역적</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <span>원본1:{{name}}</span><br>
            <span>대문자로1:{{name|toCap}}</span><br>
        </div>
        <div id="app2">
            <span>원본2:{{name}}</span><br>
            <span>대문자로2:{{name|toCap(1,2)}}</span><br>
        </div>
        <script>
            //전역객체
            Vue.filter('toCap', (param, s, e) => {
                console.log(s, e);
                return param.toUpperCase();
            });
      
            var app = new Vue({
                el: '#app',
                data: {
                    name: 'EvanYou'
                }
            });
            var app2 = new Vue({
                el: '#app2',
                data: {
                    name: 'JohnResig'
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

4. 라이프 사이클 메서드

1) Vue 라이프 사이클 hook method

  • Vue 객체는 생성에서부터 화면 연결, 값 변경에 대한 처리 등 관여하다가 처리됨
  • 특정 시점에 콜백되는 라이프 사이클 훅 메서드
  • beforeCreate
    • Vue 객체가 생성되고 데이터에 대한 관찰 기능 및 이벤트 감시자 설정 전에 호출됨
    • 거의 보이지X
  • created
    • Vue 객체가 생성된 후 데이터에 대한 관찰 가능
    • computed, methods, watch 설정이 완료된 후
  • beforeMount
    • 아직 마운트가 시작되기 전에 호출
    • DOM 구성 이전이므로 화면 건드리기에는 부적절함
  • mounted
    • DOM 요소가 el에 의한 가상 DOM으로 대체된 후에 호출됨
    • 화면에 대한 완벽한 제어가 가능한 시점
    • 부모의 mouted hook이 자식의 mounted hook보다 늦게 실행됨 (부모는 자식의 mouted hook이 끝날 때까지 대기)
  • beforeUpdate
    • 데이터가 변경되어서 가상DOM이 다시 렌더링 되기 전에 호출됨
  • updated
    • 데이터 변경으로 가상 DOM이 다시 렌더링되고 패티된 후에 호출됨
    • 훅이 호출된 시점은 이미 가상 DOM이 렌더링된 후이므로 DOM에 대한 추가 작업 필요
  • beforeDestroy
    • Vue 객체가 제거되기 전에 호출됨
  • destroyed
    • Vue 객체가 제거된 후에 호출됨
    • 훅이 호출될 때 Vue 객체의 모든 디렉티브 바인딩이 해제되고 이벤트 연결도 제거됨

  • 📋 코드 📋
    <!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>vue 객체 lifecycle hook</title>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    <body>
      <div id="app">
          <h3 v-html="num"></h3>
          <button @click="plus">+</button>
      </div>
      <script>
          var app = new Vue({
              el: '#app',
              data: {
                  num: 0,
                  title: "hook method"
              },
              methods: {
                  plus() {
                      return ++this.num;
                  }
              },
              beforeCreate() {
                  // 아직 el 이나 data가 연동되지 않았다.
                  console.log("beforeCreate", this.title, this.$el);
              },
              created() {
                  // data, computed, methods, watch 설정이 완료된다.
                  console.log("created", this.title, this.$el);
              },
              beforeMount() {
                  // data와 el이 준비 되었지만 아직 화면이 대체되지 않았다.
                  console.log("beforeMount", this.title, this.$el.innerHTML);
                  console.log("beforeMount", document.querySelector("#app").innerHTML);
              },
              mounted() {
                  // data와 el이 준비 되었으며 화면이 Virtual DOM으로 대체되었다.
                  console.log("mounted", this.title, this.$el.innerHTML);
                  console.log("mounted", document.querySelector("#app").innerHTML);
              },
              beforeUpdate() {
                  // + 를 누르면 값이 업데이트 되려고 한다. 값은 변경되었으나 화면 갱신전이다.
                  console.log("beforeUpdate", this.num, document.querySelector("#app").innerHTML);
              },
              updated() {
                  // 값이 업데이트 되었고 화면도 갱신 되었다.
                  console.log("updated", this.num, document.querySelector("#app").innerHTML);
              },
              beforeDestory() {
                  // 객체가 삭제 되기 직전이다.
                  console.log("beforeDestory", this.title, this.$el);
              },
              destroy() {
                  // 객체가 삭제된 이후이다.
                  console.log("destroy", this.title, this.$el);
              }
          });
          console.log(app);
      </script>
    </body>
    </html>
  • 📋 실행 📋

📕 이벤트

1. 이벤트 처리

  • DOM 요소에 이벤트 등록

    • v-on:evnentname=이벤트핸들러 사용
    • @eventname=이벤트핸들러 사용
  • Vue에서 처리할 수 있는 이벤트 종류는 DOM 객체의 이벤트 처리와 동일

    • 📋 코드 📋
      <!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>Vuejs 이벤트 처리</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            현재 잔고: <span>{{balance}}</span><br/>
            <label>거래 금액</label>
            <input type="number" v-model="amount">
            <button v-on:click="balance += parseInt(amount)">입금</button><br/><br/> 
            <button @click="withdraw">출금1-콜백</button>
            <button @click="withdraw()">출금2-직접호출</button>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    amount: 0,
                    balance: 1000
                },
                methods: {
                    withdraw() {
                        if (this.balance >= this.amount) {
                            this.balance -= this.amount;
                        } else {
                            alert("잔액 부족");
                        }
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

2. 이벤트 객체

  • DOM에서 발생하는 이벤트의 상세 정보 (어떤 요소에서 발생했는지 또는 입력한 키보드 키값은 무엇인지)는 이벤트 객체를 통해서 전달

1) 이벤트 객체에서 사용 속성/함수

  • 공통 속성
    • target : 이벤트 소스 (이벤트가 발생한 DOM 객체)
    • path : 배열로 target부터 window까지 조상을 찾아가는 경로
  • 키보드 이벤트 속성
    • altKey/shiftKey/ctrlKey : alt/shift/ctrl 키가 눌렸는지 여부 (true/false)
    • keyCode : 이벤트를 발생시킨 키보드의 고유 키 코드 (enter : 13)
    • charCode : keypress 이벤트에서 눌린 unicode 캐릭터 코드
  • 마우스 이벤트 속성
    • clientX/clientY : viewport 영역에서 이벤트가 발생한 좌표로 스크롤된 길이에 영향을 받지 않음
    • pageX/pageY : document 영역에서 이벤트가 발생한 좌표로 스크롤된 길이에 영향을 받음
    • screenX/screenY : screen 영역에서 이벤트가 발생한 좌표
  • 공통 함수
    • preventDefault : 기본 이벤트 동작을 중지시킴
    • stopPropagation : 이벤트 전파를 막음

2) 이벤트 핸들러 호출 방식

  • Vue에서 이벤트 핸들러를 등록할 때 콜백 방식/직접 호출 방식 모두 가능

  • 이벤트 핸들러 등록만 하는 형태는 시스템이 콜백하는 형태

    • 파라미터로 이벤트 객체가 자동으로 전달됨
  • 실행하는 형태는 직접 함수를 호출하는 것이고. 시스템이 콜백하지X

    • 이벤트 객체를 직접 활용할 수 없고, $event 이용해서 명시적으로 전달해야 함

    • 📋 코드 📋

      <!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>Vuejs 이벤트 객체</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div @click="clicked" @mouseover="over()" @mouseout="out($event)">
                Hello
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    amount: 0,
                    balance: 1000
                },
                methods: {
                    clicked(e) {
                        console.log("clicked 콜백됨,", e);
                    },
                    over(e) {
                        console.log("over 콜백 안됨,", e);
                    },
                    out(e) {
                        console.log("over 콜백 안됨. 따라서 명시적으로 $event 지정,", e);
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs 이벤트 바인딩</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            #canvas {
                width: 100px;
                height: 100px;
                background-color: yellow;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <select v-model="your_event">
                <option value="mousemove">mousemove</option>
                <option value="click">click</option>
            </select>
            >>> {{your_event}}
            <div id="canvas" @[your_event]="actionPerform($event)"></div>
            status:<input type="text" name="status" v-model="status"><br>
            x:<input type="text" name="x" v-model="x"><br>
            y:<input type="text" name="y" v-model="y">
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    your_event: 'mousemove',
                    status: '',
                    x: 0,
                    y: 0,
                },
                methods: {
                    actionPerform(e) {
                        this.status = e.type;
                        this.x = e.clientX;
                        this.y = e.clientY;
                    },
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3. 이벤트 수식어

  • 이벤트 속성을 이용할 때 직접 이벤트 객체를 사용하기 보다 간단한 이벤트 수식어(Event Modifier) 이용해서 처리 가능

  • 공통 이벤트 수식어

    • prevent : 이벤트의 기본 동작 방지
      • <form>의 submit 전송 방지
      • <a>의 클릭으로 페이지 전환 방지
      • prevaentDefault() 대체
    • stop : 하나의 이벤트가 여러 요소에 걸쳐 발생할 때 전파 중단
      • stopPropagation() 대체
    • capture : 캡쳐링 상태에서 이벤트 처리
    • self : 버블링(raising) 상태에서 이벤트 처리
    • once : 한번만 이벤트 발생시키고 이후는 동작하지 않음
    • passive : 혹시나 있을지 모를 preventDefault() 실행 안되게 함 (동작 보장)
  • 키보드 이벤트 수식어

    • 숫자 : 입력되는 키에 대한 키 코드 입력 값 제한
      • 대표적인 키들은 상수로 등록됨
      • 🗒️ 예시 : enter, tab, delete, esc, space, up, down, left, right, ctrl, altm shift
      • 조합되는 키의 경우 수식어 연결 사용 (@keyup.ctrl.67="event_name")
  • 마우스 이벤트 수식어

    • left, right, middle : 각각 마우스의 어떤 버튼이 클릭 됐는지로 제한

    • 📋 코드 📋

      <!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>Vuejs 기본 이벤트 처리 방지_이벤트 수식어 사용 전</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <h2>preventDefault</h2>
            <form action="https://www.google.com/" @submit="login">
                ID:<input type="text" placeholder="ID는 4글자 이상입니다." v-model="id" ref="myId">
                <input type="submit">
            </form>
            <h2>stopPropagation</h2>
            <div style="background-color: yellow;" @click="parent">
                parent
                <div style="background-color: green;" @click="child">
                    child
                </div>
            </div>
            <h2>keyup.enter</h2>
            num1:<input type="text" @keyup="knum"><br>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    id: ""
                },
                methods: {
                    login(e) {
                        if (this.id.length >= 4) {
                            e.target.submit();
                        } else {
                            e.preventDefault();
                            alert("ID를 4글자 이상으로 넣어주세요");
                            this.$refs.myId.focus();
      
                        }
                    },
                    parent(e) {
                        console.log("parent");
                    },
                    child(e) {
                        console.log("child");
                        e.stopPropagation();
                    },
                    knum(e) {
                        // console.log(e.keyCode); //enter는 13
                        if (e.keyCode == 13) {
                            console.log("knum");
                        }
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs 기본 이벤트 처리 방지_이벤트 수식어 사용 후</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <h2>preventDefault</h2>
            <form action="https://www.google.com/" @submit.prevent="login">
                ID:<input type="text" placeholder="ID는 4글자 이상입니다." v-model="id" ref="myId">
                <input type="submit">
            </form>
            <h2>stopPropagation</h2>
            <div style="background-color: yellow;" @click="parent">
                parent
                <div style="background-color: green;" @click.stop="child">
                    child
                </div>
            </div>
            <h2>keyup.enter</h2>
            num1:<input type="text" @keyup="knum"><br>
            num2:<input type="text" @keyup.enter="knum"><br>
            <button @click.once="one">한번만트리거됨</button>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    id: ""
                },
                methods: {
                    login(e) {
                        if (this.id.length >= 4) {
                            e.target.submit();
                        } else {
                            e.preventDefault();
                            alert("ID를 4글자 이상으로 넣어주세요");
                            this.$refs.myId.focus();
                        }
                    },
                    parent(e) {
                        console.log("parent");
                    },
                    child(e) {
                        console.log("child");
                    },
                    knum() {
                        console.log("knum");
                    },
                    one() {
                        console.log("one");
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

4. 화면에서 다른 요소 참조

  • DOM 이벤트 처리시 화면의 다른 DOM 요소를 참조하는 경우
    • 자바스크립트에서 document.querySelector("#target")와 같이 DOM 요소를 지정함
  • Vue에서는 DOM에 직접 접근하는 일이 없음
    • 필요시 ref 속성으로 DOM 요소에 표시하고, Vue 객체 내부에서는 $refs 속성으로 접근 가능
<div id="app">
    <form @submit.prevent="login">
      <label for="id">아이디</label>
      <input type="text" name="id" id="id" @keyup.prevent.enter="next" v-model.lazy="id"/>
      <!-- ref 속성으로 DOM에 표시 -->
      <input type="password" ref="pass" @keyup.enter="search"/> 
      <input type="button" value="제출"/>
    </form>
</div>
<script>
    let vi = new Vue({
        el: "#app",
        data: {
            id: "",
        },
        methods: {
            next() {
                // ref 속성으로 접근 가능
                let pass = this.$refs.pass;
                console.log(pass);
                pass.focus();
            },
            login() {
                console.log("로그인 처리");
            },
            search() {
                console.log("id: " + this.id);
            }
        }
    });
</script>
  • 📋 코드 📋
    <!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>Vuejs ref 참조</title>
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    </head>
    <body>
      <div id="app">
          num:<input type="text" ref="xyz"><br>
          <button @click="ok">OK</button>
      </div>
      <script>
          var app = new Vue({
              el: '#app',
              methods: {
                  ok() {
                      console.log(this.$refs.xyz.value);
                  }
              }
          });
      </script>
    </body>
    </html>
  • 📋 실행 📋

📕 컴포넌트

1. component

  • component 개념

    • 재사용 가능한 블록 형태의 요소를 의미
    • Vue에서의 컴포넌트도 조합해서 화면을 구성할 수 있는 블록
    • 재사용성 강화 목적
    • SPA(Single Page Application) 적용시 컴포넌트 사용 필수
  • 등록 방식에 따른 component 종류

    • 지역 컴포넌트 : 특정 Vue 객체에서만 유효한 범위를 가짐
    • 전역 컴포넌트 : 여러 Vue 객체에서 공통으로 사용 가능

2. 전역 컴포넌트

  • Vue.component(tagName, options)

    • 전역 컴포넌트는 Vue 객체의 component 속성 이용해서 등록
  • tagName

    • 컴포넌트의 이름
    • 사용자 정의 HTML 태그으이 이름
    • 모두 소문자 사용, 케밥 표현식 사용 (단어의 연결은 -(하이픈) 사용)
    • HTML태그와 다르게 빈 태그라도 <My-component> 식으로 사용X
  • options

    • 컴포넌트의 속성을 설정하는 옵션 객체
    • template, data 등 선언됨
      • template : 화면에 보유줄 모습인 html 태그 자성
      • data : Vue 객체에서 사용될 data 선언
  • 컴포넌트 사용시 주의할 점

    • template : 반드시 root element가 존재하고, 그 안에 다른 element가 나와야 함

      <!-- root 존재하는 경우는 가능 -->
      <template id="body-template">
      <div>
        <div></div>
      </div>
      <template>
      <!-- root 없는 경우는 불가능-->
      <template id="body-template">
      <div></div>
      <div></div>
      </template>
    • data : 컴포넌트의 options에 정의하는 data는 반드시 함수로 작성하고, 함수 내부에서 리턴되는 객체**를 사용

      /* data: {
      	cuttent: 0,
      } */
      // return 되는 함수로 data 정의 
      data: function() {
      	return {
      		current: 0,
      	};
      }
    • 📋 코드 📋

      <!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="app">
            <div>
                <h1>검색기능</h1>
                검색어:<input />
                <hr>
                <ul>
                    <li>야구</li>
                    <li>농구</li>
                    <li>축구</li>
                </ul>
            </div>
        </div>
        <script>
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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="app">
            <div>
                <search-component></search-component>
                <hr>
                <list-component></list-component>
            </div>
        </div>
        <template id="list-template">
            <ul>
                <li>야구</li>
                <li>농구</li>
                <li>축구</li>
            </ul>
        </template>
        <script>
      
            // 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
            var search = Vue.component("search-component", {
                //template은 반드시 root태그 필수
                template: `   
                   <div>
                      <h1>검색기능</h1>
                       검색어:<input />
                   </div> 
                `
            });
      
            var list = Vue.component("list-component", {
                template: "#list-template"
            });
      
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>전역 컴포넌트 사용 후 Data 사용</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div>
                <search-component></search-component>
                <hr>
                <list-component></list-component>
            </div>
        </div>
        <template id="list-template">
            <ul>
                <li v-for="value in hobby">{{value}}</li>
            </ul>
        </template>
        <script>
            // 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
            var search = Vue.component("search-component", {
                //template은 반드시 root태그 필수
                template: `   
                   <div>
                      <h1>검색기능</h1>
                       검색어:<input />
                   </div> 
                `
            });
            var list = Vue.component("list-component", {
                template: "#list-template",
                //data 사용 ==> 반드시 함수로 작성하고 리턴되는객체 사용
                data: function () {
                    return {
                        hobby: ["야구", "농구", "축구","수영"]
                    }
                }
            });
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>전역 컴포넌트 Data 공유문제</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div>
                <date1-component></date1-component>
                <hr>
                <date2-component></date2-component>
            </div>
        </div>
        <template id="date-template">
            <div>
                <button @click="increment">+</button>
                {{num}}
            </div>
        </template>
        <script>
            // 공유 데이터
            var current = { num: 0 };
      
            // 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
            var date1 = Vue.component("date1-component", {
                //template은 반드시 root태그 필수
                template: "#date-template",
                data: function () {
                    return current;
                },
                methods: {
                    increment() {
                        this.num = this.num + 1;
                    }
                }
            });
            var date2 = Vue.component("date2-component", {
                //template은 반드시 root태그 필수
                template: "#date-template",
                data: function () {
                    return current;
                },
                methods: {
                    increment() {
                        this.num = this.num + 1;
                    }
                }
            });
      
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>전역 컴포넌트 Data 공유 문제 해결</title>
        <!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <div>
                <date1-component></date1-component>
                <hr>
                <date2-component></date2-component>
            </div>
        </div>
        <template id="date-template">
            <div>
                <button @click="increment">+</button>
                {{num}}
            </div>
        </template>
        <script>
            // var current = { num: 0 };
      
            // 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
            var date1 = Vue.component("date1-component", {
                //template은 반드시 root태그 필수
                template: "#date-template",
                data: function () {
                    return { num: 0 };
                },
                methods: {
                    increment() {
                        this.num = this.num + 1;
                    }
                }
            });
            var date2 = Vue.component("date2-component", {
                //template은 반드시 root태그 필수
                template: "#date-template",
                data: function () {
                    return { num: 0 };
                },
                methods: {
                    increment() {
                        this.num = this.num + 1;
                    }
                }
            });
      
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3. 지역 컴포넌트

  • 지역 컴포넌트는 Vue 객체를 구성하면서 components 속성을 추가해서 등록함
new Vue(
	components: {
		'component-name':'component 내용'
	}
};
  • 나머지 작성 방법은 전역 컴포넌트와 동일

    • 📋 코드 📋

      <!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="app">
            {{message}}
            <local-component></local-component>
        </div>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!'
                },
                components: {
                    'local-component': {
                        template: `<h1>지역컴포넌트{{num}}</h1>`,
                        data: function () {
                            return {
                                num: 200
                            }
                        }
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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="app">
            {{message}}
            <global-component></global-component>
            <local-component></local-component>
        </div>
        <hr>
        <div id="app2">
            <global-component></global-component>
            <!-- <local-component></local-component> -->
        </div>
      
        <script>
            var global = Vue.component("global-component", {
                template: `<h3>global component</h3>`
            });
      
            var app2 = new Vue({
                el: '#app2'
            });
      
            var app = new Vue({
                el: '#app',
                data: {
                    message: '안녕하세요 Vue!'
                },
                components: {
                    'local-component': {
                        template: `<h3>지역컴포넌트{{num}}</h3>`,
                        data: function () {
                            return {
                                num: 200
                            }
                        }
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

📕 컴포넌트 통신

1. 컴포넌트 통신

  • 각각의 컴포넌트는 개별적으로 고유한 유효 범위를 가지기 때문에 다른 컴포넌트의 데이터를 직접 참조X

  • 컴포넌트간의 자료 전달 방식은 관계에 따라 다른 방식 사용

    • 부모/자식 (상하위) 컴포넌트의 관계

      • 상위 ➡️ 하위로의 전달은 props 속성 이용
      • 하위 ➡️ 상위로의 전달은 이벤트 통해서 데이터 전달
    • 상하위 관계가 아닌 경우

      • 이벤트 버스 이용
    • 📋 코드 📋

      <!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>Vuejs 기본 구조</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            #t1 {
                background-color: yellow;
            }
      
            #t2 {
                background-color: blue;
            }
      
            #t3 {
                background-color: green;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <top1-component></top1-component>
        </div>
        <template id="top1">
            <div id="t1">
                <h1>top1</h1>
                <top2-component></top2-component>
            </div>
        </template>
        <template id="top2">
            <div id="t2">
                <h2>top2</h2>
                <top3-component></top3-component>
            </div>
        </template>
        <template id="top3">
            <div id="t3">
                <h3>top3</h3>
            </div>
        </template>
        <script>
            const t1 = Vue.component('top1-component', {
                template: "#top1"
            });
            const t2 = Vue.component('top2-component', {
                template: "#top2"
            });
            const t3 = Vue.component('top3-component', {
                template: "#top3"
            });
            var app = new Vue({
                el: '#app',
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

2. props 속성 (상위➡️하위 데이터 전달)

  • 상위 컴포넌트의 데이터를 하위 컴포넌트에서 사용할 때 - 하위 컴포넌트의 props 속성에 선언한 변수(속성명)에 상위 컴포넌트가 태그의 '속성명=값' 형태로 전달

    • 📋 코드 📋

      <!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>Vuejs props</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <child-component xyz="hello" xyz2="hi"></child-component>
            <child-component :xyz="message" xyz2="hi"></child-component>
        </div>
        <template id="child">
            <div>
                <h1>child</h1>
                {{xyz}}<br>
                {{xyz2}}<br>
            </div>
        </template>
        <script>
            //자식
            const t1 = Vue.component('child-component', {
                template: "#child",
                props: ['xyz', 'xyz2']
            });
      
            //부모
            var app = new Vue({
                el: '#app',
                data: {
                    message: "안녕하세요"
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs props 속성명</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <!-- 전달할 데이터 키는 캐밥 표기법으로 지정-->
            <child-component xyz="hello" user-name="hi" user-age="20"></child-component>
            <child-component :xyz="message" user-name="hi"></child-component>
        </div>
        <template id="child">
            <div>
                <h1>child</h1>
                {{xyz}}<br>
                {{userName}}<br>
                {{userAge}}<br>
                {{xxx()}}
            </div>
        </template>
        <script>
            //자식
            const t1 = Vue.component('child-component', {
                template: "#child",
                props: ['xyz', 'user-name', 'userAge'] //받는 쪽에서는 카멜표기법 가능
                ,
                methods: {
                    xxx() {
                        console.log(this.userAge, this.xyz, this.userName); // this.user-name은 안됨
                    }
                }
            });
      
            //부모
            var app = new Vue({
                el: '#app',
                data: {
                    message: "안녕하세요"
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs props 배열</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <top1-component :lang-data="language"></top1-component>
        </div>
        <template id="progrmming">
            <div>
                <h1>프로그램 언어</h1>
                <ul v-for="(lang,index) in langData">
                    <li>{{lang}}</li>
                </ul>
            </div>
        </template>
        <script>
            //자식
            const t1 = Vue.component('top1-component', {
                template: "#progrmming",
                props: ['langData']
            });
      
            //부모
            var app = new Vue({
                el: '#app',
                data: function () {
                    return {
                        language: ['자바', 'SQL', 'Vue.js']
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!DOCTYPE html>
      <html>
      <head>
        <title>Vuejs 배열 활용_예방접종 샘플</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
          <h1>예방 접종 대상자</h1>
          <h3>1차 대상자</h3>
          <contact-component :contacts="list1"></contact-component>
          <h3>2차 대상자</h3>
          <contact-component :contacts="list2"></contact-component>
        </div>
        <template id="contactTemplate">
          <table border="1">
            <tr>
              <th>번호</th>
              <th>이름</th>
              <th>전화번호</th>
              <th>주소</th>
            </tr>
            <tr v-for="contact in contacts">
              <td>{{contact.no}}</td>
              <td>{{contact.name}}</td>
              <td>{{contact.phone}}</td>
              <td>{{contact.address}}</td>
            </tr>
          </table>
        </template>
        <script>
          const t1 = Vue.component("contact-component", {
            template: `#contactTemplate`,
            props: ["contacts"],
          });
      
          var app = new Vue({
            el: "#app",
            data: {
              list1: [
                { no: 10, name: "홍길동", phone: "010-1111-1111", address: "서울" },
                { no: 9, name: "이순신", phone: "010-4444-4444", address: "전라" },
                { no: 8, name: "강감찬", phone: "010-3333-3333", address: "경기" },
                { no: 7, name: "임꺽정", phone: "010-9999-9999", address: "전라" },
                { no: 6, name: "윤동주", phone: "010-8888-8888", address: "서울" },
              ],
              list2: [
                { no: 5, name: "윤봉길", phone: "010-7777-7777", address: "제주" },
                { no: 4, name: "한용운", phone: "010-6666-6666", address: "부산" },
                { no: 3, name: "백범", phone: "010-5555-5555", address: "강원" },
                { no: 2, name: "안창호", phone: "010-2222-2222", address: "울산" },
                { no: 1, name: "이육사", phone: "010-0909-0909", address: "서울" },
              ],
            },
          });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs props slot 1</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            p {
                color: red;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <child-component :xyz="message">
                <!-- 자식에게 전달할 html태그는 일반적으로 template 사용함.-->
                <template>
                    <div>
                        <p>자식에게 전달할 html</p>
                    </div>
                </template>
            </child-component>
        </div>
        
        <template id="child">
            <div>
                <h1>child</h1>
                <h2>부모에서 자식에게 문자열 전달: props</h2>
                {{xyz}}
                <h2>부모에서 자식에게 html 전달: slot</h2>
                <slot></slot>
                <slot></slot>
            </div>
        </template>
        <script>
            //자식
            const t1 = Vue.component('child-component', {
                template: "#child",
                props: ['xyz']
            });
      
            //부모
            var app = new Vue({
                el: '#app',
                data: function () {
                    return {
                        message: "안녕하세요"
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!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>Vuejs props slot2</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <style>
            p {
                color: red;
            }
        </style>
      </head>
      <body>
        <div id="app">
            <child-component :xyz="message">
                <template v-slot:header>
                    <div>
                        <p>자식에게 전달할 html,header</p>
                    </div>
                </template>
                <template v-slot:body>
                    <div>
                        <p>자식에게 전달할 html,body</p>
                    </div>
                </template>
                <template v-slot:footer>
                    <div>
                        <p>자식에게 전달할 html,footer</p>
                    </div>
                </template>
            </child-component>
        </div>
        <template id="child">
            <div>
                <h1>child</h1>
                <h2>부모에서 자식에게 문자열 전달: props</h2>
                {{xyz}}
                <h2>부모에서 자식에게 html 전달: slot</h2>
                <slot name="body"></slot>
                <slot name="header"></slot>
                <slot name="footer"></slot>
            </div>
      </template>
        <script>
            //자식
            const t1 = Vue.component('child-component', {
                template: "#child",
                props: ['xyz']
            });
      
            //부모
            var app = new Vue({
                el: '#app',
                data: function () {
                    return {
                        message: "안녕하세요"
                    }
                }
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

3. $emit 사용자정의 이벤트 (하위➡️ 상위 데이터 전달)

  • 하위 컴포넌트의 데이터를 상위 컴포넌트로 전달하기 위해서 사용자 정의 이벤트를 발생시켜서 데이터 전달

  • 하위 컴포넌트가 이벤트 발생시키면 이벤트를 통해서 사위 컴포넌트의 함수를 동작시키는 형태

  • 이벤트를 발생시킬 때에는 Vue 객체의 $emit 함수 사용

    • 📋 코드 📋

      <!DOCTYPE html>
      <html>
      <head>
        <title>Vuejs emit 1</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <!-- <button @click="receive">parent</button>  -->
            <hello-component v-on:xyz="receive"></hello-component>
        </div>
        <template id="helloTemplate">
            <div>
                <button @click="send">child</button>
            </div>
        </template>
        <script>
            Vue.component('hello-component', {
                template: `#helloTemplate`,
                methods: {
                    send: function (e) {
                        //부모에게 xyz 이벤트 발신
                        this.$emit('xyz');
                    }
                }
            });
      
            var app = new Vue({
                el: '#app',
                methods: {
                    receive: function () {
                        console.log("parent.receive");
                    }
                }
            })
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!DOCTYPE html>
      <html>
      <head>
        <title>Vuejs emit 2</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <!-- <button @click="receive">parent</button>  -->
            <hello-component v-on:xyz="receive"></hello-component>
        </div>
        <template id="helloTemplate">
            <div>
                <button @click="send">child</button>
            </div>
        </template>
        <script>
            Vue.component('hello-component', {
                template: `#helloTemplate`,
                methods: {
                    send: function (e) {
                        //부모에게 xyz 이벤트 발신
                        this.$emit('xyz', '홍길동', 20);
                    }
                }
            });
      
            var app = new Vue({
                el: '#app',
                methods: {
                    receive: function (name, age) {
                        console.log("parent.receive", name, age);
                    }
                }
            })
        </script>
      </body>
      </html>
    • 📋 실행 📋

4. 이벤트 버스 (상/하위 레벨 아닌 데이터 전달)

  • 상/하위 레벨이 아닌 컴포넌트 간은 직접적인 정보 전달이 불가능

    • 두 컴포넌트 간 직접적으로 이벤트를 연결하기 위해서 이벤트 버스 이용
  • let eventBus = new Vue();

    • 이벤트 버스는 단순한 Vue 객체

    • 이벤트 버스는 데이터를 보내려는 쪽과 데이터를 받는 쪽 모두에서 사용

    • 보내는 쪽에서 이벤트를 발신(emit)하고, 받는 쪽에서는 v-on 이용하여 이벤트 수신

    • 📋 코드 📋

      <!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>Vuejs event bus</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
      </head>
      <body>
        <div id="app">
            <comp-1></comp-1>
            <comp-2></comp-2>
        </div>
        <script>
            //이벤트 버스 생성
            let eventBus = new Vue();
            // < !--입력 컴포넌트-- >
            Vue.component('comp-1', {
                template: `<input type="text" @change="trans">`,
                methods: {
                    trans(e) {
                        eventBus.$emit("gogo", e.target.value);
                    }
                }
            });
            // < !--출력 컴포넌트-- >
            Vue.component('comp-2', {
                template: `<span>{{msg}}</span>`,
                data: function () {
                    return {
                        msg: ""
                    }
                },
                created() {
                    eventBus.$on("gogo", this.update);
                },
                methods: {
                    update(data) {
                        this.msg = data;
                    }
                }
            });
      
            var app = new Vue({
                el: '#app'
            });
        </script>
      </body>
      </html>
    • 📋 실행 📋

    • 📋 코드 📋

      <!DOCTYPE html>
      <html>
      <head>
        <title>Vuejs event bus_Todo 샘플</title>
        <script src="https://unpkg.com/vue"></script>
        <!-- 이벤트 버스 객체 생성-->
        <script>
            var eventBus = new Vue();
        </script>
        <!-- input 컴포넌트 생성-->
        <template id="inputTemplate">
            <div>
                <input type="text" @keyup.enter="add" v-model="mesg">
            </div>
        </template>
        <script>
            Vue.component('input-component', {
                template: `#inputTemplate`,
                data: function () {
                    return { mesg: '' }
                },
                methods: {
                    add: function () {
                        eventBus.$emit('xyz', this.mesg);
                    }
                }
            });
        </script>
        <!-- child2 컴포넌트 생성-->
        <template id="listTemplate">
            <div>
                <ul v-for="(a,idx) in toDoList">
                    <li>{{a}}<button @click="del(idx)">삭제</button> </li>
                </ul>
            </div>
        </template>
        <script>
            Vue.component('list-component', {
                template: `#listTemplate`,
                data: function () {
                    return { toDoList: [] }
                },
                created: function () {
                    eventBus.$on('xyz', this.add)
                },
                methods: {
                    add: function (m) {
                        this.toDoList.push(m);
                    },
                    del: function (idx) {
                        console.log(idx);
                        this.toDoList.splice(idx, 1);
                    }
                }
            });
        </script>
      </head>
      <body>
        <div id="app">
            <input-component></input-component>
            <list-component></list-component>
        </div>
        <script>
            var app = new Vue({
                el: '#app'
            })
        </script>
      </body>
      </html>

📕 Vue Router

1. Vue Router

1) Vue Router 개념

  • SPA는 서버에 웹 페이지를 요청하여 새로 갱신하지 않고, 처음의 한 페이지를 가지고 있다가 내용만 교체하는 형태로 동작
  • SPA 방식에서 router 이용하여 웹 페이지간(사식은 컴포넌트) 이동
  • Vue Router는 뷰에서 라우팅 기능을 지원하는 공식 라이브러리
  • 기본 동작은 hash(#)가 path에 연결되는 HASH 기반 동작
  • html 영역
    • <router-link to="target_URL"> : 페이지 이동 태그로 화면에서 <a> 클릭시 target_URL로 이동
    • <router-view> : 페이지 표시 태그로 변경되는 URL에 따라 해당 컴포넌트를 뿌려주는 영역
  • javascript 영역
    // Vue Router 생성
    const router = new VueRouter({
    	// 라우팅 경로 정의 : {name: "path_alias", path: "요청 URL", component: "표시할 컴포넌트"}
    	routes: [{ path: "/", component: null},
    			{path: "/sub1", component: sub1},
    			{path: "/sub2", component: sub2}]
    });
    // Vue 객체에 Router 설정
    new Vue({
    	el: "#app",
    	router: router
    })

2) Vue Router 주요 기능

  • 중첩된 경로, 뷰를 매핑 처리
  • 컴포넌트 기반의 라우팅 구현 가능
  • Vue.js의 화면 전환 효과(transition) 적용 가능
  • 히스토리 모드와 해시 모드 사용
  • 쿼리스트링, 파라미터, 와일드카드를 이용한 라우팅

3) Vue Router 구성 파악

  • 개발자 도구 사용

2. 동적 및 객체 바운딩 라우팅

1) 동적 라우팅

  • 라우터를 이용해서 컴포넌트를 연결할 때, 해당 컴포넌트에 동적으로 필요한 파라미터 전달할 경우
    • URL을 path variable 형태로 작성해서 컴포넌트에 전달
    • '경로/:변수' 형태로 사용
  • html 영역
    <router-link to="/user/hong">hong</router-link>
    <router-link to="/user/jang">jang</router-link>
  • VueRouter 영역
    const vr = new VueRouter({
    	routes: [{
    		path: "user/:id",
    		component: user
    	}]
    })
  • Vue.component 영역
    const user = Vue.component("comp-user", {
    template: "<div>여기는 서브user: {{$route.params.id}}</span></div>"
    })

2) 객체 바인딩 이용한 라우팅

  • 라우팅 구현시 경로를 지정할 때는 문자열 형태 뿐만 아니라 v-bind를 이용핸 객체 바인딩 및 프로그래밍 처리 가능
  • v-bind를 이용한 객체 바인딩
    • <router-link>의 to에 v-bind:to(축약 형식은 :to) 구문을 이용해서 객체 형태로 바인딩 시킬 수 있음
    • 세밀한 링크 설정 가능
  • 객체 바인딩 구성
    • path 속성 : 전달하려는 경로
    • query 속성 : JSON 형식, query string 형태로 전달되는 파라미터 ($route.query로 접근 가능)
    • name 속성 : path 기반이 아닌 routes 요소의 이름 기반으로 이동 가능
    • params 속성 : name 자체에는 path variable을 설정 할 수 없으므로 name 형태에서 파라미터를 전달할 때 사용, JSON 형식이며 내부적으로 전달되는 파라미터 ($route.params로 접근 가능)
  • 프로그래밍 방식 라우팅
    • 직접 link 클릭해서 이동할 수 있지만 프로그래밍적으로 특정 component로 이동해야 하는 경우 Router에게 이동에 필요한 정보를 전달해야함
    • VueRouter는 push() 함수 제공
      • query 전달 : path 및 name 속성 모두 가능
      • params 전달 : name 속성만 가능

3. 중첩 라우팅, named view

1) nested router

  • 페이지를 구성하다 보면 상위 요소가 선택되어야 의미있는 하위 요소들이 존재
    • 🗒️ 예시 : 특정 사용자의 프로필을 보거나, 그 사람이 작성한 글ㅇ르 보는 상황
  • VueRouter 구성
    • route 정보에 path, component와 함께 추가로 chidren 속성을 이용해서 하위 route 작성
  • VueRouter 영역
    • 직접 profile 호출하더라도 상위 컴포넌트인 user를 만들고 profile rntjdgkrp ehla
    const router = new VueRouter({
    	routes: [{
    		// 상위 컴포넌트에 대한 route 정보 포함
    		path: "/user/:id",
    		component: userComp,
    		// 자식 컴포넌트에 대한 route 정보 포함
    		children: [
    			{path: "profile", component: profileComp}, // 자식의 Path에는 '/' 사용X
    			{path: "posts", component: postComp}]
    		}]
    });
  • html 영역
    • 각각의 링크에 대한 <route-link>를 작성하면 되는데, 하위 컴포넌트의 경로는 상위 컴포넌트의 경로를 포함해서 작성
    <div id="app">
      <p>
        <router-link to="/user/hong">사용자 홈<router-link/>
        <!-- 상위 컴포넌트의 경로를 포함함 -->
        <router-link to="/user/hong/prifile">사용자 프로필</router-link>
        <router-link to="/user/hong/posts">사용자 포스트</router-link>
      </p>
      <!-- component들이 보일 자리 -->
      <router-view></router-view>
    </div>
  • component 영역
    // 하위 component 정의
    let profileComp = Vue.component('profile-comp', {
    	template: `<div>사용자의 프로필입니다.<\div>`
    });
    let postComp = Vue.component('post-comp', {
    	template: `<div>사용자의 작성글입니다.<\div>`
    });
    let userComp = = Vue.component('user-comp', {
    	template: `<div>사용자의{{$route.params.id}} <router-view></router-view><\div>`
    });

2) named view

  • 이름이 붙여진 <router-view>
  • 동시에 여러 개의 컴포넌트가 화면에 표시되어야 하는 경우 컴포넌트들을 특정 <router-view>에 배치되도록 <router-view name="이름">형식으로 지정
  • html 영역
    <div id="app">
      <router-view name="header"></router-view>
      <!-- 이름이 없는 router-view: default -->
      <router-view></router-view>
      <router-view name="footer"></router-view>
    </div>
  • VueRouter 영역
    • 기존의 route 정보를 구성할 때는 요소와 path가 component였다면, named view가 사용되는 경우 path 하나에 여러 개의 components 사용
      const vr = new VueRouter({
        routes: [{
            // 경로 하나에 여러 개의 컴포넌트
            path: "/",
            components: {
                header: headerComp,
                default: bodyComp,
                footer: footerComp,
            }
        }]
      });
  • Vue.component 영역
    const headerComp = {
      template: "<p>이것은 header</p>"
    };
    const bodyComp = {
      template: "<p>이것은 body</p>"
    };
    const footerComp = {
      template: "<p>이것은 footer</p>"
    };
  • 실행 결과

4. navigation guard

1) navigation guard 개념

  • router를 이용한 navigation 과정에서 라우터가 동작하기 전/후에 전처리 및 후처리를 가능하게 해주는 방법
  • 전역적으로 지정하거나 route별 지정 가능
  • 🗒️ 예시
    • 로그인하지 않은 사용자에게 로그인하도록 유도
    • 권한이 없는 사용자의 접근을 차단
    • navigation이 발생하는 로그를 작성
  • html 영역
    <div id="app">
      <h1>navigation guard test</h1>
      <p>
          <router-link to="/login">login</router-link>|
          <router-link to="/important">중요한 페이지 보러 가기</router-link>|
          <router-link to="/important?id=hong">중요한 홍 페이지 보러가기</router-link>|
          <router-link to="/normal">그냥 일반</router-link>|
      </p>
      <hr>
      <router-view></router-view>
    </div>
  • VueRouter 영역
    const router = new VueRouter({
      routes: [
      {path: "/login", component: LoginComp},
      {path: "/important", component: ImportantComp},
      {path: "/normal", component: NormalComp}
      ]
    });
  • 전처리 guard 영역
    const needLogin = ["/important"];
    router.beforeEach((to, from, next) => {
      console.log(`경로 로깅: from : ${from.path} ==> to: ${to.path}`)
      if (needLogin.includes(to.path) && to.query.id !== "hong") {
          next("/login"); // 현재의 이동이 중단되고 지정된 페이지로 리다이렉션
      } else {
          next(); // 그냥 다음 route 호출
      }
    });
  • 후처리 guard 영역
    router.afterEach((to, from) => {
      console.log(`router 작업 완료 : from : ${from.path} ==> to: ${to.path}`)
    });
  • route별 guard 영역
    const router = new VueRouter({
      routes: [
          {path: "/login", component: LoginComp},
          {path: "/important", component: ImportantComp},
          {path: "/normal", component: NormalComp,
              beforeEnter(to, from, next) {
                  console.log(`route별 guard: from : ${from.path} ==> to: ${to.path}`)
                  next();
              }
          }
      ]
    });

2) 전역 가드 작성 (전처리)

  • router.beforeEach 함수 이용하면 모든 라우터 요청이 처리되기 전에 동작하는 가드 설정 가능
  • beforeEach함수는 to, from, next를 파라미터로 갖는 callback을 받음
    • to : 호출 대상 route
    • from : 현재 route
    • next : next() 함수로서 파라미터에 따라 동작이 달라짐

3) next() 함수

  • next() 함수가 호출되지 않으면 어떠한 component 교체도 발생되지 않음
  • 종류
    • next() : 그냥 다음 route인 to를 연결
    • next("/redirect_path") : to에 대한 연결을 중지하고 지정한 path로 리다이렉션함 ({path: ""} 형식도 가능함)
    • next(false) : to로의 이동을 중지하고 다시 from으로 이동
    • next(Error) : Error 객체를 전달받으면 to로의 이동을 중지하고 route.onError()에 등록된 콜백을 수행함

📒 Vue-CLI

📕 Vue-CLI

1. SPA vs MPA

  • 웹 어플리케이션의 UI 화면을 구현할 때 사용 가능한 형태
  • SPA와 MPA 동작 방식의 차이점은 Ajax 동작으/Form 전송으로 구분

1) SPA (Single Page Application)

  • Ajax 이용해 데이터만 전달 (Client Side Rendering)
  • UI화면과 관련된 리소스를 처음 요청시 서버로부터 몽땅 받아낸 후 클라이언트에서 모든 HTML/CSS/JS 가지고 있음
    • 이후 Ajax 통신을 통해 변경하고자 하는 데이터만 받아옴
  • 장점
    • SPA는 사용 중 리소스 로딩이 없기 때문에 부드럽게 화면 전환이 이루어짐
    • 서버 입장에서 템플릿(화면)을 만드는 연산이 클라이언트로 분산되기 때문에 부담이 줄어듦
    • 컴포넌트별로 개발하기 때문에 생산성 향상
    • 모바일 앱에서도 동일한 패턴의 Rest API 사용 가능
  • 단점
    • URL이 변경되지 않기 때문에 검색엔진의 색인화가 어려움
    • 초기 구동 비용이 MPA 대비 상대적으로 비쌈

2) MPA (Multi Page Application)

  • 요청 시마다 전체 HTML 로딩 (Server Side Rendering)

3) SFC (Single File Component)

  • 파일 하나가 하나의 컴포넌트가 됨
    • 하나의 컴포넌트를 만들 때 필요한 요소들이 하나의 파일에 모이는 것
    • 화면을 구성하는 3가지 요소들을 하나로 묶어 주는 것
  • 만들어진 모듈은 import와 export를 이용해서 서로 간에 참조가 가능함
  • Vue는 .vue 확장자 파일을 이용
  • SFC 파일 구조
    • <template> : HTML 작성
      • 화면을 구성하는 html 부분
      • 반드시 하나의 root 태그 가져야함
      • 기존 작성과 차이점은 하나의 template만 존재하기 때문에 별도의 id값 지정X
    • <style> : CSS
      • 스타일을 담당하는 css 코드
      • 기본적으로 전역 레벨이 되어서 다른 컴포넌트에 영향을 줄 수 있기 때문에 현재 컴포넌트에만 국한시킬 경우 scoped 속성 지정
    • <script> : JavaScript 영역
      • 컴포넌트를 만들어서 export 해주는 역할
      • 객체는 하나만 만들고 default로 export함

4) Vue를 위한 전처리 작업

  • .vue로 개발된 파일들은 WebPack과 같은 모듈 빌더 툴을 이용해서 html 파일로 변환
    • 단순히 파일이 변환되는 것이 아니라 Babel 같은 시스템을 이용
    • ECMA6 등 높은 버전의 스크립트를 ECMA5로 다운 그레이드 시켜주기 때문에 하위 브라우저 호환성 해결
  • Vue-CLI는 복잡한 WebPack을 보다 편리하게 사용할 수 있도록 도와주는 도구

2. Vue-CLI 개발

1) Vue-CLI 설치

npm install -g @vue/cli

2) Project 생성

vue create 프로젝트명

3) Project 실행

npm run serve
// http://localhost:8080/ 요청

3. 생성된 프로젝트 구조

1) node_modules

  • 앱 개발과 배포에 필요한 npm 패키지들이 저장됨

2) public

  • 배포 버전을 빌드할 때 필요한 파일
  • 웹팩을 이용해서 이 파일을 로드한 뒤 설정을 추가해서 빌드 버전이 완성됨
  • public/index.html
    • 최종 화면에 보여줄 index.html파일의 template
    • 영역에 컴파일된 Vue 컴포넌트가 삽입됨
    • <%=BASE_URL%>
      • 웹팩의 내용을 참조하는 것
      • 변경이 필요하면 프로젝트 root 경로에 vue.config.js 파일을 만들고 내용 수정 가능

3) src

  • 컴포넌트들을 구성하는 영역으로 Vue가 컴파일하는 대상
  • assests는 image와 같은 자원들이 저장되는 곳으로 component에서 이곳의 파일들을 사용하는 경우 자동으로 배포됨
  • src/main.js
    • 최종적으로 Vue 컴포넌트들을 조합해서 배포시 index.html에 표시됨
    import Vue from "Vue"; 		// 핵심 객체 Vue import
    import App from "./App.vue";  // 개발하려는 SFC 첫 화면인 App.vue를 import
    Vue.config.productionTip = true; // Vue 앱이 처음 실행될 때 나오는 경고문을 출력한 것인지 물어봄 (상용인 경우 false로 지정)
    new Vue({ // id가 app인 html 태그에 App.vue 내용을 표시하는 문장
    	render: (h) => h(App),
    }).$mount("#app");

4) package.json

  • 프로젝트에 대한 전반적인 설정 저장
  • node.js를 이용해서 개발을 하다 보면 node_modules 경로에 다운로드 받은 많은 라이브러리들이 저장됨
    • 개발 배포시 많은 용량이라 실제 배포할 때는 node_moduls의 내용을 번들링(묶어서) 배포함
    • 배포 후 그것을 사용하려면 package.json이 있는 폴터에서 npm install 명령을 이용하면 관련 dependency가 한꺼번에 다운로드됨

📕 axios 라이브러리

1. axios

1) axios 개념

  • Ajax 처리를 위한 비동기 처리 라이브러리

2. 기본 API

  • ajax를 편리하게 처리할 수 있도록 다양한 API 제공
  • 종류
    • axios.request(config)
    • axios.get(url [,config])
    • axios.delete(url [,config])
    • axios.head(url [,config])
    • axios.options(url [,config])
    • axios.post(url, data [,config])
    • axios.put(url, [,data ,config])
    • axios.patch(url, [,data ,config])

3. Config 구성요소

  • axios 함수에 전달하는 config 객체 속성
    let axios = axios({
    	url: "./food.json", // 호출할 서버의 경로
    		method: "get", // 사용하는 http method (post/get/put/delete), default는 get
    	params: {
    		name: "hong"
    	}, // url (쿼리스트링을 구성하는 파라미터 요소)
    	data: {
    		age: 10,
    		addr: "seoul"
    	}, // request body를 통해서 서버로 전송되는 값 (post, put, patch에서 사용)
    });
  • 요청에 대한 응답 결과는 then과 catch 콜백함수로 처리
    axios.then(
    	success_callback
    ).catch(
    	error_callback
    ).finally(
    	finally_callback
    );
    {
    	// 서버가 출력한 값은 언제나 data 속성 안에 존재함
    	data: {},
    	// HTTP status code
    	status: 200, 
    	// HTTP status message from the server response
    	statusText: 'OK',
    	// 'headers' the headers that the server responsed with All header names are lower cased 
    	headers: {},
    	// 'config' is the config that was provided to 'axios' for the request
    	config: {}
    }

📕 Vuex

1. Vuex 개념

  • Vue의 상태관리 라이브러리
  • 여러 컴포넌트간 공유 데이터가 있을 때 사용함
    • 그냥 컴포넌트가 자신의 데이터를 가지고 사용할 때는 사용할 필요가 없음
  • 기존 상태 관리의 문제점
    • A 컴포넌트에서 B 컴포넌트로 값을 전달하려면 2번의 이벤트와 1번의 props 사용이 필요함

2. Vuex 라이브러리

  • 어플리케이션마다 하나의 저장소만을 사용
    • 추적 및 디버깅 용이
    • 컴포넌트들에서 상태 정보를 안전하게 접근 가능
  • 컴포넌트가 공유하는 상태 데이터는 전역에서 저장소 객체(store)를 통해서 관리
    • props를 이용한 전달, 이벤트 호출 필요X
    • 저장소는 컴포넌트의 data와 같아서 컴포넌트와 저장소 객체의 데이터 연결하기 위한 작업만 필요
  • 컴포넌트와 Vuex와의 관계
    • 컴포넌트에서 어떤 데이터를 변경하려면 Vuex의 store와 통신함
    • 컴포넌트에서 저장소에 변경을 반영하려면 commit을 호출하면서 mutation을 부름
    • mutation은 state를 변경시킴
    • state 변경은 component에 반영됨
    • 만약 비동기로 처리할 일이 있다면 actions을 통해서 처리함

3. Vuex 사용 방법

1) Vuex 설치

npm install vuex --save

2) Vuex 사용

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

3) 프로젝트 생성

vue create vuex_counter
npm install vuex --save

4. Vuex 활용

1) Vuex store 생성

  • 모듈 시스템에서 Vuex의 store를 만들 때 Vue.use()를 이용해서 Vuex 반드시 추가
  • Vuex.store는 반드시 state와 mutations 속성을 가짐
    • state는 객체 형태로 공유 데이터를 선언
    • mutations에는 state의 데이터를 변경하는 함수를 정의
  • 함수는 컴포넌트들이 $store.commit을 호출하면 실행되는 콜백 함수
    • 함수의 파라미터로는 2개가 전달되는데, 하나는 store 객체이고 다른 하나는 변경할 값
    mutatios: {
    	methods(state, payload) {
    		// payload에 전달된 값을 이용해서 state 수정함
    	}
    }
    • increment나 decrement는 별도의 파라미터를 받지 않지만, set의 경우 payload를 받아서 state의 counter에 할당함

2) Vue 객체에 store 속성 추가

  • Vuex.store를 추가할 때는 store 속성을 이용하여 다른 컴포넌트에 주입함
  • 다른 컴포넌트에서 필요하다면 this.$store로 사용 가능
    import Vue from "vue";
    import App from "./App.vue";
    Vue.config.productionsTip = false;
    import store from "./js/myVueXStore";
    new Vue({
    	// store 속성에 Vuex.store 등록함
    	// Component에서 store가 필요하면 this.$store
    	store, 
    	render: (h) => h(App),
    }).$mount("#App");

3) Counter.vue 생성

  • Vuex.store에 등록된 공유 데이터는 반드시 Vuex 통해서 관리 해야지 직접적으로 값 변경하면 X
    • 공유 데이터를 가져올 때는 computed(읽기 속성)으로 가져오고, 값을 반영해야할 경우 this.$store.commit를 이용
    • 비 공유 데이터인 newValue는 data에서 관리하므로 직접 set/get 가능함

4) helper method 사용

  • 기존의 Counter.vue를 mapState와 mapMutations를 이용하는 helper 버전으로 변경
  • 만약 선언된 mutations 함수 이름과 component에 선언한 함수의 이름이 다른 경우에는 명시적으로 지정할 수 있음
    ...mapMutations({
    	increment: "increment", // 사용할 함수 이름 : mutation 함수 이름
    	decrement: "decrement",
    	setval: "serVal",
    })
  • 이름 재지정은 mapState나 mapActions, mapGetters에도 동일하게 적용됨
    ...mapState({ storecounter: "counter", asyncounter: "asnccounter" ]),

5) 비동기 호출시 공통 데이터 관리

  • actions 함수 작성
    • 첫 번째 파라미터가 state가 아니라 Vuex.store임
    • store 객체를 통해 state와 mutations 등 다른 actions 메서드들도 호출 가능
    const state = new Vuex.Store({
    	state: {. . .},
    	mutations: {
    		mutation_method(state, payload) {
    			//
    		},
    	}, 
    	actions : {
    		action_method(state, payload) {
    			// store를 통해 state mutation은 물론 다른 action 사용 가능
    		}
    	}
    })
  • actions 함수 호출
    • commit 대신 dispatch 메서드 사용
    import {mapState} from "vuex";
    import Constant from "../js/Constant";
    export default {
    	data() {
    		return { date: "" };
    	},
    	computed: {
    		...mapState(["movielist"]) // 저장소의 이름과 동일하게 자동 연결
    	},
    	methods: {
    		[Constant.BoxOFFICE](payload) {
    			this.$store.dispatch(Constant.BOXOFFICE, payload); // 호출
    		}
    	}
    };

6) getters

  • 조회 용도 (일종의 전처리)
    • 특정 조건 조회를 위한 코드가 여러 컴포넌트에서 반복되면 중복 코드로 인해서 유지 보수성이 떨어짐
  • gettets는 store에 존재하며 state의 내용 중 필요한 것만 또는 필요한 형태로 참조할 수 있음
  • 컴포넌트(boxOfficeComponent)에서 호출할 때는 store의 getters를 통해서 호출
    export default {
    	computed: {
    		// ...mapState(["movielist"]) // 저장소의 이름과 동일하게 자동 연결
    		movielist() {
    			return this.$store.getters.under;
    		}
    	}
    }
profile
Notion으로 이동 (https://24tngus.notion.site/3a6883f0f47041fe8045ef330a147da3?v=973a0b5ec78a4462bac8010e3b4cd5c0&pvs=4)

0개의 댓글