Form forms are common in everyday business, and ElementUI is used as a component development when using Vue; In addition to the general form components provided by UI components, such as :input, select, etc., due to business differences, not limited to simple input, selection. There will be combined operations that need to process input/selected values according to business logic. It is also important to explore the implementation of various UI components and incorporate custom form components into the form form.
Each framework, component version in the example
Vue@2.6
Element@2.141.
Copy the code
Reading this article you can learn:
- The ElementUI Form is basically used, and the form validates the flow.
- V-model custom components and validation with Element from.
ElementUI
Here’s a basic example:
elementForm.vue
<template>
<div style="width:40%">
<el-form ref="form" :model="userInfo" :rules="rules">
<el-form-item label="Name" prop="name">
<el-input v-model="userInfo.name" placeholder="Name" maxlength="15"></el-input>
</el-form-item>
<el-form-item label="Age" prop="age">
<el-input v-model="userInfo.age" placeholder="Age" ></el-input>
</el-form-item>
<el-form-item label="Gender" prop="gender">
<el-radio-group v-model="userInfo.gender">
<el-radio label="0">male</el-radio>
<el-radio label="1">female</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="Hobby" prop="hobby">
<el-checkbox-group v-model="userInfo.hobby">
<el-checkbox v-for="item in hobbies" :key="item" :label="item" name="hobby"></el-checkbox>
</el-checkbox-group>
<div>
<el-input v-model.trim="hobby" placeholder="Custom" @change="handleAddHooby" size="mini" style="width:140px;"></el-input>
</div>
</el-form-item>
<el-form-item label="Birthday" prop="birthday">
<el-date-picker v-model="userInfo.birthday"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmitInfo">submit</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data(){
function validateAge(rule,value,callback){
try{
if(value===' '){
callback('Please enter age')}if(! value.match(/^\d+$/)){
callback('Please enter a number')}if(value*1 <0 || value*1 >150){
callback('Please enter a reasonable age value')
}
callback()
}catch(err){
console.log(err)
callback('Please enter age')}}return {
hobby:"".hobbies: ['basketball'.'read'.'games'.'singing'.'dancing'].userInfo: {name:' '.age:' '.gender:'1'.hobby: [].birthday:' ',},rules: {name: [{required:true.message:'Please enter your name'}].age: [{validator:validateAge,trigger:'change'}}}},methods: {handleAddHooby(){
if(this.hobbies.includes(this.hobby)){
return
}
this.hobbies.push(this.hobby)
this.hobby = ' '
},
handleSubmitInfo(){
console.log(this.userInfo)
this.$refs.form.validate((error,errrorInfo) = >{
if(error){
return}})}}}</script>
Copy the code
Focus:
<el-form ref="form" \>
Bind to retrieve the form instance and call methods such as validate manual validation and resetFields to reset the form.<el-form-item prop="name" \>
Binding, which corresponds to the rules key value of the rule set bound by the form. Verification rules are obtained during verification.<el-input v-model="userInfo.name" \>
Component input control, use of V-model instructions
v-model
Implement custom components
It was found that with the component EL-Input, the user could not enter without using the V-Model binding value.
<el-input placeholder="Name"></el-input>
Copy the code
When I looked at the Element source section, I found that the controls were in the code.
setNativeInputValue() {
const input = this.$refs.input; // this.$refs.input source code is this.getinput ();
if(! input)return;
if (input.value === this.nativeInputValue) return;
input.value = this.nativeInputValue;
},
Copy the code
The value property of the model prop and props defined in the example, so when you use this component at the parent level, If you use both v-model and value, you don’t get the props value in this component (v-model has high priority,value is ignored). You can only get a value in a custom component if you only use it.
custom-input.vue
<template>
<div>
<p>This is a custom input component</p>
<input ref="input"
v-model="inputValue"
@input="handleInput"
/>
</div>
</template>
<script>
export default {
data(){
return {
inputValue:' ',}},model: {// Define v-model how to dispose of this component, value attribute definition, event definition
prop:"value".event:"custom"
},
props: {value: [String.Number].// Since the bound property value is the same as the prop defined by the V-model, choose one or the other, v-model takes precedence and value is ignored
},
mounted(){
this.inputValue = this.value
},
methods: {/** * If you do not use the v-model, the parent component needs to listen for cusmo events and update the value of value * if you use the V-model, the v-model will listen for events based on the event type defined by the model. Update the value. **/
handleInput(e){
console.log(this.inputValue)
this.$emit('custom'.Math.random()*10); }},}</script>
Copy the code
Custom component references, v-model and value are bound at the same time, value is ignored.
// ...
<custom-input v-model="inputValue" value="admin" />
// ...
data(){
return {
inputValue:' ',}}Copy the code
Of course, the custom distributed event this.$emit(‘custom’, math.random ()*10); , we can also listen on the parent component
// ...
<custom-input v-model="inputValue" @custom='handleVModel' />
// ...
data(){
return {
inputValue:' ',}},methods: {handleVModel(val){
console.log("listener - vModel :",val)
}
}
Copy the code
Custom input component concerns:
-
Model component property setting, which defines how the V-Model directive handles the current component: data name, event name;
Prop-value; event – input ; The example defines the event event-custom
model:{ prop:"value".event:"custom" } Copy the code
You can customize the props\ Event names to handle specific businesses.
-
$emit(‘custom’, event.target.value); $emit(‘custom’, event.target.value);
-
The V-model ignores the default binding values for all form elements, such as value\checked\selected,
-
The name of the model-prop property bound to the V-model is passed to the props of the component. Define the function-value to get the value of the V-Model
Test – Define different model-prop to see how inputs are bound; The value in props can be used to initialize the input value inside the component;
// ...
model: {// Define v-model how to dispose of this component, value attribute definition, event definition
prop:"customValue".// Define different prop
event:"custom"
},
props: {customValue: [String.Number].// The prop value of the bidirectional binding needs to be defined in the props of the component
value: [String.Number],},watch: {customValue(val){
console.log(val)
}
},
mthods: {/** * the internal input box is input to format the internal input data, and the formatted data is given to the V-model, the parent binding is the given value **/
handleInput(e){
this.$emit('custom'.Math.random()*10); // The value of the V-model response defined here is given to a random number, distinguishing it from the internal input input}},/ /...
Copy the code
The prop defined by the V-model needs to be defined in the props of the component, which can be viewed by watching the value update print.
Consider: When using a V-Model in a custom form input component, the V-Model is like a higher-order component that internally maintains a property value of the Model-prop name and listens for events of the model-Event name. The event triggers an update of the value of a prop property of its own. When the value is updated, the parent and its own re-rendering are called simultaneously.
el-form
Calibration principle
How is validation detected and triggered when a user enters or changes a value
Distribute events to the parent by looking at the source section and listening for the value of value
watch: {
value(val) {
// this.$nextTick(this.resizeTextarea);
if (this.validateEvent) {
this.dispatch('ElFormItem'.'el.form.change', [val]); // Forward events to el-form-item; Dispatch is an internal custom event forwarding function}}},Copy the code
After Mounted, addValidateEvents is called. After Mounted, addValidateEvents is called. After Mounted, addValidateEvents is called.
addValidateEvents() {
const rules = this.getRules();
if (rules.length || this.required ! = =undefined) {
this.$on('el.form.blur'.this.onFieldBlur);
this.$on('el.form.change'.this.onFieldChange); // Listen for events to trigger the corresponding callback function}},onFieldChange() {
if (this.validateDisabled) {
this.validateDisabled = false;
return;
}
this.validate('change'); // Trigger verification. Change is the value of trigger in the verification rule
},
validate(trigger, callback = noop) {
this.validateDisabled = false;
const rules = this.getFilteredRule(trigger); // Merge rules bound to el-Form, rules bound to el-form-item, and Required
if((! rules || rules.length ===0) && this.required === undefined) {
callback();
return true;
}
this.validateState = 'validating';
const descriptor = {};
if (rules && rules.length > 0) {
rules.forEach(rule= > {
delete rule.trigger;
});
}
descriptor[this.prop] = rules; // Check rule set
const validator = new AsyncValidator(descriptor); // Reference library async-validator; Initializes the validation rule, instance object Validator
const model = {};
model[this.prop] = this.fieldValue;
validator.validate(model, { firstFields: true }, (errors, invalidFields) = > { // Call the validAT method to validate the given value model
this.validateState = ! errors ?'success' : 'error';
this.validateMessage = errors ? errors[0].message : ' ';
callback(this.validateMessage, invalidFields);
this.elForm && this.elForm.$emit('validate'.this.prop, ! errors,this.validateMessage || null); // el-form Any form triggers the verification event, including the current attribute name, verification result, and verification information
});
},
Copy the code
Custom component combinationel-form
check
If our custom components need to be integrated into the EL-form, and verify the rule origin. You need to distribute events in a custom component when a value changes.
We need to modify our previously customized component custom-input.vue by distributing validation events to trigger validation when the V-model value changes.
import emitter from 'element-ui/src/mixins/emitter'; // Distribute the el-form method of the event
// ...
mixins:[emitter], // Mix the way to load the current component
watch: {customValue(val){
console.log(val)
this.dispatch('ElFormItem'.'el.form.change', [val]); // When the value changes, an event is issued to el-form-item and the validation process inside the component is invoked}},Copy the code
When you’re done, reference it to the parent form component and test it. To see how it works, use the following:
<template>
<div style="width:40%">
<el-form ref="form" :model="userInfo" :rules="rules">
<! - / /... Omit the others -->
<el-form-item label="Custom" prop="randomValue">
<custom-input v-model="userInfo.randomValue" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmitInfo">submit</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import CustomInput from './custom-input'
export default {
data(){
// ...
function validateAgeRandomValue(rule,value,callback){ // Use custom validation rules for the values of custom components
try{
if(value===' '){
callback('Please enter a random number')}if(value<3){
callback('Too small')}if(value>7){
callback('Too big')
}
callback()
}catch(err){
callback('Wrong')}}return {
customInputValue:"".hobby:"".hobbies: ['basketball'.'read'.'games'.'singing'.'dancing'].userInfo: {name:' '.age:' '.gender:'1'.hobby: [].birthday:' '.randomValue:' ',},rules: {name: [{required:true.message:'Please enter your name'}].age: [{validator:validateAge,trigger:'change'}].randomValue: [{required:true.message:'Please enter a random value'}, {validator:validateAgeRandomValue}], // Custom rules}}},components:{
CustomInput
},
// ...
}
</script>
Copy the code
Testing, done! :white_check_mark:
Originally wanted to continue to write V-Model source code implementation, look very tired, too many things, see the head; Stuck_out_tongue_winking_eye: