Daehyunii's Dev-blog

[데브코스] TIL-121 Vue, 렌더링, 이벤트, 폼 입력 바인딩, 컴포넌트 본문

✏️ 2022. TIL/December (데브코스)

[데브코스] TIL-121 Vue, 렌더링, 이벤트, 폼 입력 바인딩, 컴포넌트

Daehyunii 2022. 12. 15. 01:37
조건부 렌더링

1. v-if, v-else-if, v-else

  해당 디렉티브를 사용하여 조건문을 사용할 수 있다. 각 요소 중간에 다른 요소가 들어가지 않으면 true, false에 따라 렌더링을 해준다. 참고로 빈 배열이나 객체는 truthy한 값이라 결과가 true로 나온다.

<div id="app">
  <h1 v-if="isShow">Hello Vue!</h1>
  <div v-else-if="[]">
    <h2>Application</h2>
  </div>
  <h2 v-else>Good Morning~</h2>
</div>

  만약 v-else-if에서 div 태그를 렌더링하지 않고, 그 내부의 요소만 렌더링하고 싶다면 template 태그를 사용하면 된다. v-if는 falsy한 값이 나오면 lazy하다고 할 수 있다. 구조적으로 생성조차 하지 않기 때문에 초기 렌더링 비용이 낮지만, 전환 비용은 높다.

 

2. v-show

  조건에 따라 요소를 보이거나 보이지 않게 해주는데, CSS style 속성을 통해서 처리한다. 구조적으로 화면에 출력하지만 display: none;을 사용하여 스타일로 제어한다. 따라서 초기 렌더링 비용이 높지만, 전환 비용은 낮다고 할 수 있다. 주의할 점은 v-show를 사용할 때는 되도록이면 v-cloak이라는 디렉티브를 같이 사용하는 것이 좋다.

 

3. v-cloak

  이 디렉티브는 연결된 컴포넌트 인스턴스가 컴파일을 완료할 때 까지 요소에 남아있다. 데이터를 이중 중괄호 구문을 통해 받아와야 하는 경우, 이 부분이 잠시 화면에 나타날 수 있기 때문이다. 해당 디렉티브를 사용하면 화면에 출력되어야 할 값이 준비되면 v-cloak 속성은 사라진다. 속성에 따로 값은 없고, 이름만 추가하면 된다. 그리고 해당 속성을 가진 곳에 아래와 같이 스타일을 적용해주면 위의 문제를 해결할 수 있다.

<ul>
    <template v-for="user in users">
        <li v-if="user.isActive">
            {{ user.name }}
        </li>
    </template>
</ul>

리스트 렌더링

1. v-for

  배열 또는 객체 데이터를 반복하여 렌더링할 수 있다. item in(of) items 형태로 특별한 문법을 사용한다. 여기서 items는 원본 데이터 배열 혹은 객체이고, item은 반복되는 배열 엘리먼트 혹은 객체의 value이다. v-for 블록 안에는 부모 범위 속성에 대한 모든 권한이 있다. 배열이면 현재 항목의 인덱스를, 객체이면 key를 두 번째 전달인자로 제공한다. 이를 사용할 때 key 속성을 같이 사용하는 것이 좋다. 그 요소가 고유하다는 것을 증명할 수 있다. 참고로, 객체를 반복할 때는 순서가 Object.keys()의 키 나열 순서에 따라 결정되기 때문에 구현 순서대로 반복되지 않을 수도 있다.

2. 배열 변경 감지

  Vue는 감시중인 배열의 변이 메서드를 래핑하여 뷰 갱신을 트리거한다. 여기서 변이 메서드는 push(), pop() 등의 원래 배열을 변경하는 메서드를 말한다. filter(), concat() 과 같은 원래 배열을 변경하지 않지만 새 배열을 반환하는 비-변이 메서드도 있다.

3. 필터링/정렬된 결과 표시

  원래 데이터를 실제로 변경하거나 재설정하지 않고, 배열의 필터링되거나 정렬된 버저을 표시하려고 한다. 이 경우 필터링 되거나 정렬된 배열을 반환하는 computed 속성을 만들 수 있다.

const App = {
  data() {
    return {
      numbers: [1, 2, 3, 4, 5],
    };
  },
  computed: {
    evenNumbers() {
      return this.numbers.filter((n) => n % 2 === 0);
    },
  },
};

const vm = Vue.createApp(App).mount('#app');

만약 computed 속성이 실행 가능하지 않은 경우(중첩된 v-for 루프 내부)에서는 methods를 실행해서 사용하면 된다.


이벤트 핸들링

1. 이벤트 청취

  v-on 디렉티브는 @기호로 사용할 수 있으며, DOM 이벤트를 듣고 트리거 될 때와 자바스크립트를 실행할 때 사용한다.

2. 인라인 메서드 핸들러

  메서드 이름을 직접 바인딩하는 대신 인라인 자바스크립트 구문에 메서드를 사용할 수도 있다. 필요한 경우 두 번째 혹은 세 번째 인수로 event 객체를 전달할 수 있다.

<button @click="say('hi', $event)">Say</button>

3. 복합 이벤트 핸들러

, 또는 ; 연산자를 사용하여 이벤트 핸들러 안에서 복합 메서드를 지정할 수 있다.

<div id="app">
  <h1 @click="a(); b(); c()">Hello Vue!</h1>
</div>

4. 이벤트 수식어

이벤트 핸들러 내부에서 event.preventDefault()를 호출하는 것은 보편적이다. 이러한 자주 사용하는 메서드는 v-on 이벤트에 수식어로 제공된다.

  • stop: 이벤트 버블링 방지
  • prevent: 기본 이벤트 막기
  • capture: 해당 이벤트를 실행시키기
  • self: currentTarget과 target이 같아질 때 실행시키기
  • once: 이벤트 한 번만 실행
  • passive: 화면의 렌더링과 로직을 분리해서 실행시키기

5. 키 수식어

키보드 이벤트에 사용할 수 있는 수식어를 살펴보자. 체이닝 형식으로 작성할 수 있다.

  • enter
  • tab
  • delete: Delete키와 Backspace
  • esc
  • space
  • up
  • down
  • left
  • right

6. 시스템 수식어 키목록

체이닝 형식으로 작성할 수 있다.

  • ctrl
  • alt
  • shift
  • meta: 윈도우에서는 Window키, 맥은 Command키
    • meta는 keyup에서는 동작하지 않는다.

exact라는 수식어로 해당 이벤트만 동작하도록 한정시킬 수 있다.

<button @click.exact="log">Click!</button>

7. 마우스 버튼 수식어

  • left
  • right
  • middle

8. 왜 HTML로 된 리스너를 사용하는가?

  1. HTML 템플릿을 간단히 하여 자바스크립트 코드 내에서 핸들러 함수 구현을 찾는 것이 더 쉽다.
  2. 자바스크립트에서 이벤트 리스너를 수동으로 연결할 필요가 없기 때문에 뷰모델(컴포넌트) 코드는 순수 로직과 DOM이 필요하지 않다.
  3. 뷰모델(컴포넌트)이 파기되면 모든 이벤트 리스너가 자동 제거된다.

폼 입력 바인딩

  v-model 디렉티브를 사용하여 input, textarea, select 요소들에 양방향 데이터 바인딩을 생성할 수 있다. 기본적으로 사용자 입력 이벤트에 대한 데이터를 업데이트하는 syntax sugar이다.

1. 양방향 데이터 바인딩

  msg에 사용자가 입력한 내용이 바로 적용될 수 있도록 코드를 구현해봤다. input 이벤트가 발생하면 사용자가 입력한 msg가 현재 value로 바로 적용되게 한 것이다.

<div id="app">
  <h1>{{ msg }}</h1>
  <input type="text" :value="msg" @input="msg = $event.target.value" />
</div>

v-model 디렉티브를 사용하여 이를 단축할 수 있다. v-model을 사용할 때는 한글입력이 완벽히 실시간으로 반영하지는 않는다. 그래서 이런 경우에는 위의 방법을 사용하면 된다.

<div id="app">
  <h1>{{ msg }}</h1>
  <input type="text" v-model="msg" />
</div>

2. 수식어

  • lazy
    • v-model에서 input은 이벤트 후 입력과 데이터를 동기화 한다. 해당 수식어를 사용하면 change 이벤트 이후에 동기화 할 수 있다.
  • number
    • 사용자 입력이 자동으로 숫자로 형변환 되기를 원할 때 사용한다.
  • trim
    • 사용자 입력이 될 때 앞뒤 공백을 자르고 싶을 때 사용한다.

컴포넌트 기초

  컴포넌트 등록은 전역 등록과 지역 등록의 2가지 유형이 있다. 일반적으로는 지역 등록을 하고, 자주 사용할 것 같은 컴포넌트는 전역으로 동록하면 된다.

1. Props를 이용해 자식 컴포넌트에게 데이터 전달하기

  props는 컴포넌트에 등록할 수 있는 커스텀 속성이다. 값이 prop 속성에 전달되면, 그 값은 해당 컴포넌트 인스턴스의 속성이 된다. 컴포넌트는 원하는 만큼 props를 가질 수 있다.

2. 하위 컴포넌트 이벤트 수신

  하위 컴포넌트에서 일부 기능은 상위 컴포넌트와 다시 통신해야 할 수 있다. 이벤트와 함께 값 emit하기 이벤트와 함께 특정 값은 emit하는 것이 유용할 때도 있다. $emit의 두번째 파라미터를 사용하여, 이 값을 제공할 수 있다. 부모의 이벤트를 수신할 때, $event를 사용하여 emit한 이벤트 값에 접근할 수 있다.

<div id="app">
  <upper-name
    v-for="fruit in fruits"
    :key="fruit.id"
    :name="fruit.name"
    @to-upper="toUpper(fruit, $event)"
  ></upper-name>
</div>
const App = {
  data() {
    return {
      fruits: [
        { id: '1', name: 'apple' },
        { id: '2', name: 'banana' },
        { id: '3', name: 'cherry' },
      ],
    };
  },
  methods: {
    toUpper(fruit, upperName) {
      fruit.name = upperName;
    },
  },
};
const app = Vue.createApp(App);
app.component('upper-name', {
  template: `<div @click="capitalize">{{ name }}</div>`,
  props: ['name'],
  methods: {
    capitalize() {
      this.$emit('to-upper', this.name.toUpperCase());
    },
  },
});
const vm = app.mount('#app');

 

오늘을 마무리 하며

 

  오늘은 조건문, 반복문, 이벤트 핸들링에 관해서 공부했다. 한 번에 너무 많은 내용들에 대해서 공부를 하다보니 이게,, 지금 제대로 듣고있는건지도.. 사실 좀 헷갈리는것 같다. 그리고 자바스크립트 코드에 익숙해져 있어서 그런지는 모르겠지만 일반적으로 지금까지 배워온 바닐라 자바스크립트 코드의 흐름과는 너무 다른 모습이라 헷갈리는 부분이 너무 많은 것 같다. 정해진 규칙에 맞게 작성해야하니 정해진 규칙을 정확하게 알아야 하는데 지금은 편하다는 느낌보다는 너무 뭐가 많아서 헷갈리는 느낌이 강하게 드는것이 사실이다. querySelector로 DOM 요소를 선택하고 이런 일련의 과정들이 전부 생략되어 짧은 코드를 작성하는것은 확실한 것 같은데 뭐랄까 기대한 것 만큼 편한것인지는 아직 잘 모르겠다..