基于组件的库或框架,如Vue公司给我们的精彩能够创建可重用的组件在他们各自的应用程序中传播,确保它们是一致的,并且(希望)简化如何使用它们。
特别是,表单输入往往有很多复杂的,你会希望在组件隐藏起来,比如定制设计,标签,验证,帮助信息,并确保每个片都以正确的顺序,使它们呈现正确。
编写可重用模块中ES6
你兴奋地利用新的JavaScript语言特性,但不知道哪里开始,或如何?阅读更多→
上,虽然之上,Vue公司有一个叫做内置指令v-model
是模拟2路结合通过结合一个值,并捕获输入事件。如果你要建立一个自定义输入组件,那么你肯定会想要支持的v-model
指令。
可悲的是,当我环顾四周的单选按钮或复选框在Vue公司的自定义输入的例子,他们要么没有考虑v-model
考虑所有,或他们没有正确地执行它。有一些像样的自定义文本输入的文档,但由于它没有解释自定义电台或复选框,我们将讨论这一点。
本教程旨在帮助你…
- 了解如何
v-model
在本地投入工作,主要侧重于收音机和复选框 - 了解如何
v-model
在默认情况下自定义组件的工作原理 - 了解如何创建自定义的复选框和收音机是模拟如何
v-model
对他们本身的工作原理
快速记在我们开始之前:ES2015 +代码将在整个代码示例中使用。我也有利于单个文件组件在使用语法Vue.component
或new Vue
。
如何v-model
正常工作状态?
官方的Vue文件实际上是对这个话题相当不错的,但也有一些小的盲点。在任何情况下,我们将努力几乎完全是包括在这里。
从本质上说,v-model
仅仅是一个速记指令,为我们提供了2路数据绑定,并且它的代码是简写形式,取决于它正在使用什么类型的输入。
文本框
<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>
当使用文本input
(包括类型,例如email
,number
等)或textarea
,v-model="varName"
等价于:value="varName" @input="e => varName = e.target.value"
。这意味着,输入的值被设置为varName
每次更新到输入后varName
更新为输入的值。一个正常的select
元素会像这样过,虽然multiple
选择会有所不同。
单选按钮
那么,怎么样的单选按钮?
<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="e => picked = e.target.value">
<input type="radio" value="Two" :checked="picked == 'Two'" @change="e => picked = e.target.value">
<span>Picked: {{ picked }}</span>
注意如何v-model
甚至没有接触value
了。它仍然在做了同样的事情,change
事件处理程序(虽然它改为change
代替input
),但现在它决定是否checked
应该是真实的还是取决于是否错误picked
是相同的单选按钮的值。
复选框
复选框是有点困难谈谈,因为他们有这取决于是否有只有一个复选框与给定的两种不同的行为v-model
或多个。
如果您使用的是单个复选框,v-model
将像对待一个布尔值,并忽略value
。
<input type="checkbox" value="foo" v-model="isChecked">
是相同的…
<input type="checkbox" value="foo" :checked="!!isChecked" @change="e => isChecked = e.target.checked">
如果你希望它是比其他的东西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="e => isChecked = e.target.checked ? '1' : '0'">
这几乎是它的单选框例子。如果你有一个共享模型多个复选框,则这些复选框将填充数组与被检查所有复选框的值,但要确保你通过在模型中已经是一个数组,否则你会得到一些奇怪的行为。此外,true-value
和false-value
属性不再有任何影响。
<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>
等效是有点困难,以保持在模板中,所以我将一些逻辑移动到组件上的方法:
<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
增加了复选框的值到数组时,它被选中并删除它时,它被选中。
如何v-model
上工作的组件?
由于Vue公司不知道你的组件是如何工作的,或者如果它试图充当某种类型的输入的替代品,它把与问候到相同的所有组件v-model
。它的实际工作,因为它确实为文本输入,但在事件处理程序,它并不期望一个事件对象传递给它,而它预计值传递直奔它完全相同的方式。所以…
<my-custom-component v-model="myProperty" />
…是同样的事情…
<my-custom-component :value="myProperty" @input="val => myProperty = val" />
一个组件可以更改为使用小的程度model
属性:
export default {
name: 'my-custom-component',
model: {
prop: 'foo',
event: 'bar'
},
// ...
}
v-model
将着眼于这些属性和,而不是使用value
属性,它会使用在指定属性prop
和而不是听的input
情况下,它会使用在指定的事件event
。所以上面的my-custom-component
例子实际上扩大了以下几点:
<my-custom-component :foo="myProperty" @bar="val => myProperty = val" />
这是很好的,但如果我们正在做一个自定义的无线电或复选框,这并不能很好地工作。一段时间的努力,但是,我们可以移动的逻辑v-model
上的收音机和复选框我们的自定义组件内部使用。
支持v-model
在定制无线电
相比复选框,定制无线电是非常简单的。下面是我建,只是包装了一个很基本的自定义电台input
在标签并接受label
属性添加标签文本。
<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
,但是input
标签可以采取的其他几个属性(如优势name
或disabled
),所以请确保您创建的所有props
您需要,并将它们传递到input
。您也想加入考虑无障碍 WAI-ARIA的属性,以及使用插槽用于添加内容,而不是像道具我在这里做label
。
你可能会认为,因为我没有包括name
在这个例子中,一组无线电实际上不会彼此同步。实际上,模型的更新将依次更新共享模型中的其他单选按钮,所以他们并不需要像他们在纯HTML的形式做共享一个名字,只要它们共享相同的模型。
支持v-model
在自定义复选框
制作自定义的复选框明显比单选按钮比较复杂,主要是因为我们要支持两种不同的使用情况:一个真/假复选框(可能会或可能不会使用true-value
和/或false-value
),并且所有的检查值组合成多个复选框数组。
那么,我们如何确定它是用例?你可能会认为,我们需要确定是否有其他复选框具有相同name
的属性,但实际上并不是什么Vue公司的内置系统使用。就像收音机,Vue公司不走name
的属性考虑的。当本地提交表单,这只是使用。所以,那么你可能会认为这决定它的基础上是否有共享同一模式的其他复选框,但这不是它的。它是由模型是否是一个数组确定。而已。
因此,代码将被结构类似于定制单选按钮的代码,但内部shouldBeChecked
和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>
有你有它。它可能会更好,不过,这种分成两个不同的部分组成:一个用于处理单真/假切换,一个用于在选项列表中使用。这将允许它更紧密地跟随单责任原则,但如果你正在寻找一个简易替换到复选框,这是你在找什么(加上另外所有其他有用的属性和定制功能你可能想)。