Vue.js рдореЗрдВ рдлрд╝реЙрд░реНрдо рд╕рддреНрдпрд╛рдкрди

рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░!

рдлреЙрд░реНрдо рд╕рддреНрдпрд╛рдкрди рд╕рд╛рдЗрдЯ рдкрд░ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рд╣рдореЗрдВ рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдирд╛ рд╣реИ, рдкреИрдЯрд░реНрди рд╕реЗ рдорд┐рд▓рд╛рди рдХрд░рдирд╛ рд╣реИ, рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕рддреНрдпрд╛рдкрди рдмрдирд╛рдирд╛ рд╣реИ, рдХреНрд╖реЗрддреНрд░ рд╕реЗ рдлрд╝реЛрдХрд╕ рд╣рдЯрд╛рдиреЗ рдХреЗ рдмрд╛рдж рдпрд╛ рдлрд╝реЙрд░реНрдо рдЬрдорд╛ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕рддреНрдпрд╛рдкрди рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╣реИ ... рдХрднреА-рдХрднреА рдпрд╣ рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд▓рд┐рдП рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рд┐рд░рджрд░реНрдж рдмрди рдЬрд╛рддрд╛ рд╣реИред

Vue.js рдореЗрдВ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдХрдИ рджрд┐рд▓рдЪрд╕реНрдк рдФрд░ рдЕрд╕рд╛рдорд╛рдиреНрдп рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╢рд╛рдорд┐рд▓ рд╣реИрдВ рдЬреЛ рдЖрдкрдХреА рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдВрдЧреЗред рдХрдЯ рдХреЗ рддрд╣рдд рдЕрд╡рд▓реЛрдХрди!


рдЯреАрдПрд▓, рдбреЙ


Vuelidate рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рд╕рд╛рдорд╛рдиреНрдп рдЧрд▓рддрд┐рдпрд╛рдБ


HTML5 рд╕рддреНрдпрд╛рдкрди


HTML5 рдиреЗ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рдирдП рдлрд╝реАрд▓реНрдб рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдФрд░ рд╕рддреНрдпрд╛рдкрди API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд░реВрдкреЛрдВ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рджреАред рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╕реАрдзреЗ рдЕрдкрдиреЗ vue рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдпрд╣рд╛рдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкрдВрдЬреАрдХрд░рдг рдлреЙрд░реНрдо рд╣реИ рдЬрд┐рд╕рдореЗрдВ рддреАрди рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИрдВ: рдИ-рдореЗрд▓ рдХреЗ рд▓рд┐рдП рдлрд╝реАрд▓реНрдб, рдкрд╛рд╕рд╡рд░реНрдб рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рд░реАрдкреНрд▓реЗ рдХреЗ рд▓рд┐рдПред рдкрд╣рд▓реЗ рджреЛ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдорд╛рдиреНрдпрддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреАрд╕рд░реЗ рдХреЗ рд▓рд┐рдП - рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдФрд░ рд╕рддреНрдпрд╛рдкрди рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП:

<template> <form @submit.prevent="someAction()"> <input v-model="email" type="email" required> <input v-model="password" type="password" required> <input v-model="repeatedPassword" type="password" required ref="repeatedPasswordEl"> <button type="submit">   </button> </form> </template> <script> export default { data() { return { email: null, password: null, repeatedPassword: null, }; }, watch: { repeatedPassword: 'checkPasswordsEquality', password: 'checkPasswordsEquality', }, methods: { checkPasswordsEquality() { const { password, repeatedPassword } = this; const { repeatedPasswordEl } = this.$refs; if (password !== repeatedPassword) { repeatedPasswordEl.setCustomValidity( '  ', ); } else { repeatedPasswordEl.setCustomValidity(''); } }, }, }; </script> 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рд╕реИрдВрдбрдмреЙрдХреНрд╕

рдРрд╕реЗ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рднреА, рдЖрдк рдХрдИ рд╕рдорд╕реНрдпрд╛рдПрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:

  • рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рджрд┐рдЦрд╛рддреЗ рд╣реИрдВред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЕрдкрдиреА рд╕рднреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдмрд╛рд░ рдлрд╝реЙрд░реНрдо рдЬрдорд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
  • рдкреНрд░рдкрддреНрд░ рдЬрдорд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдФрд░ рдЯрди рдХреЛрдб рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛: рдмреНрд▓рд░ рдШрдЯрдирд╛ рдкрд░ рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдкрд░ рд░рд┐рдкреЛрд░реНрдЯрд╡реИрд▓рд┐рдбрд┐рдЯреА () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВред
  • рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдХреЛ рд╕реНрдЯрд╛рдЗрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреЗрд╡рд▓ рдЫрджреНрдо рд╡рд░реНрдЧ рд╣реИрдВ: рдорд╛рдиреНрдп рдФрд░: рдЕрдорд╛рдиреНрдп, рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдбреЗрдЯрд╛ рдЧрд▓рдд рд╣реЛрдиреЗ рдкрд░ рд░рд╛рдЬреНрдп рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдЕрднреА рддрдХ рдЗрд╕рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдирд╣реАрдВ рдХреА рд╣реИред
  • рдкреНрд░рддреНрдпреЗрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЕрдкрдиреЗ рддрд░реАрдХреЗ рд╕реЗ рд╕рддреНрдпрд╛рдкрди рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╡реЗ рдЖрдкрдХреЗ рдбрд┐рдЬрд╝рд╛рдЗрди рдореЗрдВ рдмрджрд╕реВрд░рдд рджрд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВред
  • Vue.js рдореЗрдВ рдорд╛рдиреНрдпрддрд╛ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ: рдЖрдкрдХреЛ $ рд░реЗрдл рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЛ рдмрдЪрд╛рдирд╛ рд╣реЛрдЧрд╛ред

рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдлрд╝реЙрд░реНрдо рд╣реИ, рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ HTML5 рд╕рддреНрдпрд╛рдкрди рдПрдХ рдЙрддреНрдХреГрд╖реНрдЯ рд╡рд┐рдХрд▓реНрдк рд╣реИред рдЕрдиреНрдп рд╕рднреА рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред

рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдорд╛рдиреНрдпрддрд╛рдУрдВ


рдПрдХ рдФрд░ рдЖрдо рд╕рдорд╕реНрдпрд╛ рд╣реИ рдХрд┐ рдореИрдВ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдореБрдарднреЗрдбрд╝ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕рддреНрдпрд╛рдкрди рд╣реИред

 <template> <form @submit.prevent="someAction()"> <input v-model="email" type="email" @blur="isEmailTouched = true" :class="{ error: isEmailError }" > <div v-if="isEmailError">    </div> <button :disabled="!isEmailValid" type="submit">   </button> </form> </template> <script> const emailCheckRegex = /^... RegExp   Email...$/; export default { data() { return { email: null, isEmailTouched: false, }; }, computed: { isEmailValid() { return emailCheckRegex.test(this.email); }, isEmailError() { return !this.isEmailValid && this.isEmailTouched; }, }, }; </script> 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рд╕реИрдВрдбрдмреЙрдХреНрд╕

рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдХреНрд╖реЗрддреНрд░реЛрдВ рд╡рд╛рд▓реЗ рд░реВрдкреЛрдВ рдореЗрдВ, рдмрд╣реБрдд рд╕рд╛рд░реЗ рджреЛрд╣рд░рд╛рдпрд╛ рдХреЛрдб рдХрд╛ рдЬрдиреНрдо рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╡рд▓рдкрд░ рдЕрдкрдиреЗ рддрд░реАрдХреЗ рд╕реЗ рд╕рддреНрдпрд╛рдкрди рд▓рд┐рдЦрддрд╛ рд╣реИред

рд╕рднреА рд╕рдорд╕реНрдпрд╛рдУрдВ рдореЗрдВ рд╕реЗ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рддрд░реАрдХрд╛ рдЙрди рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ рдЬреЛ рд╕рдореБрджрд╛рдп рд╣рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рд╡рд░реНрддрдорд╛рди рдореЗрдВ рджреЛ рд▓реЛрдХрдкреНрд░рд┐рдп рд░реВрдк рд╕рддреНрдпрд╛рдкрди рд╕рдорд╛рдзрд╛рди рд╣реИрдВ:


рдкреНрд░рддреНрдпреЗрдХ рдХрд╛ рдЕрдкрдирд╛ рдЕрдиреВрдард╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдо рдиреАрдЪреЗ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред

рд╡реА рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ


vee-validate - рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬреЛ Vue.js рдХреЗ рдкрд╣рд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рджреМрд░рд╛рди рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛, рдореЗрдВ рдПрдХ рдмрдбрд╝рд╛ рд╕рдореБрджрд╛рдп рд╣реИ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЖрдпреБ рд╡рдЬрди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддреА рд╣реИ - 31 KB (рдорд┐рдирд┐рдлрд╝рд╛рдЗрдб + GZIP), Vue.js рд╕реЗ рдбреЗрдврд╝ рдЧреБрдирд╛ рдЕрдзрд┐рдХ! рдпрд╣ рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рддреБрд░рдВрдд рдЪреАрдЬреЛрдВ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рд╣реЛрддрд╛ рд╣реИ:

  • 35 рдмрд┐рд▓реНрдЯ-рдЗрди рд╡реИрдзреАрдЯрд░
  • рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рдЕрдВрдЧреНрд░реЗрдЬреА рдЕрдиреБрд╡рд╛рдж
  • рдорд╛рдиреНрдпрддрд╛ рдирд┐рд░реНрджреЗрд╢
  • рд╕рддреНрдпрд╛рдкрди рдШрдЯрдХ

рдкреБрд╕реНрддрдХрд╛рд▓рдп рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП 41 рднрд╛рд╖рд╛рдУрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рд╡рд╛рдВрдЫрд┐рдд рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдХреЗ рд╕рд╛рде рдЗрд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдХреБрдЫ рдЪрд░рдгреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

 npm i vee-validate 

 /* main.js */ import Vue from 'vue'; import VeeValidate, { Validator } from 'vee-validate'; import ru from 'vee-validate/dist/locale/ru'; Validator.localize('ru', ru); Vue.use(VeeValidate, { locale: 'ru', }); /* ... */ 

Vee-validate рдХреЗ рд╕рддреНрдпрд╛рдкрди рдХреЗ рджреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИрдВ: рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдФрд░ рдШрдЯрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред

рд╡реА-рдорд╛рдиреНрдп рдирд┐рд░реНрджреЗрд╢ рдХреЗ рд╕рд╛рде рдорд╛рдиреНрдпрддрд╛


рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╣реИ: рдЖрдк v- рдорд╛рдиреНрдп рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдкрд░ рд░рдЦрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдЖрдк рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛рдУрдВ рдХреА рд╕реВрдЪреА рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рд╕рддреНрдпрд╛рдкрди рдХреА рд╕реНрдерд┐рддрд┐ рдФрд░ рддреНрд░реБрдЯрд┐ рд▓рд╛рдЗрдиреЗрдВ рддрдм рдШрдЯрдХ рдлрд╝реАрд▓реНрдб рдФрд░ рдШрдЯрдХ рдХреЗ рдЕрдВрджрд░ рддреНрд░реБрдЯрд┐рдпреЛрдВ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИрдВред

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдЗрдП рдПрдХ рд╕рд░рд▓ рд░реВрдк рдмрдирд╛рддреЗ рд╣реИрдВ:

- "рд╢реНрд░реГрдВрдЦрд▓рд╛ рдФрд░ рдкрд╛рд╕рдкреЛрд░реНрдЯ рдирдВрдмрд░" рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИ
- "рдкрд╛рд╕рдкреЛрд░реНрдЯ рдЬрд╛рд░реА рдХрд░рдиреЗ рдХреА рддрд┐рдерд┐" рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИ
- "рдирд╛рдо" рдлрд╝реАрд▓реНрдб рд╢рд╛рдорд┐рд▓ рд╣реИ
- рдпрджрд┐ рдбреЗрдЯрд╛ рдЧрд▓рдд рд╣реИ рддреЛ рдлреЙрд░реНрдо рдХреА рд╕рдмрдорд┐рдЯ рдмрдЯрди рдореЗрдВ рдЕрдХреНрд╖рдо рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИ

 <template> <form @submit.prevent="someAction()"> <div> <!--             data-vv-as -          name -      --> <input type="text" v-model="passportData" v-validate="{ required: true, regex: /^\d{4} \d{6}$/ }" data-vv-as="   " name="passport_data" > <span v-if="errors.has('passport_data')"> {{ errors.first('passport_data') }} </span> </div> <div> <!--           .      v-model- lazy     fields.passport_date  invalid  ,       touched ,      blur --> <input type="text" v-model.lazy="passportDate" v-validate="{ required: true, date_format: 'dd.MM.yyyy' }" data-vv-as="  " name="passport_date" > <span v-if="fields.passport_date && fields.passport_date.touched && fields.passport_date.invalid" > {{ errors.first('passport_date') }} </span> </div> <div> <!--       ,    continues   errors.collect() --> <input type="text" v-model="name" v-validate.continues="{ required: true, alpha: true, max: 10 }" data-vv-as="" name="name" > <span v-for="error in errors.collect('name')" :key="error" > {{ error }} </span> </div> <button type="submit" :disabled="!isFormValid" >   </button> </form> </template> <script> export default { data() { return { passportData: null, name: null, passportDate: null, }; }, computed: { // ,      isFormValid () { return Object.keys(this.fields).every(field => this.fields[field].valid); }, }, }; </script> 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рд╕реИрдВрдбрдмреЙрдХреНрд╕

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрдм field.passport_date рдХреЗ рдЕрдВрджрд░ рдЭрдВрдбреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП passport_date рдлрд╝реАрд▓реНрдб рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреА рдереА - рдкрд╣рд▓реЗ рд░реЗрдВрдбрд░ рдХреЗ рджреМрд░рд╛рди, vee-validate рдХреЛ рдЖрдкрдХреЗ рдЦреЗрддреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреЛрдИ рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реИ рдФрд░, рддрджрдиреБрд╕рд╛рд░, рдЭрдВрдбреЗ рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╡рд╕реНрддреБ рдирд╣реАрдВ рд╣реИред рдЗрд╕ рдЬрд╛рдВрдЪ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╡рд┐рд╢реЗрд╖ рдореИрдкрдлрд┐рд▓реНрдб рд╣реЗрд▓реНрдкрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рдШрдЯрдХ рдорд╛рдиреНрдпрддрд╛рдУрдВ


рдкрд┐рдЫрд▓реЗ рд╡рд░реНрд╖ рдХреЗ рдЕрдВрдд рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдиреЗ рд╡рд╛рд▓реА рдирдИ рд╕рддреНрдпрд╛рдкрди рд╡рд┐рдзрд┐ рдШрдЯрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реИред рд▓реЗрдЦрдХ рд╕реНрд╡рдпрдВ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ Vue.js@2.6 рд╕реЗ рдирдП рд╕реНрд▓реЙрдЯ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЪрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИред

рдкреБрд╕реНрддрдХрд╛рд▓рдп рджреЛ рдШрдЯрдХ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:

  • ValidationProvider - рдПрдХ рдШрдЯрдХ рдЬрд┐рд╕рдореЗрдВ рдЖрдк рдорд╛рдиреНрдпрддрд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЬрд┐рд╕рдореЗрдВ рдЖрдк рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб рдХреЛ рд▓рдкреЗрдЯрддреЗ рд╣реИрдВред
  • ValidationObserver - рдПрдХ рдШрдЯрдХ рдЬреЛ рдХрдИ рдорд╛рдиреНрдпрдХрд░рдгреЛрдВ рдХреЗ рд╕рддреНрдпрд╛рдкрди рдЭрдВрдбреЗ рдХреЛ рдЬреЛрдбрд╝рддреА рд╣реИред

рдпрд╣рд╛рдБ рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдПрдХ рдлрд╛рд░реНрдо рд╣реИ, рд▓реЗрдХрд┐рди рдШрдЯрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ:

 <template> <!-- ValidationObserver      .      valid      --> <ValidationObserver v-slot="{ valid }"> <form @submit.prevent="doAction()"> <!-- ValidationProvider                 name - ,      --> <ValidationProvider name="   " :rules="{ required: true, regex: /^\d{4} \d{6}$/ }" v-slot="{ errors }" > <input type="text" v-model="passportData"> <span v-if="errors[0]"> {{ errors[0] }} </span> </ValidationProvider> <!--         input,    blur  change  mode="lazy"  mode="eager" --> <ValidationProvider name="  " :rules="{ required: true, date_format: 'dd.MM.yyyy' }" v-slot="{ errors }" mode="lazy" > <input type="text" v-model="passportDate"> <span v-if="errors[0]"> {{ errors[0] }} </span> </ValidationProvider> <!--       ,     :bails="false" --> <ValidationProvider name="" :rules="{ required: true, alpha: true, max: 10 }" v-slot="{ errors }" :bails="false" > <input type="text" v-model="name"> <span v-for="error in errors" :key="error" > {{ error }} </span> </ValidationProvider> <button type="submit" :disabled="!valid">   </button> </form> </ValidationObserver> </template> <script> import { ValidationProvider, ValidationObserver } from 'vee-validate'; export default { components: { ValidationProvider, ValidationObserver, }, data() { return { passportData: null, passportDate: null, name: null, }; }, }; </script> 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рд╕реИрдВрдбрдмреЙрдХреНрд╕

рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реБрд╡рд┐рдзрд╛рдПрдБ



рд╕рдорд╕реНрдпрд╛рдУрдВ


рдкрд╣рд▓реА рдФрд░ рд╕рдмрд╕реЗ рдмрдбрд╝реА рд╕рдорд╕реНрдпрд╛, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЗрд╕рдХрд╛ рдЖрдХрд╛рд░ рд╣реИред рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЯреНрд░реА-рд╢реЗрдХрд┐рдВрдЧ рдФрд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛рдУрдВ рдХреЗ рдЪрдпрдирд╛рддреНрдордХ рдЬреЛрдбрд╝ рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЖрдк рдЗрд╕реЗ рдкрд╕рдВрдж рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рдирд╣реАрдВ, рдЖрдкрдХреЗ рдЧрд┐рд░реЛрд╣ рдореЗрдВ рд╣рдореЗрд╢рд╛ 2 рдШрдЯрдХ рд╣реЛрдВрдЧреЗ рдФрд░ рдПрдХ рд╕рддреНрдпрд╛рдкрди рдирд┐рд░реНрджреЗрд╢, рдЕрдВрдЧреНрд░реЗрдЬреА рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдФрд░ 35 рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рд╣реЛрдВрдЧреЗред

рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдИрд╡реЗрдВрдЯ-рдЖрдзрд╛рд░рд┐рдд рд╕рджрд╕реНрдпрддрд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдХрд╛рд░рдг рд╣реИ, рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХреАрдХрд░рдг рдХрд░рддреЗ рд╕рдордп рд╕рдорд╕реНрдпрд╛рдПрдВ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИрдВ рдЬреЛ рдЗрдирдкреБрдЯ рдлрд╝реАрд▓реНрдб (рдорд╛рд╕реНрдХрд░реНрд╕, рдЖрджрд┐) рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рднреА рдмрджрд▓рддреЗ рд╣реИрдВред

рддреАрд╕рд░реА рд╕рдорд╕реНрдпрд╛ - рдПрдХ рдЕрдзрд┐рдХ рд╡реНрдпрдХреНрддрд┐рдкрд░рдХ - рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдЕрдиреБрд╡рд╛рдж рд╕рд╛рдорд╛рдиреНрдп рдФрд░ рдмрджрд╕реВрд░рдд рд╣реИрдВ, рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рд╛рд░ рдХреЛ рдкреНрд░рддрд┐рдмрд┐рдВрдмрд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред

рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдгреЛрдВ рд╕реЗ рдлреЙрд░реНрдо рд▓реЗрдВред рдпрджрд┐ рдЖрдк рдкрд╛рд╕рдкреЛрд░реНрдЯ рдХреА рдЧрд▓рдд рд╕рдВрдЦреНрдпрд╛ рдФрд░ рддрд╛рд░реАрдЦ рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреА:

        .         dd.MM.yyyy. 

рдореИрдВ рдЙрдиреНрд╣реЗрдВ рдХреБрдЫ рдФрд░ рдкрдардиреАрдп рдХреЗ рд╕рд╛рде рдмрджрд▓рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛:

          1234 567890         .. 

Vuelidate


Vuelidate рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЙрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдЬрд╡рд╛рдм рдореЗрдВ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛, рдЬрд┐рдирдореЗрдВ рд╡реЗрдИ-рдорд╛рдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╢рд╛рдорд┐рд▓ рд╣реИрдВред Vuelidate рдореЗрдВ рди рддреЛ рдЦреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИрдВрдбрд▓рд░ рд╣реИрдВ, рди рд╣реА рд╕рддреНрдпрд╛рдкрди рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд╛рджред

рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рд╕рддреНрдпрд╛рдкрди рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдорд╛рдиреНрдпрддрд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рддрдм рд╡рд╣ рдЦреБрдж рдЗрди рдЭрдВрдбреЛрдВ рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд╖реЗрддреНрд░ рд╕рддреНрдпрд╛рдкрди рдЭрдВрдбреЗ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЧрдгрдирд╛ рдХреНрд╖реЗрддреНрд░ $ v рдмрдирд╛рдПрдЧреАред

рдЕрдкрдиреЗ рд╕рд░рд▓ рд╕рддреНрдпрд╛рдкрди рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, Vuelidate рдХрд╛ рд╡рдЬрди рдХреЗрд╡рд▓ 3.4 KB (рдорд┐рдирд┐рдлрд╝рд╛рдЗрдб + GZIP) рд╣реИ, рдЬреЛ рдХрд┐ рд╡реА-рдорд╛рдиреНрдп рд╕реЗ рд▓рдЧрднрдЧ 10 рдЧреБрдирд╛ рдХрдо рд╣реИред

рдпрд╣ рдЖрд╕рд╛рдиреА рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

 npm i vuelidate 

 /* main.js */ import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) /* ... */ 

Vuelidate рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд┐рдЫрд▓реЗ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдлрд╝реЙрд░реНрдо рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦреЗрдВ:

 <template> <form @submit.prevent="someAction()"> <!--      ,  $v.passportData.$invalid   ,     --> <div> <input type="text" v-model="passportData"> <span v-if="$v.passportData.$invalid">         1234 567890 </span> </div> <!--      blur  $touch()   $v.passportDate.$dirty  true.  $v.passportDate.$error   $v.passportDate.$invalid && $v.passportDate.$dirty --> <div> <input type="text" v-model="passportDate" @blur="$v.passportDate.$touch()"> <span v-if="$v.passportDate.$error">      .. </span> </div> <!-- ,       blur,     $v.passportDate.$model - ,     : - Vuelidate     passportDate - Vuelidate   $touch()   $v.passportDate  lazy ,      blur --> <div> <input type="text" v-model.lazy="$v.passportDate.$model"> <span v-if="$v.passportDate.$error">      .. </span> </div> <!--     --> <div> <input type="text" v-model="name" @blur="$v.name.$touch()"> <span v-if="$v.name.$error"> <template v-if="!$v.name.maxLength">      {{ $v.name.$params.maxLength.max }}  </template> <template v-else-if="!$v.name.alpha">      </template> <template v-else>     </template> </span> </div> <button type="submit" :disabled="$v.$invalid">   </button> </form> </template> <script> import { required, maxLength } from 'vuelidate/lib/validators'; import moment from 'moment'; export default { data() { return { passportData: null, name: null, passportDate: null, }; }, //   ,  Vuelidate   computed- $v validations: { //        data passportData: { required, validFormat: val => /^\d{4} \d{6}$/.test(val), }, passportDate: { required, validDate: val => moment(val, 'DD.MM.YYYY', true).isValid(), }, name: { required, maxLength: maxLength(10), alpha: val => /^[-]*$/i.test(val), }, }, }; </script> 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рд╕реИрдВрдбрдмреЙрдХреНрд╕

рдХрд╕реНрдЯрдо рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЬрд▓реНрджреА рдФрд░ рдЖрд╕рд╛рдиреА рд╕реЗ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЖрдкрдХрд╛ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдкреИрд░рд╛рдореАрдЯрд░ $ рдкрд░рдо рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдЖрдП, рддреЛ рд╡рд┐рд╢реЗрд╖ рд╡рд┐рд░рд╛рдо рд╣реЗрд▓реНрдкрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдХрдИ рддреНрд░реБрдЯрд┐рдпреЛрдВ рд╡рд╛рд▓реЗ рдлрд╝реАрд▓реНрдб рдмрд╣реБрдд рд╕реА рдЬрдЧрд╣ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рд░рд╛рдХреНрд╖рд╕реА рджрд┐рдЦрддреЗ рд╣реИрдВ - рдпрд╣ рд╕рддреНрдпрд╛рдкрди рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдШрдЯрдХ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реБрд╡рд┐рдзрд╛рдПрдБ



рд╕рдорд╕реНрдпрд╛рдУрдВ


рд╕рдорд╕реНрдпрд╛рдУрдВ рдореЗрдВ рд╕реЗ, рдмреЙрдХреНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛рдУрдВ рдХреА рддреБрд▓рдирд╛рддреНрдордХ рд░реВрдк рд╕реЗ рдЕрд▓реНрдк рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдПрдХрд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИ; рдЖрдкрдХреЛ рдЕрдХреНрд╕рд░ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред

рдирд┐рд╖реНрдХрд░реНрд╖


рдореИрдВрдиреЗ рдХрдИ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдореЗрдВ Vuelidate рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдХрднреА рднреА рдЕрд╕рд╛рдзреНрдп рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╕рд╛рдордирд╛ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред рдореЗрд░реЗ рд▓рд┐рдП, рд╡рд╣ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдХрд▓реНрдк рд╣реИред рдпрджрд┐ рдЖрдк рдЕрдкрдиреЗ рдХреЛрдб рдХреЗ рдЖрдХрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрд░рд╡рд╛рд╣ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдорд╛рдиреНрдпрддрд╛рдУрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдореЙрдбрд▓ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкрд╕рдВрдж рдХрд░рддреЗ рд╣реИрдВ - рдЗрд╕реЗ рд▓реЗ рд▓реЛ, рд╕рд░рд▓ рдкреНрд░рд▓реЗрдЦрди рдФрд░ рдЕрдореАрд░ рдПрдкреАрдЖрдИ рдХрд┐рд╕реА рднреА рдЬрдЯрд┐рд▓рддрд╛ рдХреЗ рд░реВрдкреЛрдВ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред

рдпрджрд┐ рдЖрдк рдЖрдВрддрд░рд┐рдХ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдкреИрдирд▓ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рддреНрд░реБрдЯрд┐ рд▓рд╛рдЗрдиреЛрдВ рдкрд░ рд╕рдордп рдХреА рдПрдХ рднреА рдмреВрдВрдж рдЦрд░реНрдЪ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ - рд╡реА-рдорд╛рдиреНрдп рдЪреБрдиреЗрдВред рдпрд╣ рдХрдИ рд╕рддреНрдпрд╛рдкрдиреЛрдВ рдХреЛ рдЬрд▓реНрджреА рдФрд░ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдмрд┐рдирд╛ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

Source: https://habr.com/ru/post/hi444900/


All Articles