| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { type InjectionKey, inject, provide, type Ref, computed, ref, watch, type ComputedRef } from "vue";
- import type { FieldProps } from "./Field.vue";
- import type { RuleItem } from "async-validator";
- import { useCellContext } from "../basic/CellContext";
- /**
- * 校验触发时机
- * - blur: 失去焦点时触发校验
- * - change: 值改变时触发校验
- * - submit: 提交表单时触发校验
- */
- export type ValidTrigger = "blur" | "change" | "submit";
- /**
- * 表单项上下文
- */
- export type FormItemContext = {
- errorState: ComputedRef<boolean>,
- getFieldName: () => string,
- /**
- * 触发表单条目获得焦点事件
- */
- onFieldFocus: () => void;
- /**
- * 触发表单条目失去焦点事件
- */
- onFieldBlur: () => void;
- /**
- * 触发表单条目值改变事件
- * @param newValue 新值
- */
- onFieldChange: (newValue: unknown) => void;
- /**
- * 清除表单条目校验状态
- */
- clearValidate: () => void;
- /**
- * 设置表单条目点击事件监听器,设置后表单项允许点击,点击后会触发点击事件。
- * @param listener 点击事件监听器
- */
- setOnClickListener: (listener: (() => void)|undefined) => void;
- /**
- * 获取表单组件中的当前值
- * @returns 表单组件中的当前值
- */
- getFormModelValue(): any;
- /**
- * 表单项是否禁用的状态
- */
- disabled: Ref<boolean|undefined>,
- /**
- * 表单项是否只读的状态
- */
- readonly: Ref<boolean|undefined>,
- };
- export type FormItemInternalContext = {
- /**
- * 获取表单组件的实例引用,如果没有子组件,则返回 Field 自身引用。
- *
- * 本函数专用于动态表单,直接使用的情况可以在模板中绑定ref获取实例引用。
- *
- * 只有 Field 组件设置了 requireChildRef 回调才能返回子组件实例引用,否则只会返回 Field 组件实例引用。
- * @returns
- */
- getExpectedRef: () => any,
- getItemRules: () => RuleItem[],
- getFieldName: () => string,
- getValidateTrigger: () => ValidTrigger;
- getUniqueId: () => string,
- setErrorState: (errorMessage: string|null) => void;
- setBlurState(): void;
- };
- export type FormContext = {
- //由表单项组件调用
- onFieldFocus: (item: FormItemInternalContext) => void;
- onFieldBlur: (item: FormItemInternalContext) => void;
- onFieldChange: (item: FormItemInternalContext, newValue: unknown) => void;
- clearValidate: (item: FormItemInternalContext) => void;
- addFormItemField: (item: FormItemInternalContext) => number;
- removeFormItemField: (item: FormItemInternalContext) => void;
- //form props
- validateTrigger: Ref<ValidTrigger|undefined>;
- addRequireMark: Ref<boolean|undefined>;
- colon: Ref<boolean|undefined>;
- labelWidth: Ref<string|number|undefined>;
- labelAlign: Ref<"left"|"center"|"right"|undefined>;
- labelPosition: Ref<'top'|'left'|undefined>;
- labelFlex: Ref<number|undefined>;
- inputFlex: Ref<number|undefined>;
- showLabel: Ref<boolean|undefined>;
- name: Ref<string|undefined>;
- fieldProps: Ref<FieldProps|undefined>,
- disabled: Ref<boolean|undefined>,
- readonly: Ref<boolean|undefined>,
- getItemValue: (item: FormItemInternalContext) => unknown;
- getItemRequieed: (item: FormItemInternalContext) => boolean;
- };
- /**
- * 用于Props默认值回调中获取表单上下文
- * @returns FormContext
- */
- export function propGetFormContext() {
- return inject<FormContext>('formContext', null as any);
- }
- export const FormItemContextContextKey: InjectionKey<FormItemContext> = Symbol('FormItemContext');
- /**
- * 用于注入表单项上下文
- * @returns FormItemContext
- */
- export function useInjectFormItemContext() : FormItemContext {
- const context = inject<FormItemContext>(FormItemContextContextKey, null as any);
- provide(FormItemContextContextKey, null as any as FormItemContext);
- return context as FormItemContext;
- }
- /**
- * 用于注入表单上下文
- * @returns FormContext
- */
- export function useInjectFormContext() : FormContext {
- return inject<FormContext>('formContext', null as any);
- }
- /**
- * 用于注入表单项子组件值,用于实现表单项值的双向绑定。
- *
- * 组件可以通过返回的 `value` 属性获取当前值,通过 `updateValue` 方法更新值,
- * 即使外部未绑定 `modelValue` 属性,也可以正常工作。
- *
- * ```ts
- * const {
- value,
- updateValue,
- } = useFieldChildValueInjector(
- toRef(props, 'modelValue'),
- (v) => emit('update:modelValue', v)
- );
- * ```
- * @param propsModelValue 组件外部传入的modelValue
- * @param emit 组件外部的emit
- * @param secondParentContext 二级父组件上下文,用于更新二级父组件的值。
- * @param fieldClick 表单项点击事件监听器,设置后表单项允许点击,点击后会触发点击事件。
- * @param initialValue 初始值
- * @returns
- */
- export function useFieldChildValueInjector<T>(
- propsModelValue: Ref<T>,
- emit: (v: T) => void,
- secondParentContext?: {
- getValue: () => T,
- updateValue: (v: T) => void,
- },
- fieldClick?: () => void,
- initialValue?: T,
- ) {
- const cellContext = useCellContext();
- const context = useInjectFormItemContext();
- const formContext = useInjectFormContext();
- const shadowRefValue = ref(propsModelValue.value ?? context.getFormModelValue() ?? initialValue) as Ref<T>;
- const value = computed(() => {
- if (secondParentContext)
- shadowRefValue.value = secondParentContext.getValue();
- return shadowRefValue.value
- });
- watch(() => propsModelValue.value, (v) => {
- shadowRefValue.value = v;
- })
- /**
- * 更新表单项值
- * @param newValue 新值
- */
- function updateValue(newValue: T) {
- if (secondParentContext)
- secondParentContext.updateValue(newValue);
- else
- emit(newValue);
- shadowRefValue.value = newValue;
- context?.onFieldChange(newValue);
- }
- if (fieldClick) {
- if (context)
- context.setOnClickListener(fieldClick);
- else if (cellContext)
- cellContext.setOnClickListener(fieldClick);
- }
- const disabled = computed(() => formContext.disabled.value || context.disabled.value);
- const readonly = computed(() => formContext.readonly.value || context.readonly.value);
- return {
- /**
- * 临时值
- */
- value: value,
- updateValue,
- /**
- * 表单项上下文
- */
- context,
- /**
- * 表单上下文
- */
- formContext,
- /**
- * 指示顶层由表单和表单项设置的禁用状态
- */
- disabled,
- /**
- * 指示顶层由表单和表单项设置的只读状态
- */
- readonly,
- }
- }
|