elementui 按钮 表单_仿 ELEMENTUI 实现一个简单的 Form 表单

本文介绍了如何使用 Vue 和 ElementUI 的设计理念,实现一个包含 Form、FormItem 和 EInput 的自定义表单组件。通过组件设计、数据绑定和事件通信,实现了表单的校验和数据双向绑定功能。
摘要由CSDN通过智能技术生成

一、目标

ElementUI 中 Form 组件主要有以下 功能 / 模块:

Form

FormItem

Input

表单验证

在这套组件中,有 3 层嵌套,这里面使用的是 slot 插槽,我们在接下来的代码中也需要运用到它。

二、组件设计

e-form 全局校验,并提供插槽;

e-form 单一项校验和显示错误信息,并提供插槽;

e-input 负责数据的双向绑定

三、开始

e-input

export default {

name: 'EInput',

props: {

value: {

type: String,

default: ''

}

},

data() {

return {

valueInInput: this.value // 确保数据流的单向传递

}

},

methods: {

handleInput(e) {

this.valueInInput = e.target.value;

this.$emit('input', this.valueInInput); // 此处提交的事件名必须是 ‘input’

// 数据变了,定向通知 formItem 进行校验

this.dispatch('EFormItem', 'validate', this.valueInInput);

},

dispatch(componentName, eventName, params) { // 查找指定 name 的组件,

let parent = this.$parent || this.$root;

let name = parent.$options.name

while(parent && (!name || name !== componentName)) {

parent = parent.$parent;

if (parent) {

name = parent.$options.name;

}

}

if (parent) {

// 这里,我们不能用 this.$emit 直接派发事件,因为在 FormItem 组件中,Input 组件的位置只是一个插槽,无法做事件监听,

// 所以此时我们让 FormItem 自己派发事件,并自己监听。修改 FormItem 组件,在 created 中监听该事件。

parent.$emit.apply(parent, [eventName].concat(params));

}

}

}

}

这里需要注意的是 v-model 绑定的值与 props 传递的值的关系,从而能将修改后的值暴露至顶层自定义组件。使用如下:

{{ initValue }}

import EInput from './components/Input.vue';

export default {

name: "app",

components: {

EInput

},

data() {

return {

initValue: '223',

};

},

};

FormItem 的设计

{{ label }}

{{ validateMessage }}

import AsyncValidator from 'async-validator';

export default {

name: 'EFormItem',

props: {

label: { type: String, default: '' }, // 表单项的名称

prop: { type: String, default: '' } // 表单项的自定义 prop

},

inject: ['eForm'], // provide/inject,vue 跨层级通信

data() {

return {

validateState: '',

validateMessage: ''

}

},

methods: {

validate() {

return new Promise(resolve => {

const descriptor = {}; // async-validator 建议用法;

descriptor[this.prop] = this.eForm.rules[this.prop];

// 校验器

const validator = new AsyncValidator(descriptor);

const model = {};

model[this.prop] = this.eForm.model[this.prop];

// 异步校验

validator.validate(model, errors => {

if (errors) {

this.validateState = 'error';

this.validateMessage = errors[0].message;

resolve(false);

} else {

this.validateState = '';

this.validateMessage = '';

resolve(true);

}

})

})

},

dispatch(componentName, eventName, params) { // 查找上级指定 name 的组件

var parent = this.$parent || this.$root;

var name = parent.$options.name;

while (parent && (!name || name !== componentName)) {

parent = parent.$parent;

if (parent) {

name = parent.$options.name;

}

}

if (parent) {

parent.$emit.apply(parent, [eventName].concat(params));

}

}

},

created() {

this.$on('validate', this.validate); // 'validate' 事件由 e-input 组件通知,在 e-form-item 组件接收到后自行触发对应方法

},

// 因为我们需要在 Form 组件中校验所有的 FormItem ,

// 所以当 FormItem 挂载完成后,需要派发一个事件告诉 Form :你可以校验我了。

mounted() {

// 当 FormItem 中有 prop 属性的时候才校验,

// 没有的时候不校验。比如提交按钮就不需要校验。

if (this.prop) {

this.dispatch('EForm', 'addFiled', this);

}

}

}

.error {

color: red;

}

其中, methods 中的方法均是辅助方法,validate() 是异步校验的方法。

Form的设计

export default {

name: 'EForm',

props: {

model: {

type: Object,

required: true

},

rules: {

type: Object

}

},

provide() { // provide/inject,vue 跨层级通信

return {

eForm: this // form 组件实例, 在其他组件中可以通过 this.xxx 来获取属性/方法

}

},

data() {

return {

fileds: [] // 需要校验的 e-form-item 组件数组

}

},

methods: {

async validate(cb) {

const eachFiledResultArray = this.fileds.map(filed => filed.validate());

const results = await Promise.all(eachFiledResultArray);

let ret = true;

results.forEach(valid => {

if (!valid) {

ret = false;

}

});

cb(ret)

}

},

created() {

// 缓存需要检验的组件

this.fileds = [];

this.$on('addFiled', filed => this.fileds.push(filed))

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值