Vue.js Email Verification
Email checker for Vue.js. Real-time email verification in Vue components and forms.
Интегрируйте EmailVerify в ваши Vue 3 приложения для валидации email в реальном времени. Это руководство охватывает реализации как с Composition API, так и с Options API, от базовой настройки до продвинутых паттернов.
Установка
Установите пакет EmailVerify и настройте проект.
npm install emailverifyyarn add emailverifypnpm add emailverifyБыстрый старт
Composition API
Используйте Composition API для реактивной верификации email в ваших компонентах.
<template>
<div class="email-verification">
<input
v-model="email"
type="email"
placeholder="Введите email-адрес"
@blur="verifyEmail"
class="email-input"
/>
<div v-if="isLoading" class="status loading">
Проверка...
</div>
<div v-else-if="result" :class="['status', result.status]">
<span v-if="result.status === 'valid'">✓ Валидный email</span>
<span v-else-if="result.status === 'invalid'">✗ Невалидный email</span>
<span v-else>? Не удалось проверить</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { emailverify } from 'emailverify';
const email = ref('');
const isLoading = ref(false);
const result = ref<any>(null);
const verifyEmail = async () => {
if (!email.value) return;
isLoading.value = true;
try {
result.value = await emailverify.verify({
email: email.value,
apiKey: import.meta.env.VITE_EMAILVERIFY_API_KEY
});
} catch (error) {
console.error('Верификация не удалась:', error);
result.value = null;
} finally {
isLoading.value = false;
}
};
</script>
<style scoped>
.email-input {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
width: 100%;
}
.status {
margin-top: 8px;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
}
.status.valid {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.invalid {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status.loading {
background-color: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
</style>Options API
Для проектов, использующих паттерн Options API:
<template>
<div class="email-verification">
<input
v-model="email"
type="email"
placeholder="Введите email-адрес"
@blur="verifyEmail"
class="email-input"
/>
<div v-if="isLoading" class="status loading">
Проверка...
</div>
<div v-else-if="result" :class="['status', result.status]">
{{ statusMessage }}
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { emailverify } from 'emailverify';
export default defineComponent({
name: 'EmailVerification',
data() {
return {
email: '',
isLoading: false,
result: null
};
},
computed: {
statusMessage(): string {
if (this.result?.status === 'valid') return '✓ Валидный email';
if (this.result?.status === 'invalid') return '✗ Невалидный email';
return '? Не удалось проверить';
}
},
methods: {
async verifyEmail() {
if (!this.email) return;
this.isLoading = true;
try {
this.result = await emailverify.verify({
email: this.email,
apiKey: import.meta.env.VITE_EMAILVERIFY_API_KEY
});
} catch (error) {
console.error('Верификация не удалась:', error);
this.result = null;
} finally {
this.isLoading = false;
}
}
}
});
</script>Справочник по Composables
useEmailVerification
Пользовательский composable для управления состоянием и логикой верификации email.
import { ref, computed } from 'vue';
import { emailverify } from 'emailverify';
export function useEmailVerification(apiKey: string) {
const email = ref('');
const isLoading = ref(false);
const error = ref<string | null>(null);
const result = ref<any>(null);
const isValid = computed(() => result.value?.status === 'valid');
const isInvalid = computed(() => result.value?.status === 'invalid');
const isDisposable = computed(() => result.value?.result?.disposable || false);
const verify = async (emailToVerify?: string) => {
const emailAddress = emailToVerify || email.value;
if (!emailAddress) {
error.value = 'Email-адрес обязателен';
return;
}
isLoading.value = true;
error.value = null;
try {
result.value = await emailverify.verify({
email: emailAddress,
apiKey
});
} catch (err) {
error.value = err instanceof Error ? err.message : 'Верификация не удалась';
result.value = null;
} finally {
isLoading.value = false;
}
};
const reset = () => {
email.value = '';
result.value = null;
error.value = null;
isLoading.value = false;
};
return {
email,
isLoading,
error,
result,
isValid,
isInvalid,
isDisposable,
verify,
reset
};
}useEmailInput
Composable для обработки ввода email с debouncing и кэшированием.
import { ref, computed, watch } from 'vue';
import { useEmailVerification } from './useEmailVerification';
const CACHE_DURATION = 30 * 60 * 1000; // 30 минут
export function useEmailInput(apiKey: string) {
const email = ref('');
const cache = new Map<string, { result: any; timestamp: number }>();
const { verify: verifyWithAPI, isLoading, error, result } = useEmailVerification(apiKey);
const verify = async () => {
if (!email.value) return;
// Сначала проверяем кэш
const cached = cache.get(email.value);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
result.value = cached.result;
return;
}
// Верификация через API
await verifyWithAPI(email.value);
// Кэширование результата
if (result.value) {
cache.set(email.value, {
result: result.value,
timestamp: Date.now()
});
}
};
const clearCache = () => cache.clear();
return {
email,
isLoading,
error,
result,
verify,
clearCache
};
}Интеграция с компонентами
Интеграция с VeeValidate
Интегрируйте верификацию email с VeeValidate для валидации форм.
<template>
<Form @submit="onSubmit" class="form">
<div class="form-group">
<label>Email-адрес</label>
<Field
name="email"
type="email"
placeholder="your@email.com"
v-slot="{ field, meta }"
:rules="validateEmail"
>
<input
v-bind="field"
:class="{ 'input-error': meta.touched && !meta.valid }"
@blur="verifyEmail(field.value)"
/>
</Field>
<div v-if="verificationResult" :class="['verification-status', verificationResult.status]">
{{ getStatusMessage(verificationResult) }}
</div>
<ErrorMessage name="email" class="error-message" />
</div>
<button type="submit" :disabled="isLoading">
{{ isLoading ? 'Проверка...' : 'Отправить' }}
</button>
</Form>
</template>
<script setup lang="ts">
import { Form, Field, ErrorMessage } from 'vee-validate';
import * as yup from 'yup';
import { ref } from 'vue';
import { useEmailVerification } from './composables/useEmailVerification';
const schema = yup.object({
email: yup.string().email('Невалидный email').required('Email обязателен')
});
const { verify, result: verificationResult, isLoading } = useEmailVerification(
import.meta.env.VITE_EMAILVERIFY_API_KEY
);
const validateEmail = async (value: string) => {
if (!value) return 'Email обязателен';
try {
await schema.validate({ email: value });
return true;
} catch {
return 'Неверный формат email';
}
};
const verifyEmail = async (email: string) => {
if (email) {
await verify(email);
}
};
const getStatusMessage = (result: any) => {
switch (result.status) {
case 'valid':
return '✓ Валидный email-адрес';
case 'invalid':
return '✗ Невалидный email-адрес';
case 'unknown':
return '? Не удалось проверить этот email';
default:
return 'Неизвестный статус';
}
};
const onSubmit = (values: any) => {
if (verificationResult.value?.status === 'valid') {
console.log('Форма отправлена:', values);
}
};
</script>
<style scoped>
.form-group {
margin-bottom: 16px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
input {
width: 100%;
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
input.input-error {
border-color: #dc3545;
background-color: #fff5f5;
}
.error-message {
color: #dc3545;
font-size: 12px;
margin-top: 4px;
}
.verification-status {
margin-top: 8px;
padding: 8px 12px;
border-radius: 4px;
font-size: 13px;
}
.verification-status.valid {
background-color: #d4edda;
color: #155724;
}
.verification-status.invalid {
background-color: #f8d7da;
color: #721c24;
}
</style>Интеграция с Element Plus
Использование EmailVerify с компонентами форм Element Plus.
<template>
<el-form :model="form" @submit.prevent="handleSubmit">
<el-form-item label="Email" prop="email">
<el-input
v-model="form.email"
type="email"
placeholder="Введите email"
@blur="verifyEmail"
:loading="isLoading"
/>
<el-alert
v-if="verificationResult"
:title="getStatusTitle()"
:type="getAlertType()"
:closable="false"
style="margin-top: 8px"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="handleSubmit"
:loading="isLoading"
>
Отправить
</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { useEmailVerification } from './composables/useEmailVerification';
const form = reactive({
email: ''
});
const { verify, result: verificationResult, isLoading } = useEmailVerification(
import.meta.env.VITE_EMAILVERIFY_API_KEY
);
const verifyEmail = async () => {
if (form.email) {
await verify(form.email);
}
};
const getStatusTitle = () => {
switch (verificationResult.value?.status) {
case 'valid':
return 'Email валиден';
case 'invalid':
return 'Email невалиден';
default:
return 'Не удалось проверить email';
}
};
const getAlertType = () => {
return verificationResult.value?.status === 'valid' ? 'success' : 'error';
};
const handleSubmit = async () => {
await verifyEmail();
if (verificationResult.value?.status === 'valid') {
console.log('Email подтвержден, отправка формы...');
}
};
</script>SSR с Nuxt 3
Серверная верификация
Верифицируйте email на сервере для лучшей безопасности и производительности.
// server/api/verify-email.ts
import { emailverify } from 'emailverify';
export default defineEventHandler(async (event) => {
const { email } = await readBody(event);
if (!email) {
throw createError({
statusCode: 400,
statusMessage: 'Email обязателен'
});
}
try {
const result = await emailverify.verify({
email,
apiKey: process.env.EMAILVERIFY_API_KEY!
});
return result;
} catch (error) {
throw createError({
statusCode: 500,
statusMessage: 'Верификация не удалась'
});
}
});Клиентская интеграция в Nuxt
Используйте серверный эндпоинт из ваших Nuxt компонентов.
<template>
<div class="email-verification">
<input
v-model="email"
type="email"
placeholder="your@email.com"
@blur="verifyEmail"
/>
<div v-if="pending" class="status loading">
Проверка...
</div>
<div v-else-if="result" :class="['status', result.status]">
{{ statusMessage }}
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
const email = ref('');
const { data: result, pending, execute: verifyEmail } = await useFetch(
'/api/verify-email',
{
method: 'POST',
body: computed(() => ({ email: email.value })),
immediate: false
}
);
const statusMessage = computed(() => {
if (!result.value) return '';
switch (result.value.status) {
case 'valid':
return '✓ Валидный email';
case 'invalid':
return '✗ Невалидный email';
default:
return '? Неизвестный статус';
}
});
</script>Продвинутые паттерны
Верификация с debounce
Сокращение API-вызовов с помощью debounced верификации email.
import { ref, watch } from 'vue';
import { useEmailVerification } from './composables/useEmailVerification';
export function useDebouncedEmailVerification(apiKey: string, delay = 500) {
const email = ref('');
const debounceTimer = ref<NodeJS.Timeout | null>(null);
const { verify, ...rest } = useEmailVerification(apiKey);
watch(email, (newEmail) => {
if (debounceTimer.value) {
clearTimeout(debounceTimer.value);
}
debounceTimer.value = setTimeout(() => {
if (newEmail) {
verify(newEmail);
}
}, delay);
});
return { email, verify, ...rest };
}Стратегия кэширования email
Реализация интеллектуального кэширования для сокращения API-вызовов.
const CACHE_KEY_PREFIX = 'emailverify_';
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 часа
export function useCachedEmailVerification(apiKey: string) {
const { verify: verifyWithAPI, result, isLoading } = useEmailVerification(apiKey);
const getCacheKey = (email: string) => `${CACHE_KEY_PREFIX}${email}`;
const verify = async (email: string) => {
const cacheKey = getCacheKey(email);
const cached = localStorage.getItem(cacheKey);
if (cached) {
const { result: cachedResult, timestamp } = JSON.parse(cached);
if (Date.now() - timestamp < CACHE_DURATION) {
result.value = cachedResult;
return;
}
}
await verifyWithAPI(email);
if (result.value) {
localStorage.setItem(
cacheKey,
JSON.stringify({
result: result.value,
timestamp: Date.now()
})
);
}
};
const clearCache = (email?: string) => {
if (email) {
localStorage.removeItem(getCacheKey(email));
} else {
const keys = Object.keys(localStorage);
keys.forEach(key => {
if (key.startsWith(CACHE_KEY_PREFIX)) {
localStorage.removeItem(key);
}
});
}
};
return { verify, result, isLoading, clearCache };
}Обработка ошибок и повторные попытки
Реализация надежной обработки ошибок с логикой повторных попыток.
export function useEmailVerificationWithRetry(apiKey: string, maxRetries = 3) {
const { verify: verifyWithAPI, result, isLoading, error } = useEmailVerification(apiKey);
const verifyWithRetry = async (email: string, retryCount = 0): Promise<any> => {
try {
await verifyWithAPI(email);
return result.value;
} catch (err) {
if (retryCount < maxRetries) {
// Ожидание перед повторной попыткой (экспоненциальная задержка)
await new Promise(resolve => setTimeout(resolve, Math.pow(2, retryCount) * 1000));
return verifyWithRetry(email, retryCount + 1);
}
throw err;
}
};
return { verifyWithRetry, result, isLoading, error };
}Поддержка TypeScript
EmailVerify SDK включает полную поддержку TypeScript с определениями типов.
interface VerificationRequest {
email: string;
apiKey: string;
}
interface VerificationResult {
status: 'valid' | 'invalid' | 'unknown' | 'accept_all';
result: {
disposable: boolean;
smtp_valid: boolean;
format_valid: boolean;
email_provider: string;
risk_level: 'low' | 'medium' | 'high';
};
score: number;
}
interface UseEmailVerificationReturn {
email: Ref<string>;
isLoading: Ref<boolean>;
error: Ref<string | null>;
result: Ref<VerificationResult | null>;
isValid: ComputedRef<boolean>;
isInvalid: ComputedRef<boolean>;
isDisposable: ComputedRef<boolean>;
verify: (emailToVerify?: string) => Promise<void>;
reset: () => void;
}Тестирование
Юнит-тесты с Vitest
Тестирование ваших composables для верификации email с Vitest.
import { describe, it, expect, vi } from 'vitest';
import { useEmailVerification } from './composables/useEmailVerification';
vi.mock('emailverify', () => ({
emailverify: {
verify: vi.fn()
}
}));
describe('useEmailVerification', () => {
it('верифицирует валидный email', async () => {
const { verify, result, isValid } = useEmailVerification('test-key');
await verify('user@example.com');
expect(result.value?.status).toBe('valid');
expect(isValid.value).toBe(true);
});
it('отмечает невалидный email', async () => {
const { verify, result, isInvalid } = useEmailVerification('test-key');
await verify('invalid@');
expect(result.value?.status).toBe('invalid');
expect(isInvalid.value).toBe(true);
});
it('обрабатывает ошибки верификации', async () => {
const { verify, error } = useEmailVerification('test-key');
try {
await verify('');
} catch (err) {
expect(error.value).toBeTruthy();
}
});
});Тесты компонентов
Тестирование ваших Vue компонентов с Vue Test Utils.
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import EmailVerification from './EmailVerification.vue';
describe('EmailVerification', () => {
it('рендерит поле ввода', () => {
const wrapper = mount(EmailVerification);
expect(wrapper.find('input[type="email"]').exists()).toBe(true);
});
it('показывает статус верификации', async () => {
const wrapper = mount(EmailVerification);
await wrapper.find('input').setValue('user@example.com');
await wrapper.find('input').trigger('blur');
expect(wrapper.find('.status').exists()).toBe(true);
});
it('показывает состояние загрузки во время верификации', async () => {
const wrapper = mount(EmailVerification);
await wrapper.find('input').setValue('user@example.com');
expect(wrapper.find('.status.loading').exists()).toBe(true);
});
});