본문으로 바로가기

Vue.js 입문

category Frontend/Vue.js 2020. 2. 3. 23:01
    반응형

    Vue.js 소개

    Github

    https://github.com/ssyauu580/Vue.js.git

    SPA(SinglePageApplication) <-> MPA(MultiPageApplication)

    ClientSideRendering <-> ServerSideRendering

    MVVM

    모델(Model) - 뷰(View) - 뷰 모델(View Model)

    • 화면의 요소들을 제어하는 코드와 데이터 제어 로직을 분리하여 코드를 더 직관적으로 이해할 수 있다.
    • 추후 유지보수가 간편해진다.

    Vue 용어

    모델(Model)

    • 데이터를 담는 용기. 서버에서 가져온 데이터를 자바스크립트 객체로 저장

    돔 리스너(DOM Listener)

    • 돔의 변경 내역에 대해 즉각적으로 반응하여 특정 로직 수행

    데이터 바인딩(Data Binding)

    • 뷰(View)에 표시되는 내용과 모델의 데이터를 동기화

    뷰 모델(View Model)

    • 뷰와 모델의 중간 영역. 돔 리스너데이터 바인딩을 제공하는 영역

    그 외

    • 양방향 데이터 바인딩 사용으로 화면의 값과 모델의 값이 동기화 된다.
    • 가상 돔을 활용하여 화면 전체를 다시 그리지 않고 프레임워크에서 정의한 방식에 따라 화면을 갱신한다.

    인스턴스

    뷰 인스턴스는 뷰로 화면을 개발하기 위해 필수적으로 생성해야 하는 기본 단위이다.

    new Vue({
        //뷰 인스턴스 옵션
        el : #app,
        data : {
            message : 'Hello Vue.js'
        }
    });

    인스턴스가 적용되는 과정

    인스턴스가 화면에 적용되는 과정은 다음과 같다.

    뷰 라이브러리 파일 로딩 > 인스턴스 객체 생성 > 특정 화면 요소에 인스턴스를 붙임 > 인스턴스 내용이 화면 요소로 변환 > 변환된 화면 요소를 사용자가 최종 확인

    인스턴스 라이프 사이클

    인스턴스가 생성되었을 때 호출할 동작을 정의하는 속성. 속성에서 실행되는 로직을 라이프 사이클 훅(Hook)이라고 한다.

    <html>
      <head>
        <title>Vue Sample</title>
      </head>
    
      <body>
        <div id="app">
          {{message}}
        </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
        <script type="text/javascript">
          new Vue({
            el : '#app',
            data : {
              message : 'Hello Vue.js!',
            },
            beforeCreate : function () {
                console.log("beforeCreate")
            },
            created : function () {
                console.log("created");
            },
            mounted : function () {
              console.log("mounted");
    
              //Message 값 변경
              this.message = 'Hello Vue!';
            },
            beforeUpdate : function () {
              console.log("");
            },
            updated : function () {
              // 값이 변경되었을 떄 호출
              console.log("updated");
            }
          });
        </script>
      </body>
    </html>

    컴포넌트

    컴포넌트란 마치 레고 블록과 같다. 뷰의 컴퓨넌트를 조합하여 화면을 구성할 수 있다. 컴포넌트 기반 방식의 이점은 코드를 재사용하기가 쉽다. 리액트, 앵귤러 모두 컴포넌트 개반 개발 방식을 추구한다.

    전역 컴포넌트 등록

    Vue.component('컴포넌트 이름', {
    
    });

    지역 컴포넌트 등록

    new Vue({
        components : {
            '컴포넌트 이름' : 컴포넌트 내용
        }
    });

    컴포넌트 실행과정

    뷰 라이브러리 파일 로딩 > 인스턴스 객체 생성 > 특정 화면 요소에 인스턴스를 붙임 > 인스턴스 내용이 화면 요소로 변환(등록된 컴포넌트 내용도 변환) > 변환된 화면 요소를 사용자가 최종 확인

    <html>
      <head>
        <title>Vue Sample</title>
      </head>
    
      <body>
        <div id="app">
          {{message}}
    
          <global-component></global-component>
          <local-component></local-component>
        </div>
    
        <div id="app2">
          <global-component></global-component>
          <local-component></local-component>
        </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
        <script type="text/javascript">
          // 전역컴포넌트
          Vue.component('global-component', {
            template : '<div>전역컴포넌트입니다.</div>'
          });
    
          // 지역컴포넌트
          var localComponent = {
              template : '<div>지역컴포넌트입니다.</div>'
          };
    
          new Vue({
            el : '#app',
            data : {
              message : 'Hello Vue.js!',
            },
            components : {
              'local-component' : localComponent
            }
          });
    
          new Vue({
            el : '#app2'
          });
        </script>
      </body>
    </html>
    

    컴포넌트 통신

    지역 혹은 전역으로 등록된 컴포넌트가 자식 컴포넌트
    해당 컴포넌트를 등록한 인스턴스가 부모 컨포넌트

    데이터 전달(상위에서 하위로)

    <html>
      <head>
        <title>Vue Sample</title>
      </head>
    
      <body>
        <div id="app">
          <global-component v-bind:propsdata = 'message'></global-component>
        </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
        <script type="text/javascript">
    
          // 하위 컴포넌트
          Vue.component('global-component', {
            props : ['propsdata'],
            template : '<div>{{propsdata}}</div>'
          });
    
          // 상위 컴포넌트
          new Vue({
            el : '#app',
            data : {
              message : 'Hello Vue.js!'
            }
          });
    
          new Vue({
            el : '#app2'
          });
        </script>
      </body>
    </html>

    이벤트 전달(하위에서 상위로)

    <html>
    <head>
      <title>Vue Sample</title>
    </head>
    
    <body>
      <div id="app">
        <global-component v-on:show-log='printLog'></global-component>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
      <script type="text/javascript">
    
        // 하위 컴포넌트
        Vue.component('global-component', {
          props : ['propsdata'],
          template : '<div v-on:click="showLog">버튼</div>',
          methods : {
            showLog : function() {
              this.$emit('show-log');
            }
          }
    
        });
    
        // 상위 컴포넌트
        new Vue({
          el : '#app',
          data : {
            message : 'Hello Vue.js!'
          },
          methods : {
            printLog : function () {
              console.log('부모 컴포넌트 메소드 호출');
            }
          }
    
        });
      </script>
    </body>
    </html>

    이벤트버스(관계없는 컴포넌트간 통신)

    <html>
    <head>
      <title>Vue Sample</title>
    </head>
    
    <body>
      <div id="app">
        <global-component></global-component>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
      <script type="text/javascript">
    
        // 이벤트버스를 통해서 동일 관계 컴포넌트간에 데이터를 교환한다.
        var eventBus = new Vue();
    
        // 하위 컴포넌트
        Vue.component('global-component', {
          props : ['propsdata'],
          template : '<div>하위 컴포넌트 영역입니다. <button v-on:click="showLog">show</button></div>',
          methods : {
            showLog : function() {
              eventBus.$emit('trigger', 100);
            }
          }
    
        });
    
        // 상위 컴포넌트
        new Vue({
          el : '#app',
          data : {
            message : 'Hello Vue.js!'
          },
    
          // 라이프 사이클
          created : function () {
            eventBus.$on('trigger', function(value) {
              console.log("이벤트를 전달 받음. : ", value);
            });
          }
        });
      </script>
    </body>
    </html>

    뷰 라우터

    라우팅이란? 웹 페이지 간의 이동 밥법을 말한다. 미리 해당 페이지들을 받아 놓고 페이지 이동 시에 클라이언트의 라우팅을 이용하여 화면을 갱신하는 패턴. 리액트와 앵귤러 모두 라우팅을 이요하여 화면을 전환하고 있으며, 일반적인 HTML 파일들도 라우팅 자바스크립트 라이브러리를 이용하여 라우팅 방식의 페이지 구현이 가능하다.

    뷰 라우팅

    <html>
      <head>
        <meta charset="utf-8">
        <title></title>
      </head>
      <body>
        <div id="app">
          <h1>뷰 라우터 예시</h1>
          <p>
            <router-link to="/main"> main 컴포넌트 이동 </router-link>
            <router-link to="/login"> login 컴포넌트 이동 </router-link>
          </p>
    
          <router-view></router-view>
        </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
        <!-- 라우터 CDN -->
        <script src="https://unpkg.com/vue-router@3.0.1/dist/vue-router.js"> </script>
        <script type="text/javascript">
          var main = {
            template : '<div>main</div>'
          };
    
          var login = {
            template : '<div>login</div>'
          };
    
          // 라우트
          var routes = [
            {path : '/main', component : main},
            {path : '/login', component : login}
          ]
    
          // 뷰 라우터
          var router = new VueRouter ({
            routes
          });
    
          // 뷰 인스턴스
          var app = new Vue ({
            router
          }).$mount('#app');
    
        </script>
      </body>
    </html>

    네임드 뷰 라우팅

    <html>
    <head>
      <meta charset="utf-8">
      <title></title>
    </head>
    <body>
      <div id="app">
        <h1>뷰 라우터 예시</h1>
        <p>
          <router-link to="/main"> main 컴포넌트 이동 </router-link>
          <router-link to="/login"> login 컴포넌트 이동 </router-link>
        </p>
    
        <router-view name="header"></router-view>
        <router-view></router-view>
        <router-view name="footer"></router-view>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
      <!-- 라우터 CDN -->
      <script src="https://unpkg.com/vue-router@3.0.1/dist/vue-router.js"> </script>
      <script type="text/javascript">
    
      // 컴포넌트
      var main = {
        template : '<div>This is Main</div>'
      };
    
      var body = {template : '<div>This is Body</div>'};
      var header = {template : '<div>This is Header</div>'};
      var footer = {template : '<div>This is Footer</div>'};
    
      // 라우트
      var routes = [
        {path : '/main',
        component : main},
    
        {path : '/login',
    
        // 네임드 컴포넌트
        components : {
          default : body,
          header : header,
          footer : footer
        }}
      ]
    
      // 뷰 라우터
      var router = new VueRouter ({
        routes
      });
    
      // 뷰 인스턴스
      var app = new Vue ({
        router
      }).$mount('#app');
    
      </script>
    </body>
    </html>

    뷰 HTTP 통신

    Axios

    <html>
    <head>
      <meta charset="utf-8">
      <title></title>
    </head>
    <body>
      <div id="app">
        <button v-on:click="getData">프레임워크 목록 가져오기</button>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
      <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
      <script type="text/javascript">
    
      new Vue({
        el : '#app',
        methods : {
          getData : function() {
            // URL 막힘
            axios.get('https://raw.githubusercontent.com/joshua1988/doit-vuejs/mas-ter/data/demo.json')
            .then(function(response) {
              console.log(response);
            });
          }
        }
    
      });
      </script>
    </body>
    </html>

    데이터 바인딩

    HTML화면 요소를 뷰 인스턴스의 데이터와 연결하는 것

    • {{}}

      • 뷰 인스턴스 데이터를 HTML 태그에 연결

      • 자바스크립틑 표현식 사용 가능

      • computed를 사용하여 HTML 태그안에서 연산을 분리한다.

        <div id="app">
        <p>{{message}}</p>
        <p>{{message + "!!!!"}}</p>
        <p>{{message.split('').reverse().join('')}}</p>
        
        <p>var a= 10;</p><!-- 선언문은 사용 불가능 -->
        <p>if(true) {return 100}</p><!-- 분기 구문은 사용 불가능 -->
        
        <p> {{reversedMessage}}</p>
        </div>
        ...
        <script>
         new Vue({
          el : '#app',
          data {
              messsage : 'Hello Vue.js'
          },
          // 데이터 속성을 자동으로 계산해 주는 속성
          computed : {
              reversedMessage : function () {
                  return this.message.split('').reverse().join('');
              }
          }
        });
        </script>
    • v-bind

      • 뷰 인스턴스 데이터를 HTML 속성값에 연결

    디렉티브(Directive)

    HTML 태그 안에서 v- 접두사를 가지는 모든 속성을 의미한다. 디렉티브는 화면의 요소를 더 쉽게 조작하기 위해 사용한다. (앵귤러와 리액트도 비슷한 방식으로 화면 조작)

    디렉티브 이름 역할 약어
    v-if 태그 화면 표시 여부  
    v-for HTML 태그반복  
    v-show display:none  
    v-bind HTML 속성연결 :데이터이름
    v-on 이벤트 @이벤트이름
    v-model 뷰 인스턴스와 데이터 동기화  

    <html>
      <head>
        <title>Vue Sample</title>
      </head>
    
      <body>
        <div id="app">
          <a v-if="flag">도 닦는 개발자 Vue.js</a>
          <ul>
            <li v-for="system in systems">{{system}}</li>
          </ul>
    
          <p v-show="flag">도 닦는 개발자 Vue.js</p>
          <h5 v-bind:id="uid">뷰 입문서</h5>
          <button v-on:click="popupAlert">경고 창 버튼</button>
        </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
        <script type="text/javascript">
          new Vue({
            el : '#app',
            data : {
              flag : true,
              systems : ['android', 'ios', 'window'],
              uid : 10
            },
            methods : {
              popupAlert : function() {
                return alert('경고 창 표시');
              }
    
            }
          });
        </script>
      </body>
    </html>

    고급 템플릿 기법

    computed 속성

    HTML과 연산을 분리

    • 연산된 데이터 캐싱(중복 계산하지 않음)
    <div id="app">
        <p> {{reversedMessage}}</p>
    </div>
    ...
    <script>
     new Vue({
      el : '#app',
      data {
          messsage : 'Hello Vue.js'
      },
      // 데이터 속성을 자동으로 계산해 주는 속성
      computed : {
          reversedMessage : function () {
              return this.message.split('').reverse().join('');
          }
      }
    });
    </script>

    watch 속성

    데이터가 바뀔 때마 호출된다.
    computed는 간단한 연산에 적합한 반면 watch는 시간이 상대적으로 많이 소모되는 작업에 적합하다.

    <html>
    <head>
      <title>Vue Sample</title>
    </head>
    
    <body>
      <div id="app">
        <input v-model="message"/>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
      <script type="text/javascript">
      new Vue({
        el : '#app',
        data : {
          message : '도 닦는 개발자 Vue.js'
        },
        watch : {
          message : function(data) {
            console.log("값이 바뀝니다. : ", data);
          }
        }
      }
    );
    </script>
    </body>
    </html>

    싱글 파일 컴포넌트

    • HTML, CSS, Javascript 간 분리 가능
    • 컴포넌트 모듈화 가능

    *.vue 형태

    <template>
        <!-- HTML 태그 내용 -->
    </template>
    
    <script>
    export default {
        // ES6
        // 자바스크립트 내용
    }
    </script>
    
    <style>
        /*CSS 스타일 내용*/
    </style>

    뷰 CLI

    뷰를 사용하기 위한 프로젝트를 구성해준다.

    • Node.js를 설치한다. (자바스크립트 기반 웹 서버)
    • *.vue 파일을 브라우저가 인식할 수 있는 형태로 변환 (뷰 로더)
      • ES6 -> ES5, 브라우저는 ES6를 지원하는 경우가 많지만 Node.js의 경우 미지원
      • Babel를 사용하여 *.vue 파일을 인식할 수 있도록 변환
    1. Node.js 설치(NPM 자동설치)
    2. vue-cli 설치
    3. 프로젝트 생성

    NPM 자동 설치

    할일 목록 앱 만들기

    Github 주소

    프로젝트를 통한 학습

    • 어플리케이션 컴포넌트 설계 및 싱글 파일 컴포넌트 작성
    • 데이터 바인딩 및 디렉티브를 사용하여 반응성있는 어플리케이션 개발
    • 컴포넌트간 데이터 통신
    반응형