danbibibi
article thumbnail
Published 2023. 5. 5. 15:55
[Vue 기초 3] Event, Binding WEB/front-end

v-on

DOM 이벤트를 듣고 해당 이벤트가 발생되면, 지정된 메소드를 호출

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue.js</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button v-on:click="counter += 1">클릭</button>
      <p>위 버튼을 클릭한 횟수는 {{counter}} 번 입니다.</p>
    </div>
    <script>
      new Vue({
        el: '#app',
        data: {
          counter: 0,
        },
      });
    </script>
  </body>
</html>
v-on:click = @click

 

method Event Handler

  • 이벤트 발생시 처리 로직을 v-on에 모두 넣기는 힘듦
  • v-on에서는 이벤트 발생시 처리해야 하는 method의 이름을 받아 처리
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <button v-on:click="greet">Greet</button>
  </div>
  <script>
    var vm = new Vue({
      el: "#app",
      data: {
        name: "DANBI",
      },
      methods: {
        greet: function (event) {
          alert("Hello " + this.name + "!");
          console.dir(event.target);
        },
      },
    });

      // JavaScript를 이용한 메소드를 호출도 가능
      //vm.greet(); // => 'Hello Vue.js!'
  </script>
</body>

</html>

 

Inline Event Handler

  • 메소드 이름을 직접 바인딩 하는 대신 인라인 JavaScript 구문에 메소드를 사용할 수도 있음
  • 원본 DOM 이벤트에 엑세스 해야 하는 경우 특별한 $event 변수를 사용해 메소드에 전달할 수도 있음
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue.js</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <form action="http://www.naver.com">
        <button v-on:click="greet1('HARRY')">Greet</button>
        <button v-on:click="greet2($event, 'DOBI')">Greet</button>
      </form>
    </div>
    <script>
      new Vue({
        el: '#app',
        methods: {
          greet1: function (msg) {
            alert('Hello ' + msg + '!');
            console.dir(event.target);
          },
          greet2: function (e, msg) {
            if (e) e.preventDefault();
            alert('Hello ' + msg + '!');
            console.dir(e.target);
          },
        },
      });
    </script>
  </body>
</html>

 

Event Modifier (이벤트 수식어)

  • method는 DOM의 이벤트를 처리하는 것 보다 data 처리를 위한 로직만 작업하는 것이 좋음
  • 이 문제를 해결하기 위해, Vue는 v-on 이벤트 수식어를 제공
  • 수식어는 점으로 표시된 접미사
<!-- 클릭 이벤트 전파 중단 --> 
<a v-on:click.stop="doThis"></a>

<!-- 제출 이벤트가 페이지를 다시 로드 하지 않음 --> 
<form v-on:submit.prevent="onSubmit"></form>

<!-- 수식어는 체이닝 가능 --> 
<a v-on:click.stop.prevent="doThat"></a>

<!-- 단순히 수식어만 사용 가능 --> 
<form v-on:submit.prevent></form>

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue.js</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <h2>페이지 이동</h2>

      <a href="test.html" @click="sendMsg1">페이지 이동 막기1</a><br />
      <a href="test.html" @click="sendMsg2">페이지 이동 막기2</a><br />
      <a href="test.html" @click.prevent="sendMsg1">페이지 이동 막기3</a><br />
    </div>
    <script>
      new Vue({
        el: '#app',
        methods: {
          sendMsg1() {
            alert('이동할까요?');
          },
          sendMsg2(e) {
            e.preventDefault();
            alert('이동막기');
          },
        },
      });
    </script>
  </body>
</html>

 

Key Modifier (키 수식어)

Vue는 키 이벤트를 수신할 때 v-on에 대한 키 수식어를 추가할 수 있음

<input v-on:keyup.enter="submit">
key code
.enter (.13)
.tab
.delete (Delete, Backspace 모두 캡처)
.esc
.space
.up
.down
.left
.right

 

ref, $refs

  • 뷰에서는 $refs 속성을 이용해 DOM에 접근할 수 있음
  • 단, 뷰의 가장 중요한 목적 중 하나는 개발자가 DOM을 다루지 않게 하는 것이므로, 되도록 ref 사용을 피하는 것이 좋음
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <style>
    .success {
      color: dodgerblue;
    }

    .fail {
      color: darkred;
    }
  </style>
</head>

<body>
  <div id="app">
    <h2>엘리먼트 참조하기</h2>
    <!-- 아이디 : <input type="text" v-model="id"> -->
    아이디 : <input type="text" v-model="id" ref="id" @keyup="idCheck" />
    <button @click="idCheck">아이디 중복 체크</button>
    <div v-bind:class="{success : isSuccess, fail : isFail}" v-bind:style="myStyle" v-html="msg"></div>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        id: '',
        msg: '',
        isSuccess: false,
        isFail: false,
        myStyle: {
          fontSize: '25px',
        },
      },
      methods: {
        idCheck() {
          if (this.id.length < 5 || this.id.length > 12) {
            this.msg = `아이디는 5자이상 12자리 이하입니다.`;
            this.$refs.id.focus();
            console.dir(this.$refs.id);
            this.isSuccess = false;
            this.isFail = false;
            return;
          } else {
            if (this.id === 'dobi') {
              this.msg = `<b>${this.id}</b>는 사용할 수 없습니다.`;
              this.isSuccess = false;
              this.isFail = true;
            } else {
              this.msg = `<b>${this.id}</b>는 사용할 수 있습니다.`;
              this.isSuccess = true;
              this.isFail = false;
            }
          }
          console.log(this.$refs.id.value);
        },
      },
    });
  </script>
</body>

</html>

 

 

CSS class binding

  • element의 class와 style을 변경
  • v-bind:class는 조건에 따라 class를 적용할 수 있음
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue.js</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      .active {
        background: rgb(106, 148, 238);
        color: white;
      }

      div {
        width: 200px;
        height: 200px;
        border: 1px solid #444;
      }
    </style>
  </head>

  <body>
    <div id="app">
      <div v-bind:class="{ active: isActive }">VueCSS적용</div>
      <button v-on:click="toggle">VueCSS</button>
    </div>
    <script type="text/javascript">
      new Vue({
        el: "#app",
        data: {
          isActive: false,
        },
        methods: {
          toggle: function () {
            this.isActive = !this.isActive;
          },
        },
      });
    </script>
  </body>
</html>

 

From Input binding

  • text와 textarea 태그는 value 속성과 input 이벤트를 사용함
  • 체크박스들과 라디오버튼들은 checked 속성과 change 이벤트를 사용
  • select 태그는 value를 prop으로, change를 이벤트로 사용

 

text, textarea

* textarea(여러줄을 가진 문장)의 경우, 보간법이 작동하지 않음 → v-model 사용

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <div>
      아이디 :
      <input v-model.trim="id" placeholder="아이디를 입력하세요" />
      <input v-model.lazy="id" placeholder="아이디를 입력하세요" />
    </div>
    <div>
      메세지 :
      <textarea v-model="message" placeholder="내용을 입력하세요"></textarea>
    </div>
    <p>{{ id }} 님에게 보내는 메세지 : {{ message }}</p>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        id: '',
        message: '',
      },
    });
  </script>
</body>

</html>
v-model은 기본적으로 사용자가 값을 변경할 때마다 자동으로 바인딩 갱신
.lazy 수식어를 추가하여 change 이벤트 이후에 동기화하도록 할 수 있음

 

checkbox

  • 하나의 체크박스는 단일 boolean 값을 가짐
  • 여러 개의 체크박스는 같은 배열을 바인딩 할 수 있음
  • 배열의 값과 cehckbox의 value 속성이 같을 경우 체크 처리됨
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <div> 가고 싶은 여행지를 선택하세요!</div>
    <input type="checkbox" id="seoul" value="서울" v-model="checkedAreas" />
    <label for="seoul">서울</label>
    <input type="checkbox" id="busan" value="부산" v-model="checkedAreas" />
    <label for="busan">부산</label>
    <input type="checkbox" id="jeju" value="제주" v-model="checkedAreas" />
    <label for="jeju">제주</label>
    <input type="checkbox" id="daejeon" value="대전" v-model="checkedAreas" />
    <label for="daejeon">대전</label>
    <input type="checkbox" id="gyeongju" value="경주" v-model="checkedAreas" />
    <label for="gyeongju">경주</label>
    <br />
    <span>체크한 이름: {{ checkedAreas }}</span>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        checkedAreas: [],
      },
    });
  </script>
</body>

</html>

 

radio

선택된 항목의 value 속성의 값을 관리

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <div> 이번에 다녀온 여행지를 선택해주세요!</div>
    <div>
      <input type="radio" id="seoul" value="서울" v-model="ckArea" />
      <label for="seoul">서울</label>
      <input type="radio" id="busan" value="부산" v-model="ckArea" />
      <label for="busan">부산</label>
      <input type="radio" id="jeju" value="제주" v-model="ckArea" />
      <label for="jeju">제주</label>
      <input type="radio" id="daejeon" value="대전" v-model="ckArea" />
      <label for="daejeon">대전</label>
      <input type="radio" id="gyeongju" value="경주" v-model="ckArea" />
      <label for="gyeongju">경주</label>
    </div>
    <span>선택한 지역 : {{ ckArea }}</span>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        ckArea: '경주',
      },
    });
  </script>
</body>

</html>

 

select

  • 선택된 항목의 value 속성의 값을 관리
  • v-model 표현식의 초기 값이 어떤 옵션에도 없으면, <select> element는 “선택없음” 상태로 렌더링 됨
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <div>
      <p>여행지를 선택하세오</p>
      <select v-model="selectedArea">
        <option disabled value="">선택하세요</option>
        <option value="seoul">서울</option>
        <option value="busan">부산</option>
        <option value="jeju">제주</option>
        <option value="daejeon">대전</option>
        <option value="gyeongju">경주</option>
      </select>
    </div>
    <span>선택한 지역 : {{ selectedArea }}</span><br />
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        selectedArea: '',
      },
    });
  </script>
</body>

</html>

 

다음과 같이 v-for를 이용하여 동적 option 렌더링도 가능하다!

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vue.js</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <div>
      <p>여행지를 선택하세오</p>
      <select v-model="selectedArea">
        <option v-for="option in options" v-bind:value="option.value">{{ option.text }}</option>
      </select>
    </div>
    <span>선택한 지역 : {{ selectedArea }}</span>
  </div>
  <script>
    new Vue({
      el: '#app',
      data: {
        selectedArea: '',
        options: [
          { text: '서울', value: 'seoul' },
          { text: '부산', value: 'busan' },
          { text: '대전', value: 'daejeon' },
          { text: '경주', value: 'gyeongju' },
          { text: '제주', value: 'jeju' },
        ],
      },
      created() {
        param = 'gyeongju';
        this.selectedArea = param;
      },
    });
  </script>
</body>

</html>

 

form Modifiers (폼 수식어)

.lazy

change 이벤트 이후에 동기화 가능

<input v-model.lazy="msg">

 

.number

사용자 입력을 자동으로 숫자로 형 변환

<input v-model.number="age" type="number">

 

.trim

사용자 입력에서 양쪽 공백을 제거

<input v-model.trim="msg">
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로