Dandy Now!
  • [개발자의품격][부트캠프][1기][21차시] Vue.js #10 | 전역 컴포넌트, 커스텀 디렉티브
    2022년 03월 15일 15시 56분 12초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    전역 컴포넌트

    main.js에 자식 컴포넌트를 import 하고 app.component를 추가하면 전역 컴포넌트로 사용할 수 있다. 여기에서는 app.component의 첫 번째 파라미터명을 'page-title'로 작성하였는데, 원하는 이름을 쓰면 된다.

    // src/main.js
    ...
    import PageTitle from './components/fragments/PageTitle.vue'
    
    // createApp(App).use(store).use(router).mount('#app') // 기존
    // 위 코드에 app을 붙여 아래 코드와 같이 분리한다. 이때 import한 컴포넌트를 추가한다.
    const app = createApp(App)
    app.use(store)
    app.use(router)
    app.component('page-title', PageTitle) // 추가
    app.mount('#app')

     


     

    커스텀 디렉티브

    v-focus

    v-focus라는 커스텀 디렉티브를 생성 및 적용하는 코드를 작성한다. <input> 태그 속성에 커스텀 디렉티브 v-focus를 넣는다.

    // src/views/5_advanced/CustomDirectiveView.vue
    <template>
      <div>
        <div><input type="text" name="" id="" v-focus /></div>
      </div>
    </template>
    <script>
    export default {
      ...
      // directives에 커스텀 디렉티브 focus를 만든다.
      directives: {
        focus: {
          mounted(el) {
            el.focus() // focus() 함수를 이용해 입력창에 포커스를 위치시킨다.
          }
        }
      },

     

    [그림 1] v-focus 적용 화면

     

    v-number

    v-number라는 커스텀 디렉티브를 생성 및 적용하는 코드를 작성한다. v-number 디렉티브의 기능은 숫자만 입력되도록 하는 것이다. <input> 태그 속성에 커스텀 디렉티브 v-number를 넣는다. directives안에서 커스텀 디렉티브를 생성한다. [그림 2]와 같이 입력창에 0~9를 입력하면 콘솔 창에서 아스키코드 값이 출력된다.

    // src/views/5_advanced/CustomDirectiveView.vue
    <template>
      <div>
        ...
        <div><input type="text" name="" id="" v-number /></div>
      </div>
    </template>
    <script>
    export default {
      ...
      // directives에 커스텀 디렉티브 number를 만든다.
      directives: {
        ...
        number: {
          mounted(el) {
            el.addEventListener('keydown', () => {
              console.log(event.key, event.keyCode)
            })
          }
        }
      },

     

    [그림 2] 콘솔 창에 출력된 0~9의 아스키 코드 값

     

    커스텀 디렉티브 number에 특정 키만 입력 가능하도록 추가적인 기능을 구현한다. 이때 event.preventDefault() 함수를 사용하였다. 그런데 [그림 3]과 같이 한글은 event.preventDefault()가 작동하지 않는다. 따라서 아래 코드는 실무에서 사용하지 않는다.

    // src/views/5_advanced/CustomDirectiveView.vue
    <script>
    export default {
      ...
      directives: {
        ...
        number: {
          mounted(el) {
            el.addEventListener('keydown', () => {
              console.log(event.key, event.keyCode)
              // 특정 키만 입력 가능하게 만든다.
              // 48~57 || backspace || left || right || delete || enter || tab
              if (
                !(
                  (event.keyCode >= 48 && event.keyCode <= 57) ||
                  event.keyCode === 8 ||
                  event.keyCode === 37 ||
                  event.keyCode === 39 ||
                  event.keyCode === 46 ||
                  event.keyCode === 13 ||
                  event.keyCode === 9
                )
              ) {
                event.preventDefault() // preventDefault() 함수는 이벤트가 일어나는 것을 막는다.
              }
            })
          }
        }
      },

     

    [그림 3] 한글이 작성되는 문제

     

    input 시점을 이용한 v-number

    키 이벤트 시점 중 사용자 눈에는 보이지 않지만 value가 할당되는 input 시점을 이용하여 코드를 작성한다.

    // src/views/5_advanced/CustomDirectiveView.vue
    export default {
      ...
      directives: {
        ...
        // 키 이벤트 시점: keydown, keypress, input, keyup
        // keyup 시점에야 비로소 사용자 눈에 보여지고,
        // input 시점에는 value가 할당된다.
        // 이점을 이용한다.
        number: {
          mounted(el) {
            el.addEventListener('input', () => {
              console.log(event.target.value)
              event.target.value = event.target.value.replace(/[^0-9]/g, '')
            })
          }
        }

     

    ※ input 시점을 이용한 커스텀 디렉티브 전체 코드(lowercase, uppercase, korean 포함)

    더보기
    <!-- src/views/5_advanced/CustomDirectiveView.vue -->
    <template>
      <div>
        <div><input type="text" name="" id="" v-focus /></div>
        <div><input type="text" name="" id="" v-number /></div>
        <div><input type="text" name="" id="" v-lowercase /></div>
        <div><input type="text" name="" id="" v-uppercase /></div>
        <div><input type="text" name="" id="" v-korean /></div>
      </div>
    </template>
    <script>
    export default {
      components: {},
      directives: {
        focus: {
          mounted(el) {
            el.focus()
          }
        },
        // 키 이벤트 시점: keydown, keypress, input, keyup
        // keyup 시점에야 비로소 사용자 눈에 보여지고,
        // input 시점에는 value가 할당된다.
        // 이점을 이용한다.
        number: {
          mounted(el) {
            el.addEventListener('input', () => {
              console.log(event.target.value)
              event.target.value = event.target.value.replace(/[^0-9]/g, '')
            })
          }
        },
        lowercase: {
          mounted(el) {
            el.addEventListener('input', () => {
              console.log(event.target.value)
              event.target.value = event.target.value.replace(/[^a-z]/g, '')
            })
          }
        },
        uppercase: {
          mounted(el) {
            el.addEventListener('input', () => {
              console.log(event.target.value)
              event.target.value = event.target.value.replace(/[^A-Z]/g, '')
            })
          }
        },
        korean: {
          mounted(el) {
            el.addEventListener('input', () => {
              console.log(event.target.value)
              event.target.value = event.target.value.replace(
                /[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣]|\|/g,
                ''
              )
            })
          }
        }
      },
      data() {
        return {
          sampleData: ''
        }
      }
    }
    </script>

     

    ※ input 시점을 이용한 커스텀 디렉티브 전체 코드(main.js)

    더보기
    // src/main.js
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    import PageTitle from './components/fragments/PageTitle.vue'
    
    import 'bootstrap/dist/css/bootstrap.min.css'
    import 'bootstrap/dist/js/bootstrap.js'
    
    const app = createApp(App)
    app.use(store)
    app.use(router)
    app.component('page-title', PageTitle)
    
    app.directive('focus', {
      mounted(el) {
        el.focus()
      }
    })
    
    app.directive('number', {
      mounted(el) {
        el.addEventListener('input', () => {
          event.target.value = event.target.value.replace(/[^0-9]/g, '')
        })
      }
    })
    
    app.directive('lowercase', {
      mounted(el) {
        el.addEventListener('input', () => {
          event.target.value = event.target.value.replace(/[^a-z]/g, '')
        })
      }
    })
    
    app.directive('uppercase', {
      mounted(el) {
        el.addEventListener('input', () => {
          event.target.value = event.target.value.replace(/[^A-Z]/g, '')
        })
      }
    })
    
    app.directive('korean', {
      mounted(el) {
        el.addEventListener('input', () => {
          event.target.value = event.target.value.replace(
            /[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣]|\|/g,
            ''
          )
        })
      }
    })
    
    app.mount('#app')
    728x90
    반응형
    댓글