vue.js

Vue Event

코딩 화이팅 2023. 5. 3. 14:16

Instance Life Cycle Hooks

  • 각 Vue 인스턴스는 생성될 때 일련의 초기화 단계를 걸친다.
    • 데이터 관찰 설정이 필요한 경우
    • 템플릿을 컴파일하는 경우
    • 인스턴스를 DOM에 마운트(연결)하는 경우
    • 데이터가 변경되어 DOM을 업데이트 하는 경우
  • 그 과정에서 사용자 정의 로직을 실행할 수 있는 Life Cycle Hooks도 호출
  • 크게 4개의 파트(생성, 부착, 갱신, 소멸)로 나뉜다.
  • 모든 Life Cycle Hooks는 자동으로 this 컨텍스트를 인스턴스에 바인딩하므로 데이터, 계산된 속성 및 메소드에 접근 가능(화살표 함수 사용 X)

beforeCreate / created

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>{{count}}</div>
      <button @click="count++">증가</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            count: 0,
          };
        },
        beforeCreate() {
          console.log("beforeCreate count : " + this.count);
        },
        created() {
          console.log("created count : " + this.count);
          console.log("created에 연결된 DOM : " + this.$el);
        },        
      });
    </script>
  </body>
</html>

beforeMount / mounted

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>{{count}}</div>
      <button @click="count++">증가</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            count: 0,
          };
        },
        beforeMount() {
          console.log("beforeMount count : " + this.count);
          console.log("beforeMount에 연결된 DOM : " + this.$el);
        },
        mounted() {
          console.log("mounted count : " + this.count);
          console.log("mounted에 연결된 DOM : " + this.$el);
        },
      });
    </script>
  </body>
</html>

beforeUpdated / updated

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>{{count}}</div>
      <button @click="count++">증가</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            count: 0,
          };
        },      
        beforeUpdate() {
          console.log("beforUpdate 호출");
        },
        updated() {
          console.log("updated 호출");
          console.log("updated count : " + this.count);
        },
        // 파괴는 따로 하지는 않겠다.
      });
    </script>
  </body>
</html>

처음에는 아무것도 뜨지 않았다가 값이 변경되면 위와 같이 update된 값들이 호출된다.

Vue Event Handling

Vue Listening to Event

v-on 디렉티브를 사용하여 DOM 이벤트를 듣고 트리거될 때 JavaScript를 실행할 수 있음

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- 이벤트 청취 -->
      <button @click="count+=1">증가</button>
      <!-- v-on : @ -->
      <div>{{count}}</div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            count: 0,
          };
        },
      });
    </script>
  </body>
</html>

Vue Method Event Handler

  • 많은 이벤트 핸들러의 로직은 복잡하여 v-on 속성 값으로 작성하기는 간단하지 않음
  • 때문에 v-on이 호출하고자하는 method의 이름을 받는 이유
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- 이벤트 메소드 처리 -->
      <button @click="greet">인사</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "OPP",
          };
        },
        methods: {
          //event라고 하는것은 넘기지 않아도 괜찮아~~
          greet(event) {
            alert(`${this.name}님 하이요`);
            event.target.innerText = "얍";
            console.log(event);
          },
        },
      });
    </script>
  </body>
</html>

처음에는 인사라는 버튼으로 시작을 하지만 인사 버튼을 누르면

메시지가 뜨고 확인을 누르면

얍이라는 버튼으로 바뀌고 이벤트들의 속성들을 볼 수 있다.

Vue Method in Inline Handlers

  • 메소드 이름을 직접 바인딩 하는 대신 인라인 JavaScript 구문에 메소드를 사용할 수도 있음
  • 때로 인라인 명령문 핸들러에서 원본 DOM 이벤트에 엑세스 해야할 수도 있음
    $event 변수를 사용해 메소드에 전달할 수 있음
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- 이벤트 메소드 인자 넘겨보기  -->
      <button @click="greet1('봉준르')">인사</button>
      <button @click="greet2($event, '봉준르')">인사</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "OPP",
          };
        },
        methods: {
          greet1(msg, e) {
            alert(`${this.name}${msg}`);
            console.log(e);
          },
          //봉준르라는 msg를 넘겨받아 쓸 수 있다.msg와 e의 순서는 바뀌면 안됨.
          //e라고 하는 걸 파라미터로 받았지만 지정해준게 없으니 뭔지 알 수가 없음
          greet2(e, msg) {
            alert(`${this.name}${msg}`);
            console.log(e);
          },
          //$event를 붙여주면 event를 받아올 수 있다.
        },
      });
    </script>
  </body>
</html>

왼쪽 인사

오른쪽 인사

Vue Event Modifier

  • 이벤트 핸들러 내부에서 event.preventDefault()(기본 이벤트를 막아줌)등을 호출하는 것은 보편적인 일이다.
  • 메소드 내에서는 쉽게 작업을 할 수 있지만, methods는 DOM의 이벤트를 처리하는 것보다 data 처리를 위한 로직만 작업하는 것이 좋음.
  • v-on 이벤트에 이벤트 수식어를 제공
  • 체이닝 가능(여러개 붙일 수 있음)
  • prevent : event.preventDefault() 호출-제출 이벤트가  페이지를 다시 로드X
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- 이벤트 수식어   -->
      <h2>페이지이동</h2>
      <a href="test03.html" @click="sendMsg">페이지 이동막기1</a><br />
      <a href="test03.html" @click="sendMsg2">페이지 이동막기2</a><br />
      <a href="test03.html" @click.prevent="sendMsg">페이지 이동막기3</a><br />
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "OPP",
          };
        },
        methods: {
          sendMsg() {
            alert("막아");
          },
          sendMsg2(event) {
            alert("막아");
            event.preventDefault();
          },
        },
      });
    </script>
  </body>
</html>

1번을 누르면

페이지 이동을 해버린다. 하지만 2번과 3번을 누르면 첫번째 사진처럼 막아라는 alert창이 뜨고 그 페이지에 그대로 머물게 된다.

Vue Key Modifier

  • Vue는 키 이벤트를 수신할 때 v-on에 대한 키 수식어를 추가할 수 있음
  • .enter(.13)
  • .tab
  • .delete("Delete"와 "Backspace"키 모두 캡쳐)
  • .esc
  • .space
  • .up / .down / .left / .right
  • 전역 config.keyCodes 객체를 통해 사용자 지정 키 수식어 별칭 지정 가능
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- 이벤트 키 수식어   -->
      <h2>이름 검색</h2>
      <input type="text" v-model="name" placeholder="이름 입력1" id="search" />
      <button @click="send">전송</button><br />
      이거는 전송을 눌렀을 때 alert
      <input
        type="text"
        v-model="name"
        placeholder="이름 입력2"
        @keyup="send"
      /><br />
      입력이 끝나서 키보드가 위로 올라왔을 때 alert창이 뜬다.
      <input
        type="text"
        v-model="name"
        placeholder="이름 입력3"
        @keyup.13="send"
      /><br />
      13은 엔터의 의미로 엔터를 치면 alert창이 뜬다.
      <!-- 위 아래는 같다 -->
      <input
        type="text"
        v-model="name"
        placeholder="이름 입력3"
        @keyup.enter="send"
      /><br />
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "OPP",
          };
        },
        methods: {
          send() {
            // document.querySelector("#search").value
            alert(this.name);
          },
        },
      });
    </script>
  </body>
</html>

Vue Bindings

ref, $refs

  • $refs : ref 속성이 등록된 자식 컴포넌트와 DOM 엘리먼트 객체
    템플릿이나 계산된 속성에서 사용X
  • ref : 엘리먼트 또는 자식 컴포넌트에 대한 참조를 등록하는데 사용
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <!-- $refs, ref   -->
      <h2>이름 등록</h2>
      <input type="text" v-model="name" placeholder="이름 입력" ref="name" />
      <!-- 이름중복체크 -->
      <button @click="check">중복쳌</button>
      <button @click="send">전송</button><br />
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "OPP",
          };
        },
        methods: {
          send() {
            alert(`${this.name} 등록`);
          },
          check() {
            //만약에 통과하지 못했다면 다시 input태그에 바로 작성이 가능하도록 활성화가 되면 좋겠다.
            // this.name : 요걸 이용해서 우리의 back 서버로 요청을 날리겠다.
            //입력을 하지 않았을 때만 판단~~ / 실제로는 서버로 요청을 날려서.. 그 여부 또한 확인해주는게 좋음
            if (this.name.length === 0) {
              alert("아이디를 입력해주세요.");
              this.$refs.name.focus();
              console.log(this.$refs);
              console.log(this.$refs.name);
              return;
            }
            alert("아이디 중복쳌 성공");
          },
        },
      });
    </script>
  </body>
</html>

이름이 등록된 상태에서 중복쳌을 누르면 아래와 같은 alert가 뜬다.

아무것도 입력되지 않은 상태에서 중복쳌을 누르면 아래와 같이 alert가 뜬다.

 

$ref가 뭔지 출력되고, $ref.name이 출력된다. 그리고 이름 입력란이 다시 활성화가 돼 바로 입력할 수 있게 해준다.

Class Bindings

  • 데이터 바인딩은 엘리먼트의 클래스 목록과 인라인 스타일을 조작하기 위해 일반적으로 사용
  • 문자열 이외에 객체 또는 배열을 이용할 수 있음.
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
    <style>
      div {
        width: 200px;
        height: 200px;
        border: 1px solid black;
      }
      .dark {
        background-color: black;
        color: white;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div v-bind:class="myclass"></div>
      <div :class="{dark: isDark}"></div>
      isDark를 통해 dark라는 것을 true,false 만들어준다.
      <button @click="toggle">다크모드전환</button>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            myclass: {
              dark: true,
              //   white: true,
            },
            isDark: false,
          };
        },
        methods: {
          toggle() {
            this.isDark = !this.isDark;
            isDark를 true,false를 반대로 해준다.
          },
        },
      });
    </script>
  </body>
</html>

다크모드전환을 누르면 밑에 얍이 검정 흰색으로 바뀐다.

Form Input Bindings

  • v-model 디렉티브를 사용하여 form input과 textarea 엘리먼트에 양방향 데이터 바인딩을 생성할 수 있음
  • text와 textarea : value, input 이벤트 사용
  • checkbox, radio : checked, change 이벤트 사용
  • select : value, chanege 이벤트 사용
  • v-model은 모든 form 엘리먼트의 초기 value와 checked 그리고 selected 속성을 무시함

Form : text, textarea

텍스트 영역의 보간 (<textarea> {{message}} </textarea>)은 작동X v-model을 사용

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <input type="text" v-model="name" placeholder="이름 입력" /> <br />
      <textarea v-model.lazy="msg"></textarea><br />
      v-model.lazy : 작성하고 벗어나는 순간 바뀐다.
      <!-- <textarea>{{msg}}</textarea><br />  요런식으로는 작성 x  -->

      <div>{{name}}님에게 보내는 메시지는 {{msg}}와 같습니다.</div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            name: "",
            msg: "",
          };
        },
      });
    </script>
  </body>
</html>

Form : checkbox

  • 하나의 체크박스일 경우 boolean 값을 표현
  • 여러개의 체크박스는 같은 배열을 바인딩할 수 있음
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>이메일 수신 동의? <input type="checkbox" v-model="email" /></div>
      <div>로봇이니? <input type="checkbox" v-model="robot" true-value="Y" false-value="N" /></div>
      true-value="Y" false-value="N"로 바꿔 줄 수 있다.
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            email: false,
            robot: "Y",
          };
        },
      });
    </script>
  </body>
</html>

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>
        <h2>내가 가고 싶은 여행지~~ 체크해주세요.</h2>
        <input type="checkbox" id="busan" v-model="checkAreas" value="부산" />
        <label for="busan">부산</label>
        label을 넣어서 부산이나 일본을 눌러도 체크가 되게 만들 수 있다.
        <input type="checkbox" id="japan" v-model="checkAreas" value="일본" />
        <label for="japan">일본</label>

        <p>나는 이번에 여기를 갈거야 `~ {{checkAreas}}</p>
      </div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            checkAreas: [],
          };
        },
      });
    </script>
  </body>
</html>

Form : radio

라디오 박스일 경우 선택된 항목의 value 속성의 값을 관리

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>
        <h2>현재 당신이 속해있는 캠퍼스를 고르세요</h2>
        <input type="radio" id="seoul" v-model="campus" value="seoul" />
        <label for="seoul">서울</label>
        <input type="radio" id="daejeon" v-model="campus" value="daejeon" />
        <label for="daejeon">대전</label>
        <input type="radio" id="buk" v-model="campus" value="buk" />
        <label for="buk">부울경</label>
        <input type="radio" id="gumi" v-model="campus" value="gumi" />
        <label for="gumi">구미</label>
        <input type="radio" id="gwangju" v-model="campus" value="gwangju" />
        <label for="gwangju">광주</label>

        <p>나의 캠퍼스는 `~ {{campus}}</p>
      </div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            campus: "",
          };
        },
      });
    </script>
  </body>
</html>

Form : select(단일)

  • select box일 경우 선택된 항목의 value 속성의 값을 관리
  • v-model 표현식의 초기 값이 어떤 옵션에도 없으면 <select> 엘리먼트는 '선택없음' 상태로 렌더링
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>
        <h2>현재 당신이 속해있는 캠퍼스를 고르세요</h2>
        <select v-model="campus">
          <option value="" disabled>선택하세요~</option>
          <option value="seoul">서울</option>
          <option value="daejeon">대전</option>
          <option value="buk">부울경</option>
          <option value="gumi">구미</option>
          <option value="gwangju">광주</option>
        </select>

        <div v-if="campus">
          <p>나의 캠퍼스는 {{campus}}</p>
        </div>
        캠퍼스가 있을 때만 보여주게 하기

      </div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            campus: "",
          };
        },
      });
    </script>
  </body>
</html>

미리 배열로 만들어놓고 만든 배열들을 반복문으로 불러오기

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>
        <h2>지망하는 캠퍼스를 골라보세요</h2>
        <select v-model="campus" name="campus">
          <option v-for="area in areas" :value="area.value">{{area.name}}</option>
        </select>

        <div v-if="campus">
          <p>나의 지망 캠퍼스는 {{campus}}</p>
        </div>
      </div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            campus: "",
            areas: [
              {
                name: "서울",
                value: "seoul",
              },
              {
                name: "대전",
                value: "daejeon",
              },
              {
                name: "부울경",
                value: "buk",
              },
              {
                name: "구미",
                value: "gumi",
              },
              {
                name: "광주",
                value: "gwangju",
              },
            ],
          };
        },
      });
    </script>
  </body>
</html>

Form : select(다중)

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>Vue</title>
  </head>
  <body>
    <div id="app">
      <div>
        <h2>지망하는 캠퍼스를 골라보세요</h2>
        <select v-model="campus" multiple>
          <option value="" disabled>선택하세요~</option>
          <option value="seoul">서울</option>
          <option value="daejeon">대전</option>
          <option value="buk">부울경</option>
          <option value="gumi">구미</option>
          <option value="gwangju">광주</option>
        </select>

        <div v-if="campus">
          <p>나의 지망 캠퍼스는 {{campus}}</p>
        </div>
      </div>
    </div>

    <script>
      const app = new Vue({
        el: "#app",
        data() {
          return {
            campus: [],
            // 배열로 바꿔줘야된다.
          };
        },
      });
    </script>
  </body>
</html>