원쌤의 Vue.js 퀵스타트 책을 보았다(Vue3)_2

2023. 12. 5. 17:46뷰(Vue)

반응형

신규 프로젝트에 적용시키기 전 1주일 마다 원쌤의 Vue.js 퀵스타트 책 기준으로 1장 ~ 2장씩 스터디를 진행 하였다.

 

3장에서의 내용은 Vue에서 기본적으로 사용되는 문법에 관련된 것이었다.

  • v-bind —> 앞에 : 를 붙이면 축약처리 v-bind:href = url주소 === :href = url주소
  • v-text
  • v-html
  • v-on —> 앞에@를 붙이면됨

처음에 볼 때는 생소하였으나 결국은 하나의 문법이다. 
( {{}}는 콧수염을 닮았다고 하여 Mustache Expression 이라고도 함.)

위와같이 바인딩하여 표시되는 애들은 단방향 데이터 바인딩 이라고 한다.

데이터가 변경 되는걸 감지하거나 해서 새로 렌더링 해주는게 아니라는 거다.

그런부분들을 연동하여 데이터 변경 될 때 마다 그려주는 문법이 존재하는데

v-model 이다.

책 03-05.html 파일에서는 v-model=”hobby”에 값을 바인딩하여 변경을 감지하여 렌더링 하는 모습을 보여준다.

data() 영역 안에 v-model의 대상이 되는 값과 매칭이 되야한다.

<div id="app">
      <div>
        <h2>취미생활</h2>
        <input type="checkbox" id="hobbyA" value="A" v-model="hobby" />
        <label for="hobbyA">운동</label><br />
        <input type="checkbox" id="hobbyB" value="B" v-model="hobby" />
        <label for="hobbyB">독서</label><br />
        <input type="checkbox" id="hobbyC" value="C" v-model="hobby" />
        <label for="hobbyC">음악</label><br />
        <input type="checkbox" id="hobbyD" value="D" v-model="hobby" />
        <label for="hobbyD">댄스</label><br />
        <input type="checkbox" id="hobbyE" value="E" v-model="hobby" />
        <label for="hobbyE">역사</label><br />
      </div>
      <div>
        <h2>상품 분류 선택</h2>
        <select v-model="category">
          <option value="">----상품 분류를 선택하세요----</option>
          <option value="C01">레저</option>
          <option value="C02">가전</option>
          <option value="C03">음식</option>
          <option value="C04">도서</option>
          <option value="C05">주방</option>
        </select>
      </div>
      <hr />
      <div>
        선택한 취미 : {{hobby.join(',')}} <br />
        선택한 상품 분류 : {{category}}
      </div>
  </div>

var vm = Vue.createApp({
        name: "App",
        data() {
          return {
            hobby: [],
            category: "",
          };
        },
      }).mount("#app");
  • v-model 과 함께 쓰이는 수식어(Modifier)가 존재한다.

v-model.lazy —> 입력 후 바로 렌더링 안되고 포커스가 이동하는 이벤트 발생시 변경적용됨.

v-model.number —> 숫자 입력시 number타입으로 자동 형변환되어 적용 대신 영문+숫자 입력시 문자로보고 숫자+영어 형태로 입력시 숫자만 바인딩됨

v-model.trim —> 앞뒤 공백 자동제거

v-model을 사용하게 되면 한글 입력을 받을때 마지막 입력 값이 짤리는 경우가 발생한다.

그런경우 change이벤트에 반응하는 js function을 만들어서 연결하여 처리가 가능하다.

인터넷에 v-model의 경우 축약형이 없는지 궁금해서 찾아봤는데.. 아래에서 사용되는것들의 모음이 v-model 이였다.

v-model === v-bind:value + v-on:input

<input id="a" type="text" :value="name" @input="changeName" />
<input id="a" type="text" v-bind:value="name" v-on:input="handle"="changeName" />

var vm = Vue.createApp({
        name: "App",
        data() {
          return { name: "" };
        },
        methods: {
          changeName(e) {
            this.name = e.target.value;
          },
        },
      }).mount("#app");
  • v-show

화면에 보여줄지 말지 결정하는 값이다. 렌더링자체는 수행이 된다. (js기능중 hide느낌인것 같다.)

예제에서는 입력된 값이 특정 조건일 때 이미지를 보여주고 있었다.

css상으로 display: none; 이 자동으로 적용되고 있었다.

<div id="app">
      예금액 : <input type="text" v-model="amount" />
      <img
        v-show="amount < 0"
        src="https://contactsvc.bmaster.kro.kr/img/error.png"
        title="마이너스는 허용하지 않습니다"
        style="width: 15px; height: 15px; vertical-align: middle"
      />
  </div>

var vm = Vue.createApp({
        data() {
          return { amount: "" };
        },
      }).mount("#app");

if-else-if-else 3가지 스탭을 가진 디렉티브다. 별다른 설명은 필요없을듯 하다..?
사용하는 태그명만 다를 뿐이지 익숙한 모습이다.

  • v-if
  • v-else-if
  • v-else
 
<div id="app">
    잔고 : <input type="text" v-model="balance" />
    <br />
    회원님의 등급 :
    <span v-if="balance >= 1000000">Gold</span>
    <span v-else-if="balance >= 500000">Silver</span>
    <span v-else-if="balance >= 200000">Bronze</span>
    <span v-else>Basic</span>
  </div>
  <script type="text/javascript" src="https://unpkg.com/vue"></script>
  <script type="text/javascript">
    var vm = Vue.createApp({
      name: "App",
      data() {
        return { balance: 0 };
      },
    }).mount("#app");
  </script>
  • v-for 디렉티브

for 반복문이다.

여기서 중요한 부분은 key로 선언된 부분에 고유 값 이 필요하고 필수값이라는것 이다.(대부분PK를 이용한다.)
Vue3에서는 v-for를 수행할때 key부분이 없는경우 정상동작 안하거나 에러를 보여준다.

<template v-for="(contact, index) in contacts" :key="contact.no">
            <tr>
              <td>{{contact.no}}</td>
              <td>{{contact.name}}</td>
              <td>{{contact.tel}}</td>
            </tr>
            <tr class="divider" v-if="index % 4 === 3">
              <td colspan="3"></td>
            </tr>
</template>

<script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return {
            contacts: [
              { no: 1011, name: "RM", tel: "010-3456-8299" },
              { no: 1012, name: "정국", tel: "010-3456-8298" },
              { no: 1013, name: "제이홉", tel: "010-3456-8297" },
              { no: 1014, name: "슈가", tel: "010-3456-8296" },
              { no: 1015, name: "진", tel: "010-3456-8295" },
              { no: 1016, name: "뷔", tel: "010-3456-8294" },
              { no: 1017, name: "지민", tel: "010-3456-8293" },
            ],
          };
        },
      }).mount("#app");
</script>
  • 주의사항

그냥 주어지는 인덱스 값을 사용 할 수도 있지만. 그렇게 되면 고유값을 사용 할 때 보다 성능이 떨어지게 된다.

(이유) 고유값을 기준으로 어떤게 변했는지 확인하여 처리하는 로직이 있음. 인덱스 값의 경우 같이 변경되므로 모든걸 새로 그려야하는 상황이 발생한다.

그리고 data()에 바인딩된 값을 변경 하는것은 직접 하면 안된다.(proxy로 인한 렌더링 이슈)

 
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>03-16</title>
    <style>
      #list {
        width: 600px;
        border: 1px solid black;
        border-collapse: collapse;
      }
      #list td,
      #list th {
        border: 1px solid black;
        text-align: center;
      }
      #list > thead > tr {
        color: yellow;
        background-color: purple;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <table id="list">
        <thead>
          <tr>
            <th>번호</th>
            <th>이름</th>
            <th>전화번호</th>
          </tr>
        </thead>
        <tbody id="contacts">
          <tr v-for="contact in contacts" :key="contact.no">
            <td>{{contact.no}}</td>
            <td>{{contact.name}}</td>
            <td>{{contact.tel}}</td>
          </tr>
        </tbody>
      </table>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var model = {
        contacts: [
          { no: 1011, name: "RM", tel: "010-3456-8299" },
          { no: 1012, name: "정국", tel: "010-3456-8298" },
          { no: 1013, name: "제이홉", tel: "010-3456-8297" },
          { no: 1014, name: "슈가", tel: "010-3456-8296" },
        ],
      };

      var vm = Vue.createApp({
        name: "App",
        data() {
          return model;
        },
      }).mount("#app");
    </script>
  </body>
</html>

위와 같을때 model에 직접 접근이 가능한데 이렇게 하는 경우 렌더링 변경이 없음.(프록시 객체를 통하지 않았기때문에…)

다음과 같이 console창에서 직접 조작가능.

ex) model.contacts[0].tel='010-9999-9999';

뷰 프록시 객체에 접근하여 조작하게 되면 변경사항이 바로 반영됨.

ex)vm.contacts.push( {no:1202, name:'ㅂ',tel:'010-5555-6666'})

  • v-pre

{{}} 머스타치 문법이 그대로 표출됨.

<span v-pre>{{message}}</span>
  • v-once

html요소를 단 한번만 렌더링 한다.

<span v-once>{{message}}</span>
  • v-cloak

렌더링시 머스타치 문법으로 표현된 문구가 제대로 값이 렌더링 되기전에 그대로 잠깐 보여질때가 있다. 거기에 대해서 css지정이 가능하다.
(잠깐 랜더링전 데이터 바인딩이 안된상태일때 {{}}}내부 값이 그대로 보여지는게 그게 싫다면 설정하면 된다.)

[v-cloak] {
        display: none;
      }

<div id="app" v-cloak>
      <table id="list">
        <thead>
          <tr>
            <th>번호</th>
            <th>이름</th>
            <th>전화번호</th>
          </tr>
        </thead>
        <tbody id="contacts">
          <tr v-for="contact in contacts" :key="contact.no">
            <td>{{contact.no}}</td>
            <td>{{contact.name}}</td>
            <td>{{contact.tel}}</td>
          </tr>
        </tbody>
      </table>
    </div>
반응형