/** * @description 用于触发多表单验证 * @author xmf */ import { ref, markRaw } from 'vue' export default { name: 'CipFormValidate', setup (props, { slots, expose }) { const defaultSlot = ref([]) const isComponent = vnode => !!vnode.component const isFormComponent = (vnode) => { if (!isComponent(vnode)) return false const componentName = (vnode.type?.name ?? '').toLocaleLowerCase() return componentName.indexOf('form') > -1 } const getComponent = vnode => vnode?.component const getMethodByComponent = (component = {}, method) => component.ctx?.[method] ?? component.exposed?.[method] const clearValidate = (vnodeList = []) => { // eslint-disable-next-line no-unused-expressions const handler = (component) => { const clearValidate = getMethodByComponent(component, 'clearValidate') // eslint-disable-next-line no-unused-expressions clearValidate?.() } return findFormAndHandler(vnodeList, handler).then(() => {}) } const findFormAndHandler = async (vnodeList = [], handler = () => {}, depth = 1) => { for (let i = 0; i < vnodeList.length; i++) { const vnode = vnodeList[i] if (isFormComponent(vnode)) { const component = getComponent(vnode) await handler(component) } else { if (depth > props.maxDepth) return false // 使用defineAsyncComponent 是 subTree 及为下个组件 const childVnodeList = isComponent(vnode) ? (vnode.component.subTree?.children ?? [vnode.component.subTree]) : vnode.children // 如果是文字节点则跳过不处理 if (typeof childVnodeList === 'string') { continue } if (childVnodeList?.length > 0) { await findFormAndHandler(childVnodeList, handler, ++depth) // 此处++必须在前 } } } } const validForms = async (vnodeList = []) => { const validList = [] const handler = async (component) => { try { const validate = getMethodByComponent(component, 'validate') await validate?.() validList.push(true) } catch (e) { validList.push(e) } } try { await findFormAndHandler(vnodeList, handler) } catch (e) { console.log('findFormAndHandler', e) } return validList } const validate = async () => { const validList = await validForms(defaultSlot.value) if (!validList.some(valid => valid !== true)) { return true } else { // 此处不需要报错 throw new Error('未通过表单验证') } } const clear = () => { return clearValidate(defaultSlot.value) } expose({ validate, clear }) return () => { const slot = slots.default?.() if (slot) { defaultSlot.value = markRaw(slot) } return slot } } }