똑같은 삽질은 2번 하지 말자

Vee-Validate 사용법(in Nuxt) 본문

Vue

Vee-Validate 사용법(in Nuxt)

곽빵 2021. 6. 13. 17:55

개요

Vee-Validate 란?

Validation을 보다 간결하게 작성해주는걸 도와주는 라이브러리

 

이번에 사용한 버젼(Vue3 용은 꽤 다른방식이니 주의바람)

"vee-validate": "3.4.9",

 

vee-validate를 전역적으로 사용해 줄 수 있게 plugins에 등록해준다.

 

nuxt.config.js

plugins: [
  { src: '~/plugins/vee-validate', ssr: true },
],
// build를 설정안하면 ssr이 안되므로 반드시 해야한다.
build: {
  transpile: ['vee-validate/dist/rules'],
},

plugins/vee-validate.js

import Vue from 'vue'
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate'
import { required, digits, numeric, email, confirmed } from 'vee-validate/dist/rules' // 기본룰을 들록

// limit라는 validation을 만들어주었다.
extend('limit', (value, params) => {
  const [min, max] = params
  if ((value && value.length < min) || value.length > max) {
    return `{_field_} 은(는) ${min}자 ~ ${max}자로 입력해 주세요`
  }
  return true
})

extend('max', (value, args) => {
  if (value.length > Number(args[0])) {
    return `{_field_} 은(는) ${args}자 이하로 입력해 주세요.`
  }
  return true
})
// 기존에 존재하던 required는 message만 변경
extend('required', {
  ...required,
  message: '{_field_} 은(는) 반드시 입력해야 합니다',
})

extend('required-select', {
  ...required,
  message: '{_field_} 은(는) 반드시 선택해야 합니다',
})

extend('numeric', {
  ...numeric,
  message: '{_field_} 은(는) 숫자로만 구성되어야 합니다',
})
extend('digits', {
  ...digits,
  message: '{_field_} 은(는) 11자리 여야 합니다',
})

extend('email', {
  ...email,
  message: '잘못 입력된 이메일 주소 입니다',
})

// provider 에 :rules="{ confirmed: 'provider name 명을 적어주면 된다'}"
extend('confirmed', {
  ...confirmed,
  message: '비밀번호와 비밀번호확인이 일치하지 않습니다',
})

Vue.component('ValidationObserver', ValidationObserver)
Vue.component('ValidationProvider', ValidationProvider)

 

ValidationProvider: 검증할 요소 (input 등)을 감싸 검증을 도와준다.

ValidationObserver: 양식(Form) 전체의 요소를 검증할 수 있도록 도와준다. (하위 요소로 ValidationProvider를 여러개 둘 수 있음)

extend: 사용할 validation을 주입하기 위해 사용하는 함수인데 위의 코드처럼 커스텀 할때도 사용된다.

 

Sample.vue

<template>
  <div class="contactMe-container">
    <h1>CONTACT ME</h1>
    <DivideLine color="darker" />
    <div class="contactMe-wrap">
      <ValidationObserver v-slot="{ handleSubmit }" tag="div" class="form-group">
        <form @submit.prevent="handleSubmit(sendEmail)">
          <ValidationProvider
            v-slot="{ errors }"
            rules="limit:2,20"
            tag="div"
            name="Name"
            class="input-text"
            :class="name ? 'value-inputed active' : ''"
          >
            <label>Name</label>
            <input v-model="name" placeholder="Name" type="text" @focus="onFocus" @blur="outFocus" />
            <p v-if="errors[0]">
              <font-awesome-icon icon="exclamation-triangle" />
              {{ errors[0] }}
            </p>
          </ValidationProvider>
          <ValidationProvider
            v-slot="{ errors }"
            rules="email|required"
            tag="div"
            name="Email"
            class="input-text"
            :class="email ? 'value-inputed active' : ''"
          >
            <label>Email</label>
            <input
              v-model="email"
              placeholder="Email"
              type="text"
              @focus="(e) => onFocus(e)"
              @blur="(e) => outFocus(e)"
            />
            <p v-if="errors[0]">
              <font-awesome-icon icon="exclamation-triangle" />
              {{ errors[0] }}
            </p>
          </ValidationProvider>
          <ValidationProvider
            v-slot="{ errors }"
            rules="max:100|required"
            tag="div"
            name="Message"
            class="input-text"
            :class="message ? 'value-inputed active' : ''"
          >
            <label>Message</label>
            <input
              v-model="message"
              placeholder="message"
              type="textarea"
              @focus="(e) => onFocus(e)"
              @blur="(e) => outFocus(e)"
            />
            <p v-if="errors[0]">
              <font-awesome-icon icon="exclamation-triangle" />
              {{ errors[0] }}
            </p>
          </ValidationProvider>
          <div class="mt-3">
            <button>Send</button>
          </div>
        </form>
      </ValidationObserver>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from '@vue/composition-api'
import DivideLine from './DivideLine.vue'

export default defineComponent({
  components: { DivideLine },
  setup() {
    const name = ref('')
    const email = ref('')
    const message = ref('')

    const onFocus = (e: Event) => {
      console.log('onFocus')
      const target = e.target as HTMLElement
      target.parentElement?.classList.add('active')
    }
    const outFocus = (e: Event) => {
      console.log('outFocus')
      const target = e.target as HTMLElement
      target.parentElement?.classList.remove('active')
    }
    const sendEmail = () => {
      console.log('sendEmail')
    }

    return {
      name,
      email,
      message,
      onFocus,
      outFocus,
      sendEmail,
    }
  },
})
</script>

ValidationObserver v-slot="{ handleSubmit }" -> handleSubmit으로 form의 submit을 제어할 수 있다.

ValidationProvider v-slot="{ errors }" -> errors에는 error message들이 들어있다.

vee-validate에서 설정한 {_field_}는 ValidationProvider의 name 속성에 설정한 값이 삽입된다.

 

 

결과화면

Comments