데브코스 35일차 TIL : Vue 문법 [ 조건부렌더링, 리스트렌더링, $event, $emit, 폼입력 바인딩]

te-ing·2021년 9월 30일
0
post-thumbnail
<style>
.active {
      color: red;
    }
    .title--small {
      font-size: 40px;
    }
    .color--orange {
      color: orange;
    }
  </style>
  <div id="app">
    <button @click="toggle">Toggle</button>
    <h1 :class="{ active, 'title--small color--orange':small}" class="title">{{ msg }}</h1>
  </div>
  
  <script>
    const App = {
      data() {
        return {
          msg: 'Hello Vue!',
          active: false,
          small:true,
        }
      },

active:active 는 active로 생략가능

title—small은 html표기법으로, 'title—small': small 으로 해줘야함

'title--small color--orange':small'' 처럼 안에서는 띄어쓰기로 여러개의 클래스 사용가능

<h1 :class="{ active, 'title--small color--orange':small}" class="title">{{ msg }}</h1>
return {
          msg: 'Hello Vue!',
          active: false,
          small:true,
          classObject: {
            active: false,
            'title--small color--orange': true
          }
        }
			},
      methods: {
        toggle() {
          this.active = !this.active
          this.small = !this.small
        }
      }
    }
<h1 :class="classObject" class="title">{{ msg }}</h1>
return {
          msg: 'Hello Vue!',
          classObject: {
            active: false,
            'title--small color--orange': true
          }
        }

classObject로 묶어서 사용 가능

return {
          msg: 'Hello Vue!',
          active: false,
          small:true,
        }
      },
      computed: {
        classObject: {
            active: this.active,
            'title--small color--orange': this.small
        }
      },
      methods: {
        toggle() {
          this.active = !this.active
          this.small = !this.small
        }
      }
    }

반응형 데이터로 활용하려면 computed로 계산된 데이터로 만들어줘야함

대괄호를 이용하여 여러가지 class 적용

<h1 :class="[active, title]">Hello Vue!</h1>

대괄호를 이용해 2가지 class 적용

inline style 적용법이 데이터 바인딩이나 동적관리에서는 권장됨

<h1 *v-if*="isShow">Hello Vue!</h1>, <h2 *v-else*>Good Morning~</h2> 연결가능

template 태그

<template v-else-if="[]">
      <h2>Hi</h2>
    </template>

template 요소는 html에서 보이지 않고 컨테이너로 묶을 수 있음

조건부렌더링

v-show와 v-if="false"의 차이점, v-cloak디렉티브

v-show 디렉티브는 display: none 속성을 다룸

v-if="false" or "true" 를 통해 화면표기를 다루면 <!—v-if—>으로 구조적으로 없앰

따라서 v-if는 초기렌더링 비용이 낮은 반면 전환비용이 높고, v-show는 그의 역을 가짐
일반적으로는 v-if를 작성하며 v-show를 사용할 땐 v-cloak디렉티브, [v-cloak] { display: none;} 을 사용하는 것을 권장

v-clock: 연결된 인스턴스의 컴파일이 완료되기 전까지 존재하며, 생성되면 사라짐

v-if와 v-for

v-if의 실행 우선순위가 v-for의 우선순위보다 높기 때문에 v-ifv-for 범위의 변수에 접근하지 못한다. 즉, v-ifv-for 는 같은 동시에 사용하면 안되며, 사용하려면 template를 통해 분리하여야 한다.

리스트렌더링

v-for의 배열과 객체에서 item, index / value, name, index사용

<li v-for="(item, index) in items"> {{ parentMsg }} - {{ index }} - {{item.msg }} </li> item과 index는 원하는 인자이름으로 사용 가능

<li v-for="value in myObject">{{ value }}</li> myObject라는 객체의 값을 가져온다.

<li v-for="(value, name, index) in myObject">{{index}}. {{ name }} :{{ value }}</li>

v-for 정수사용 가능

<span v-for="n in 10">{{ n }} </span> : 12345678910

❗ v-for 사용 시 주의할 점

...

❗v-for의 렌더링은 데이터 순서가 바뀔 때 DOM요소를 항목의 순서대로 이동시키지 않고, 각 요소를 적절한 위치에 패치하고 해당 인덱스에서 렌더링할 내용을 반영하는지 확인한다.
따라서 v-for를 사용할 때에는 key를 통해 고유값을 추가하는 것이 권장된다.

❗ v-for 객체의 index는 객체를 반복할 때 순서는 Object.keys()의 순서대로 결정되며, 자바스크립트 엔진과 일관적이지 않기 때문에 사용시 주의를 요하며, 반복순서 정도로만 사용하는 것을 권장한다.

<div id="app">
    <form @submit="addNewTodo">
      <label for="new-todo">Add a todo</label>
      <input v-model="newTodoText"
             id="new-todo" 
             placeholder="E.g. Feed a cat">
      <button>Add</button>
    </form>
    <ul>
      <todo-item v-for="todo in todos" 
                :key="todo.id"
                :todo="todo"
                @remove="removeTodo" />
                <!-- @romove를 통해 $emit으로 정의했던 removeTodo 함수를 받는다. -->
    </ul>
  </div>
  
  <script>
    function generateId() {
      return `${Date.now()}${Math.random()}`
    }

    const TodoItem = {
      template: `
      <li >
          {{ todo.title }}
          <button @click="$emit('remove', todo.id)">Remove</button>
      </li>
      `,
      props: ['todo'] // 컴포넌트 밖에서 todo 데이터를 받는다.
    }

    const App = {
      components: {
        TodoItem
      },
      data () {
        return {
          newTodoText: '',
          todos: []
        }
      },
      methods: {
        addNewTodo(e) {
          e.preventDefault()
          this.todos.push({
            id: generateId(),
            title: this.newTodoText
          })
          this.newTodoText = ''
          console.log(this.todos);
        },
        removeTodo(todoId) {
          this.todos = this.todos.filter(todo => {
            return todo.id !== todoId
          })
        }
      }
  }

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

$emit

<button @click="$emit('remove(사용자정의함수)', todo.id)">Button</button>

@click시, $emit으로 todo.id값을 사용자정의함수에 담아 보낸다.

todo-item의 @remove="removeTodo"으로 @click 이벤트와 $emit했던 todo.id값을 받는다.

$event

<h1 @click="say('Hello~', $event)">{{ msg }}</h1>

say(*message*, *event*) { console.log(message); console.log(event); }

$event로 event를 받을 수 있다.

여러개의 methods 사용

<h1 @click="a(), b(), c()"> ... </h1> or <h1 @click="a(); b(); c();"> ... </h1>

v-on의 이벤트 수식어

event.preventDefault() 또는 event.stopPropagation() 대신 Vue의 이벤트 수식어 사용가능

<a href="https://google.com" target="_blank" @click.prevent="method">Google</a>

@click.prevnet=""@click.prevent 으로 줄일 수 있음

  • @click.stop : event.stopPropagation() 의 역할로 이벤트 버블링 정지
    • 이벤트버블링: 하위개체의 이벤트 실행시 상위 개체의 핸들러까지 실행되는 것
  • @submit.prevent : event.preventDefault() 의 역할
  • .once 한번만 동작
  • .capture 하위 이벤트 실행시, capture가 있는 최상위 개체부터 하위 이벤트까지 내려오며 각각 실행되며, capture 수식어가 있는 디렉티브에서만 실행된다.
  • .self event.currentTarget는 이벤트가 연결된 곳, evnet.target은 이벤트를 실행한 곳인데, .self는 이벤트가 연결된 곳과 실행된 곳이 같아야 실행된다.
  • .passive 화면의 렌더링과 로직의 동작처리를 분리시켜서 사용경험을 높임

Vue 키수식어

@keydown.meta : 윈도우키 혹은 맥의 command키, keyup에서는 실행되지 않음

<input @keyup.alt.enter="clear" /> alt+enter 같이 체이닝가능

@keydown.arrow-down.exact 다른 키를 같이 누르면 동작하지 않음

@click.middle.exact 휠클릭과 다른 키를 같이 누르면 동작하지 않음

폼입력 바인딩 - 양방향 데이터 바인딩

v-model

<h1>{{ msg }}</h1>
    <input type="text" 
           :value="msg"
           @input="msg = $event.target.value" />
		<input type="text" v-model="msg" /> 

인풋의 값으로 msg값이 변하고, 변화된 msg가 <h1>으로 업데이트된다.
:value="msg" @input="msg = $event.target.value"v-model="msg"으로 단축할 수 있다.

v-model은 text, 체크박스, Select태그별로 달라지는 이벤트를 통합하여 신경쓰지 않아도 된다.

주의할점은 v-model은 IME(문자조합 ex 한글자모결합) 중 v-model이 업데이트되지 않으며, input type의 속성값보다 v-model의 데이터를 우선한다.

textarea에서 v-model 사용시 style="white-space: pre-line;을 넣어줘야 줄바꿈 된다.

<textarea v-model="msg" @change="log"></textarea>
<h1 style="white-space: pre-line;">{{ msg }}</h1>

checkbox의 v-model과 빈 배열 []

<div id="app">
    <input type="checkbox" value="떡볶이" v-model="checked" />
    <input type="checkbox" value="라볶이" v-model="checked" />
    <input type="checkbox" value="계란튀김" v-model="checked" />
  </div>

<script>
    const App = {
      data() {
        return {
          checked: []
      }
    },
    watch: {
      checked(newValue) {
        console.log(newValue);
      }
    }
  }

// <input type="radio" v-model="picked" value="연어덮밥" /> ,
// picked: '', picked(newValue) { console.log(newValue); } 

v-model의 checked 값을 빈배열 []으로 넣으면 어떤 checkbox에 체크했는지 알 수 있다.

비슷한 방식으로 ratio는 단일선택이므로 picked 값을 빈값 ''으로 넣으면 어떤 ratio에 체크했는지 알 수 있으며, selectv-model="selected", selected: ''으로 사용할 수있다.

v-model 수식어

  • v-model.lazy : <input v-model.lazy="msg">일 때 input 대신 change 이후 동기화된다.
  • v-model.number: 사용자 입력을 자동으로 숫자 타입으로 변환
  • v-model.trim: 사용자 입력의 앞뒤공백 제거
profile
프론트엔드 개발자

0개의 댓글