UNPKG

element-plus-fast-form

Version:

基于 Vue 3 和 Element-Plus 的表单和 CRUD 组件封装库

1,029 lines (967 loc) 36.5 kB
const __BROWSER__ = typeof window !== 'undefined' && typeof document !== 'undefined'; import { ref, reactive, h, isReactive, isRef, toRaw, resolveComponent, Fragment, defineComponent, createVNode, mergeProps, isVNode, markRaw, nextTick, watch } from 'vue'; import { Plus, Delete } from '@element-plus/icons-vue'; var EOptions = /* @__PURE__ */ ((EOptions2) => { EOptions2["el-select"] = "el-option"; EOptions2["el-radio-group"] = "el-radio"; EOptions2["el-checkbox-group"] = "el-checkbox"; EOptions2["el-cascader"] = "span"; EOptions2["el-tree-select"] = "span"; return EOptions2; })(EOptions || {}); const virtualizedComponentMap = { "el-select-v2": "options" }; const InitialValueMap = { "el-checkbox-group": [] }; const getType = (val) => Object.prototype.toString.call(val).slice(8, -1).toLowerCase(); function cloneDeepWith(value, customizer, map = /* @__PURE__ */ new WeakMap()) { if (value === null || typeof value !== "object") { return value; } if (map.has(value)) { return map.get(value); } if (customizer) { const result = customizer(value, null, void 0, map); if (result !== void 0) { return result; } } const type = getType(value); switch (type) { case "date": { if (value instanceof Date) { return new Date(value.getTime()); } return value; } case "regexp": { if (value instanceof RegExp) { const flags = value.flags; const result = new RegExp(value.source, flags); result.lastIndex = value.lastIndex; return result; } return value; } case "map": { if (value instanceof Map) { const mapResult = /* @__PURE__ */ new Map(); map.set(value, mapResult); value.forEach((val, key) => { const keyResult = typeof key === "object" && key !== null ? cloneDeepWith(key, customizer, map) : key; const valueResult = cloneDeepWith(val, customizer, map); mapResult.set(keyResult, valueResult); }); return mapResult; } return value; } case "set": { if (value instanceof Set) { const setResult = /* @__PURE__ */ new Set(); map.set(value, setResult); value.forEach((val) => { const itemResult = cloneDeepWith(val, customizer, map); setResult.add(itemResult); }); return setResult; } return value; } case "array": { if (Array.isArray(value)) { const arrResult = []; map.set(value, arrResult); value.forEach((item, index) => { const customResult = customizer ? customizer(item, index, value, map) : void 0; arrResult[index] = customResult !== void 0 ? customResult : cloneDeepWith(item, customizer, map); }); return arrResult; } return value; } case "object": { if (!value || typeof value !== "object" || Array.isArray(value)) { return value; } const proto = Object.getPrototypeOf(value); const ctor = proto?.constructor; if (ctor && ctor !== Object) { try { const objResult2 = new ctor(); map.set(value, objResult2); Object.entries(value).forEach(([key, val]) => { if (Object.prototype.hasOwnProperty.call(value, key)) { const customResult = customizer ? customizer(val, key, value, map) : void 0; objResult2[key] = customResult !== void 0 ? customResult : cloneDeepWith(val, customizer, map); } }); return objResult2; } catch (e) { console.warn("Failed to clone with constructor, falling back to plain object clone", e); } } const objResult = Object.create(proto); map.set(value, objResult); const allKeys = [ ...Object.keys(value), ...Object.getOwnPropertySymbols(value) ]; allKeys.forEach((key) => { if (Object.prototype.propertyIsEnumerable.call(value, key)) { const val = value[key]; const customResult = customizer ? customizer(val, key, value, map) : void 0; objResult[key] = customResult !== void 0 ? customResult : cloneDeepWith(val, customizer, map); } }); return objResult; } default: return value; } } const groupRow = "_groupRow_72w7s_8"; const border = "_border_72w7s_13"; const hasOperate = "_hasOperate_72w7s_20"; const operate = "_operate_72w7s_24"; const hasSuffix = "_hasSuffix_72w7s_30"; const styles = { groupRow: groupRow, border: border, hasOperate: hasOperate, operate: operate, hasSuffix: hasSuffix }; function randomHashStr() { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); } function _isSlot(s) { return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !isVNode(s); } // 自定义 cloneDeep,遇到 component 字段直接 markRaw, 避免被reactive,提高性能 function deepCloneWithMarkRaw(obj) { return cloneDeepWith(obj, (value, key) => { if (key === "component" && (typeof value === "object" || typeof value === "function")) { return markRaw(value); } // lodash 默认处理 return undefined; }); } class FormCore { formValue = {}; formRef = ref(); formConfig = []; rowProps = {}; colProps = {}; formProps = {}; disabled = ref(false); showOperate = true; constructor(config) { const processedConfig = this._handleConfig(config.formConfig); this.formConfig = reactive(processedConfig); this.rowProps = this._handleConfig(config.rowProps || {}); this.colProps = this._handleConfig(config.colProps || {}); this.formProps = this._handleConfig(config.formProps || {}); this.disabled.value = this.formProps?.disabled ?? false; const model = this._handleConfig(this.formProps?.model || {}); this.showOperate = config.showOperate ?? true; const vals = this._initValue(model, processedConfig); Object.assign(this.formValue, vals); this.formValue = reactive(this.formValue); this.addItem = this.addItem.bind(this); this.removeItem = this.removeItem.bind(this); } _generateSuffix(itemConfig) { return h("span", {}, [itemConfig?.suffix]); } _generateComponent(itemConfig, slots, nestedData) { // console.log("---_generateComponent---", itemConfig.formItemProps.prop); let component = null; if (itemConfig.component === "slot") { component = this._generateSlot(itemConfig, slots, nestedData); } else if (this._isVueComponent(itemConfig.component)) { component = this._generateCustomComponent(itemConfig, nestedData); } else if (typeof itemConfig?.component === "string") { if (itemConfig?.component?.startsWith("el-")) { component = this._generateElementComponent(itemConfig, nestedData); } else { component = this._generateString(itemConfig); } } if (itemConfig?.suffix) { component = h("div", { className: styles.hasSuffix, style: { width: itemConfig.componentProps?.style?.width } }, [component, this._generateSuffix(itemConfig)]); } return component; } _generateNestedData(nestedKey, prop, value) { const lastData = { [prop]: value }; if (!this.formValue[nestedKey.prop]) { this.formValue[nestedKey.prop] = []; this.formValue[nestedKey.prop][nestedKey.key] = lastData; } else { this.formValue[nestedKey.prop][nestedKey.key] = { ...this.formValue[nestedKey.prop][nestedKey.key], ...lastData }; } } /** * 处理配置对象 * @param config 配置对象 * @returns 处理后的普通对象 */ _handleConfig(config) { const rawConfig = isReactive(config) || isRef(config) ? toRaw(config) : config; return deepCloneWithMarkRaw(rawConfig); } _isVueComponent(arg) { return Object.prototype.hasOwnProperty.call(arg, "render") || Object.prototype.hasOwnProperty.call(arg, "setup"); } _isNoFormItemProps(itemConfig) { if (itemConfig.formItemProps?.prop === "" || !itemConfig.formItemProps?.prop) { return true; } return false; } /** * 获取子类方法 * @returns 子类方法对象 */ _getSubClassMethods() { const proto = Object.getPrototypeOf(this); const methods = {}; Object.getOwnPropertyNames(proto).forEach(key => { if (typeof this[key] === "function" && key !== "constructor") { methods[key] = this[key].bind(this); } }); return methods; } _generateElementComponent(itemConfig, nestedData) { if (this._isNoFormItemProps(itemConfig)) { return null; } return h(resolveComponent(itemConfig.component), { ...itemConfig.componentProps, modelValue: nestedData ? this.formValue?.[nestedData.prop]?.[nestedData.key]?.[itemConfig.formItemProps.prop] : this.formValue[itemConfig.formItemProps.prop], "onUpdate:modelValue": value => { if (nestedData) { this._generateNestedData(nestedData, itemConfig.formItemProps.prop, value); } else { this.formValue[itemConfig.formItemProps.prop] = value; } }, style: { width: itemConfig.componentProps?.style?.width || "100%" }, nestedKey: nestedData?.key ?? null, nestedProp: nestedData?.prop ?? null }, itemConfig?.componentProps?.options?.length && !virtualizedComponentMap.hasOwnProperty(itemConfig.component) ? { default: c => { const data = c?.data || {}; return EOptions[itemConfig.component] == "span" ? data?.label : h(Fragment, {}, [...(itemConfig?.componentProps?.options || []).map(i => { return h(resolveComponent(EOptions[itemConfig.component]), { key: i.key || i.value, ...i }); })]); } } : {}); } _generateString(itemConfig) { const defaultValue = itemConfig.defaultValue; return h(itemConfig.component, { ...itemConfig.componentProps }, defaultValue || null); } _generateCustomComponent(itemConfig, nestedData) { const methods = this._getSubClassMethods(); return h(itemConfig.component, { formValue: this.formValue, ...(this._isNoFormItemProps(itemConfig) ? {} : { prop: itemConfig.formItemProps.prop, modelValue: nestedData ? this.formValue?.[nestedData.prop]?.[nestedData.key]?.[itemConfig.formItemProps.prop] : this.formValue[itemConfig.formItemProps.prop], "onUpdate:modelValue": value => { if (nestedData) { this._generateNestedData(nestedData, itemConfig.formItemProps.prop, value); } else { this.formValue[itemConfig.formItemProps.prop] = value; } } }), nestedKey: nestedData?.key ?? null, nestedProp: nestedData?.prop ?? null, ...methods, ...itemConfig.componentProps }); } _generateSlot(itemConfig, slots, nestedData) { // const methods = this._getSubClassMethods(); return slots?.[itemConfig.formItemProps.prop]?.({ formValue: this.formValue, ...(this._isNoFormItemProps(itemConfig) ? {} : { modelValue: nestedData ? this.formValue?.[nestedData.prop]?.[nestedData.key]?.[itemConfig.formItemProps.prop] : this.formValue[itemConfig.formItemProps.prop] }), nestedKey: nestedData?.key ?? null, nestedProp: nestedData?.prop ?? null // ...methods, }); } _initValue(formValue, config, isRemoveValue = true, // 是否删除旧值 parentProp, key) { const values = {}; config.filter(i => i?.formItemProps?.prop)?.forEach(item => { if (item.children) { const listValue = []; item.children.forEach((i, k) => { listValue.push(this._initValue(formValue, i, isRemoveValue, item.formItemProps.prop, k)); }); values[item.formItemProps.prop] = listValue; } else { const initialValue = InitialValueMap[item.component] || null; const preValue = parentProp ? formValue?.[parentProp]?.[key]?.[item.formItemProps.prop] || null : formValue[item.formItemProps.prop] || null; const defaultValue = item.defaultValue; values[item.formItemProps.prop] = isRemoveValue ? defaultValue || initialValue || preValue : preValue; } }); return values; } addItem(prop, config) { const index = this.formConfig.findIndex(i => i.formItemProps.prop === prop); if (index > -1) { if (config && config.length > 0) { this.formConfig[index].children.push(config); } else { this.formConfig[index].children.push(this.formConfig[index]?.children?.[0]); } const processedConfig = this._handleConfig(this.formConfig); const vals = this._initValue(this.formValue, processedConfig); Object.assign(this.formValue, vals); } } removeItem(prop, key) { const index = this.formConfig.findIndex(i => i.formItemProps.prop === prop); if (index > -1) { this.formValue[prop].splice(key, 1); this.formConfig[index].children.splice(key, 1); const processedConfig = this._handleConfig(this.formConfig); const vals = this._initValue(this.formValue, processedConfig); Object.assign(this.formValue, vals); } } getform() { return /* @__PURE__ */ defineComponent({ setup: (_props, { slots }) => { return () => { let _slot3; const finalFormProps = { ref: this.formRef, ...this.formProps, model: this.formValue, disabled: this.disabled.value }; // console.log("---setup----"); return createVNode(resolveComponent("el-form"), finalFormProps, { default: () => [createVNode(resolveComponent("el-row"), mergeProps(this.rowProps || {}, { "gutter": this.rowProps?.gutter || 24 }), _isSlot(_slot3 = (this.formConfig || []).map(item => { let _slot2; return Array.isArray(item.children) ? createVNode("div", { "class": `${styles.groupRow}` }, [(item.children || []).map((citem, ckey) => { return createVNode(resolveComponent("el-row"), mergeProps(this.rowProps || {}, { "gutter": this.rowProps?.gutter || 24, "class": [styles.border, this.showOperate ? styles.hasOperate : ""] }), { default: () => [citem?.map(c => { let _slot; return createVNode(resolveComponent("el-col"), mergeProps({ "key": `${item.formItemProps.prop}.${ckey}.${c.formItemProps?.prop || randomHashStr()}` }, c?.colProps || this.colProps || {}, { "span": c?.colProps?.span || this.colProps?.span || 24 }), { default: () => [createVNode(resolveComponent("el-form-item"), mergeProps(c.formItemProps, { "class": styles["form-item"], "prop": `${item.formItemProps.prop}.${ckey}.${c.formItemProps?.prop || randomHashStr()}` }), _isSlot(_slot = this._generateComponent(c, slots, { prop: item.formItemProps.prop, key: ckey })) ? _slot : { default: () => [_slot] })] }); }), this.showOperate && createVNode("div", { "class": styles.operate }, [createVNode(resolveComponent("el-button"), { "icon": Plus, "circle": true, "size": "small", "onClick": () => { this.addItem(item.formItemProps.prop); } }, null), ckey > 0 ? createVNode(resolveComponent("el-popconfirm"), { "title": "\u786E\u5B9A\u5220\u9664\u5417\uFF1F", "onConfirm": () => { this.removeItem(item.formItemProps.prop, ckey); }, "confirm-button-text": "\u786E\u5B9A", "cancel-button-text": "\u53D6\u6D88" }, { reference: createVNode(resolveComponent("el-button"), { "icon": Delete, "circle": true, "size": "small" }, null) }) : null])] }); })]) : createVNode(resolveComponent("el-col"), mergeProps(item?.colProps || this.colProps || {}, { "span": item?.colProps?.span || this.colProps?.span || 8, "key": item.formItemProps.prop }), { default: () => [createVNode(resolveComponent("el-form-item"), mergeProps(item.formItemProps, { "class": styles["form-item"] }), _isSlot(_slot2 = this._generateComponent(item, slots)) ? _slot2 : { default: () => [_slot2] })] }) // jsx不支持v-memo指令,目前版本只有模板预发支持! // withDirectives( // h( // resolveComponent("el-col"), // { // ...(item?.colProps || this.colProps || {}), // span: item?.colProps?.span || this.colProps?.span || 8, // key: item.formItemProps.prop, // }, // [ // h( // resolveComponent("el-form-item"), // { // ...item.formItemProps, // class: styles["form-item"], // }, // this._generateComponent(item, slots) // ), // ] // ) // , // [ // [ // resolveDirective("memo")!, // [ // item.formItemProps.prop, // 唯一标识 // this.formValue[item.formItemProps.prop], // ], // ], // ] // ) ; })) ? _slot3 : { default: () => [_slot3] })] }); }; } }); } } class Form extends FormCore { constructor(config) { super(config); this.setComponentProps = this.setComponentProps.bind(this); this.setFormValue = this.setFormValue.bind(this); this.setFormConfig = this.setFormConfig.bind(this); this.setFormConfigs = this.setFormConfigs.bind(this); this.addFormConfig = this.addFormConfig.bind(this); this.removeFormConfig = this.removeFormConfig.bind(this); this.setFormDisabled = this.setFormDisabled.bind(this); } /** * 解析嵌套prop路径 * @param prop prop字符串,支持格式: * - "parentProp.index.childProp" (3段式,用于设置/删除) * - "parentProp.index" (2段式,用于添加) * - "normalProp" (普通格式) * @returns 解析结果 */ _parseNestedProp(prop) { const parts = prop.split("."); // 支持3段式:parentProp.index.childProp(用于设置/删除操作) if (parts.length === 3) { const [parentProp, indexStr, childProp] = parts; const childIndex = parseInt(indexStr, 10); if (!isNaN(childIndex)) { return { isNested: true, parentProp, childIndex, childProp, originalProp: prop, isAddMode: false }; } } // 支持2段式:parentProp.index(用于添加操作) if (parts.length === 2) { const [parentProp, indexStr] = parts; const childIndex = parseInt(indexStr, 10); if (!isNaN(childIndex)) { return { isNested: true, parentProp, childIndex, originalProp: prop, isAddMode: true }; } } return { isNested: false, originalProp: prop }; } /** * 根据解析后的路径找到目标配置项 * @param parsedProp 解析后的prop信息 * @returns 目标配置项 */ _findTargetConfig(parsedProp) { if (!parsedProp.isNested) { // 非嵌套,直接查找 return this.formConfig.find(item => item.formItemProps.prop === parsedProp.originalProp) || null; } // 嵌套格式,先找父级配置 const parentConfig = this.formConfig.find(item => item.formItemProps.prop === parsedProp.parentProp); if (!parentConfig || !parentConfig.children) { return null; } // 如果是添加模式(2段式),返回父级配置用于后续验证 if (parsedProp.isAddMode) { return parentConfig; } // 设置/删除模式(3段式),找到指定索引的子配置数组 const childConfigs = parentConfig.children[parsedProp.childIndex]; if (!Array.isArray(childConfigs)) { return null; } // 在子配置数组中找到目标配置项 return childConfigs.find(item => item.formItemProps.prop === parsedProp.childProp) || null; } /** * 动态更新表单项的组件属性 * @param prop 表单项的 prop 值,支持嵌套格式: "parentProp.index.childProp" * @param componentProps 需要更新的组件属性对象 */ setComponentProps(prop, componentProps) { const parsedProp = this._parseNestedProp(prop); const targetItem = this._findTargetConfig(parsedProp); if (targetItem) { if (!targetItem.componentProps) { targetItem.componentProps = {}; } // 只赋值属性,不整体替换对象,以保持响应式 Object.assign(targetItem.componentProps, componentProps); } } /** * 动态更新表单值 * @param key 表单项的 key * @param value 要更新的值 */ setFormValue(formData) { Object.assign(this.formValue, formData); } /** * 更新指定表单项的配置 * @param prop 表单项的 prop 值,支持嵌套格式: "parentProp.index.childProp" * @param config 新的配置项 */ setFormConfig(prop, config) { const parsedProp = this._parseNestedProp(prop); const targetItem = this._findTargetConfig(parsedProp); if (targetItem) { // 创建新的配置项 const newConfig = { ...targetItem, formItemProps: { ...targetItem.formItemProps, ...(config.formItemProps || {}), prop: parsedProp.isNested ? parsedProp.childProp : parsedProp.originalProp // 确保prop正确 }, componentProps: { ...targetItem.componentProps, ...(config.componentProps || {}) }, ...(config.component && { component: config.component }), ...(config.colProps && { colProps: { ...targetItem.colProps, ...config.colProps } }) }; // 更新配置项 if (parsedProp.isNested) { // 嵌套情况:需要找到父配置和子配置数组 const parentConfig = this.formConfig.find(item => item.formItemProps.prop === parsedProp.parentProp); if (parentConfig && parentConfig.children) { const childConfigs = parentConfig.children[parsedProp.childIndex]; const targetIndex = childConfigs.findIndex(item => item.formItemProps.prop === parsedProp.childProp); if (targetIndex > -1) { childConfigs[targetIndex] = newConfig; } } } else { // 非嵌套情况:直接更新顶层配置 const targetIndex = this.formConfig.findIndex(item => item.formItemProps.prop === parsedProp.originalProp); if (targetIndex > -1) { this.formConfig[targetIndex] = newConfig; } } // 处理defaultValue更新 if (config.hasOwnProperty("defaultValue")) { if (parsedProp.isNested) { // 嵌套表单的值更新 if (!this.formValue[parsedProp.parentProp]) { this.formValue[parsedProp.parentProp] = []; } if (!this.formValue[parsedProp.parentProp][parsedProp.childIndex]) { this.formValue[parsedProp.parentProp][parsedProp.childIndex] = {}; } this.formValue[parsedProp.parentProp][parsedProp.childIndex][parsedProp.childProp] = config.defaultValue; } else { // 顶层表单的值更新 this.formValue[parsedProp.originalProp] = config.defaultValue; } } } } /** * 批量替换表单配置 * @param newFormConfig 新的表单配置数组 * @param isRemoveValue 是否删除旧值 */ async setFormConfigs(newFormConfig, isRemoveValue = true) { // 处理新配置 const processedConfig = this._handleConfig(newFormConfig); if (isRemoveValue) { // 完全重新初始化模式 // 清空当前配置 this.formConfig.splice(0, this.formConfig.length); // 添加新配置 this.formConfig.push(...processedConfig); // 重新初始化表单值 const vals = this._initValue({}, processedConfig); // 清空并重新设置表单值 Object.keys(this.formValue).forEach(key => { delete this.formValue[key]; }); Object.assign(this.formValue, vals); } else { // 保留旧值模式 // 保存当前表单值的副本 const currentFormValue = { ...this.formValue }; // 清空当前配置 this.formConfig.splice(0, this.formConfig.length); // 添加新配置 this.formConfig.push(...processedConfig); // 使用当前表单值作为基础,为新配置项初始化值 const vals = this._initValue(currentFormValue, processedConfig, false); // 清空并重新设置表单值(保留旧值 + 新配置项的初始值) Object.keys(this.formValue).forEach(key => { delete this.formValue[key]; }); Object.assign(this.formValue, vals); } await nextTick(); setTimeout(() => { this.formRef.value?.clearValidate(); }, 0); } /** * 在指定位置添加表单配置项 * @param config 要添加的表单配置 * @param targetProp 目标位置,支持嵌套格式: "parentProp.index" 表示在父级数组的指定索引位置添加 * @param index 插入的位置索引,如果不传则追加到末尾(仅在非嵌套情况下有效) */ addFormConfig(config, targetProp, index) { if (!targetProp) { // 没有指定目标位置,使用原有逻辑在顶层添加 this._addToTopLevel(config, index); return; } const parsedTarget = this._parseNestedProp(targetProp); if (parsedTarget.isNested) { // 嵌套格式:在指定的子数组中添加配置项 this._addToNestedArray(config, parsedTarget); } else { // 普通格式:在顶层添加 this._addToTopLevel(config, index); } } /** * 在顶层添加配置项 */ _addToTopLevel(config, index) { // 检查是否已存在相同 prop 的配置 const exists = this.formConfig.some(item => item.formItemProps.prop === config.formItemProps.prop); if (!exists) { // 处理新配置 const processedConfig = this._handleConfig([config])[0]; // 根据 index 插入配置 if (typeof index === "number" && index >= 0 && index <= this.formConfig.length) { this.formConfig.splice(index, 0, processedConfig); } else { this.formConfig.push(processedConfig); } // 初始化表单值 const vals = this._initValue(this.formValue, [processedConfig]); // 更新表单值 Object.assign(this.formValue, vals); } } /** * 在嵌套数组中添加配置项 */ _addToNestedArray(config, parsedTarget) { // 找到父级配置 const parentConfig = this.formConfig.find(item => item.formItemProps.prop === parsedTarget.parentProp); if (parentConfig && parentConfig.children) { // 检查指定索引的子数组是否存在 const childIndex = parsedTarget.childIndex; const childrenLength = parentConfig.children.length; if (childIndex < childrenLength) { const childConfigs = parentConfig.children[childIndex]; // 检查是否已存在相同 prop 的配置 const exists = childConfigs.some(item => item.formItemProps.prop === config.formItemProps.prop); if (!exists) { // 处理新配置 const processedConfig = this._handleConfig([config])[0]; // 添加到子数组 childConfigs.push(processedConfig); // 更新表单值 - 为新添加的配置项初始化值 const vals = this._initValue({}, [processedConfig]); // 确保嵌套表单值结构正确 if (!this.formValue[parsedTarget.parentProp]) { this.formValue[parsedTarget.parentProp] = []; } if (!this.formValue[parsedTarget.parentProp][parsedTarget.childIndex]) { this.formValue[parsedTarget.parentProp][parsedTarget.childIndex] = {}; } // 将新配置项的初始值合并到对应的嵌套表单值中 Object.assign(this.formValue[parsedTarget.parentProp][parsedTarget.childIndex], vals); } } } } /** * 删除表单配置项 * @param props 要删除的表单项的 prop 值数组,支持嵌套格式: "parentProp.index.childProp" * @param isRemoveValue 是否删除旧值 */ removeFormConfig(props, isRemoveValue = true) { // 分离普通prop和嵌套prop const topLevelProps = []; const nestedProps = []; props.forEach(prop => { const parsedProp = this._parseNestedProp(prop); if (parsedProp.isNested) { nestedProps.push({ parsedProp, originalProp: prop }); } else { topLevelProps.push(prop); } }); // 删除嵌套配置项 this._removeNestedConfigs(nestedProps, isRemoveValue); // 删除顶层配置项 this._removeTopLevelConfigs(topLevelProps, isRemoveValue); } /** * 删除顶层配置项 */ _removeTopLevelConfigs(props, isRemoveValue = true) { // 找出所有要删除的索引 const indexesToRemove = props.reduce((acc, prop) => { const index = this.formConfig.findIndex(item => item.formItemProps.prop === prop); if (index > -1) { acc.push(index); } return acc; }, []); if (indexesToRemove.length > 0) { // 从大到小排序,避免删除时索引变化 indexesToRemove.sort((a, b) => b - a); // 批量删除配置 indexesToRemove.forEach(index => { const prop = this.formConfig[index].formItemProps.prop; this.formConfig.splice(index, 1); if (isRemoveValue) { delete this.formValue[prop]; } }); } } /** * 删除嵌套配置项 */ _removeNestedConfigs(nestedProps, isRemoveValue = true) { // 按父级prop分组,便于批量操作 const groupedByParent = {}; nestedProps.forEach(item => { const parentProp = item.parsedProp.parentProp; if (!groupedByParent[parentProp]) { groupedByParent[parentProp] = []; } groupedByParent[parentProp].push(item); }); // 逐个处理每个父级 Object.entries(groupedByParent).forEach(([parentProp, items]) => { const parentConfig = this.formConfig.find(item => item.formItemProps.prop === parentProp); if (parentConfig && parentConfig.children) { // 按子数组索引分组 const groupedByChildIndex = {}; items.forEach(item => { const childIndex = item.parsedProp.childIndex; if (!groupedByChildIndex[childIndex]) { groupedByChildIndex[childIndex] = []; } groupedByChildIndex[childIndex].push(item); }); // 处理每个子数组 Object.entries(groupedByChildIndex).forEach(([childIndexStr, childItems]) => { const childIndex = parseInt(childIndexStr, 10); if (childIndex < parentConfig.children.length) { const childConfigs = parentConfig.children[childIndex]; // 找到要删除的配置项索引 const indexesToRemove = []; childItems.forEach(item => { const index = childConfigs.findIndex(config => config.formItemProps.prop === item.parsedProp.childProp); if (index > -1) { indexesToRemove.push(index); } }); // 从大到小排序删除 indexesToRemove.sort((a, b) => b - a); // 删除配置项和对应的表单值 indexesToRemove.forEach(index => { const childProp = childConfigs[index].formItemProps.prop; childConfigs.splice(index, 1); // 删除对应的表单值 if (isRemoveValue && this.formValue[parentProp] && this.formValue[parentProp][childIndex] && this.formValue[parentProp][childIndex][childProp] !== undefined) { delete this.formValue[parentProp][childIndex][childProp]; } }); } }); } }); } setFormDisabled(disabled) { this.disabled.value = disabled; } } function useForm(config) { const form = new Form(config); const FastForm = form.getform(); const isInit = ref(false); const { formRef, formValue, addItem, removeItem, setComponentProps, setFormValue, setFormConfig, addFormConfig, removeFormConfig, setFormDisabled, setFormConfigs } = form; if (isReactive(config) || isRef(config.formConfig)) { watch(() => config.formConfig, newVal => { if (newVal.length > 0 && !isInit.value) { isInit.value = true; form.setFormConfigs(newVal); } }); } return { FastForm, formValue, rawFormValue: toRaw(formValue), formRef, addItem, removeItem, setComponentProps, setFormValue, setFormConfig, addFormConfig, removeFormConfig, setFormDisabled, setFormConfigs }; } const hooks = { useForm }; const ElementPlusFastForm = { install: (app) => { app.config.globalProperties.$useForm = useForm; }, ...hooks }; const isBrowser = typeof window !== "undefined" && typeof document !== "undefined"; if (isBrowser) { const debounce = (fn, delay) => { let timer = null; return function(...args) { const _t = this; clearTimeout(timer); timer = setTimeout(function() { fn.apply(_t, args); }, delay); }; }; if (window.ResizeObserver) { const _ResizeObserver = window.ResizeObserver; window.ResizeObserver = class ResizeObserver extends _ResizeObserver { constructor(callback) { callback = debounce(callback, 16); super(callback); } }; } } export { ElementPlusFastForm as default, useForm }; // 条件性注入 CSS if (typeof window !== 'undefined' && typeof document !== 'undefined') { const style = document.createElement('style'); style.textContent = "._form-item_1d203_1 :deep(._el-form-item__content_1d203_1 > *){width:100%}._form-item_1d203_1 .el-form-item__content>*{width:100%}._groupRow_1d203_8{width:100%;padding:0 24px 24px}._border_1d203_13{border:1px solid #dcdfe6;padding:12px 0;margin-bottom:12px;border-radius:8px;position:relative}._operate_1d203_21{position:absolute;right:8px;bottom:8px}\n"; document.head.appendChild(style); } // 条件性注入 CSS if (typeof document !== 'undefined') { const style = document.createElement('style'); style.textContent = "._form-item_72w7s_1 :deep(._el-form-item__content_72w7s_1 > *){width:100%}._form-item_72w7s_1 .el-form-item__content>*{width:100%}._groupRow_72w7s_8{width:100%;padding:0 24px 24px}._border_72w7s_13{border:1px solid #dcdfe6;padding:12px;margin-bottom:12px;border-radius:8px;position:relative}._border_72w7s_13._hasOperate_72w7s_20{padding-bottom:24px}._operate_72w7s_24{position:absolute;right:8px;bottom:8px}._hasSuffix_72w7s_30{display:flex;align-items:center}._hasSuffix_72w7s_30>*:last-child{margin-left:8px;font-size:14px}._hasSuffix_72w7s_30>*:first-child{flex:1;width:unset!important}\n"; document.head.appendChild(style); }