目录
处理表单输入
1,单行文本
2,多行文本textarea
3,复选框checkbox
4,单选按钮radio
5,select下拉选择框
6,所有input类型
父子组件的表单数据交换
1,使用sync
2,使用v-model模式
vue开发中获取表单输入的值,不是像JQuery那样是主动查询一个Html组件,然后访问其属性,取得它的值。
vue获取表单输入的数据,是通过被动的方式。在vue组件有输入操作时,主动将数值绑定到data变量上;在提交表单前,从data数据源取得表单数据。
vue对有限个数的表单组件进行特别处理,包括:
<!-- 单行文本 -->
<input type="text" v-model.trim="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>
其input type为text。v-model.trim用于将用户输入值绑定在变量message上,trim这个修饰指令实现的是自动将输入值去除首尾空格。
v-model实现的是一种双向绑定。这是一种语法糖,上面的v-model相当于一个v-bind:value+一个v-on:input,如下所示:
<input v-bind:value="message" v-on:input="message=$event.target.value">
v-model代表的一定是属性value与事件input的结合。vue开发里所有支持v-model绑定的表单组件,都实现了对input事件的处理,即使原生的html组件没有input事件也是如此。
<p>{{ message1 }}</p>
<textarea @input="handleInput" v-model.lazy="message1" placeholder="add multiple lines"></textarea>
<!-- 复选框 -->
<p>
<input @input="handleInput" type="checkbox" id="checkbox" v-model.number="checked" true-value="1" false-value="2" />
<label for="checkbox">{{ checked }}</label>
</p>
其input type为checkbox。v-model.number用于将复选框选择的结果绑定到变量checked上,number修饰实现的是自动转换输入为数值类型。
true-value与false-value定义的是真、假数值,即选择与非选择时的取值,默认是true与false。但是需要注意,这两个属性定义的选项值都是字符串,所以在v-model上需要使用number修饰。
复选框支持多个放在一起,组合一组多选选项的集合:
<!-- 多个复选框 -->
<p>
<input type="checkbox" id="checkbox1" v-model="checked2" value="value1" />
<label for="checkbox1">value1</label>
<input type="checkbox" id="checkbox2" v-model="checked2" value="value2" />
<label for="checkbox2">value2</label>
<input type="checkbox" id="checkbox3" v-model="checked2" value="value3" />
<label for="checkbox3">value3</label>
<br/>
<span>Checked names: {{ checked2 }}</span>
</p>
多个checkbox放在一起,绑定到一个变量checked2上,就实现了多选效果。checked2的数据类型是一个数组。
<!-- 单选按钮 -->
<div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<br />
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br />
<input type="radio" id="three" value="Three" v-model="picked" />
<label for="three">Three</label>
<br />
<span>Picked: {{ picked }}</span>
</div>
其input type为radio。
<!-- 选择框 -->
<div>
<select v-model="selected">
<option disabled value>请选择</option>
<option :value="{ number: 1 }">1</option>
<option :value="{ number: 2 }">2</option>
<option :value="{ number: 3 }">3</option>
</select>
<span>Selected: {{ selected.number }}</span>
</div>
这是由select组件实现的,并不是input组件了。选项option的value支持绑定一个js对象,在这样设置时,select选择的结果selected也是一个js对象。
下拉选择框也同时多选:
<!-- 多选选择框 -->
<div>
<select multiple v-model="selected2">
<option disabled value>请选择</option>
<option :value="{ number: 1 }">1</option>
<option :value="{ number: 2 }">2</option>
<option :value="{ number: 3 }">3</option>
</select>
<span>Selected: {{ selected2 }}</span>
</div>
给select添加multiple属性,下拉选择框就会默认展开,同时支持按住SHIFT多选,选择的结果selected2是一个数组。
上面仅是介绍了text、radio、checkbox三种input类型。事实上input组件功能十分丰富,它共有这些类型:
button 定义可点击的按钮(通常与 JavaScript 一起使用来启动脚本)。
checkbox 定义复选框。
colorNew 定义拾色器。
dateNew 定义 date 控件(包括年、月、日,不包括时间)。
datetimeNew 定义 date 和 time 控件(包括年、月、日、时、分、秒、几分之一秒,基于 UTC 时区)。
datetime-localNew 定义 date 和 time 控件(包括年、月、日、时、分、秒、几分之一秒,不带时区)。
emailNew 定义用于 e-mail 地址的字段。
file 定义文件选择字段和 "浏览..." 按钮,供文件上传。
hidden 定义隐藏输入字段。
image 定义图像作为提交按钮。
monthNew 定义 month 和 year 控件(不带时区)。
numberNew 定义用于输入数字的字段。
password 定义密码字段(字段中的字符会被遮蔽)。
radio 定义单选按钮。
rangeNew 定义用于精确值不重要的输入数字的控件(比如 slider 控件)。
reset 定义重置按钮(重置所有的表单值为默认值)。
searchNew 定义用于输入搜索字符串的文本字段。
submit 定义提交按钮。
telNew 定义用于输入电话号码的字段。
text 默认。定义一个单行的文本字段(默认宽度为 20 个字符)。
timeNew 定义用于输入时间的控件(不带时区)。
urlNew 定义用于输入 URL 的字段。
weekNew 定义 week 和 year 控件(不带时区)。
这些类型的input组件,都可以以一种自定义组件的方式使用之。
在vue开发中我们经常会需要定义一个子组件,然后在这个子组件中获取的表单数据,需要往父组件传递。这里有三种传递方法:
子组件代码为:
<template>
<input name="xxxx" v-model="currentValue" @input="handleModelInput" />
</template>
<script>
export default {
name: "ModelComponent2",
props: {
value: [String, Number, Date]
},
methods: {
handleModelInput() {
this.$emit("update:value", this.currentValue);
}
},
watch: {
// 属性是只读的
value(newValue) {
this.currentValue = newValue;
}
},
data: () => ({
currentValue: ""
})
};
</script>
在子组件中,使用v-model获取了原生input组件的输入,并绑定在currentValue变量之上。监听属性value,是为了将属性value的值,极时同步到变量currentValue上,因为vue的属性是单向的,并不能将一个属性用于v-model。
v-model会自动更新输入值到变量currentValue上,但不会自动派发事件。所以我们需要将input事件绑定到函数handleModelInput上,当输入变化时,在当前自定义组件内主动派发一个"update:value"事件,这个事件名称采用的是"update:"+属性名称的格式,是一个vue语法约定。
父组件代码为:
<p>
<SyncComponent1 :value.sync="text1" ></SyncComponent1>
text1:{{text1}}
</p>
运行效果:
使用这种sync模式,假设属性为xxx,要求为:
1,在子组件中当属性变化时,主动派发一个“update:xxx”事件,并附带xxx的值
2,在父组件中,使用:xxx.sync将数据双向绑定到一个data变量上
在这里有一个问题,v-model与sync有什么区别呢?貌似两者实现的功能是一样的,sync实现的效果v-model也能实现。
不同点在于v-model用于表单数据绑定,指定了属性名为value,事件名为input,不能变。而sync模式,在属性名称的设置上,在事件的派发时机上都比较灵活。
既然默认的vue表单组件可以实现v-model双向绑定,自定义组件同样也能实现。
子组件代码为:
<template>
<input name="xxxx" v-model="currentValue" @input="handleModelInput" />
</template>
<script>
export default {
name: "SyncComponent2",
props: {
value: [String, Number]
},
methods: {
handleModelInput() {
this.$emit("input", this.currentValue);
}
},
watch: {
// 属性是只读的
value(newValue) {
this.currentValue = newValue;
}
},
data: () => ({
currentValue: ""
})
};
</script>
父组件代码为:
<p>
<SyncComponent2 v-model="text2" ></SyncComponent2>
text2:{{text2}}
</p>
运行效果与方法1是一样的。可以看到父组件代码没有变化。变化的是子组件代码,不再派发"update:value"事件了,取而代之的是派发input事件。这样在父组件中,子组件就被装扮成了和其它vue表单组件一样了,也可以直接使用v-model进行双向绑定了。
如果我不想或不方便派发input事件或update:xxx事件,怎么办?也有方法。可以使用model。
子组件代码:
<template>
<input name="xxxx" v-model="currentValue" @input="handleModelInput" />
</template>
<script>
export default {
name: "SyncComponent3",
model: {
prop: 'value',
event: 'change'
},
props: {
value: [String, Number]
},
methods: {
handleModelInput() {
// 与aync模式相比,发射的事件不同
this.$emit("change", this.currentValue);
}
},
watch: {
// 属性是只读的
value(newValue) {
this.currentValue = newValue;
}
},
data: () => ({
currentValue: ""
})
};
</script>
model充许自定义一个属性名称和事件名称,例如value和change,这样当在子组件中派发change事件时,在父组件中可以像方法2那样使用子组件:
<SyncComponent3 v-model="text3" ></SyncComponent3>
text3:{{text3}}
</p>
本文涉及的源码可以从这里下载:
https://git.code.tencent.com/shiqiaomarong/vue-go-rapiddev-example/tags/v20200112