使用Vue创建自定义表单inputs

编辑推荐:3月31日前,点击注册激活 Coding.net 立赠30天付费会员 ,体验极速代码托管服务!
特别声明:此篇文章内容来源于@Joseph Zimmerman的《Creating Custom Inputs With Vue.js》一文。
基于伟德1946手机版的库或者框架(例如Vue)让我们在开发可复用的伟德1946手机版带来了极大的方便。这些伟德1946手机版可以非常简单的在独立的应用程序中被使用,并且最终呈现的效果一致。 比如,表单输入的场景,在功能上往往相对复杂,通常我们的做法是希望使用伟德1946手机版将表单中自定义的设计、标签、验证和帮助信息等进行封装,以确保这些能被依次正确的渲染。 在Vue中一个特别重要的指令v-model,可以通过绑定和捕获输入事件来实现数据的双向绑定。如果你要构建自定义input伟德1946手机版,那么该伟德1946手机版毫无疑问的需要支持v-model指令了。 遗憾的是,当我查阅Vue实现自定义的单选按钮(<input type="radio" />)或者复选框(<input type="checkbox" />)的示例时,发现他们要么没有考虑到v-model指令,要么就没有正确的实现。有一些自定义input使用文档,但它没有解释自定义单选按钮和复选框如何使用,我将在下面的例子中将对这方面做出相应的阐述和解释。 这篇文章将会帮助你理解以下几点内容:
  • 理解v-model指令在原生的input上是如何实现的,主要侧重于单选按钮和复选框
  • 理解v-model指令一般在自定义伟德1946手机版中是如何实现的
  • 学习如何创建具有类似v-model指令功能的自定义单选按钮和复选框
本文涉及到的示例代码,将采用到ES2015+。在使用vue.component或者new Vue({})来编码时,我更倾向于使用单文件伟德1946手机版的语法,这样能使项目结构更清晰。

v-model是如何工作的?

官方的Vue文档对于v-model如何工作已经讲的很清楚,但是仍然有一些遗漏点。不过不要紧,为了更好的理解v-model,我会从头介绍这块内容。v-model实质上只是为我们提供双向数据绑定功能的语法糖。其会随着不同类型的表单控件而不同。比如下面的示例:

文本输入框

<input v-model="message" placeholder="Edit me" /> <p>Message: {{ message }}</p> <p>Message:</p> <p>{{ message }}</p> <textarea v-model="message" placeholder="Add multiple lines"></textarea>
当使用文本输入框(包括emailnumber类型等)或者textarea类型时,v-model="varName"等同于:value="varName" @input = "e => varName = e.target.value"。这意味着每次在文本框输入时,input事件通过输入事件将value值传给varName,每次输入时使用这种方式更新varName。同样,除了含有multiple属性的select元素,普通的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-modelinputvalue值没有直接关系。但是它依然在change事件发生时做了同样的事情(尽管input事件变成了change事件)。然后根据picked的值是否与该单选按钮的值相同,确定单选按钮是否被选中。

多选框

多选框相对而言要复杂一点。因为它有两种不同的表现行为,这取决于只有一个单独的checkbox绑定了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" /> 如果希望它可以不仅仅表示truefalse的话,可以使用true-valuefalse-true属性来设置复选框被选中或未选中的值。 <input type="checkbox" value="foo" v-model="isChecked" true-value="1" false-value="0" /> 等同于下面的代码: <input type="checkbox" value="foo" v-model="isChecked == '1'" @change="isChecked = $event.target.checked ? '1' : '0'" > 上面的示例是单一复选框的例子。如果你有多个复选框,而且它们共用一个v-model的值,那么这些复选框将由一个所有复选框被选中的value值所组成的数组。同时必须确保传递的v-model的值是数组类型,否则会产生一些奇怪的问题。当然,true-valuefalse-value在多个复选框的场景下不起任何作用 <div id="app"> <my-checkbox></my-checkbox> </div> <template id="my-checkbox"> <div> <input type="checkbox" value="foo" v-model="checkedVals" /> foo <input type="checkbox" value="boo" v-model="checkedVals" /> boo <input type="checkbox" value="bar" v-model="checkedVals"> bar <p>{{ checkedVals }}</p> </div> </template> let app = new Vue({ el: '#app', components: { 'myCheckbox': { template:'#my-checkbox', data () { return { checkedVals: ['bar'] } } } } })
上面的代码很难通过my-checkobx的属性添加方法来实现v-model,所以将部分逻辑添加到伟德1946手机版的方法上。 <div id="app"> <my-checkbox></my-checkbox> </div> <template id="my-checkbox"> <div> <input type="checkbox" value="foo" v-model="checkedVals" /> foo <input type="checkbox" value="boo" v-model="checkedVals" /> boo <input type="checkbox" value="bar" v-model="checkedVals"> bar <p>{{ checkedVals }}</p> </div> </template> let app = new Vue({ el: '#app', components: { 'myCheckbox': { template:'#my-checkbox', data () { return { checkedVals: ['bar'] } }, methods: { shouldBeChecked: function (val) { return this.checkedVals.includes(val) }, updateVals: function (e) { let isChecked = e.target.checked let val = e.target.value if (isChecked) { this.checkedVals.push(val) } else { this.checkedVals.splice(this.checkedVals.indexOf(val), 1) } } } } } }) 从上面的代码可以看出,复选框的实现要比前面介绍的文本框、单选按钮的实现要复杂得多。但当我们把复选框伟德1946手机版的方法进行分解,会发现其实也没有那么难。当该复选框的值包含在模型数组中时,shouldBeCheckedtrue,否则为 false。当它被勾选时,updateVals 将该复选框的值添加到数组。当它被取消勾选时,updateVals 将复选框的值从数组中删除。

v-model 如何在伟德1946手机版上工作?

由于 Vue 并不知道自定义伟德1946手机版的功能是什么,如果自定义伟德1946手机版用作和表单 input 元素类似的功能,Vue 将该自定义伟德1946手机版视为与 v-model 实现原理相同。自定义伟德1946手机版实际的工作原理与文本输入框完全相同,只是在事件处理程序中,它不会将事件对象传递给它,而是期望将值直接传递给它。所以: <my-custom-component v-model="myProperty" /> 代码等同于: <my-custom-component :value="myProperty" @input="val => myProperty = val" /> 自定义伟德1946手机版可以使用model属性将上面的实现转换为: export default { name: 'my-custom-component', model: { prop: 'foo', event: 'bar' }, // ... } v-model 指令会查找 model 中所有的值,使用 prop 中指定的属性,代替之前使用 value 属性。同时它也将使用 event 中指定的事件,而不是 input 事件。所以上面的自定义伟德1946手机版示例将实际扩展为以下内容: <my-custom-component :foo="myProperty" @bar="val => myProperty = val" /> 这看起来不错,但如果我们要制作一个自定义单选按钮或复选框,可能就会有问题了。通过做一些修改,可以将 v-model 实现的逻辑转移到自定义的单选按钮和复选框伟德1946手机版中。

使用v-model实现自定义单选按钮

与复选框相比,自定义单选按钮非常简单。下面是一个非常基本的自定义单选按钮,我设计的只是将input放置在 label 标签中,并接受 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>
注意:我只写了用于解释 v-model 实现原理的 props 值,至于需要使用 input 的其他的几个属性(例如 name 或者 disabled),需要在 props 中创建,并传递给 input。你还需要通过添加 WAI-ARIA 属性来考虑可访问性,以及使用 slots(插槽) 来分发内容,而不是像我在 props 中所设置的 label 值那么简单。
你可能会认为,我在这个例子中没有包括 name 属性,一组单选按钮实际上将不会相互同步。实际上,模型的更新反过来会更新共享该模型的其他单选按钮,因此只要共享相同的模型,他们就不需要像普通的 HTML 表单那样共享一个 name 属性。

使用 v-model 实现自定义复选框

自定义复选框比单选按钮显然更复杂一些,主要是因为我们必须支持两种不同的用法:单个 true / false 复选框(可能使用或不使用 true-valuefalse-value)和多个将所有选中的 value 值添加到模型数组的复选框。 你可能会认为我们首先需要确定复选框元素是否具有相同的 name 属性,但这并不是 Vue 内部的实现方式。就像单选按钮一样,Vue 根本不考虑 name 属性。name属性只是在提交原生表单时会用到。你可能会认为它是根据复选框是否共享相同的模型,但也不是这样的,它仅仅是通过模型是否是数组来判断是单个还是多个复选框。 因此,这段代码将依据自定义单选按钮的实现方式进行重构,在 sholdBeCheckedupdateInput 函数中的需要根据 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 }, trueValue: { default: true }, falseValue: { default: false } }, computed: { shouldBeChecked() { if (this.modelValue instanceof Array) { return this.modelValue.includes(this.value) } 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> 现在已经实现了自定义复选框伟德1946手机版。如果将其分解成两个不同的伟德1946手机版可能会更好:一个用于处理单个 true / false 切换,一个用于选项列表(多个复选框)。这样处理的话,伟德1946手机版将更紧密地遵循单一责任原则。如果你正在寻找自定义复选框伟德1946手机版的方案,这就是你要查找的内容。 推荐一个优秀的自定义单选按钮和复选框的Vue伟德1946手机版pretty checkbox

扩展阅读

想了解更多关于自定义 input 元素,Vue 伟德1946手机版和 Vue 的内容。以下资源可能正是你所需要的:

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。
如需转载,烦请注明出处:https://www.w3cplus.com/vue/creating-custom-inputs-vue-js.html
返回顶部