Vue框架入門(三)

一、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;
            }
        });
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章