# 입력 이동 시 자동 중복 검사로 수정하기 (버튼 없이)
아래 코드는 “중복 확인” 버튼 없이, 아이디 입력 후 포커스가 비밀번호 입력으로 이동하는 순간(blur 또는 Enter로 다음 필드 포커스) 자동으로 중복 여부를 검사하도록 변경한 예시입니다. 기존 JS 버전(Composition API)을 기준으로 수정했습니다.
핵심 변경 사항
- 디바운스 실시간 검사 대신, 아이디 인풋에서 포커스가 빠질 때(blur) 또는 Enter로 다음 필드로 이동할 때 중복 검사 실행.
- 별도의 “중복 확인” 버튼 제거.
- 회원가입 버튼 활성화 조건은 동일하게 유지: 형식 OK && 중복 아님 && 에러 없음.
## 1) 컴포저블 업데이트 (composables/useUsernameCheck.js)
- watch에 의한 자동 디바운스 호출 제거.
- 외부에서 이벤트로 호출할 수 있는 checkNow를 그대로 사용.
- 형식 검사는 입력 시에도 즉시 반영하고 싶다면 watch로 형식만 반영하도록 분리.
```js
// composables/useUsernameCheck.js
import { ref, computed, watch } from 'vue';
import { checkUsernameExists } from '@/api/auth';
const USERNAME_REGEX = /^[a-z0-9_]{4,16}$/;
export function useUsernameCheck() {
const username = ref('');
const isFormatValid = ref(null); // true | false | null
const isChecking = ref(false);
const isDuplicate = ref(null); // true | false | null
const error = ref(null);
const validateFormat = (v) => {
if (!v) return null;
return USERNAME_REGEX.test(v);
};
// 입력 중에는 형식만 즉시 업데이트 (서버 호출은 blur 시점에만)
watch(username, (v) => {
isFormatValid.value = validateFormat(v);
// 사용자가 수정 중이면 이전 중복 결과는 무의미하므로 리셋
isDuplicate.value = null;
error.value = null;
});
const doCheck = async (v) => {
const valid = validateFormat(v);
isFormatValid.value = valid;
// 유효하지 않거나 비어 있으면 서버 호출하지 않음
if (!v || !valid) {
isDuplicate.value = null;
return;
}
try {
isChecking.value = true;
const exists = await checkUsernameExists(v);
isDuplicate.value = exists;
error.value = null;
} catch (e) {
error.value = '아이디 중복 확인 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.';
isDuplicate.value = null;
} finally {
isChecking.value = false;
}
};
// 외부에서 호출할 메서드: blur나 Enter 시점에 호출
const checkNow = () => doCheck(username.value);
const canSubmit = computed(() => {
return (
isFormatValid.value === true &&
isDuplicate.value === false &&
!isChecking.value &&
!error.value
);
});
return {
username,
isFormatValid,
isChecking,
isDuplicate,
error,
checkNow,
canSubmit,
};
}
```
## 2) 컴포넌트 수정 (components/SignUpUsernameField.vue)
- 버튼 제거.
- 아이디 인풋에서 blur 시점에 checkNow 호출.
- Enter로 비밀번호 필드로 이동하는 경우에도 검사되도록 keydown.enter에서 먼저 checkNow를 await한 후 다음 필드에 포커스 이동.
- 비밀번호 인풋에 ref를 주어 포커스 제어.
```vue
<!-- components/SignUpUsernameField.vue -->
<script setup>
import { computed, ref, nextTick } from 'vue';
import { useUsernameCheck } from '@/composables/useUsernameCheck';
const {
username,
isFormatValid,
isChecking,
isDuplicate,
error,
checkNow,
canSubmit,
} = useUsernameCheck();
const password = ref('');
const passwordInputRef = ref(null);
const helperText = computed(() => {
if (!username.value) return '소문자/숫자/언더스코어 4~16자';
if (isChecking.value) return '아이디 확인 중...';
if (error.value) return error.value;
if (isFormatValid.value === false) return '형식이 올바르지 않습니다.';
if (isDuplicate.value === true) return '이미 사용 중인 아이디입니다.';
if (isDuplicate.value === false) return '사용 가능한 아이디입니다.';
return '';
});
// Enter로 비밀번호로 이동하려 할 때, 먼저 중복검사 실행 후 포커스 이동
const onUsernameEnter = async (e) => {
e.preventDefault();
await checkNow();
await nextTick();
if (passwordInputRef.value) {
passwordInputRef.value.focus();
}
};
// blur로 비밀번호로 넘어갈 때도 검사 실행
const onUsernameBlur = async () => {
await checkNow();
};
</script>
<template>
<div class="field">
<label for="username">아이디</label>
<input
id="username"
v-model.trim="username"
type="text"
placeholder="아이디를 입력하세요"
autocomplete="username"
inputmode="latin"
@blur="onUsernameBlur"
@keydown.enter="onUsernameEnter"
/>
<p
class="helper"
:class="{
error: isFormatValid === false || isDuplicate === true || !!error,
success: isDuplicate === false
}"
aria-live="polite"
>
{{ helperText }}
</p>
<label for="password">비밀번호</label>
<input
id="password"
ref="passwordInputRef"
v-model="password"
type="password"
placeholder="비밀번호를 입력하세요"
autocomplete="new-password"
/>
<button type="submit" :disabled="!canSubmit">회원가입</button>
</div>
</template>
<style scoped>
.field { display: grid; gap: 8px; }
.helper { font-size: 12px; margin: 0; }
.helper.error { color: #d32f2f; }
.helper.success { color: #2e7d32; }
</style>
```
## 동작 요약
- 사용자가 아이디를 입력하는 동안에는 형식 유효성만 실시간 표시.
- 아이디 인풋에서 포커스를 잃거나 Enter로 다음 필드로 이동하면 서버에 중복 확인 요청.
- 결과에 따라 “사용 가능/이미 사용 중/오류” 상태 메시지 업데이트.
- 회원가입 버튼은 형식 OK, 중복 아님일 때만 활성화.
## 추가 팁
- 같은 아이디에 대한 반복 호출을 줄이려면 마지막 검사 값 캐싱(Map) 추가를 고려.
- blur/enter 이외에도 “폼 제출 시” 서버에서 최종 재검증은 필수. 경쟁 상태를 방지하기 위함.
- 레이턴시가 길다면 비밀번호 필드로 포커스는 즉시 이동하되, 아이디 영역에 로딩 상태를 보여주는 현재 UX가 일반적입니다.
출처
카테고리 없음
중복확인 버튼없이 패스워드 입력으로 넘어가면 중복여부를 확인하도록 수정해줘
반응형
반응형