上一节中,通过v-model
的学习,我们可以实现双向数据绑定的的效果。在整个教程中,我们看到的示例都是表单控件方面的。实际上v-model
还可以和组件结合在一起实现双向数据的绑定效果。
在Web的表单控件中,我们经常为了一些特殊的视觉效果,做自定义的表单风格,比如单选按钮、复选框和下拉选择框之类的。那么我们通过Vue来做这些表单控件的组件,会让我们变得更为轻松,而且一劳永逸。接下来我们看看怎么实现单选按钮和复选框的组件。
自定义单选按钮
与复选框相比,定制单选安扭相对而言要简单。以下是一个非常基本的自定义单选按钮。将input
和label
包装在标签中。下面这个示例是来自@Invoke的Vue单选按钮。
我们把整个Demo写在Codepen上,以便大家更为方便的查阅代码。
创建radio
组件,代码如下:
Vue.component('radio',{
template: `
<div class="custom-radio" v-bind:class="{ inverted: inverted }">
<input type="radio" v-bind:name="name" v-bind:class="className" v-bind:id="id" v-bind:checked="checked" v-bind:value="value" v-bind:required="required" v-on:change="updateInput" />
<label v-bind:for="id">{{ label }}</label>
</div>
`,
props: {
name: {
type: String,
required: false
},
className: {
type: String,
required: false
},
id: {
type: String,
required: false
},
value: {
type: String,
required: false
},
required: {
type: Boolean,
required: false,
default: false
},
checked: {
type: Boolean,
required: false,
default: false
},
label: {
type: String,
required: true
},
inverted: {
type: Boolean,
required: false,
default: false
}
},
methods: {
updateInput: function(event) {
this.$emit('input', event.target.value);
}
}
})
通过Vue.component()
创建了一个radio
组件,同时把组件需要的模板(HTML)结构定义在template
中:
<div class="custom-radio" v-bind:class="{ inverted: inverted }">
<input type="radio" v-bind:name="name" v-bind:class="className" v-bind:id="id" v-bind:checked="checked" v-bind:value="value" v-bind:required="required" v-on:change="updateInput" />
<label v-bind:for="id">{{ label }}</label>
</div>
其实除了上面的方式之外,还可以单独创建一个radio.vue
文件,在这个文件中通过<template>
来声明组件所需要的标签元素:
<template>
<div class="custom-radio" v-bind:class="{ inverted: inverted }">
<input type="radio" v-bind:name="name" v-bind:class="className" v-bind:id="id" v-bind:checked="checked" v-bind:value="value" v-bind:required="required" v-on:change="updateInput" />
<label v-bind:for="id">{{ label }}</label>
</div>
</tempalte>
组件对应需要的逻辑代码放置在<script>
中:
<script>
export default {
props: {
name: {
type: String,
required: false
},
className: {
type: String,
required: false
},
id: {
type: String,
required: false
},
value: {
type: String,
required: false
},
required: {
type: Boolean,
required: false,
default: false
},
checked: {
type: Boolean,
required: false,
default: false
},
label: {
type: String,
required: true
},
inverted: {
type: Boolean,
required: false,
default: false
}
},
methods: {
updateInput: function(event) {
this.$emit('input', event.target.value);
}
}
}
</script>
我们创建了所需的props
并将其传递给input
。比如单选按钮常见的一些属性,比如name
、checked
、id
等。除些之外,还可以添加WAI-ARIA属性,以及使用slots
添加内容,而不是像上面在label
里的props
。
在props
中定义了单选按钮组件需要的一些属性,另外在methods
中创建了一个updateInput
方法,用来监听input
的变化。
这样一来,咱们就完成了单选按钮radio
组件的创建,我们可以这样使用:
<!-- HTML -->
<div id="app">
<radio name="method" value="phone" label="Phone" id="phone"></radio>
<radio name="method" value="email" label="Email" id="email"></radio>
</div>
// JavaScript
let app = new Vue({
el: '#app'
})
除了这样的方式之外,还可以这样使用:
<template>
<div id="app">
<Radio name="method" value="phone" label="Phone" id="phone"/>
</div>
</tempalte>
<script>
import Radio from 'radio.vue'
export default {
components: {
Radio
}
}
</script>
<style>
/* 添加样式 */
</style>
为了节约篇幅,样式代码就不贴上来了。最终的效果如下:
自定义复选框
使用自定义复选框比单选按钮明显要更复杂,主要是因为我们必须支持两种不同的用例:单个true
/false
复选框(可能使用或不使用true-value
和/或false-value
)和多个复选框将所有检查的值合并到一个数组中。
那么我们如何确定哪个用例呢?你可能会认为我们需要确定是否有其他复选框具有相同的name
属性,但这并不是Vue的内置系统所使用的。就像单选框一样,Vue根本不考虑name
属性,它只是在本地提交表单时使用。那么你可能认为它会根据是否有其他复选框共享相同的model
来确定,但也不是这样。它是由模型是否是数组来决定的,仅此而已。
来看一个复选框按钮的组件代码:
<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
},
// 我们将 `true-value` 和 `false-value` 设置为 true 和 false
// 我们可以随时使用它们,而不用检查它们是否被设置。
// 也可以在这里使用驼峰命名,但要用连字符分隔属性名称
// 使用组件时仍然有效
trueValue: {
default: true
},
falseValue: {
default: false
}
},
computed: {
shouldBeChecked() {
if(this.modelValue instanceof Array){
return this.modelValue.includes(this.value)
}
// 请注意,"true-value"和 "false-value"是 JS 中的驼峰命名
return this.modelValue === this.trueValue
}
},
method: {
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
切换,一个用于选项列表。这将允许它更紧密地遵循单一责任原则,但如果你正在寻找选择框的替代品,那么这就是你正在寻找的(加上所有其他有用的属性和自定义功能的添加)。
@Invoke也提供了一个Vue复选框组件checkbox
。代码就不贴了,其和radio
组件的代码有点类似,直接上效果吧,如果想看代码,可以在Codepen上查看:
对于自定单选按钮和复选框,其功能上的代码都相近,你只需要在CSS样式上进修改。就能得到不同的效果。比如上面的两个示例。当然,还可以做一些其他的功能,比如@CSWApps写的Bootstrap的单选按钮组组件:
这篇文章涉及到了Vue的组件相关知识,但我们从未接触过组件这方面相关的知识,或许上面有些代码还不能明白是起什么作用,但不用担心,我们现在只要知道这样做就能有这样的效果就可以,至于原理和为什么,我们后面会搞懂的。
总结
这篇文章介绍了怎么使用Vue实现自定义的表单的单选按钮和复选框两个组件。并且通过v-model
实现双向数据绑定。在表单控件中,除了单选按钮和复选框之外,还有其他表单控件,比如input
和select
等控件。那么我们可以使用类似的方法实现自定义的表单组件。如果你感兴趣的话,自己动手写一个下拉选择框的组件。有关于Vue的组件和Vue相关的资料,也可以看看:
- Awesome-Vue 组件集:Awesome-Vue 是一个巨大的 Vue 相关项目和资源列表,随时想看该列表中的任何内容都可以,但是我想特别指出 UI 库和组件集,因为它们几乎有所有的单复选框的例子,可以看看,还可以研究他们的源代码。
- Vue Curated:这是一个类似于 Awesome-Vue 的列表,但经过了更严格的筛选,所以列表中的所有内容都值得一看。
- Vue组件指南:官方 Vue 指南是了解有关 Vue 相关基础知识的好地方。
- Vue API文档:本文档介绍了 Vue 的深入细节。
作者是Vue初学者,对Vue的理解还不到家,如果文章中有何不对,还请大婶拍正。如果你有这方面的经验,欢迎在下面的平论中与我们一起分享。
如需转载,烦请注明出处:https://www.w3cplus.com/vue/custom-radio-and-checkbox-component-with-vue.html