vue3-uikit
368 строк · 9.6 Кб
1<template>
2<div>
3<h3>Search</h3>
4<div class="input-wrapper">
5<div class="flex">
6<input
7v-model="searchQuery"
8type="text"
9placeholder="Поиск..."
10:class="{
11'input-error': !$v.searchQuery.$pending && !$v.searchQuery.$model,
12}"
13/>
14<button @click="handleSearch" class="btn-search">Поиск</button>
15</div>
16<p
17v-if="!$v.searchQuery.$pending && !$v.searchQuery.$model"
18class="error-message"
19>
20Запрос поиска обязателен.
21</p>
22</div>
23
24<h3>Field with Tooltip</h3>
25<div class="input-wrapper">
26<input
27v-model="tooltipInput"
28type="text"
29@focus="showTooltip = true"
30@blur="showTooltip = false"
31placeholder="Наведи для подсказки"
32:class="{
33'input-error': !$v.tooltipInput.$pending && !$v.tooltipInput.$model,
34}"
35/>
36<div v-if="showTooltip" class="tooltip">Это подсказка</div>
37<p
38v-if="!$v.tooltipInput.$pending && !$v.tooltipInput.$model"
39class="error-message"
40>
41Поле с подсказкой обязательно для заполнения.
42</p>
43</div>
44
45<!-- Поле Email -->
46<h3>Email</h3>
47<div class="input-wrapper">
48<input
49v-model="emailField"
50type="email"
51placeholder="Введите ваш email"
52:class="{
53'input-error': !$v.emailField.$pending && !$v.emailField.$invalid,
54}"
55/>
56<p
57v-if="!$v.emailField.$pending && $v.emailField.$invalid"
58class="error-message"
59>
60Неверный формат email. Убедитесь, что email содержит символ `@`.
61</p>
62</div>
63
64<h3>Password</h3>
65<div class="input-wrapper">
66<input
67v-model="password"
68type="password"
69placeholder="Введите ваш пароль к примеру K7Z*$Q3PS/"
70:class="{ 'input-error': $v.password.$error }"
71/>
72<!-- Ошибка обязательного поля -->
73<p
74v-if="$v.password.$error && $v.password.required"
75class="error-message"
76>
77Пароль обязателен.
78</p>
79<!-- Ошибка минимальной длины -->
80<p
81v-if="$v.password.$error && $v.password.minLength"
82class="error-message"
83>
84{{ $v.password.minLength.$message }}
85</p>
86<!-- Ошибка отсутствия заглавной буквы -->
87<p
88v-if="$v.password.$error && $v.password.containsUppercase"
89class="error-message"
90>
91{{ $v.password.containsUppercase.$message }}
92</p>
93<!-- Ошибка отсутствия цифры -->
94<p
95v-if="$v.password.$error && $v.password.containsNumber"
96class="error-message"
97>
98{{ $v.password.containsNumber.$message }}
99</p>
100<!-- Ошибка отсутствия специального символа -->
101<p
102v-if="$v.password.$error && $v.password.containsSpecial"
103class="error-message"
104>
105{{ $v.password.containsSpecial.$message }}
106</p>
107</div>
108
109<h3>Date</h3>
110<div class="input-wrapper">
111<input
112v-model="date"
113type="date"
114:class="{ 'input-error': !$v.date.$pending && !$v.date.$model }"
115/>
116<p v-if="!$v.date.$pending && !$v.date.$model" class="error-message">
117Пожалуйста, выберите дату.
118</p>
119</div>
120
121<h3>Textarea</h3>
122<div class="input-wrapper">
123<textarea
124v-model="textarea"
125placeholder="Введите ваше сообщение"
126:class="{ 'input-error': !$v.textarea.$pending && !$v.textarea.$model }"
127></textarea>
128<p
129v-if="!$v.textarea.$pending && !$v.textarea.$model"
130class="error-message"
131>
132Сообщение обязательно для заполнения.
133</p>
134</div>
135
136<h3>Select</h3>
137<div class="input-wrapper">
138<select
139v-model="selectedOption"
140:class="{
141'input-error':
142!$v.selectedOption.$pending && !$v.selectedOption.$model,
143}"
144>
145<option disabled value="">Пожалуйста, выберите вариант</option>
146<option value="option1">Вариант 1</option>
147<option value="option2">Вариант 2</option>
148<option value="option3">Вариант 3</option>
149</select>
150<p
151v-if="!$v.selectedOption.$pending && !$v.selectedOption.$model"
152class="error-message"
153>
154Пожалуйста, выберите вариант.
155</p>
156</div>
157
158<h3>Checkbox</h3>
159<div class="input-wrapper">
160<label class="checkbox-label">
161<input v-model="checked" type="checkbox" />
162Принять условия
163</label>
164<p
165v-if="!$v.checked.$pending && !$v.checked.$model"
166class="error-message"
167>
168Вы должны согласиться с условиями.
169</p>
170</div>
171
172<h3>Radio Buttons</h3>
173<div class="input-wrapper">
174<label class="radio-label">
175<input v-model="picked" type="radio" value="option1" />
176Вариант 1
177</label>
178<label class="radio-label">
179<input v-model="picked" type="radio" value="option2" />
180Вариант 2
181</label>
182<p v-if="!$v.picked.$pending && !$v.picked.$model" class="error-message">
183Пожалуйста, выберите один из вариантов.
184</p>
185</div>
186</div>
187</template>
188
189<script>
190import { ref } from "vue";
191import useVuelidate from "@vuelidate/core";
192import { required, email, helpers, minLength } from "@vuelidate/validators";
193
194export default {
195name: "Input",
196setup() {
197// Определение полей формы как реактивные переменные
198const searchQuery = ref("");
199const tooltipInput = ref("");
200const emailField = ref("");
201const password = ref("");
202const date = ref("");
203const textarea = ref("");
204const selectedOption = ref("");
205const checked = ref(false);
206const picked = ref("");
207
208// Кастомные валидаторы для пароля
209const containsUppercase = helpers.withMessage(
210"Должна быть хотя бы одна заглавная буква",
211(value) => /[A-Z]/.test(value)
212);
213const containsNumber = helpers.withMessage(
214"Должна быть хотя бы одна цифра",
215(value) => /\d/.test(value)
216);
217const containsSpecial = helpers.withMessage(
218"Должен быть хотя бы один специальный символ",
219(value) => /[!@#$%^&*(),.?":{}|<>]/.test(value)
220);
221
222// Правила валидации для всех полей формы
223const validations = {
224searchQuery: { required },
225tooltipInput: { required },
226emailField: {
227required,
228email,
229},
230password: {
231required,
232minLength: helpers.withMessage(
233"Пароль должен содержать минимум 8 символов",
234minLength(8)
235),
236containsUppercase,
237containsNumber,
238containsSpecial,
239},
240date: { required },
241textarea: { required },
242selectedOption: { required },
243checked: { required },
244picked: { required },
245};
246
247// Vuelidate с автоматической валидацией и установкой dirty статуса
248const $v = useVuelidate(
249validations,
250{
251searchQuery,
252tooltipInput,
253emailField,
254password,
255date,
256textarea,
257selectedOption,
258checked,
259picked,
260},
261{
262$autoDirty: true, // Поле считается изменённым сразу после ввода
263$autoValidate: true, // Автоматическая валидация при изменении значения
264}
265);
266
267// Функция для обработки поиска
268const handleSearch = () => {
269alert(`Искать: ${searchQuery.value}`);
270};
271
272// Видимость подсказки
273const showTooltip = ref(false);
274
275return {
276searchQuery,
277tooltipInput,
278emailField,
279password,
280date,
281textarea,
282selectedOption,
283checked,
284picked,
285showTooltip,
286$v,
287handleSearch,
288};
289},
290};
291</script>
292
293<style scoped>
294.input-wrapper {
295margin-bottom: 20px;
296position: relative;
297}
298
299input,
300textarea,
301select {
302padding: 10px;
303border: 1px solid #ccc;
304border-radius: 4px;
305font-size: 14px;
306width: 100%;
307transition: border-color 0.3s;
308}
309
310input:focus,
311textarea:focus,
312select:focus {
313border-color: #6200ea;
314}
315
316.input-error {
317border-color: #f44336;
318}
319
320.error-message {
321color: #f44336;
322font-size: 12px;
323margin: 5px 0 0;
324}
325
326.btn-search {
327padding: 10px;
328margin-left: 5px;
329border: none;
330background-color: #6200ea;
331color: white;
332cursor: pointer;
333border-radius: 4px;
334font-size: 14px;
335transition: background-color 0.3s;
336}
337
338.btn-search:hover {
339background-color: #3700b3;
340}
341
342.tooltip {
343position: absolute;
344top: 100%;
345left: 0;
346padding: 5px;
347background-color: #333;
348color: white;
349border-radius: 4px;
350font-size: 12px;
351white-space: nowrap;
352z-index: 10;
353}
354
355.checkbox-label,
356.radio-label {
357display: flex;
358flex-direction: row-reverse;
359align-items: center;
360margin-bottom: 5px;
361white-space: nowrap;
362}
363
364.checkbox-label input,
365.radio-label input {
366margin-right: 10px;
367}
368</style>
369