vue.js 공부하기

꿀이·2022년 4월 3일
0

vue.js 공부하기


기존 개발 방식

querySelect를 이용하면 해당 태그정보를 가져올 수 있다. 그리고 innerHTML 로 해당 태그에 값들을 넣어줄 수 있다. 근데 이때 값의 변경이 일어날때마다 태그를 갱신을 해주는 코드도 같이 작성을 해줬어야 한다.

<참고> div#app 을 입력하면 다음과 같이 자동입력 div id="app"

  <div id="app">
    hello world
  </div>

  <script>
    var div = document.querySelector('#app');
    var str = 'hello world@@@';
    div.innerHTML = str;
    
    console.log(div);
    str = 'hello world!!!';//바뀐 데이터의 내용이 화면에 반영이 되지 않는다.
    div.innerHTML = str;
  </script>

Object.defineProperty()

얘를 통해서 이미 존재하는 객체 속성(?)을 수정할수 있다.

<body>
  <div id="app"></div>
  <script>
    var div = document.querySelector('#app');
    var viewModel = {};
    //Object.defineProperties(대상 객체, 객체의 속성,{
    //  정의할 내용을 여기다가 적어준다
    //});
    Object.defineProperty(viewModel,'str',{
      get: function(){
        console.log('접근');
      },
      set: function(newValue){
        console.log('할당',newValue);
        div.innerHTML = newValue;
      }
    })
  </script>
</body>

위와 같이 즉각적으로 html 태그에 반영이 되는걸 확인

vue 에서 data의 message 부분을 수정하면 즉각적으로 변경이 되는걸 확인할 수 있다. 뭔가 vue에서 defineProperties() 를 수행해주는게 있는듯


뷰 인스턴스

아래와 같이 Vue를 생성해서 사용할 수 있다. 이럭헤 하면 id="#app" 을 찾아서 뷰의 속성(?) 을 적용시켜줄 수 있다. 이때 data 속성은 반응형으로 적용된다.

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data:{
        message: 'hi'
      }
    });
  </script>

뷰 컴포넌트

컴포넌트는 화면의 영역을 구분한다고 생각하자, key : {value} 로 작성할 수 있음, key에 매핑되는 템플릿을 html 에서 사용할 수 있음

뭐랄까... 앞으로 자바스크립만으로 html 을 제어할 수 있을거 같은 느낌적인 느낌

전역컴포넌트의 경우 모든 인스턴스에서 접근이 가능하다. app2에서도 사용가능한걸 확인. 하지만 app1 의 지역컴포넌트인 footer의 경우 app2 에서 사용할 수 없는걸 확인

  <div id="app">
    <app-header></app-header>
    <app-footer></app-footer>

  </div>

  <div id="app2">
    <app-header></app-header>
    <app-footer></app-footer>
  </div>


  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    //전역 컴포넌트 : 실무에서는 전역을 잘 안쓴다.
    //Vue.component(컴포넌트 이름),컴포넌트 내용);
    Vue.component('app-header',{
      template : '<h1>Header</h1>'
    })
    new Vue({
      el: '#app',
      //지역 컴포넌트 등록 방식
      components:{
        'app-footer' : {
          template : '<footer>footer</footer>'
        }
      }
    });
    new Vue({
      el:'#app2'
    })
  </script>


컴포넌트 통신 방법

하나의 인스턴스에 여러개의 컴포넌트 들이 있다고 한다. 근데 각각의 영역에서 사용자가 입력값을 넣고, 그값들이 다른 영역에 영향을 미친다고 할때 vue 에서는 다음과 같이 약속했다. 하위에서 상위로 갈때는 emit 상위에서 하위로 갈때는 props


props

각각의 컴포넌트들은 pros 속성을 가지고 있다. v-bind를 통해서 각각의 컴포넌트의 props 속성과 인스턴스의 data 를 연결시켜줄 수 있다.

    <div id="app">
      <!-- <app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 데이터 이름" ></app-header> -->
      <app-header v-bind:propsdata="message"></app-header>
      <app-content v-bind:propsdata="num"></app-content>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    
    <script>

      var appHeader = {
        template: '<h1>{{propsdata}}</h1>',
        props:['propsdata']
      }
      var appContent = {
        template : '<div>{{propsdata}}</div>',
        props:['propsdata']
      }

      var vm = new Vue({
        el:'#app',
        components: {
          'app-header' :appHeader,
          'app-content':appContent
        },
        data:{
          message:'hi',
          num:10,
        }
      })
    </script>

event emit

아래 예시를 보면 버튼을 하나 만들었는데 클릭했을때 실행되는 함수와 매핑을 시켜줬다. this.$emit('add') 를 실행하는데 이렇게 하면 상위 컴포넌트로 'add' 라는 이벤트를 올려준다.

그리고 나서 html div 태그를 보면 v-on:add="addnum" 이 있는데, 하위 컴포넌트에서 올라오는 이벤트와 이후 실행되어야 하는 메서드를 매핑시켜준다.

  <div id="app">
    <!-- <app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름="상위 컴포넌트의 메서드 이름"></app-header> -->
    <app-header v-on:pass="logtext"></app-header>
    <app-content v-on:add="addnum"></app-content>
    <p>{{num}}</p>
  </div>

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

    var appHeader = {
      template : '<button v-on:click="passEvent">click me</button>',
      methods:{
        passEvent: function () {
          console.log(this);
          this.$emit('pass');
        }
      }
    }
    var appConent={
      template : '<button v-on:click="addEvent">add num</button>',
      methods:{
        addEvent:function(){
          this.$emit('add');
        }
      }
      
    }

    var vm = new Vue({
      el: '#app',
      components : {
        'app-header' : appHeader,
        'app-content' : appConent,
      },
      methods:{
        logtext: function(){
          console.log('hi');
        },
        addnum: function(){
          this.num++;
        }
      },
      data : {
        num: 10,
      }
    })
  </script>

같은 컴포넌트 레벨 간의 통신 방법

같은 컴포넌트 레벨간에 통신을 하는 방법은 위에서 공부한 event emit & props 를 활용해서 만들어 볼 수 있다.

  1. appContent 의 버튼을 클릭해서 이벤트 emit
  2. 인스턴스에서 emit 으로 올라온 값을 처리하는 methods 인 setnum 호출
  3. appHeader 의 props 속성과 num 바인딩

 <div id="app">
    <app-header v-bind:propsdata="num"></app-header>
    <app-content v-on:pass="setnum"></app-content>
  </div>

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

    var appHeader = {
      template : '<div>header!!!</div>',
      props:['propsdata'],
      
    }

    var appContent = {
      template : '<div>content<button v-on:click="passNum">pass</button></div>',
      methods : {
        passNum : function(){
          this.$emit('pass',10);
        }
      }
    }

    new Vue({
      el : '#app',
      components :{
        'app-header' : appHeader,
        'app-content' : appContent,
      },
      data:{
        num: 0,
      },
      methods:{
        setnum:function(val){
          this.num += val;
        }
      }

    })
  </script>

app-content v-on:pass="setnum" 이부분을 보면 매개변수를 안넘기는 것처럼 보이는데 암묵적으로 'pass' 와 같이 올라온 10이 매개변수로 넘어가는거다.

라우터

라우터란 무엇일까... url 에 해당하는 view 를 연결시켜주는 역할을 하는것 같다. 우선 라우터 인스턴스를 생성해서 routes: [] 배열에다가 path 와 해당하는 컴포넌트를 등록해준다. 이후에 vue 인스턴스의 router 속성에 해당 라우터를 매핑시켜주자.

이렇게 하고 html에 router-view 태그를 입력한 후에 url을 접속하면 해당 화면이 바뀌는걸 볼 수 있다.
근데 이때 url 을 직접 입력해서 이동하면 클라이언트가 이용을 못할거니까. a태그 역할을 하는 router-link 태그를 추가!!

  <div id="app">
    <div>
      <!--참고! router-link*2 : 이렇게 하면 알아서 두개를 만들어 준다. -->
      <!-- 얘같은 경우는 a 태그로 변환이 되어서 찍힌다. 라우터에서 페이지 이동을 하기 위한 링크 태그라고 생각하자 -->
      <router-link to="/login">Login</router-link>
      <router-link to="/main">Main</router-link>
    </div>
    <router-view></router-view>
  </div>
  
  
  <!-- vue 를 먼저 추가하고 라우터를 추가해줘야 한다. 순서 주의!! -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router@3.5.3/dist/vue-router.js"></script>

  <script>
    var LoginComponent = {
      template: '<div>login</div>'
    }

    var MainComponent = {
      template: '<div>Main</div>'
    }

    //라우터 인스턴스 생성
    var myRouter = new VueRouter({
	  //mode : 'history' 를 하면 url 시작부분에 # 을 제거할 수 있다.
	  mode:'history',
      //페이지의 라우팅 정보 (어떤 url 로 이동했을때 뿌려지는 화면)
      routes : [
        {
          //페이지의 url
          path:'/login',
          //해당 url 에서 표시될 컴포넌트
          //s가 붙지 않는거에 주의 : 해당 페이지 마다 뿌려질 해당하는 컴포넌트는 하나니까
          component: LoginComponent
        },
        {
          path:'/main',
          component: MainComponent
        }
      ]
    })

    new Vue({
      el: '#app',
      router: myRouter,
      
    })

  </script>

템플릿 문법

데이터 바인딩

  • v-if="변수" 를 통해서 bool 값 체크해서 해당 태그를 보여줄지 안보여줄지를 설정한다. 해당하지 않을경우 개발자 도구로 elements 에 표시도 안된다.

  • v-show="변수" 얘도 v-if 와 비슷하지만 elements 에 표시가 된다. css style 의 display 속성을 none 으로 바꿔서 출력해준다.

  • computed 의 경우 함수라고 생각하면 될거같다. 이름 그대로 뭔가 함수를 통해서 로직을 실행해주는듯

  <div id="app">
    {{str}}
    <p v-bind:id="uuid" v-bind:class="name">{{num}}</p>
    <!-- <p id="abc1234">{{num}}</p> 와 같이 동작-->
    <p>{{doubleNum}}</p>
    <div v-if="loading">
      Loading...
    </div>
    <div v-else>
      test user has been logged in
    </div>
    <!-- if 랑 show 의 차이점은 css style 에서 display 를 none 으로 처리한다.
         if는 아얘 태그 자체가 없어진다. -->
    <div v-show="loading">
      Loading...
    </div>

    <input type="text" v-model="message">
    <p>
      {{message}}
    </p>

  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var vm = new Vue({
      el: '#app',
      data:{
        str: 'hi',
        num: 10,
        uuid:'abc1234',
        name: 'text-blue',
        loading: true,
        message: ''
      },
      computed:{
        doubleNum:function(){
          return this.num*2;
        }
      }
    })
    
  </script>

methods 속성 & v-on

  • v-on:click="메서드 이름" 을 통해서 클릭했을때 해당하는 메서드를 호출할 수 있다.

  • v-on:keyup="메서드 이름" 을 통해서 키보드 이벤트에 해당하는 메서드를 호출할 수 있다.

  <div id="app">
    <button v-on:click="logText">click me</button>
    <!-- keyup에 enter 룰 붙혀주면 엔터를 눌렀을때만 발생하게 할 수도 있다. -->
    <input type="text" v-on:keyup.enter="logText">
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      methods: {
        logText: function(){
          console.log('clicked');
        }
      },

    })
  </script>

watch

watch 속성의 경우 data 의 값을 보고 있다가 변화가 일어난다면 매핑되는 함수를 실행해 준다. 보통 watch 의 경우 통신과 같은 무거운 연산을 사용한다고 하고, 그외의 단순 계산같은 것들은 compute 속성을 사용한다고 한다.

  <div id="app">
    <button v-on:click="addNum">increase</button>
    {{num}}
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    new Vue({
      el:'#app',
      data:{
        num:10,
      },  
      watch:{//데이터를 대상으로 데이터의 변화에 따라서 특정 로직을 실행할 수 있다.
        num: function(){
          this.logText();
        }
      },
      methods:{
        addNum:function(){
          this.num = this.num+1;
        },
        logText: function(){
          console.log('changed');
        }
      }
    })
profile
내게 맞는 옷을 찾는중🔎

0개의 댓글