FormItem 中检查当前项完成了,现在我们需要处理一下 Form 组件中的全局校验。表单提交时,需要对 form 进行一个全局校验。大致的思路是:循环遍历表单中的所有派发上来的 FormItem ,让每一个 FormItem 执行自己的校验函数,如果有一个为 false ,则校验不通过;否则,校验通过。我们通过代码实现一下:
<template> <form> <slot></slot> </form> </template> <script> export default { props: { model: { type: Object, required: true }, rules: { type: Object } }, provide() { return { eForm: this, // provide this component's instance } }, data() { return { fileds: [], } }, created() { // 解释一 this.fileds = []; this.$on('addFiled', filed => this.fileds.push(filed)); }, 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); } }, } </script> <style lang="scss" scoped> </style>
解释一:用 fileds 缓存需要校验的表单项,因为我们在 FormItem 中派发了事件。只有需要校验的 FormItem 会被派发到这里,而且都会保存在数组中。
if (this.prop) { this.dispatch('EForm', 'addFiled', this); }
解释二:当点击提交按钮时,会触发这个事件。
解释三:遍历所有被添加到 fileds 中的 FormItem 项,让每一项单独去验证,会返回 Promise 的 true 或 false 。将所有的结果,放在一个数组 eachFiledResultArray 中。
解释四:获取所有的结果,统一进行处理,其中有一个结果为 false ,验证就不能通过。
至此,一个最简化版本的仿 ElementUI 的表单就实现了。
四. 总结
当然上面的代码还有很多可以优化的地方,比如说 dispatch 函数,我们可以写一遍,使用的时候用 mixin 导入。由于篇幅关系,这里就不做处理了。
通过这次实现,我们首先总结一下其中所涉及的知识点。
父组件传递给子组件用 props
子组件派发事件,用 $emit
跨层级数据交互,用 provide 和 inject
用 slot 可以预留插槽
其次是一些思想:
单项数据流:父组件传递给子组件的值,子组件内部只能用,不能修改。
组件内部的 name 属性,可以通过 this.$parent.$options.name 查找。
想要批量处理很多异步的结果,可以用 promise 对象。
最后,文章会首先发布在我的 Github ,以及公众号上,欢迎关注,欢迎 star。