vue3-uikit

Форк
0
368 строк · 9.6 Кб
1
<template>
2
  <div>
3
    <h3>Search</h3>
4
    <div class="input-wrapper">
5
      <div class="flex">
6
        <input
7
          v-model="searchQuery"
8
          type="text"
9
          placeholder="Поиск..."
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
17
        v-if="!$v.searchQuery.$pending && !$v.searchQuery.$model"
18
        class="error-message"
19
      >
20
        Запрос поиска обязателен.
21
      </p>
22
    </div>
23

24
    <h3>Field with Tooltip</h3>
25
    <div class="input-wrapper">
26
      <input
27
        v-model="tooltipInput"
28
        type="text"
29
        @focus="showTooltip = true"
30
        @blur="showTooltip = false"
31
        placeholder="Наведи для подсказки"
32
        :class="{
33
          'input-error': !$v.tooltipInput.$pending && !$v.tooltipInput.$model,
34
        }"
35
      />
36
      <div v-if="showTooltip" class="tooltip">Это подсказка</div>
37
      <p
38
        v-if="!$v.tooltipInput.$pending && !$v.tooltipInput.$model"
39
        class="error-message"
40
      >
41
        Поле с подсказкой обязательно для заполнения.
42
      </p>
43
    </div>
44

45
    <!-- Поле Email -->
46
    <h3>Email</h3>
47
    <div class="input-wrapper">
48
      <input
49
        v-model="emailField"
50
        type="email"
51
        placeholder="Введите ваш email"
52
        :class="{
53
          'input-error': !$v.emailField.$pending && !$v.emailField.$invalid,
54
        }"
55
      />
56
      <p
57
        v-if="!$v.emailField.$pending && $v.emailField.$invalid"
58
        class="error-message"
59
      >
60
        Неверный формат email. Убедитесь, что email содержит символ `@`.
61
      </p>
62
    </div>
63

64
    <h3>Password</h3>
65
    <div class="input-wrapper">
66
      <input
67
        v-model="password"
68
        type="password"
69
        placeholder="Введите ваш пароль к примеру K7Z*$Q3PS/"
70
        :class="{ 'input-error': $v.password.$error }"
71
      />
72
      <!-- Ошибка обязательного поля -->
73
      <p
74
        v-if="$v.password.$error && $v.password.required"
75
        class="error-message"
76
      >
77
        Пароль обязателен.
78
      </p>
79
      <!-- Ошибка минимальной длины -->
80
      <p
81
        v-if="$v.password.$error && $v.password.minLength"
82
        class="error-message"
83
      >
84
        {{ $v.password.minLength.$message }}
85
      </p>
86
      <!-- Ошибка отсутствия заглавной буквы -->
87
      <p
88
        v-if="$v.password.$error && $v.password.containsUppercase"
89
        class="error-message"
90
      >
91
        {{ $v.password.containsUppercase.$message }}
92
      </p>
93
      <!-- Ошибка отсутствия цифры -->
94
      <p
95
        v-if="$v.password.$error && $v.password.containsNumber"
96
        class="error-message"
97
      >
98
        {{ $v.password.containsNumber.$message }}
99
      </p>
100
      <!-- Ошибка отсутствия специального символа -->
101
      <p
102
        v-if="$v.password.$error && $v.password.containsSpecial"
103
        class="error-message"
104
      >
105
        {{ $v.password.containsSpecial.$message }}
106
      </p>
107
    </div>
108

109
    <h3>Date</h3>
110
    <div class="input-wrapper">
111
      <input
112
        v-model="date"
113
        type="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
124
        v-model="textarea"
125
        placeholder="Введите ваше сообщение"
126
        :class="{ 'input-error': !$v.textarea.$pending && !$v.textarea.$model }"
127
      ></textarea>
128
      <p
129
        v-if="!$v.textarea.$pending && !$v.textarea.$model"
130
        class="error-message"
131
      >
132
        Сообщение обязательно для заполнения.
133
      </p>
134
    </div>
135

136
    <h3>Select</h3>
137
    <div class="input-wrapper">
138
      <select
139
        v-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
151
        v-if="!$v.selectedOption.$pending && !$v.selectedOption.$model"
152
        class="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
165
        v-if="!$v.checked.$pending && !$v.checked.$model"
166
        class="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>
190
import { ref } from "vue";
191
import useVuelidate from "@vuelidate/core";
192
import { required, email, helpers, minLength } from "@vuelidate/validators";
193

194
export default {
195
  name: "Input",
196
  setup() {
197
    // Определение полей формы как реактивные переменные
198
    const searchQuery = ref("");
199
    const tooltipInput = ref("");
200
    const emailField = ref("");
201
    const password = ref("");
202
    const date = ref("");
203
    const textarea = ref("");
204
    const selectedOption = ref("");
205
    const checked = ref(false);
206
    const picked = ref("");
207

208
    // Кастомные валидаторы для пароля
209
    const containsUppercase = helpers.withMessage(
210
      "Должна быть хотя бы одна заглавная буква",
211
      (value) => /[A-Z]/.test(value)
212
    );
213
    const containsNumber = helpers.withMessage(
214
      "Должна быть хотя бы одна цифра",
215
      (value) => /\d/.test(value)
216
    );
217
    const containsSpecial = helpers.withMessage(
218
      "Должен быть хотя бы один специальный символ",
219
      (value) => /[!@#$%^&*(),.?":{}|<>]/.test(value)
220
    );
221

222
    // Правила валидации для всех полей формы
223
    const validations = {
224
      searchQuery: { required },
225
      tooltipInput: { required },
226
      emailField: {
227
        required,
228
        email,
229
      },
230
      password: {
231
        required,
232
        minLength: helpers.withMessage(
233
          "Пароль должен содержать минимум 8 символов",
234
          minLength(8)
235
        ),
236
        containsUppercase,
237
        containsNumber,
238
        containsSpecial,
239
      },
240
      date: { required },
241
      textarea: { required },
242
      selectedOption: { required },
243
      checked: { required },
244
      picked: { required },
245
    };
246

247
    // Vuelidate с автоматической валидацией и установкой dirty статуса
248
    const $v = useVuelidate(
249
      validations,
250
      {
251
        searchQuery,
252
        tooltipInput,
253
        emailField,
254
        password,
255
        date,
256
        textarea,
257
        selectedOption,
258
        checked,
259
        picked,
260
      },
261
      {
262
        $autoDirty: true, // Поле считается изменённым сразу после ввода
263
        $autoValidate: true, // Автоматическая валидация при изменении значения
264
      }
265
    );
266

267
    // Функция для обработки поиска
268
    const handleSearch = () => {
269
      alert(`Искать: ${searchQuery.value}`);
270
    };
271

272
    // Видимость подсказки
273
    const showTooltip = ref(false);
274

275
    return {
276
      searchQuery,
277
      tooltipInput,
278
      emailField,
279
      password,
280
      date,
281
      textarea,
282
      selectedOption,
283
      checked,
284
      picked,
285
      showTooltip,
286
      $v,
287
      handleSearch,
288
    };
289
  },
290
};
291
</script>
292

293
<style scoped>
294
.input-wrapper {
295
  margin-bottom: 20px;
296
  position: relative;
297
}
298

299
input,
300
textarea,
301
select {
302
  padding: 10px;
303
  border: 1px solid #ccc;
304
  border-radius: 4px;
305
  font-size: 14px;
306
  width: 100%;
307
  transition: border-color 0.3s;
308
}
309

310
input:focus,
311
textarea:focus,
312
select:focus {
313
  border-color: #6200ea;
314
}
315

316
.input-error {
317
  border-color: #f44336;
318
}
319

320
.error-message {
321
  color: #f44336;
322
  font-size: 12px;
323
  margin: 5px 0 0;
324
}
325

326
.btn-search {
327
  padding: 10px;
328
  margin-left: 5px;
329
  border: none;
330
  background-color: #6200ea;
331
  color: white;
332
  cursor: pointer;
333
  border-radius: 4px;
334
  font-size: 14px;
335
  transition: background-color 0.3s;
336
}
337

338
.btn-search:hover {
339
  background-color: #3700b3;
340
}
341

342
.tooltip {
343
  position: absolute;
344
  top: 100%;
345
  left: 0;
346
  padding: 5px;
347
  background-color: #333;
348
  color: white;
349
  border-radius: 4px;
350
  font-size: 12px;
351
  white-space: nowrap;
352
  z-index: 10;
353
}
354

355
.checkbox-label,
356
.radio-label {
357
  display: flex;
358
  flex-direction: row-reverse;
359
  align-items: center;
360
  margin-bottom: 5px;
361
  white-space: nowrap;
362
}
363

364
.checkbox-label input,
365
.radio-label input {
366
  margin-right: 10px;
367
}
368
</style>
369

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.