一、Element Form
資料地址:https://element.eleme.cn/#/zh-CN/component/form
下面以Form表單爲例,介紹Element UI的使用。
第1步:使用腳手架創建vue工程;
vue create vue-form
第2步:添加element插件。
vue add element
選擇按需加載:
第3步:在App.js文件中定義Form表單;
<template>
<div id="app">
<h3>{{title}}</h3>
<el-form :model="ruleForm" :rules="rules" ref="loginForm">
<el-form-item label="用戶名" prop="name">
<el-input v-model="ruleForm.name" placeholder="用戶名"></el-input>
</el-form-item>
<el-form-item label="密碼" prop="pwd">
<el-input v-model="ruleForm.pwd" placeholder="密碼"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">登錄</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
ruleForm: {
name: '',
pwd: '',
},
rules: {
name: [
{required: true, message: '請輸入用戶名'},
],
pwd: [
{required: true, message: '請輸入密碼'},
{min: 6, max: 10, message: '請輸入6~10位的密碼'},
]
}
}
},
methods: {
submitForm() {
}
},
}
</script>
<style scoped>
</style>
ruleForm屬性用戶綁定輸入框,如:ruleForm.name綁定用戶名輸入框,ruleForm.pwd綁定密碼輸入框。rules屬性定義了各個表單項的校驗規則。
第4步:修改plugins/element.js文件,導入Button、Form、FormItem、Input組件;
import Vue from 'vue'
import { Button, Form, FormItem, Input } from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
二、自定義Form組件
2.1 組件設計
通過上面Form組件的使用,我們可以看出表單組件的結構如下圖所示:
其中,表單各個組件的職責分爲:
1)Form負責定義校驗規則;
2)FormItem負責顯示錯誤信息;
3)Input負責數據的雙向綁定;
4)Button負責表單校驗,以及提交表單;
2.2 構建表單
下面程序模擬Element UI表單構建出我們的表單結構:
<template>
<k-form :model="ruleForm" :rules="rules" ref="loginForm">
<k-form-item label="用戶名" prop="name">
<k-input v-model="ruleForm.name"></k-input>
</k-form-item>
<k-form-item label="密碼" prop="pwd">
<k-input v-model="ruleForm.pwd" type="password"></k-input>
</k-form-item>
<k-form-item>
<el-button type="primary" @click="submitForm">登錄</el-button>
</k-form-item>
</k-form>
{{ruleForm}}
</template>
<script>
import KForm from "./Form.vue";
import KFormItem from "./FormItem.vue";
import KInput from "./Input.vue";
export default {
components: {
KForm,
KFormItem,
KInput,
},
data() {
return {
ruleForm: {
name: '',
pwd: '',
},
rules: {
name: [
{required: true, message: '請輸入用戶名'},
],
pwd: [
{required: true, message: '請輸入密碼'},
{min: 6, max: 10, message: '請輸入6~10位的密碼'},
]
}
}
},
methods: {
submitForm() {
this.$refs.loginForm.validate(valid => {
if (valid) {
alert('提交登錄');
} else {
console.log('校驗失敗');
return false;
}
});
}
}
}
</script>
<style scoped>
</style>
2.3 定義Form
第1步:在components目錄下新建Form.vue文件;
第2步:定義模版;
<template>
<form>
<slot></slot>
</form>
</template>
第3步:定義屬性。
<script>
export default {
provide() {
return {
form: this // 將表單實例傳輸給後代
}
},
props: {
model: {
type: Object,
required: true,
},
rules: {
type: Object
}
},
}
</script>
2.4 定義FormItem
第1步:在components目錄下新建FormItem.vue文件;
第2步:定義模版;
<template>
<div>
<label v-if="label">{{label}}</label>
<div>
<!-- 定義插槽 -->
<slot></slot>
<!-- 校驗結果 -->
<p v-if="validateStatus == 'error'" class="error">{{errorMessage}}</p>
</div>
</div>
</template>
第3步:定義屬性;
<script>
export default {
inject: ['form'], // 注入form,獲取model和rules屬性
props: ['label', 'prop'],
data() {
return {
validateStatus: '',
errorMessage: '',
}
},
}
</script>
2.5 定義Input
第1步:在components目錄下新建Input.vue文件;
第2步:定義模版;
<template>
<div>
<!-- 用戶輸入數據時會自動觸發input事件 -->
<input :type="type" :value="inputValue" @input="handleInput"/>
</div>
</template>
第3步:定義屬性;
<script>
export default {
props: {
value: {
type: String,
defaultValue: '',
},
type: {
type: String,
defaultValue: 'text',
},
},
data() {
return {
inputValue: this.value
}
},
methods: {
// 當輸入框內容發生變化,會自動觸發@input事件,從而執行handlerInput函數
handleInput(e) {
// e.target.value返回輸入框的內容
this.inputValue = e.target.value;
// 通知父組件更新
this.$emit('input', this.inputValue);
}
}
}
</script>
2.5 添加表單項校驗
首先這裏再強調一下,表單項校驗應該有FileItem完成。
第1步:修改handleInput方法,向FormItem組件派發一個validate事件;
methods: {
handleInput(e) {
...
// 通知父組件FormItem做校驗
this.$parent.$emit('validate', this.inputValue);
}
}
第2步:在FormItem的created生命週期方法中監聽validate事件;
created() {
this.$on('validate', this.validate);
},
第3步:在FormItem中定義validate函數。
methods: {
// 使用async-validator進行校驗
validate(value) {
// 該Promise封裝了校驗代碼
// 然後在父組件中使用Promise.all()函數保證組件校驗的執行順序
return new Promise((resolve) => {
// 校驗規則
const descriptor = {
[this.prop]: this.form.rules[this.prop]
};
// 校驗器
const validator = new schema(descriptor);
// 調用校驗方法validate
// 第一個參數:需要校驗的數據模型
// 第二個參數:回調函數
validator.validate({[this.prop]: value}, (errors) => {=> {
if (errors) {
// 校驗失敗
this.validateStatus = 'error';
this.errorMessage = errors[0].message;
resolve(false);
} else {
// 校驗成功
this.validateStatus = '';
this.errorMessage = '';
resolve(true);
}
});
});
},
}
爲了保證多個表單項校驗的執行順序,上面把校驗結果添加到Promise對象中。如果校驗成功,返回true,否則返回false。
第4步:在FormItem中導入async-validator。
<script>
import schema from 'async-validator';
export default {
...
}
</script>
FormItem文件的完成代碼如下所示:
<template>
<div>
<label v-if="label">{{label}}</label>
<div>
<slot></slot>
<p v-if="validateStatus == 'error'" class="error">{{errorMessage}}</p>
</div>
</div>
</template>
<script>
import schema from 'async-validator';
export default {
inject: ['form'], // 注入form,獲取model和rules屬性
props: ['label', 'prop'],
data() {
return {
validateStatus: '',
errorMessage: '',
}
},
created() {
this.$on('validate', this.validate);
},
methods: {
// 使用async-validator進行校驗
validate(value) {
// 該Promise封裝了校驗代碼
// 然後在父組件中使用Promise.all()函數保證組件校驗的執行順序
return new Promise((resolve) => {
// 校驗規則
const descriptor = {
[this.prop]: this.form.rules[this.prop]
};
// 校驗器
const validator = new schema(descriptor);
// 調用校驗方法validate
// 第一個參數:需要校驗的數據模型
// 第二個參數:回調函數
validator.validate({[this.prop]: value}, (errors) => {
if (errors) {
// 校驗失敗
this.validateStatus = 'error';
this.errorMessage = errors[0].message;
resolve(false);
} else {
// 校驗成功
this.validateStatus = '';
this.errorMessage = '';
resolve(true);
}
});
});
},
}
}
</script>
<style scoped>
.error {
color: red;
}
</style>
2.6 添加表單校驗
第1步:在FormItem組件的mounted函數中,向Form組件派發一個formItemAdd事件,並把當前需要校驗的FormItem組件發送給Form組件;
mounted() { // 當前組件掛載後,派發一個事件
// 只有當FormItem有prop屬性時才需要派發事件
if (this.prop) {
// 向Form組件派發事件,然後把當前組件發送給Form組件
this.$parent.$emit('formItemAdd', this);
}
},
第2步:在Form組件的created函數中,監聽formItemAdd事件,並且把校驗的FormItem存儲到fields中;
created() {
// 監聽事件,當FormItem組件掛載後,緩存需要校驗的FormItem組件
this.fields = [];
this.$on('formItemAdd', (item) => this.fields.push(item));
},
第3步:在Form組件中定義校驗方法;
methods: {
async validate(callback) {
// 提交表單時候,重新校驗所有表單項的validate方法
// 然後等待所有校驗結果返回後,再進行統一處理
const promises = this.fields.map(item => item.validate());
const results = await Promise.all(promises);
let ret = true; // 是否校驗成功,默認成功
results.forEach(valid => {
if (!valid) {
ret = false; // 只要有一個表單項校驗失敗,則校驗失敗
}
});
callback(ret);
}
}
第4步:修改FormItem的validate方法,把value參數去掉,然後從form組件的model屬性中動態獲取value。
this.form.model[this.prop]}
第5步:修改登錄按鈕的事件函數,執行表單驗證。
methods: {
submitForm() {
this.$refs.loginForm.validate(valid => {
if (valid) {
alert('提交登錄');
} else {
console.log('校驗失敗');
return false;
}
});
}
}