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

2023. 12. 20. 11:03뷰(Vue)

반응형

 

주 단위로 Vue 스터디를 진행했던 내용들을 그냥 개인적으로 정리하기 위해서 작성중인 글이다.

5장에 중요포인트는 주로 사용되는 이벤트를 보통 JS에서 많이 컨트롤 했었는데 그런부분들에 대해서 편의성 기능을 많이 넣어둔것 같다. 추후 사용시에 편리하게 사용 가능한 방법들에 대해서 보여주고 하는게 많았다.

이벤트 처리에 대한 설명이다. 주로 사용되는 부분들이 여기에 포함된다.

KeyUp, keyPress, keyDown, click, doubleClick 등등 자바스크립트로 확인하던 부분들이 모두 여기에 들어간다.

js로 특정 객체를 선택하여 이벤트를 걸지않고 onclick이벤트를 주던것과 동일하게 생각하면 될 듯 하다.

 
<div id="app">
      금액 : <input type="text" v-model.number="amount" /><br />
      <button v-on:click="balance += parseInt(amount)">입금</button>
      <button v-on:click="balance -= parseInt(amount)">인출</button>
      <br />
      <h3>계좌 잔고 : {{balance}}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { amount: 0, balance: 0 };
        },
      }).mount("#app");
    </script>

위와 같은 코드가 있다고 할 때 onclick 으로 특정 값을 변환하여 보여주고 하던부분을 Vue에서 제공하는 이벤트 핸들러를 사용하여 표현 하는 것으로 보면 된다.

  • 그리고 인라인 형태가 아닌 별도의 메서드를 명시하여 편하게 사용도 가능하다.
 
<div id="app">
      금액 : <input type="text" v-model.number="amount" /><br />
      <button @click="deposit">입금</button>
      <button @click="withdraw">인출</button>
      <br />
      <h3>계좌 잔고 : {{balance}}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { amount: 0, balance: 0 };
        },
        methods: {
          deposit() {
            let amt = parseInt(this.amount);
            if (amt <= 0) {
              alert("0보다 큰 값을 예금해야 합니다");
            } else {
              this.balance += amt;
            }
          },
          withdraw() {
            let amt = parseInt(this.amount);
            if (amt <= 0) {
              alert("0보다 큰 값을 인출할 수 있습니다");
            } else if (amt > this.balance) {
              alert("잔고보다 많은 금액을 인출할 수 없습니다");
            } else {
              this.balance -= amt;
            }
          },
        },
      }).mount("#app");
    </script>
  • 주의사항으로는 인라인형태로 사용 할 경우 화살표함수를 사용해야 this연결이 전역이 아닌 컴포넌트에서 관리하는 대상을 바라본다는 것이다.
 
<div id="app">
      <input id="a" type="text" :value="name" @input="(e) => this.name = e.target.value" />
      <br />
      입력하신 이름 : <span>{{name}}</span>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { name: "" };
        },
      }).mount("#app");
    </script>

지원되는 이벤트는 JS에서 관리하던 대부분의 이벤트를 대부분 지원 하는 것 같다.

preventDefault()

stopPropagation()

또한 당연히 지원한다.

contextmenu(오른쪽 클릭시 브라우저에 보여지는 팝업) 또한 이벤트로 막을 수 있다.

<div id="app">
      <div @contextmenu="ctxStop" style="position: absolute; top: 5px; right: 5px; bottom: 5px; left: 5px">
        <a href="https://facebook.com" @click="confirmFB">페이스북</a>
      </div>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        methods: {
          ctxStop(e) {
            e.preventDefault();
          },
          confirmFB(e) {
            if (!confirm("페이스북으로 이동할까요?")) {
              e.preventDefault();
            }
          },
        },
      }).mount("#app");
    </script>

contextmenu를 막는 간단한 방법또한 지원한다.

<div id="app">
      <div @contextmenu.prevent style="position: absolute; top: 5px; right: 5px; bottom: 5px; left: 5px">
        <a href="https://facebook.com" @click="confirmFB">페이스북</a>
      </div>
    </div>

마찬가지로 이벤트 전파를 막는 stopPropagation() 또한 축약버전으로 지원하고있다.

1번

<div id="app">
  <div id="outer" @click.stop="outerClick">
    <div id="inner" @click.stop="innerClick"></div>
  </div>
</div>

그리고 이벤트가 포착되는 순간에 바로 멈추도록 다음과 같이 chaining하여 사용 가능한데 다음과 같이 하게되면 동작이 조금 다르게 된다.

2번

<div id="app">
      <div id="outer" @click.capture.stop="outerClick">
        <div id="inner" @click.stop="innerClick"></div>
      </div>
    </div>

1번의 경우 inner, outer를 누르면 각 click메서드가 동작하는데 capture를 통해서 이벤트 감지순간을 잡게되면 outer만 동작한다.

그외에도 once도 있는데 이 경우에는 단 한번만 이벤트가 동작하고 멈추게된다.

<div id="app">
      금액 : <input type="text" v-model.number="amount" /><br />
      <button @click="balance += parseInt(amount)">입금</button>
      <button @click="balance -= parseInt(amount)">인출</button>
      <button @click.once="balance += 10000">계좌 개설 이벤트</button>
      <br />
      <h3>계좌 잔고 : {{balance}}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { amount: 0, balance: 0 };
        },
      }).mount("#app");
    </script>

이벤트에서 제공하는 keyCode를 사용하는 부분도 동일하게 사용된다.

input을 사용한 검색창에서 엔터키코드(13)을 확인하고 비동기 요청을 하는부분이다.

 
<div id="app">
      이름 : <input type="text" v-model.trim="name" @keyup="search" placeholder="영문 두글자 이상을 입력하세요" /><br />
      <ul>
        <li v-for="c in contacts">{{c.name}} : {{c.tel}}</li>
      </ul>
      <div v-show="isLoading">검색중</div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript" src="https://unpkg.com/axios"></script>
    <script type="text/javascript" src="https://unpkg.com/lodash"></script>
    <script type="text/javascript">
      const BASEURL = "https://contactsvc.bmaster.kro.kr";
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { name: "", contacts: [], isLoading: false };
        },
        methods: {
          search(e) {
            if (e.keyCode === 13) {
              if (this.name.length >= 2) {
                this.fetchContacts();
              } else {
                this.contacts = [];
              }
            }
          },
          fetchContacts() {
            this.isLoading = true;
            axios.get(BASEURL + `/contacts_long/search/${this.name}`).then((response) => {
              this.isLoading = false;
              this.contacts = response.data;
            });
          },
        },
      }).mount("#app");
    </script>

이 경우에도 기존에는 조건을 다 명시해야했지만 Vue에서는 수식어로 제공한다.(enter)

<input type="text" v-model.trim="name" @keyup.enter="search" placeholder="영문 두글자 이상을 입력하세요" /><br />

다양하게 조합하여 사용하는 것도 가능하여 단축키를 제공 해야 하는 형태 일 때 편하게 사용 가능 할 듯 하다.

마우스 버튼과 관련된 이벤트 또한 마찬가지로 존재한다.

left, right, middle 등이 존재하고 currentIndex값으로 class를 active하게 해주는 형태로 사용한 코드가 아래와 같다.(05-13)

<div id="app">
      <div
        class="container"
        style="position: absolute; top: 0; left: 0; bottom: 0; right: 0"
        @contextmenu.prevent
        @click.left="if (currentIndex > 0) currentIndex--;"
        @click.right="if (currentIndex < itemlist.length-1) currentIndex++;"
        @click.ctrl.left="currentIndex=0"
        @click.ctrl.right="currentIndex=itemlist.length-1"
      >
        <div>
          - 왼쪽버튼 : 위로<br />
          - 오른쪽 버튼 : 아래로<br />
          - CTRL + 왼쪽 버튼 : 처음으로<br />
          - CTRL + 오른쪽 버튼 : 마지막으로<br />
        </div>
        <hr />
        <ul class="list-group">
          <li
            class="list-group-item"
            :class="index === currentIndex ? 'active' : ''"
            v-for="(item,index) in itemlist"
            :key="item"
          >
            {{item}}
            <span v-if="index === currentIndex" className="float-right badge badge-secondary">
              <i class="fa fa-arrow-left" aria-hidden="true"></i>
            </span>
          </li>
        </ul>
      </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return {
            itemlist: ["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9"],
            currentIndex: 0,
          };
        },
      }).mount("#app");
    </script>

여러개의 키 옵션이 겹치는 경우 exact 수식어를 주어서 정확한 키 입력값에 대해서 확인 및 처리가 가능하다.

click, click.ctrl, click.ctrl.alt는 모두 겹치는 부분이 존재하기 때문에 생각하던 대로 동작하지 않게됨.

<div id="app">
      <ul>
        <li>마우스 왼쪽만 클릭 : 1씩 증가</li>
        <li>CTRL+왼쪽 클릭 : 10씩 증가</li>
        <li>CTRL+ALT+왼쪽 클릭 : 100씩 증가</li>
      </ul>
      <button @click.exact="num=num+1" @click.ctrl.exact="num=num+10" @click.ctrl.alt.exact="num=num+100">
        클릭하세요</button
      ><br />
      <br />
      <h3>카운트 : {{num}}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
      var vm = Vue.createApp({
        name: "App",
        data() {
          return { num: 0 };
        },
      }).mount("#app");
    </script>
반응형