Riot.js позволяет создавать легковесные, переиспользуемые компоненты с минимальным количеством кода, что делает работу с кастомными элементами форм особенно удобной. Формы в веб-приложениях часто требуют нестандартного поведения: валидации, динамических списков, интерактивных элементов. Кастомные компоненты упрощают эту задачу, предоставляя мощный инструмент для инкапсуляции логики и стилей.
Кастомный элемент создаётся с помощью функции
riot.component() или с использованием старого синтаксиса
тегов .riot. Простейший пример кастомного текстового
поля:
<text-input>
<input type="text" onin put={updateValue} value={value}>
<script>
export default {
value: '',
updateValue(e) {
this.value = e.target.value
this.emit('change', this.value)
}
}
</script>
</text-input>
Ключевые моменты:
export default содержит состояние компонента и
методы.oninput привязано к функции
updateValue, которая обновляет локальное состояние и
эмиттирует событие наружу.emit позволяет родительскому компоненту
реагировать на изменения значения.Для форм важно синхронизировать состояние между компонентом и его родителем. В Riot.js используется механизм свойств (props) и событий:
<custom-checkbox checked={isChecked} oncha nge={toggleCheck}></custom-checkbox>
Внутри компонента:
<checkbox>
<input type="checkbox" checked={props.checked} oncha nge={handleChange}>
<script>
export default {
handleChange(e) {
this.emit('change', e.target.checked)
}
}
</script>
</checkbox>
Особенности связывания:
props передаются при создании компонента и доступны
через props.props запрещено — только локальная
копия состояния.Кастомные элементы позволяют инкапсулировать правила валидации:
<email-input>
<input type="email" value={value} onin put={validateEmail}>
<span if={error} class="error">{error}</span>
<script>
export default {
value: '',
error: '',
validateEmail(e) {
this.value = e.target.value
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
this.error = pattern.test(this.value) ? '' : 'Некорректный email'
this.emit('change', { value: this.value, valid: !this.error })
}
}
</script>
</email-input>
Важные аспекты:
Формы часто требуют объединения нескольких кастомных элементов:
<login-form>
<email-input oncha nge={updateEmail}></email-input>
<password-input oncha nge={updatePassword}></password-input>
<button oncl ick={submitForm}>Войти</button>
<script>
export default {
email: '',
password: '',
updateEmail(e) { this.email = e.value },
updatePassword(e) { this.password = e.value },
submitForm() {
console.log({ email: this.email, password: this.password })
}
}
</script>
</login-form>
Принципы работы:
Кастомные компоненты форм могут использоваться внутри циклов
each для динамических полей:
<tags-input>
<div each={tag, i in tags}>
<input type="text" value={tag} onin put={e => updateTag(e, i)}>
<button oncl ick={e => removeTag(i)}>Удалить</button>
</div>
<button oncl ick={addTag}>Добавить тег</button>
<script>
export default {
tags: [''],
addTag() { this.tags = [...this.tags, ''] },
removeTag(i) { this.tags = this.tags.filter((_, index) => index !== i) },
updateTag(e, i) {
this.tags[i] = e.target.value
this.update()
}
}
</script>
</tags-input>
Особенности:
each позволяет динамически добавлять и
удалять поля.update() вручную обновляет компонент после
изменения массива.Каждый кастомный элемент Riot.js имеет собственный CSS:
<text-input>
<input type="text" class="input">
<style>
.input {
border: 1px solid #ccc;
padding: 6px 10px;
border-radius: 4px;
font-size: 14px;
}
.input:focus {
border-color: #007bff;
outline: none;
}
</style>
</text-input>
Выводы по стилям:
Riot.js-компоненты легко интегрируются с другими библиотеками, например, для масок ввода или сложной валидации:
<phone-input>
<input ref="phone" onin put={formatPhone}>
<script>
import IMask from 'imask';
export default {
onMounted() {
this.mask = IMask(this.$refs.phone, { mask: '+{7}(000)000-00-00' });
},
formatPhone() {
this.emit('change', this.$refs.phone.value)
}
}
</script>
</phone-input>
Особенности:
ref позволяет напрямую работать с
DOM-элементами.Кастомные элементы форм в Riot.js обеспечивают мощный механизм для построения интерактивных, динамических и переиспользуемых интерфейсов с минимальной нагрузкой на код и с высокой читаемостью. Их структура позволяет сочетать реактивное поведение, валидацию, динамическое управление состоянием и интеграцию со сторонними инструментами.