оригинал:woohoo.smashing magazine.com/2017/08/пока горячо…
Компонентные библиотеки или фреймворки (например, Vue) позволяют нам разрабатыватьмногоразовые компонентыпринес большое удобство. Эти компоненты можно легко использовать в автономных приложениях, и конечный результат будет согласованным.
Например, в сценарии ввода формы функция часто бывает более сложной, обычно мы хотим использовать компоненты, чтобы поместить форму в форму.индивидуальный дизайн, метки, проверка, справочная информация и т. д. инкапсулированы, чтобы обеспечить их правильное последовательное отображение.
Vue имеет специальную и важную директиву v-model, которая реализует двустороннюю привязку данных путем связывания и захвата входных событий. Если вы создаете пользовательский компонент ввода, то этот компонент, несомненно, должен поддерживать директиву v-model.
К сожалению, когда я смотрю на пользовательские примеры для переключателей или флажков Vue, они либо не учитывают директиву v-model, либо неправильно ее реализуют. Есть несколько настраиваемых полей вводаРабота с документацией, но не объясняет, как работают пользовательские переключатели и флажки, я приведу несколько примеров и инструкций ниже.
Эта статья призвана помочь вам понять следующие моменты:
- Поймите, как директива v-model реализована в собственных полях ввода, сосредоточив внимание на переключателях и флажках.
- Поймите, как директива v-model обычно реализуется в пользовательских компонентах.
- Узнайте, как создать собственный переключатель и флажок с аналогичными функциями инструкции V-Model.
Для примеров кода, используемых в этой статье, я буду использовать ES2015+. При написании кода с использованием vue.component или нового Vue я предпочитаю использоватькомпонент одного файласинтаксис, что делает структуру проекта более понятной.
Как обычно работает v-модель?
Официальныйvue-документацияЭто было довольно ясно по этой теме, но все еще есть некоторые упущения. Короче говоря, я объясню этот кусок с самого начала. v-model — это, по сути, просто синтаксический сахар, который предоставляет нам возможности двусторонней привязки данных. Это зависит от различных типов элементов управления формы. Конкретные примеры следующие:
<input v-model="message" placeholder="edit me">
<p>Message: {{ message }}</p>
<!-- OR -->
<p>message:</p>
<p style="white-space: pre-line">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
При использовании полей ввода текста (включая электронную почту, числовые типы и т. д.) или типов текстовых полейv-model ="varName"
Эквивалентно:value ="varName" @input ="e => varName = e.target.value"
. Это означает, что каждый раз, когда вы вводите текст в текстовое поле, событие ввода передает значение в varName через событие ввода, и varName обновляется таким образом каждый раз, когда вы вводите. Аналогично, за исключением элементов select с атрибутом Multiple, обычные
select также реализован таким образом.
Радио-кнопки
Так как же реализована радиокнопка?
<input type="radio" value="One" v-model="picked">
<input type="radio" value="Two" v-model="picked">
<span>Picked: {{ picked }}</span>
Эквивалентно следующему коду:
<input type="radio" value="One" :checked="picked == 'One'" @change="picked = $event.target.value">
<input type="radio" value="Two" :checked="picked == 'Two'" @change="picked = $event.target.value">
<span>Picked: {{ picked }}</span>
Вы обнаружите, что v-модель не имеет прямого отношения к стоимости. Но он по-прежнему делает то же самое с событием изменения (хотя событие изменяется с ввода на изменение). Затем определите, выбран ли переключатель, основываясь на том, совпадает ли значение pick со значением переключателя.
Флажки
Поля с множественным выбором немного сложнее обсуждать. Потому что у него есть два разных поведения, в зависимости от того, есть ли только один флажок, привязанный к директиве v-model, или несколько привязанных директив v-model.
Если вы используете один флажок, v-model будет рассматривать его как логическое значение и игнорировать значение.
<input type="checkbox" value="foo" v-model="isChecked">
эквивалентен приведенному ниже коду:
<input type="checkbox" value="foo" :checked="isChecked" @change="isChecked = $event.target.value">
Если вы хотите, чтобы он мог представлять больше, чем просто true и false, вы можете использовать свойства true-value и false-value для установки проверенных и непроверенных значений флажка.
<input type="checkbox" value="foo" v-model="isChecked" true-value="1" false-value="0">
эквивалентен приведенному ниже коду:
<input type="checkbox" value="foo" :checked="isChecked == '1'" @change="isChecked = $event.target.checked ? '1' : '0'">
Это пример одного флажка. Если у вас есть несколько флажков, разделяющих модель, эти флажки будут заполнены массивом значений значений всех отмеченных флажков. Вы также должны убедиться, что модель, которую вы передаете, является типом массива, иначе возникнут странные проблемы. Конечно, истинное значение и ложное значение не будут иметь никакого значения в этом сценарии.
<template>
<div>
<input type="checkbox" value="foo" v-model="checkedVals">
<input type="checkbox" value="bar" v-model="checkedVals">
<input type="checkbox" value="baz" v-model="checkedVals">
</div>
</template>
<script>
export default {
data: () => ({
checkedVals: ['bar']
})
}
</script>
В приведенном выше коде сложно реализовать v-модель, добавляя методы через атрибуты элемента, поэтому я перенес часть логики в методы компонента.
<template>
<div>
<input type="checkbox" value="foo" v-model="checkedVals">
<input type="checkbox" value="bar" v-model="checkedVals">
<input type="checkbox" value="baz" v-model="checkedVals">
</div>
</template>
<script>
export default {
data() {
return { checkedVals: ['bar'] }
},
methods: {
shouldBeChecked(val) {
return this.checkedVals.includes(val)
},
updateVals(e) {
let isChecked = e.target.checked
let val = e.target.value
if (isChecked) {
this.checkedVals.push(val)
} else {
this.checkVals.splice(this.checkedVals.indexOf(val), 1)
}
}
}
}
</script>
Как видно из приведенного выше кода, реализация флажка намного сложнее, чем реализация текстового поля и радиокнопки, представленных ранее. Но когда мы разложим метод компонента флажка, мы обнаружим, что это не так сложно. shouldBeChecked имеет значение true, если значение флажка содержится в массиве модели, и значение false в противном случае. Когда он установлен, updateVals добавляет значение флажка в массив. Когда флажок снят, updateVals удаляет значение флажка из массива.
Как v-model работает с компонентами?
Поскольку Vue не знает, какова функция пользовательского компонента, если пользовательский компонент используется как функция, аналогичная элементу ввода формы, Vue рассматривает пользовательский компонент так же, как принцип реализации v-модели. Пользовательский компонент на самом деле работает точно так же, как поле ввода текста, за исключением того, что в обработчике событий он не передает ему объект события, вместо этого он ожидает, что значение будет передано непосредственно ему. так
<my-custom-component v-model="myProperty" />
Код эквивалентен следующему
<my-custom-component :value="myProperty" @input="val => myProperty = val" />
Пользовательские компоненты могут использовать атрибут модели для преобразования приведенной выше реализации в следующую реализацию кода:
export default {
name: 'my-custom-component',
model: {
prop: 'foo',
event: 'bar'
},
// ...
}
Директива v-model будет искать все значения в модели и использовать свойство, указанное вами в prop, вместо использования ранее свойства value. Также он будет использовать событие, указанное в событии, вместо входного события. Таким образом, приведенный выше пример пользовательского компонента фактически расширится до следующего:
<my-custom-component :foo="myProperty" @bar="val => myProperty = val" />
Выглядит хорошо, но если бы мы сделали настраиваемый переключатель или флажок, могла бы возникнуть проблема. С некоторыми изменениями мы можем переместить логику, реализованную v-model, в наши настраиваемые компоненты радиокнопок и флажков.
Реализация пользовательских переключателей с использованием v-модели
По сравнению с флажками пользовательские переключатели очень просты. Ниже приведен очень простой пользовательский переключатель, все, что я разработал, — это обернуть текстовое поле ввода тегом метки и принять свойство метки, чтобы добавить текст метки.
<template>
<label>
<input type="radio" :checked="shouldBeChecked" :value="value" @change="updateInput">
{{ label }}
</label>
</template>
<script>
export default {
model: {
prop: 'modelValue',
event: 'change'
},
props: {
value: {
type: String,
},
modelValue: {
default: ""
},
label: {
type: String,
required: true
},
},
computed: {
shouldBeChecked() {
return this.modelValue == this.value
}
}
methods: {
updateInput() {
this.$emit('change', this.value)
}
}
}
</script>
Примечание: я написал значение props только для того, чтобы объяснить принцип реализации v-model.Что касается других свойств (например, name или disabled), которые необходимо использовать на входе, их нужно создать в реквизитах и передать на вход. Вам также необходимо добавитьWAI-ARIAсвойства, чтобы учитывать доступность и использоватьслотыраздавать контент вместо того, что я задал в props Значение метки так же просто.
Вы можете подумать, что я не включил атрибут имени в этот пример, что группа переключателей на самом деле не будет синхронизирована друг с другом. На самом деле, обновление модели, в свою очередь, обновит другие переключатели, которые используют эту модель, поэтому, пока они используют одну и ту же модель, им не нужно совместно использовать атрибут имени, как в обычной HTML-форме.
Реализация пользовательских флажков с v-моделью
Пользовательские флажки, очевидно, немного сложнее, чем переключатели, в основном потому, что мы должны поддерживать два разных использования: один флажок «истина/ложь» (возможно, с или без значения «истина» или «ложь») и несколько флажков, которые добавляют все проверенные значения. значения в массив модели.
Вы можете подумать, что нам сначала нужно определить, имеют ли элементы флажка одинаковый атрибут имени, но это не так, как это реализовано внутри Vue. Как и радиокнопки, Vue вообще не принимает во внимание атрибут имени. Атрибут name используется только при отправке нативных форм. Вы можете подумать, что это зависит от того, используют ли флажки одну и ту же модель, но это не так, это просто один или несколько флажков в зависимости от того, является ли модель массивом.
Следовательно, этот код будет реорганизован в соответствии с реализацией пользовательского переключателя, а функции sholdBeChecked и updateInput должны быть логически разделены в зависимости от того, является ли modelValue массивом.
<template>
<label>
<input type="checkbox" :checked="shouldBeChecked" :value="value" @change="updateInput">
{{ label }}
</label>
</template>
<script>
export default {
model: {
prop: 'modelValue',
event: 'change'
},
props: {
value: {
type: String,
},
modelValue: {
default: false
},
label: {
type: String,
required: true
},
// We set `true-value` and `false-value` to the default true and false so
// we can always use them instead of checking whether or not they are set.
// Also can use camelCase here, but hyphen-separating the attribute name
// when using the component will still work
trueValue: {
default: true
},
falseValue: {
default: false
}
},
computed: {
shouldBeChecked() {
if (this.modelValue instanceof Array) {
return this.modelValue.includes(this.value)
}
// Note that `true-value` and `false-value` are camelCase in the JS
return this.modelValue === this.trueValue
}
},
methods: {
updateInput(event) {
let isChecked = event.target.checked
if (this.modelValue instanceof Array) {
let newValue = [...this.modelValue]
if (isChecked) {
newValue.push(this.value)
} else {
newValue.splice(newValue.indexOf(this.value), 1)
}
this.$emit('change', newValue)
} else {
this.$emit('change', isChecked ? this.trueValue : this.falseValue)
}
}
}
}
</script>
Пользовательский компонент флажка теперь реализован. Было бы лучше, если бы вы разбили его на два разных компонента: один для обработки одного переключателя true/false и один для списка параметров (несколько флажков). Таким образом, компоненты будут более точно придерживаться принципа единой ответственности. Если вы ищете настраиваемый компонент флажка, это то, что вам нужно.
Расширенное чтение
Хотите узнать больше о пользовательских элементах ввода, компонентах Vue и Vue. Следующие ресурсы могут быть именно тем, что вам нужно.
Наборы компонентов Awesome-VueAwesome-Vue — это коллекция списков проектов и ресурсов, связанных с Vue, не стесняйтесь просматривать все в этом списке, но я хочу указать, в частности, на библиотеки пользовательского интерфейса и наборы компонентов, потому что они почти имеют флажки и радио для примеров, вы можете взять посмотрите, если вам нравится читать их исходный код.
Vue Curated Этот список похож на Awesome-Vue, но он более солидный, так что все в списке заслуживает внимания.
Vue Component Guide Официальное руководство по Vue, безусловно, хорошее место, чтобы узнать об основах Vue.
Vue API Documentation Документация поможет вам по-настоящему погрузиться в детали Vue.