Front-end/Vue

Vue Core

c62 2022. 11. 23. 13:54

정의


  • approachable - 접근하기 쉬운(프로그레시브 framework특징 - 점진적 도입 가능)
  • versatile - 다재다능한
  • performant - 효율적인(virtual dom 기반의 효율적 랜더링)
  • maintainable - 유지보수 가능한(컴포넌츠 기반 설계로 유지보수에 용이하도록 개발가능)
  • testable - 테스트 가능한

특징


  • reusable components - 재사용 가능한 컴포넌트들
  • reactive - 반응형

기능


선언적 렌더링

DOM 과 데이터를 연결시켜 반응형이 되도록 함

v- 접두어가 붙어있는 속성을 디렉티브 라고함

  • 텍스트 보간
    • <div id="app">
        {{ message }}
      </div>
  • 일회성 보간
    • // 하위 요소들 까지 한번만 렌더링되기 때문에 주의 필요
      // 성능 최적화에 좋음
      <span v-once> {{ msg }} </span>
  • 속성 바인딩
    • <!-- 콜론(:) 으로 전달인자 title 사용 -->
      <span v-bind:title="message">
      <!-- 약어 -->
      <span :title="message">
  • 원시 HTML
    • 이중 중괄호( “{{ }}” ) 는 HTML이 아닌 텍스트로 데이터를 해석하므로 실제 HTML을 출력시 디렉티브 사용
    • 데이터 바인딩은 무시됨
    • 사용자 입력을 기반으로하는 부분에 사용해선 안됨(XSS 취약점)
    • <span v-html="rawHtml"></span>
  • javascript 표현식 사용
    • 모든 바인딩 내에서 javascript 표현식 모든기능 지원
    • 단일 표현식만 포함 가능
    • 전역 객체 사용가능(Math, Date, …)
    • 디렉티브 속성값에서 표현식 사용 가능
    • <!-- 아래는 구문입니다, 표현식이 아닙니다. -->
      {{ var a = 1 }}
      
      <!-- 삼항연산자 표현식 사용 -->
      {{ ok ? 'YES' : 'NO' }}

조건문과 반복문

  • 조건문
    • v-if, v-show
    • //조건에 부합하지 않을시 렌더링 되지않음
      <div v-if="type === 'A'">
        A
      </div>
      
      // 항상 렌더링 되고 display속성으로 토글
      <div v-show="type === 'B'">
        B
      </div>
    •  
  • 반복문
    • 배열 데이터를 바인딩 하여 표시
    • DOM노드를 추적하고 엘리먼트를 재사용, 재정렬 하기위해 고유 key를 제공해야함
    • 객체의 속성또한 반복가능
      • 단, Object.keys()의 키 나열 순서에 따라 결정되므로 javascript 엔진에 따라 일관적이지 않을 수 있음
    • <ol>
        <li v-for="todo in todos" v-bind:key="item.id">
          {{ toto.text }}
          ...

사용자 입력 핸들링

  • v-on
    • vue 인스턴스에서 메소드를 호출하는 이벤트 리스너 추가
    • <button v-on:click="closePopup">팝업 닫기</button>
      <!-- 약어 -->
      <button @click="closePopup">팝업 닫기</button>
    • 수식어 추가
      • .stop - 이벤트 전파 중단
      • .prevent - 엘리먼트가 가진 기존의 이벤트을 막음 (ex- v-on:submit.prevent=”realSubmit”)
      • .capture - 내부 엘리먼트에서 처리되기전에 현재 엘리먼트에서 처리
      • .self - event.target이 엘리먼트 자체인 경우에만 트리거 처리(자식 엘리먼트에서 불가)
      • .once - 최대 한번만 트리거 됨
      • .passive - 절대 preventDefault 를 호출하지 않을것임을 명시하는 값으로 모바일 환경 성능향상에 도움
    • $emit
      • 이벤트를 트리거 하는 method
      • $emit(eventName)으로 부모 컴포넌트의 리스너에서 감지할 수 있음
      • // 자식 컴포넌트
        ...
        methods:{
          clickEvent: function(){
            this.$emit('click');
          }
        }
  • v-model
    • 입력과 앱 상태를 양방향으로 바인딩
    • 수식어 추가
      • .lazy - input 대신 change 이벤트 이후에 동기화 될수 있도록함
      • .number - 사용자 입력이 자동으로 형변환 되도록 하는 수식어
      • .trim - 자동 trim
    • <p>{{ message }}</p>
      <input v-model="message">

컴포넌트

 
  • vue.js에서 부모-자식 컴포넌트 관계는 props는 아래로, events는 위로 라고 요약 할 수 있음
  • 독립적이고 재사용할 수 있어 대규모 어플리케이션을 구축할 수 있는 추상적 개념
  • 미리 정의된 옵션을 가진 vue 인스턴스
  • js
    • // 자식 컴포넌트
      
      Vue.component('todo-item', {
        //부모 영역의 데이터를 자식 컴포넌트에 상속 가능
        props: ['todo'],
        template: '<li>{{ todo.text }}</li>'
      })
  • html
    • <!-- 부모 컴포넌트 -->
      
      <ol>
        <!--
          todo-item 컴포넌트에 todo 객체에 item을 할당하여 제공
          각 구성 요소에 "key"를 제공해야함 
        -->
        <todo-item
          v-bind:todo="item"
          v-bind:key="item.id"
        ></todo-item>
      </ol>

Vue 인스턴스


데이터와 메소드

vue 인스턴스가 생성될때 data 객체에 있는 모든 속성이 vue의 반응형 시스템에 추가됨

data 에 있는 속성들은 인스턴스가 생성될때 존재한 것들만 반응형 시스템에 추가

var vm = new Vue({
  data: {
    a:1
  }
})
  • Object.feeze() 로 생성된 변수는 속성의 변경이 불가능
    • var obj = {
        foo: 'bar'
      }
      Object.freeze(obj)
      var vm = new Vue({
        data:obj
      })
  • vue 인스턴스 속성, 메소드는 다른 사용자 정의 속성과 구분하기 위해 $ 접두어를 붙여 사용
    • var vueData = vm.$data

인스턴스 라이프사이클 훅

각 Vue 인스턴스가 생성되는 단계별로 호출되는 훅

모든 라이프사이클 훅은 this 컨텍스트가 호출하는 vue 인스턴스를 가리키며 호출

options 속성이나 훅에 화살표 함수 사용을 지양하길 권장

-> 화살표 함수는 this를 가지지 않기때문

new Vue({
  data: {
    a: 1
  },
  // created hook
  created: function () {
    console.log('a: ' + this.a)
  }
})
 

  • 라이프사이클 훅 종류
    • beforeCreate
      • vue인스턴스 초기화 직후
    • created
      • 인스턴스 생성, 반응형 시스템 적용 이후
      • 컴포넌트 data에 접근가능
      • 보통 이 시점에 서버로 데이터를 요청
      • 컴포넌트 내부의 노드를 접근하는것은 불가능
    • beforeMount
      • 가상DOM은 생성되어있으나 실제 DOM에 mount되지 않은 상태
    • mounted
      • 실제 DOM에 mounted되고 난 후 동작
      • 완전히 mount된 상태를 보장하지 않음
      • DOM구조를 조작하는 로직 사용 불가
    • beforeUpdate
      • data가 변경되어 가상 DOM 에 re-render하기 전에 호출
    • updated
      • 가상 DOM 렌더링 및 실제 DOM 변경 이후 호출
      • 변경된 data가 DOM 에도 적용된 상태
    • beforeDestory
      • 해당 vue 인스턴스가 해체되기 직전 호출
      • 모든 속성에 접근 가능
      • 이벤트 리스너 해제 등 처리
    • destroyed
      • 인스턴스가 해체되고 난 직후 호출
      • 인스턴스 속성에 접근 불가

 

computed와 watch


computed

복잡한 javascript 연산을 위한 vue 인스턴스 속성

method에 함수를 정의하는것과 결과는 같지만 computed는 종속 대상을 따라 캐싱 된다는것이 다름

→ 의존성 없는 데이터로만 연산하는경우 절대로 업데이트 되지 않음

// 매번 새로 함수 실행
methods: {
  reversedMessage: function(){
    return this.message.split('').reverse().join('')
  }
},
// 반응형 데이터(this.message)가 변경될 경우만 다시 연산
computed: {
  impactMessage: function(){
    return `${this.message}!!`
  }
}
  • setter 함수
    • 기본적으로 getter함수만 가지고있지만 setter함수도 사용가능
    • computed:{
        fullName: {
          //getter
          get: function(){
            return this.firstName + ' ' + this.lastName
          },
          //setter
          set: function(newValue) {
            ...
          }
        }
      }
      
      //vm.fullName = 'Ian Nam'을 실행하면 setter가 
      //var name = vm.fullName 을 실행하면 getter가 호출됨

watch

감시할 데이터를 지정하고 그 데이터가 바뀌면 실행할 콜백함수

비동기식 또는 시간이 많이 소요되는 작업을 수행시 유용

watch: {
  // question 데이터가 변경될때 마다 이 기능이 실행됩니다.
  question: function (newQuestion){
    this.answer = '입력을 기다리는 중...'
    this.debouncedGetAnser()
  }
}

Slot


slot은 부모 컴포넌트에서 자식 컴포넌트의 엘리먼트를 지정할때 사용

부모에 따라 자식 컴포넌트가 영향을 받기때문에 컴포넌트 재사용에 용이

자식 컴포넌트에서 부모 컴포넌트로 유연하게 element를 상속받기 위함

// 부모 컴포넌트
<base-layout url="/profile">
  <h1 slot="header">--header--</h1> 
  Your Profile
  <template slot="footer">
    <p>--footer--</p>
  </template>
</base-layout>

// 자식 컴포넌트
<div class="container">
  <slot name="header"></slot>
  <slot>Default Profile</slot>
  <slot name="footer"></slot>
</div>

// 결과
<div class="container">
  <h1>--header--</h1>
  Your Profile
  <p>--footer--</p>
</div>

<base-layout> 템플릿이 <slot>요소를 가지고있지 않다면 그자리에 들어갈 내용은 무시됩니다.

scope

슬롯 안의 데이터 옵션을 사용하고 싶을때

슬롯으로 전달된 속성들을 받기위해

부모 컴포넌트에서의 데이터를 슬롯에 전달하고 싶을때

<slot-example>
  <template slot-scope="slotProps">
    {{ slotProps.msg }}
  </template>
</slot-example>

nextTick


javascript 특성상 비동기적으로 처리되어 DOM 업데이트를 기다리기위해 사용하는 api

<div id="app">
	<div v-for="item in list">
    	<div v-bind:id="bindId(item)"></div>	
    </div>
</div>

<script>
...
created: function(){
  for(var i=0; i<100; i++) {
  	this._data.list.push(i);
  }
  
  // [error-case] 아직 생성되지 않은 dom 을 선택했으므로 에러 발생!!
  var dom = document.getElementById('item-0');	
  dom.style.backgroundColor = 'red';
  
  // [success-case] DOM 업데이트 이후 콜백
  this.$nextTick(function(){
    var dom = document.getElementById('item-0');	
    dom.style.backgroundColor = 'red';
  })
}
methods: {
  bindId: function(item) {
      	return 'item-' + item;
      }
  }
</script>

 

참고자료

https://vuejs.org/guide/introduction.html