【Vue.js】Vue.js组件库Element中的上传、评分、穿梭框和表单
1、Upload 上传
通过点击或者拖拽上传文件。
点击上传
通过 slot 你可以传入自定义的上传按钮类型和文字提示。可通过设置limit和on-exceed来限制上传文件的个数和定义超出限制时的行为。可通过设置before-remove来阻止文件移除操作。
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
multiple
:limit="3"
:on-exceed="handleExceed"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
}
}
}
</script>
用户头像上传
使用 before-upload 限制用户上传的图片格式和大小。
<el-upload
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
<script>
export default {
data() {
return {
imageUrl: ''
};
},
methods: {
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw);
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
}
}
</script>
照片墙
使用 list-type 属性来设置文件列表的样式。
<el-upload
action="https://jsonplaceholder.typicode.com/posts/"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<script>
export default {
data() {
return {
dialogImageUrl: '',
dialogVisible: false
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
}
}
}
</script>
文件缩略图
使用 scoped-slot 去设置缩略图模版。
<el-upload
action="#"
list-type="picture-card"
:auto-upload="false">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="file.url" alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleDownload(file)"
>
<i class="el-icon-download"></i>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<script>
export default {
data() {
return {
dialogImageUrl: '',
dialogVisible: false,
disabled: false
};
},
methods: {
handleRemove(file) {
console.log(file);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
handleDownload(file) {
console.log(file);
}
}
}
</script>
图片列表缩略图
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
}
}
}
</script>
上传文件列表控制
通过 on-change 钩子函数来对列表进行控制。
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-change="handleChange"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{
name: 'food.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
}, {
name: 'food2.jpeg',
url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
}]
};
},
methods: {
handleChange(file, fileList) {
this.fileList = fileList.slice(-3);
}
}
}
</script>
拖拽上传
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
手动上传
<el-upload
class="upload-demo"
ref="upload"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
:auto-upload="false">
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
submitUpload() {
this.$refs.upload.submit();
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
}
}
}
</script>
Attribute
参数 |
说明 |
类型 |
可选值 |
默认值 |
---|---|---|---|---|
action |
必选参数,上传的地址 |
string |
— |
— |
headers |
设置上传的请求头部 |
object |
— |
— |
multiple |
是否支持多选文件 |
boolean |
— |
— |
data |
上传时附带的额外参数 |
object |
— |
— |
name |
上传的文件字段名 |
string |
— |
file |
with-credentials |
支持发送 cookie 凭证信息 |
boolean |
— |
false |
show-file-list |
是否显示已上传文件列表 |
boolean |
— |
true |
drag |
是否启用拖拽上传 |
boolean |
— |
false |
accept |
接受上传的文件类型(thumbnail-mode 模式下此参数无效) |
string |
— |
— |
on-preview |
点击文件列表中已上传的文件时的钩子 |
function(file) |
— |
— |
on-remove |
文件列表移除文件时的钩子 |
function(file, fileList) |
— |
— |
on-success |
文件上传成功时的钩子 |
function(response, file, fileList) |
— |
— |
on-error |
文件上传失败时的钩子 |
function(err, file, fileList) |
— |
— |
on-progress |
文件上传时的钩子 |
function(event, file, fileList) |
— |
— |
on-change |
文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 |
function(file, fileList) |
— |
— |
before-upload |
上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传 |
function(file) |
— |
— |
before-remove |
删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除 |
function(file, fileList) |
— |
— |
list-type |
文件列表的类型 |
string |
text/picture/picture-card |
text |
auto-upload |
是否在选取文件后立即进行上传 |
boolean |
— |
true |
file-list |
上传的文件列表, 例如: [{name: ‘food.jpg’, url: ‘https://xxx.cdn.com/xxx.jpg’}] |
array |
— |
[] |
http-request |
覆盖默认的上传行为,可以自定义上传的实现 |
function |
— |
— |
disabled |
是否禁用 |
boolean |
— |
false |
limit |
最大允许上传个数 |
number |
— |
— |
on-exceed |
文件超出个数限制时的钩子 |
function(files, fileList) |
— |
- |
Slot
name |
说明 |
---|---|
trigger |
触发文件选择框的内容 |
tip |
提示说明文字 |
Methods
方法名 |
说明 |
参数 |
---|---|---|
clearFiles |
清空已上传的文件列表(该方法不支持在 before-upload 中调用) |
— |
abort |
取消上传请求 |
( file: fileList 中的 file 对象 ) |
submit |
手动上传文件列表 |
— |
2、Rate 评分
评分组件。
基础用法
评分默认被分为三个等级,可以利用颜色数组对分数及情感倾向进行分级(默认情况下不区分颜色)。三个等级所对应的颜色用colors属性设置,而它们对应的两个阈值则通过 low-threshold 和 high-threshold 设定。你也可以通过传入颜色对象来自定义分段,键名为分段的界限值,键值为对应的颜色。
<div class="block">
<span class="demonstration">默认不区分颜色</span>
<el-rate v-model="value1"></el-rate>
</div>
<div class="block">
<span class="demonstration">区分颜色</span>
<el-rate
v-model="value2"
:colors="colors">
</el-rate>
</div>
<script>
export default {
data() {
return {
value1: null,
value2: null,
colors: ['#99A9BF', '#F7BA2A', '#FF9900'] // 等同于 { 2: '#99A9BF', 4: { value: '#F7BA2A', excluded: true }, 5: '#FF9900' }
}
}
}
</script>
辅助文字
用辅助文字直接地表达对应分数。
为组件设置 show-text 属性会在右侧显示辅助文字。通过设置 texts 可以为每一个分值指定对应的辅助文字。texts 为一个数组,长度应等于最大值 max。
<el-rate
v-model="value"
show-text>
</el-rate>
<script>
export default {
data() {
return {
value: null
}
}
}
</script>
其它 icon
当有多层评价时,可以用不同类型的 icon 区分评分层级。
设置icon-classes属性可以自定义不同分段的图标。若传入数组,共有 3 个元素,为 3 个分段所对应的类名;若传入对象,可自定义分段,键名为分段的界限值,键值为对应的类名。本例还使用void-icon-class指定了未选中时的图标类名。
<el-rate
v-model="value"
:icon-classes="iconClasses"
void-icon-class="icon-rate-face-off"
:colors="['#99A9BF', '#F7BA2A', '#FF9900']">
</el-rate>
<script>
export default {
data() {
return {
value: null,
iconClasses: ['icon-rate-face-1', 'icon-rate-face-2', 'icon-rate-face-3'] // 等同于 { 2: 'icon-rate-face-1', 4: { value: 'icon-rate-face-2', excluded: true }, 5: 'icon-rate-face-3' }
}
}
}
</script>
只读
只读的评分用来展示分数,允许出现半星。
为组件设置 disabled 属性表示组件为只读,支持小数分值。此时若设置 show-score,则会在右侧显示目前的分值。可以提供 score-template 作为显示模板,模板为一个包含了 {value} 的字符串,{value} 会被解析为分值。
<el-rate
v-model="value"
disabled
show-score
text-color="#ff9900"
score-template="{value}">
</el-rate>
<script>
export default {
data() {
return {
value: 3.7
}
}
}
</script>
Attributes
参数 |
说明 |
类型 |
可选值 |
默认值 |
---|---|---|---|---|
value / v-model |
绑定值 |
number |
— |
0 |
max |
最大分值 |
number |
— |
5 |
disabled |
是否为只读 |
boolean |
— |
false |
allow-half |
是否允许半选 |
boolean |
— |
false |
low-threshold |
低分和中等分数的界限值,值本身被划分在低分中 |
number |
— |
2 |
high-threshold |
高分和中等分数的界限值,值本身被划分在高分中 |
number |
— |
4 |
colors |
icon 的颜色。若传入数组,共有 3 个元素,为 3 个分段所对应的颜色;若传入对象,可自定义分段,键名为分段的界限值,键值为对应的颜色 |
array/object |
— |
[’#F7BA2A’, ‘#F7BA2A’, ‘#F7BA2A’] |
void-color |
未选中 icon 的颜色 |
string |
— |
#C6D1DE |
disabled-void-color |
只读时未选中 icon 的颜色 |
string |
— |
#EFF2F7 |
icon-classes |
icon 的类名。若传入数组,共有 3 个元素,为 3 个分段所对应的类名;若传入对象,可自定义分段,键名为分段的界限值,键值为对应的类名 |
array/object |
— |
[‘el-icon-star-on’, ‘el-icon-star-on’,‘el-icon-star-on’] |
void-icon-class |
未选中 icon 的类名 |
string |
— |
el-icon-star-off |
disabled-void-icon-class |
只读时未选中 icon 的类名 |
string |
— |
el-icon-star-on |
show-text |
是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容 |
boolean |
— |
false |
show-score |
是否显示当前分数,show-score 和 show-text 不能同时为真 |
boolean |
— |
false |
text-color |
辅助文字的颜色 |
string |
— |
#1F2D3D |
texts |
辅助文字数组 |
array |
— |
[‘极差’, ‘失望’, ‘一般’, ‘满意’, ‘惊喜’] |
score-template |
分数显示模板 |
string |
— |
{value} |
Events
事件名称 |
说明 |
回调参数 |
---|---|---|
change |
分值改变时触发 |
改变后的分值 |
3、Transfer 穿梭框
基础用法
Transfer 的数据通过 data 属性传入。数据需要是一个对象数组,每个对象有以下属性:key 为数据的唯一性标识,label 为显示文本,disabled 表示该项数据是否禁止转移。目标列表中的数据项会同步到绑定至 v-model 的变量,值为数据项的 key 所组成的数组。当然,如果希望在初始状态时目标列表不为空,可以像本例一样为 v-model 绑定的变量赋予一个初始值。
<template>
<el-transfer v-model="value" :data="data"></el-transfer>
</template>
<script>
export default {
data() {
const generateData = _ => {
const data = [];
for (let i = 1; i <= 15; i++) {
data.push({
key: i,
label: `备选项 ${ i }`,
disabled: i % 4 === 0
});
}
return data;
};
return {
data: generateData(),
value: [1, 4]
};
}
};
</script>
可搜索
在数据很多的情况下,可以对数据进行搜索和过滤。
设置 filterable 为 true 即可开启搜索模式。默认情况下,若数据项的 label 属性包含搜索关键字,则会在搜索结果中显示。你也可以使用 filter-method 定义自己的搜索逻辑。filter-method 接收一个方法,当搜索关键字变化时,会将当前的关键字和每个数据项传给该方法。若方法返回 true,则会在搜索结果中显示对应的数据项。
<template>
<el-transfer
filterable
:filter-method="filterMethod"
filter-placeholder="请输入城市拼音"
v-model="value"
:data="data">
</el-transfer>
</template>
<script>
export default {
data() {
const generateData = _ => {
const data = [];
const cities = ['上海', '北京', '广州', '深圳', '南京', '西安', '成都'];
const pinyin = ['shanghai', 'beijing', 'guangzhou', 'shenzhen', 'nanjing', 'xian', 'chengdu'];
cities.forEach((city, index) => {
data.push({
label: city,
key: index,
pinyin: pinyin[index]
});
});
return data;
};
return {
data: generateData(),
value: [],
filterMethod(query, item) {
return item.pinyin.indexOf(query) > -1;
}
};
}
};
</script>
可自定义
可以对列表标题文案、按钮文案、数据项的渲染函数、列表底部的勾选状态文案、列表底部的内容区等进行自定义。
可以使用 titles、button-texts、render-content 和 format 属性分别对列表标题文案、按钮文案、数据项的渲染函数和列表顶部的勾选状态文案进行自定义。数据项的渲染还可以使用 scoped-slot 进行自定义。对于列表底部的内容区,提供了两个具名 slot:left-footer 和 right-footer。此外,如果希望某些数据项在初始化时就被勾选,可以使用 left-default-checked 和 right-default-checked 属性。最后,本例还展示了 change 事件的用法。注意:由于 jsfiddle 不支持 JSX 语法,所以使用 render-content 自定义数据项的例子在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。
<template>
<p style="text-align: center; margin: 0 0 20px">使用 render-content 自定义数据项</p>
<div style="text-align: center">
<el-transfer
style="text-align: left; display: inline-block"
v-model="value"
filterable
:left-default-checked="[2, 3]"
:right-default-checked="[1]"
:render-content="renderFunc"
:titles="['Source', 'Target']"
:button-texts="['到左边', '到右边']"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}'
}"
@change="handleChange"
:data="data">
<el-button class="transfer-footer" slot="left-footer" size="small">操作</el-button>
<el-button class="transfer-footer" slot="right-footer" size="small">操作</el-button>
</el-transfer>
</div>
<p style="text-align: center; margin: 50px 0 20px">使用 scoped-slot 自定义数据项</p>
<div style="text-align: center">
<el-transfer
style="text-align: left; display: inline-block"
v-model="value4"
filterable
:left-default-checked="[2, 3]"
:right-default-checked="[1]"
:titles="['Source', 'Target']"
:button-texts="['到左边', '到右边']"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}'
}"
@change="handleChange"
:data="data">
<span slot-scope="{ option }">{{ option.key }} - {{ option.label }}</span>
<el-button class="transfer-footer" slot="left-footer" size="small">操作</el-button>
<el-button class="transfer-footer" slot="right-footer" size="small">操作</el-button>
</el-transfer>
</div>
</template>
<style>
.transfer-footer {
margin-left: 20px;
padding: 6px 5px;
}
</style>
<script>
export default {
data() {
const generateData = _ => {
const data = [];
for (let i = 1; i <= 15; i++) {
data.push({
key: i,
label: `备选项 ${ i }`,
disabled: i % 4 === 0
});
}
return data;
};
return {
data: generateData(),
value: [1],
value4: [1],
renderFunc(h, option) {
return <span>{ option.key } - { option.label }</span>;
}
};
},
methods: {
handleChange(value, direction, movedKeys) {
console.log(value, direction, movedKeys);
}
}
};
</script>
数据项属性别名
默认情况下,Transfer 仅能识别数据项中的 key、label 和 disabled 字段。如果你的数据的字段名不同,可以使用 props 属性为它们设置别名。
本例中的数据源没有 key 和 label 字段,在功能上与它们相同的字段名为 value 和 desc。因此可以使用props 属性为 key 和 label 设置别名。
<template>
<el-transfer
v-model="value"
:props="{
key: 'value',
label: 'desc'
}"
:data="data">
</el-transfer>
</template>
<script>
export default {
data() {
const generateData = _ => {
const data = [];
for (let i = 1; i <= 15; i++) {
data.push({
value: i,
desc: `备选项 ${ i }`,
disabled: i % 4 === 0
});
}
return data;
};
return {
data: generateData(),
value: []
};
}
};
</script>
Attributes
参数 |
说明 |
类型 |
可选值 |
默认值 |
---|---|---|---|---|
value / v-model |
绑定值 |
array |
— |
— |
data |
Transfer 的数据源 |
array[{ key, label, disabled }] |
— |
[ ] |
filterable |
是否可搜索 |
boolean |
— |
false |
filter-placeholder |
搜索框占位符 |
string |
— |
请输入搜索内容 |
filter-method |
自定义搜索方法 |
function |
— |
— |
target-order |
右侧列表元素的排序策略:若为 original,则保持与数据源相同的顺序;若为 push,则新加入的元素排在最后;若为 unshift,则新加入的元素排在最前 |
string |
original / push / unshift |
original |
titles |
自定义列表标题 |
array |
— |
[‘列表 1’, ‘列表 2’] |
button-texts |
自定义按钮文案 |
array |
— |
[ ] |
render-content |
自定义数据项渲染函数 |
function(h, option) |
— |
— |
format |
列表顶部勾选状态文案 |
object{noChecked, hasChecked} |
— |
{ noChecked: '${checked}/${total}', hasChecked: '${checked}/${total}'} |
props |
数据源的字段别名 |
object{key, label, disabled} |
— |
— |
left-default-checked |
初始状态下左侧列表的已勾选项的 key 数组 |
array |
— |
[ ] |
right-default-checked |
初始状态下右侧列表的已勾选项的 key 数组 |
array |
— |
[ ] |
Slot
name |
说明 |
---|---|
left-footer |
左侧列表底部的内容 |
right-footer |
右侧列表底部的内容 |
Scoped Slot
name |
说明 |
---|---|
— |
自定义数据项的内容,参数为 { option } |
Methods
方法名 |
说明 |
参数 |
---|---|---|
clearQuery |
清空某个面板的搜索关键词 |
‘left’ / ‘right’,指定需要清空的面板 |
Events
事件名称 |
说明 |
回调参数 |
---|---|---|
change |
右侧列表元素变化时触发 |
当前值、数据移动的方向(‘left’ / ‘right’)、发生移动的数据 key 数组 |
left-check-change |
左侧列表元素被用户选中 / 取消选中时触发 |
当前被选中的元素的 key 数组、选中状态发生变化的元素的 key 数组 |
right-check-change |
右侧列表元素被用户选中 / 取消选中时触发 |
当前被选中的元素的 key 数组、选中状态发生变化的元素的 key 数组 |
4、Form 表单
由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。
典型表单
包括各种表单项,比如输入框、选择器、开关、单选框、多选框等。
在 Form 组件中,每一个表单域由一个 Form-Item 组件构成,表单域中可以放置各种类型的表单控件,包括 Input、Select、Checkbox、Radio、Switch、DatePicker、TimePicker。
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
methods: {
onSubmit() {
console.log('submit!');
}
}
}
</script>
W3C 标准中有如下规定:当一个 form 元素中只有一个输入框时,在该输入框中按下回车应提交该表单。如果希望阻止这一默认行为,可以在
<el-form>
标签上添加 @submit.native.prevent。
行内表单
当垂直方向空间受限且表单较简单时,可以在一行内放置表单。
设置 inline 属性可以让表单域变为行内的表单域。
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="审批人">
<el-input v-model="formInline.user" placeholder="审批人"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="formInline.region" placeholder="活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
formInline: {
user: '',
region: ''
}
}
},
methods: {
onSubmit() {
console.log('submit!');
}
}
}
</script>
对齐方式
根据具体目标和制约因素,选择最佳的标签对齐方式。
通过设置 label-position 属性可以改变表单域标签的位置,可选值为 top、left,当设为 top 时标签会置于表单域的顶部。
<el-radio-group v-model="labelPosition" size="small">
<el-radio-button label="left">左对齐</el-radio-button>
<el-radio-button label="right">右对齐</el-radio-button>
<el-radio-button label="top">顶部对齐</el-radio-button>
</el-radio-group>
<div style="margin: 20px;"></div>
<el-form :label-position="labelPosition" label-width="80px" :model="formLabelAlign">
<el-form-item label="名称">
<el-input v-model="formLabelAlign.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-input v-model="formLabelAlign.region"></el-input>
</el-form-item>
<el-form-item label="活动形式">
<el-input v-model="formLabelAlign.type"></el-input>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
labelPosition: 'right',
formLabelAlign: {
name: '',
region: '',
type: ''
}
};
}
}
</script>
表单验证
在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误。
Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。校验规则参见 async-validator。
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="活动名称" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域" prop="region">
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间" required>
<el-col :span="11">
<el-form-item prop="date1">
<el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1" style="width: 100%;"></el-date-picker>
</el-form-item>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-form-item prop="date2">
<el-time-picker placeholder="选择时间" v-model="ruleForm.date2" style="width: 100%;"></el-time-picker>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch v-model="ruleForm.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质" prop="type">
<el-checkbox-group v-model="ruleForm.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源" prop="resource">
<el-radio-group v-model="ruleForm.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式" prop="desc">
<el-input type="textarea" v-model="ruleForm.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
ruleForm: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
],
resource: [
{ required: true, message: '请选择活动资源', trigger: 'change' }
],
desc: [
{ required: true, message: '请填写活动形式', trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
自定义校验规则
这个例子中展示了如何使用自定义验证规则来完成密码的二次验证。
本例还使用status-icon属性为输入框添加了表示校验结果的反馈图标。
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
var checkAge = (rule, value, callback) => {
if (!value) {
return callback(new Error('年龄不能为空'));
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('请输入数字值'));
} else {
if (value < 18) {
callback(new Error('必须年满18岁'));
} else {
callback();
}
}
}, 1000);
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
ruleForm: {
pass: '',
checkPass: '',
age: ''
},
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
自定义校验 callback 必须被调用。 更多高级用法可参考 async-validator。
动态增减表单项
除了在 Form 组件上一次性传递所有的验证规则外还可以在单个的表单域上传递属性的验证规则。
<el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
<el-form-item
prop="email"
label="邮箱"
:rules="[
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
]"
>
<el-input v-model="dynamicValidateForm.email"></el-input>
</el-form-item>
<el-form-item
v-for="(domain, index) in dynamicValidateForm.domains"
:label="'域名' + index"
:key="domain.key"
:prop="'domains.' + index + '.value'"
:rules="{
required: true, message: '域名不能为空', trigger: 'blur'
}"
>
<el-input v-model="domain.value"></el-input><el-button @click.prevent="removeDomain(domain)">删除</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('dynamicValidateForm')">提交</el-button>
<el-button @click="addDomain">新增域名</el-button>
<el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
dynamicValidateForm: {
domains: [{
value: ''
}],
email: ''
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
removeDomain(item) {
var index = this.dynamicValidateForm.domains.indexOf(item)
if (index !== -1) {
this.dynamicValidateForm.domains.splice(index, 1)
}
},
addDomain() {
this.dynamicValidateForm.domains.push({
value: '',
key: Date.now()
});
}
}
}
</script>
数字类型验证
数字类型的验证需要在 v-model 处加上 .number 的修饰符,这是 Vue 自身提供的用于将绑定值转化为 number 类型的修饰符。
<el-form :model="numberValidateForm" ref="numberValidateForm" label-width="100px" class="demo-ruleForm">
<el-form-item
label="年龄"
prop="age"
:rules="[
{ required: true, message: '年龄不能为空'},
{ type: 'number', message: '年龄必须为数字值'}
]"
>
<el-input type="age" v-model.number="numberValidateForm.age" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('numberValidateForm')">提交</el-button>
<el-button @click="resetForm('numberValidateForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
numberValidateForm: {
age: ''
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
嵌套在 el-form-item 中的 el-form-item 标签宽度默认为零,不会继承 el-form 的 label-width。如果需要可以为其单独设置 label-width 属性。
表单内组件尺寸控制
通过设置 Form 上的 size 属性可以使该表单内所有可调节大小的组件继承该尺寸。Form-Item 也具有该属性。
如果希望某个表单项或某个表单组件的尺寸不同于 Form 上的size属性,直接为这个表单项或表单组件设置自己的size即可。
<el-form ref="form" :model="sizeForm" label-width="80px" size="mini">
<el-form-item label="活动名称">
<el-input v-model="sizeForm.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="sizeForm.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="sizeForm.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="sizeForm.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="sizeForm.type">
<el-checkbox-button label="美食/餐厅线上活动" name="type"></el-checkbox-button>
<el-checkbox-button label="地推活动" name="type"></el-checkbox-button>
<el-checkbox-button label="线下主题活动" name="type"></el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="sizeForm.resource" size="medium">
<el-radio border label="线上品牌商赞助"></el-radio>
<el-radio border label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item size="large">
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
sizeForm: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
};
},
methods: {
onSubmit() {
console.log('submit!');
}
}
};
</script>
Form Attributes
参数 |
说明 |
类型 |
可选值 |
默认值 |
---|---|---|---|---|
model |
表单数据对象 |
object |
— |
— |
rules |
表单验证规则 |
object |
— |
— |
inline |
行内表单模式 |
boolean |
— |
false |
label-position |
表单域标签的位置,如果值为 left 或者 right 时,则需要设置 label-width |
string |
right/left/top |
right |
label-width |
表单域标签的宽度,例如 ‘50px’。作为 Form 直接子元素的 form-item 会继承该值。支持 auto |
string |
— |
— |
label-suffix |
表单域标签的后缀 |
string |
— |
— |
hide-required-asterisk |
是否显示必填字段的标签旁边的红色星号 |
boolean |
— |
false |
show-message |
是否显示校验错误信息 |
boolean |
— |
true |
inline-message |
是否以行内形式展示校验信息 |
boolean |
— |
false |
status-icon |
是否在输入框中显示校验结果反馈图标 |
boolean |
— |
false |
validate-on-rule-change |
是否在 rules 属性改变后立即触发一次验证 |
boolean |
— |
true |
size |
用于控制该表单内组件的尺寸 |
string |
medium / small / mini |
— |
disabled |
是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效 |
boolean |
— |
false |
Form Methods
方法名 |
说明 |
参数 |
---|---|---|
validate |
对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise |
Function(callback: Function(boolean, object)) |
validateField |
对部分表单字段进行校验的方法 |
Function(props: array |
resetFields |
对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 |
— |
clearValidate |
移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果 |
Function(props: array |
Form Events
事件名称 |
说明 |
回调参数 |
---|---|---|
validate |
任一表单项被校验后触发 |
被校验的表单项 prop 值,校验是否通过,错误消息(如果存在) |
Form-Item Attributes
参数 |
说明 |
类型 |
可选值 |
默认值 |
---|---|---|---|---|
prop |
表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的 |
string |
传入 Form 组件的 model 中的字段 |
— |
label |
标签文本 |
string |
— |
— |
label-width |
表单域标签的的宽度,例如 ‘50px’。支持 auto |
string |
— |
— |
required |
是否必填,如不设置,则会根据校验规则自动生成 |
boolean |
— |
false |
rules |
表单验证规则 |
object |
— |
— |
error |
表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息 |
string |
— |
— |
show-message |
是否显示校验错误信息 |
boolean |
— |
true |
inline-message |
以行内形式展示校验信息 |
boolean |
— |
false |
size |
用于控制该表单域下组件的尺寸 |
string |
medium / small / mini |
- |
Form-Item Slot
name |
说明 |
---|---|
— |
Form Item 的内容 |
label |
标签文本的内容 |
Form-Item Scoped Slot
name |
说明 |
---|---|
error |
自定义表单校验信息的显示方式,参数为 { error } |
Form-Item Methods
方法名 |
说明 |
参数 |
---|---|---|
resetField |
对该表单项进行重置,将其值重置为初始值并移除校验结果 |
- |
clearValidate |
移除该表单项的校验结果 |
- |
- JS魔法堂:函数重载 之 获取变量的数据类型
- 开发问题(一)在windows和linux端口占用问题
- Linux文件系统的实现
- Design Pattern: Not Just Mixin Pattern
- 关于PHP字符编码的函数区别
- Java集合源码分析(二)Linkedlist
- array_shift() 函数
- 可穿戴设备:不要纠结“可穿戴”
- RXTX for JAVA 串口通信
- Java集合源码分析(一)ArrayList
- 运行jar包找不到主类
- spring cloud 学习(7) - 生产环境如何不停机热发布?
- jupyter notebook 在mac OS上的安装
- Hadoop(七)HDFS容错机制详解
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【SpringBoot web-3】web项目统一数据封装与全局异常处理
- 送你 8 张图,好好理解一下。
- 【前端系列-1】ajax与Springboot通信将数据库数据渲染到前端表格
- 【前端系列-2】layui+springboot实现表格增删改查
- 容器技术|Docker三剑客之docker-swarm
- 【前端系列-3】layui表格使用自定义模板templet
- 【前端系列-4】layui表格集成select选择框和switch开关
- 使用docker Registry快速搭建私有镜像仓库(内附干货)
- 【前端系列-5】layui-from swtich使用小结
- Python解析变长结构体
- 如何优雅地在JS中使用枚举定义
- 【Java基础-1】 Java8新特性Stream详解
- 【Java基础-2】构造函数与构造代码块
- 【Java基础-3】数据结构之JSON浅析
- linux环境svn服务端及windows环境客户端安装配置