새로운 강의는 이제 https://memi.dev 에서 진행합니다.
memi가 Vue & Firebase로 직접 만든 새로운 사이트를 소개합니다.

바로가기


모던웹(NEMV) 혼자 제작 하기 3기 - 56 회원가입 프론트 적용하기

2 분 소요

뷰티파이 예제로 만들고 있는 모델에 맞게 수정해보겠습니다.

비벨(vee-validate) 한글화

참고: https://baianat.github.io/vee-validate/guide/localization.html

fe/src/views/register.vue

import ko from 'vee-validate/dist/locale/ko' // add

export default {
  $_veeValidate: {
    validator: 'new'
  },

  data: () => ({
    // ..
    dictionary: {
      messages: ko.messages, // add
      // ..
    }
  }),

  mounted () {
    this.$validator.localize('ko', this.dictionary) // en -> ko
  },
  // .. 
}
  • locale/ko 등록
  • 사전(dictionary) 메세지 등록
  • 시작할때 ko로 로컬라이즈

공식홈의 예제로 간단히 변경해두었습니다.

간단한 표현만 한글화가 지원되고 더 디테일하게 변경하고 싶으면 dictionary custom 부분에서 변경해주면됩니다.

알림 메세지(스낵바) 추가

fe/src/views/register.vue

    <v-snackbar
      v-model="sb.act"
    >
      {{ sb.msg }}
      <v-btn
        :color="sb.color"
        flat
        @click="sb.act = false"
      >
        닫기
      </v-btn>
    </v-snackbar>
  </v-container>
</template>
<script>
  data: () => ({
    sb: {
      act: false,
      msg: '',
      color: 'warning'
    },
  // ..
  methods: {
    pop (m, cl) {
      this.sb.act = true
      this.sb.msg = m
      this.sb.color = cl
    },
    // ..
</script>

console.log 대신 pop이라는 함수를 만들어서 스낵바로 표시해봤습니다.

모델에 맞게 페이지 변경

fe/src/views/register.vue

<template>
  <v-container fluid fill-height>
    <v-layout align-center justify-center>
      <v-flex xs12 sm8 md4>
        <v-card class="elevation-12">
          <v-toolbar dark color="primary">
            <v-toolbar-title>회원 가입</v-toolbar-title>
            <v-spacer></v-spacer>
          </v-toolbar>
          <v-card-text>
            <form>
              <v-text-field
                v-validate="'required|min:4|max:20'"
                v-model="form.id"
                :counter="20"
                :error-messages="errors.collect('id')"
                label="아이디"
                data-vv-name="id"
                required
              ></v-text-field>
              <v-text-field
                v-validate="'required|min:6|max:40'"
                v-model="form.pwd"
                :counter="40"
                :error-messages="errors.collect('pwd')"
                label="비밀번호"
                data-vv-name="pwd"
                required
                type="password"
              ></v-text-field>
              <v-text-field
                v-validate="'required|min:1|max:40'"
                v-model="form.name"
                :counter="40"
                :error-messages="errors.collect('name')"
                label="이름"
                data-vv-name="name"
                required
              ></v-text-field>

              <v-checkbox
                v-validate="'required'"
                v-model="agree"
                :error-messages="errors.collect('agree')"
                value="1"
                label="약관동의: 암호화도 안되어 있는 사이트인데 정말 가입하겠습니까?"
                data-vv-name="agree"
                type="checkbox"
                required
              ></v-checkbox>

              <v-btn @click="submit">가입</v-btn>
              <v-btn @click="clear">초기화</v-btn>
            </form>
          </v-card-text>
        </v-card>
      </v-flex>
    </v-layout>
    <v-snackbar
      v-model="sb.act"
    >
      {{ sb.msg }}
      <v-btn
        :color="sb.color"
        flat
        @click="sb.act = false"
      >
        닫기
      </v-btn>
    </v-snackbar>
  </v-container>
</template>

<script>
import ko from 'vee-validate/dist/locale/ko'

export default {
  $_veeValidate: {
    validator: 'new'
  },

  data: () => ({
    form: {
      id: '',
      name: '',
      pwd: ''
    },
    sb: {
      act: false,
      msg: '',
      color: 'warning'
    },
    agree: null,
    dictionary: {
      messages: ko.messages,
      attributes: {
        id: '아이디',
        pwd: '비밀번호',
        name: '이름',
        agree: '약관동의'
        // custom attributes
      },
      custom: {
        // name: {
        //   required: () => 'Name can not be empty',
        //   max: 'The name field may not be greater than 10 characters'
        //   // custom messages
        // },
        // select: {
        //   required: 'Select field is required'
        // }
      }
    }
  }),

  mounted () {
    this.$validator.localize('ko', this.dictionary)
  },

  methods: {
    submit () {
      this.$validator.validateAll()
        .then(r => {
          if (!r) throw new Error('모두 기입해주세요')
          return this.$axios.post('register', this.form)
        })
        .then(r => {
          if (!r.data.success) throw new Error('서버가 거부했습니다.')
          this.pop('가입 완료 되었습니다.', 'success')

          this.$route.push('/sign')
        })
        .catch(e => this.pop(e.message, 'warning'))
    },
    pop (m, cl) {
      this.sb.act = true
      this.sb.msg = m
      this.sb.color = cl
    },
    clear () {
      this.form.id = ''
      this.form.pwd = ''
      this.form.name = ''
      this.agree = null
      this.$validator.reset()
    }
  }
}
</script>
  • 전송될 데이터를 form 변수에 담았습니다.
  • 텍스트 필드 룰: required|min:4|max:20 이면 꼭 넣어야하고 4글자 이상 20글자 이하 인것이죠
  • v-model로 값들과 양방향 바인딩 상태입니다.
  • error.collect()로 아마도 data-vv-name와 연결되어 메세지가 표시되는 것 같습니다.(자세히는 모름..)
  • :counter의 경우 그저 표시용입니다. 제한사항은 아님!
  • dictionary.attr.. 는 메세지에서 ‘id’를 ‘아이디’로 표시해줍니다.
  • this.$validator.validateAll() 로 false 가 나올경우 에러로 보냅니다.
  • 액시오스 요청으로 form 내용을 전송합니다.

적용된 화면

alt apply

마치며

역시 직접 설명하는 것 보다는 값들을 변경해보며 확인하는 것이 훨씬 이해가 빠릅니다~

영상

댓글남기기