UNPKG

@modulab/form

Version:

表单

193 lines (159 loc) 5.01 kB
import { useTemplateRef } from 'vue'; import { provide, inject, ref, useAttrs, watch } from 'vue'; export const FormContextKey = Symbol('formContext'); export const FormItemContextKey = Symbol('formItemContextKey'); export function useFormContext() { const formRef = useTemplateRef('formRef'); // 内部状态 const formModel = ref({}); // 最终提交的数据 const formData = ref({}); // 维护联动回调 const fieldWatchers: Record<string, Array<(val: any) => void>> = {}; // 子组件方法表 const fieldMethods: Record<string, any> = {}; function update(key: string, value: any) { formModel.value[key] = value; if (fieldWatchers[key]) { fieldWatchers[key].forEach((cb) => cb(value)); } } function watchField(key: string, cb: (val: any) => void) { if (!fieldWatchers[key]) { fieldWatchers[key] = []; } fieldWatchers[key].push(cb); return () => { fieldWatchers[key] = fieldWatchers[key].filter((fn) => fn !== cb); }; } function registerFieldMethods(key: string, methods: Record<string, any>) { fieldMethods[key] = methods; } function callFieldMethod(key: string, methodName: string, ...args: any[]) { if (fieldMethods[key]?.[methodName]) { return fieldMethods[key][methodName](...args); } } function updateFormData(key: string | string[], value: any, split = true) { const keys = Array.isArray(key) ? [...key] : [key]; const values = Array.isArray(value) ? value : [value]; keys.forEach((key, key_idx) => { formData.value[key] = split ? values[key_idx] : value; }); } function backfill(data: Record<any, any>) { Object.keys(data).forEach((key) => { callFieldMethod(key, 'setValue', data[key]); }); } async function validate() { return await formRef.value.validate(); } const context = { formRef, formModel, formData, update, updateFormData, validate, watchField, registerFieldMethods, callFieldMethod, backfill, }; provide(FormContextKey, context); return context; } export function useFormItemContext(props) { const visible = ref(props.visible); function setVisible(val: boolean) { visible.value = val; } const context = { visible, setVisible, }; provide(FormItemContextKey, context); return context; } export function useFormField(options: Record<string, any>, split = true) { const attrs = useAttrs(); const { prop, defaultValue } = options; // props 是复数用于多字段 const { fields } = attrs; const value = ref(defaultValue); const { update, updateFormData, registerFieldMethods } = inject(FormContextKey); const { setVisible } = inject(FormItemContextKey); update(prop, defaultValue); updateFormData( fields ? fields : prop, fields ? [defaultValue, defaultValue] : defaultValue, split, ); function setValue(val: any) { value.value = val; } registerFieldMethods(prop, { setValue, }); watch(value, (val) => { update(prop, val); if (val === null) { updateFormData( fields ? fields : prop, fields ? [val, val] : val, split, ); } else { updateFormData(fields ? fields : prop, val, split); } }); return { value, update, setValue, setVisible, registerFieldMethods, }; } export function useCurrentOptions( options: any[] | (() => Promise<any[]> | any[]), ) { const currentOptions = ref<any[]>([]); async function setOptions(source: typeof options) { try { if (typeof source === 'function') { const result = await source(); currentOptions.value = Array.isArray(result) ? result : []; } else { currentOptions.value = source ?? []; } } catch (e) { console.error(e); } } watch( () => options, async (newOptions) => { await setOptions(newOptions); }, { immediate: true }, ); return { currentOptions, setOptions, reload: () => setOptions(options) }; } export function useDependency(value, methods) { const attrs = useAttrs(); const { watchField, formModel } = inject(FormContextKey); const { dependsOn, onDependency } = attrs; // 如果声明了依赖 if (dependsOn && onDependency) { const keys = Array.isArray(dependsOn) ? dependsOn : [dependsOn]; keys.forEach((k) => { watchField(k, (val) => { onDependency(val, methods, formModel.value, value); }); }); } }