持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情
🏀 安装
首先用vue-cli新建个项目.
vue create use_elementui
官网提供了npm、CDN两种在项目中引入Element的方式,我们使用第一种,npm安装:
npm install element-ui --save
关于使用组件,可以引入整个Element,也可以按需引入,表单中涉及的组件还是比较多的,方便起见,我们就使用完整引入,需要注意的就是样式文件需要单独引入
// main.js
import Vue from "vue";
import App from "./App.vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css"; // 单独引入样式
Vue.config.productionTip = false;
Vue.use(ElementUI);
new Vue({
render: (h) => h(App),
}).$mount("#app");
⚽ 使用Form组件
在components文件夹下新建Form.vue文件,专门用于放置el-form相关的代码,在HelloWorld.vue中使用Form.vue。
我们从使用官网提供的表单验证组件开始,完整代码由于比较长就附在了文章末尾,最终表单组件的显示如下:
Element UI中的一个<el-form>元素就是一个表单,它可以包含多个控件,比如输入框、选择器、单选框、多选框等,每个控件也称为表单项,即<el-form-item>。
表单和表单项都有一系列的属性和方法,详细可以对照官网查看,这里就不一一演示了,我打算从功能出发来梳理表单组件中的核心逻辑,在这个过程中用到哪些属性/方法,就展开介绍一下,其它属性/方法可以对照官网自己练习用法。
⚽ 收集数据
拿上面的案例来说,Form组件通过表单项收集的数据都通过v-model存放在ruleForm对象中,以<el-input>元素为例,下面代码只保留我们关注的部分:
<template>
<!-- 只保留关注的代码 -->
<div>
<el-form :model="ruleForm">
<el-form-item>
<el-input v-model="ruleForm.name"></el-input>
</el-form>
<div>
<template>
<script>
data(){
return {
ruleForm: {
name: "",
},
}
}
</script>
name的值为<el-input v-model="ruleForm.name"></el-input>输入框的默认值,这里设的是空值,name: "",如果我们将它设为name: "This is name",可以看到此时对应的活动名称输入框会显示出相应的默认值,对其它表单项的内容来说,也是同样的道理。
需要注意的一点是v-model是赋在表单控件上的,比如上面的<el-input>,而不是表单项上,表单中使用的是model属性,这点不要混肴了。事实上,如果不涉及校验,表单中的model属性在收集数据时是可以不要的。
⚽ 校验数据
Form组件的数据校验涉及的属性为rules,相对复杂一些。
从校验方式来看,我们可以选择默认的校验方式,也可以使用validator函数来自定义校验方法,两者遵循的都是async-validator这一校验规则。
从校验对象来看,表单和表单项的内容都可以被校验,但<el-form>上的rules优先级小于<el-item-form>上的rules规则验证,也就是说,当两者同时存在时,校验规则遵循的是<el-item-form>上的rules。
下面我们来实践一下:
<template>
<!-- 只保留关注的代码 -->
<div>
<el-form ref="ruleForm" :model="ruleForm" :rules="rules">
<el-form-item label="活动名称" prop="name"> // prop的值必须与rules中的字段对应
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
<div>
<template>
<script>
data(){
return {
rules: {
name: [
{
required: true, // 该字段是否必填
message: "请输入活动名称", // 没填写时的错误提示语
trigger: "blur", // 在什么时候触发验证
},
{
min: 3, // 字段最小长度
max: 5, // 字段最大长度
message: "长度在 3 到 5 个字符", // 不满足规则时的错误提示语
trigger: "blur", // 在什么时候触发验证
}
]
}
}
}
</script>
可以看到:rule作用在el-form上,并且绑定了一个变量rules。接着我们就在rules中编写活动名称name的验证规则。prop属性的值就是form中定义的name字段,只有这样rules中定义的对name的校验规则才能和对应的表单关联起来,否则验证规则是不会生效的。
这里需要注意的是,表单el-form上绑定的form数据中的字段、prop设置的值以及rules绑定的rules数据中的字段,这三个必须都要一致,否则校验会出现问题。
为了演示自定义校验规则的使用,这里增加了一个表单项:
<el-form-item label="年龄" prop="age" required>
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
校验规则如下:
data() {
const 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);
};
return {
age: [{ validator: checkAge, trigger: "blur" }],
}
}
上面例子中展示了输入的年龄必须大于18岁的验证规则,添加了一个checkAge校验方法,它的通用语法规则是:
validate( source , [options], callback )
source是需要校验的属性和值,必传参数。options是描述处理验证对象的选项。callback校验完成之后的回调函数。
该方法返回的是 Promise 对象,所以有:
then()成功回调catch(({ errors, fields })=>{})失败回调
进一步的了解可以看一下async-validator这个表单异步校验库的官方文档
。这里我们需要注意的是检验方法必须写在data()中return的外层,否则校验无法生效。
⚽ 表单提交与重置
methods: {
// 提交表单
submitForm(formName) {
this.$refs[formName].validate((valid, failedInfo) => {
if (valid) {
alert("submit!");
} else {
console.log("error submit caused by:");
console.log(failedInfo);
return false;
}
});
},
// 重置表单
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
表单方法validate是对整个表单进行校验的方法,参数为一个回调函数。
该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个promise。
上面validate方法的逻辑是:点击提交按钮时,如果表单校验通过,就弹出提示框;如果校验未通过,就打印出错误信息,可以看到错误信息会告诉我们是哪些表单项未通过校验:
resetFields方法则是对整个表单进行重置,将所有字段值重置为初始值并且移除校验结果,这里需要注意的是在使用resetFileds时,必须给表单项el-form-item设置prop值,否则无法进行重置。
🏀 完整代码
// HelloWorld.vue
<template>
<div class="hello">
<Form />
</div>
</template>
<script>
import Form from "./Form.vue";
export default {
name: "HelloWorld",
components: {
Form,
},
};
</script>
// Form.vue
<template>
<div>
<h1>El-Form</h1>
<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 label="年龄" prop="age" required>
<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>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
data() {
// 自定义校验规则
const 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);
};
return {
// 通过表单收集到的数据
ruleForm: {
name: "", // 活动名称 <el-input>
region: "", // 活动区域 <el-select>
date1: "", // 活动时间-日期 <el-time-picker>
date2: "", // 活动时间-时间 <el-time-picker>
delivery: false, // 即时配送 <el-switch>
type: [], // 活动性质 <el-checkbox-group>
resource: "", // 特殊资源 <el-radio-group>
desc: "", // 活动形式 <el-input>
age: "", // 年龄 <el-input>
},
// 表单检验规则:async-validator
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",
},
],
age: [{ validator: checkAge, trigger: "blur" }],
},
};
},
methods: {
// 提交表单,<el-button>
submitForm(formName) {
this.$refs[formName].validate((valid, failedInfo) => {
if (valid) {
alert("submit!");
} else {
console.log("error submit caused by:");
console.log(failedInfo);
return false;
}
});
},
// 重置表单,<el-button>
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
};
</script>