店滴开发者手册店滴开发者手册
首页
指南
插件
接口
智能设备
element后台
SDK
首页
指南
插件
接口
智能设备
element后台
SDK
  • 后台

    • 管理系统开发文档
    • ddButton 组件开发文档
    • DdDrawer 抽屉组件
    • DdOperMenu 操作区域按钮组组件
    • EleForm 基础表单组件
    • EleFormDynamic 动态表单组件
    • EleFormImageUploader 图片上传组件
    • EleFormMap 地图组件
    • EleFormTreeSelect 树形选择组件
    • VueUeditorWrap 百度编辑器组件
    • EleFormUploadFile 文件上传组件
    • EleFormVideoUploader 视频上传组件
    • 表单配置文档
    • DdLevelTable 层级表格组件
    • ListForm 弹窗表单组件
    • DdTable 组件使用文档

ListForm 弹窗表单组件

组件介绍

ListForm是一个通用的弹窗表单组件,支持动态加载指定目录下的创建(create)和编辑(update)组件,实现弹窗的显示/隐藏控制和父子组件间的数据传输。组件内部通过事件总线和props实现灵活的数据通信。

核心功能

  • 支持通过路由路径或手动指定路径动态加载Vue组件
  • 弹窗显示/隐藏状态双向绑定管理
  • 父子组件间的数据传递和事件通信
  • 支持创建/编辑两种模式,也可扩展其他模式
  • 操作结果反馈和自动/手动刷新页面数据
  • 表单数据重置和组件清理机制

基本用法

引入组件

<template>
  <div class="app-container">
    <!-- 其他页面内容 -->
    <list-form
      :params="formObj.params"
      :row="formObj.row"
      :type="formObj.type"
      :title="formObj.title"
      :dialogWidth="formObj.dialogWidth"
      :top="formObj.top"
      @update:dialogVisible="listFormClose"
      @success="handleSuccess"
    />
  </div>
</template>

<script>
// 无需显式引入,组件已全局注册

export default {
  // ...
}
</script>

基本配置

data() {
  return {
    formObj: {
      type: null, // 'create' 或 'update'
      title: '客户列表', // 弹窗标题
      dialogVisible: false, // 弹窗显示状态
      row: {}, // 用于编辑时传递当前行数据
      params: {}, // 传递给子组件的参数
      dialogWidth: '80%', // 弹窗宽度
      top: '8vh' // 弹窗距离顶部的距离
    }
  }
},
methods: {
  // 打开创建弹窗
  handleCreate() {
    this.formObj = {
      type: 'create',
      title: '新增客户',
      dialogVisible: true,
      params: { /* 初始参数 */ }
    };
    this.$formEvent.$emit('form-event', true);
  },

  // 打开编辑弹窗
  editRow(row) {
    this.formObj = {
      type: 'update',
      title: '编辑',
      dialogVisible: true,
      row: row,
      params: { /* 其他参数 */ }
    };
    this.$formEvent.$emit('form-event', true);
  },

  // 弹窗关闭回调
  listFormClose(visible) {
    this.formObj.dialogVisible = visible;
    this.getList(); // 关闭弹窗后刷新列表
  },

  // 操作成功回调
  handleSuccess(data) {
    this.formObj.dialogVisible = false;
    this.getList(); // 刷新数据列表
  }
}

属性说明

属性名类型默认值说明
typeString'create'弹窗类型,可选值:'create'或'update'等
titleString'创建'弹窗标题
dialogVisibleBooleanfalse控制弹窗显示/隐藏,支持双向绑定
rowObject{}用于编辑时传递当前行数据,会自动赋值给dialog.formData
paramsObject{}传递给子组件的额外参数
dialogWidthString'80%'弹窗宽度
topString'8vh'弹窗距离顶部的距离

事件说明

事件名参数说明
update:dialogVisiblevisible: Boolean弹窗显示状态变化时触发,用于双向绑定
successdata: Object表单提交成功后触发,传递表单数据
handleSuccessdata: Object同success事件,表单提交成功后触发
cancel-表单取消操作时触发
handleCancel-同cancel事件,表单取消操作时触发
formClosevisible: Boolean表单关闭时触发,传递关闭状态

弹窗控制流程

显示弹窗

  1. 父组件设置formObj.type为'create'或'update'
  2. 设置formObj.dialogVisible为true
  3. 可选:设置formObj.row传递编辑数据
  4. 调用this.$formEvent.$emit('form-event', true)触发弹窗显示
  5. 组件自动加载对应类型的表单组件

隐藏弹窗

  1. 点击弹窗关闭按钮
  2. 表单提交成功后自动关闭
  3. 点击取消按钮
  4. 父组件修改formObj.dialogVisible为false
  5. 关闭时会触发formClose事件并刷新列表
// 组件内部关闭逻辑
handleClose() {
  this.dialog.visible = false;
  this.currentComponent = null; // 重置组件引用
  this.$emit("update:dialogVisible", false); // 同步状态到父组件
  this.$emit("formClose", false); // 通知父组件关闭
  this.resetForm(); // 重置表单数据
}

// 重置表单
handleDialogCancel() {
  this.dialog.visible = false;
  console.log('表单取消');
  this.$emit("cancel");
  this.$emit("handleCancel");
  this.$emit("formClose", false);
}

数据传输

父传子

  1. 通过row属性传递编辑数据:

    // 父组件
    data() {
      return {
        formObj: {
          // ...
          row: { id: 123, name: '测试数据' }
        }
      }
    }
    
  2. 通过params属性传递额外参数:

    // 父组件
    data() {
      return {
        formObj: {
          // ...
          params: { category: 'customer', status: 'active' }
        }
      }
    }
    
  3. 子组件接收数据:

    // 子组件(动态加载的create.vue/update.vue)
    export default {
      props: {
        formData: { type: Object, default: () => ({}) }, // 来自父组件的row
        params: { type: Object, default: () => ({}) } // 来自父组件的params
      },
      // ...
    }
    

子传父

通过事件机制将数据从子组件传递回父组件:

// 子组件
handleSubmit() {
  this.$refs.form.validate(valid => {
    if (valid) {
      // 提交表单数据
      this.$emit('handleSuccess', this.formData);
    }
  });
}

handleCancel() {
  this.$emit('handleCancel');
}

// 父组件
<list-form
  @success="handleSuccess"
  @handleSuccess="handleSuccess"
  @cancel="handleCancel"
  @handleCancel="handleCancel"
  @update:dialogVisible="listFormClose"
/>

methods: {
  handleSuccess(data) {
    console.log('操作成功', data);
    this.getList(); // 刷新列表
  },
  handleCancel() {
    console.log('操作取消');
  },
  listFormClose(visible) {
    this.formObj.dialogVisible = visible;
  }
}

动态组件加载

ListForm会根据当前路由路径自动加载对应目录下的组件:

// 动态加载组件核心代码
async loadComponent(type) {
  try {
    // 支持两种加载方式:自动路径和手动指定路径
    if (this.params.componentPath) {
      // 手动指定路径加载
      const component = require(`@/views/${this.params.componentPath}/${type}.vue`).default;
      this.currentComponent = component;
      console.log("手动指定路径组件加载成功:", `@/views/${this.params.componentPath}/${type}.vue`);
    } else {
      // 获取当前路由对应的组件路径
      const currentPath = this.$route.path;
      // 提取目录路径
      const dirPath = currentPath.substring(0, currentPath.lastIndexOf("/"));

      // 动态导入组件 - 支持两种路径格式
      let component;
      try {
        // 尝试使用项目别名格式
        component = require(`@projectName/views${dirPath}/${type}.vue`).default;
        console.log("自动路径组件加载成功(项目别名):", `@projectName/views${dirPath}/${type}.vue`);
      } catch (e) {
        // 失败则使用常规格式
        component = require(`@/views${dirPath}/${type}.vue`).default;
        console.log("自动路径组件加载成功(常规路径):", `@/views${dirPath}/${type}.vue`);
      }
      this.currentComponent = component;
    }
  } catch (error) {
    console.error("组件加载失败:", error);
    this.$message.error(`加载${type === "create" ? "创建" : "编辑"}组件失败`);
  }
}

完整示例

父组件中使用ListForm (完整示例)

<template>
  <div class="app-container">
    <!-- 公共操作区 -->
    <div class="common-header">
      <el-button type="primary" @click="handleCreate">新增</el-button>
    </div>

    <!-- 检索区域 -->
    <div class="search-form">
      <el-input v-model="searchForm.keyword" placeholder="请输入关键词" style="width: 200px;"></el-input>
      <el-button type="primary" @click="getList">搜索</el-button>
    </div>

    <!-- 数据列表 -->
    <el-table :data="dataList" style="width: 100%">
      <el-table-column prop="name" label="名称"></el-table-column>
      <el-table-column prop="code" label="编码"></el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="small" @click="editRow(scope.row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- ListForm组件 -->
    <list-form
      :params="formObj.params"
      :row="formObj.row"
      :type="formObj.type"
      :title="formObj.title"
      :dialogVisible="formObj.dialogVisible"
      :dialogWidth="formObj.dialogWidth"
      :top="formObj.top"
      @update:dialogVisible="listFormClose"
      @success="handleSuccess"
      @handleSuccess="handleSuccess"
      @cancel="handleCancel"
      @handleCancel="handleCancel"
      @formClose="formClose"
    />
  </div>
</template>

<script>
// 无需显式引入,组件已全局注册

export default {
  data() {
    return {
      dataList: [],
      searchForm: {
        keyword: ''
      },
      formObj: {
        type: null,
        title: '',
        dialogVisible: false,
        row: {},
        params: {},
        dialogWidth: '80%',
        top: '8vh'
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    // 获取数据列表
    getList() {
      // 实际项目中这里会调用API获取数据
      this.dataList = [
        { id: 1, name: '测试数据1', code: 'TEST001' },
        { id: 2, name: '测试数据2', code: 'TEST002' }
      ];
    },

    // 打开创建弹窗
    handleCreate() {
      this.formObj = {
        type: 'create',
        title: '新增',
        dialogVisible: true,
        params: {
          // 可选:手动指定组件路径
          // componentPath: 'path/to/custom/component'
        }
      };
      this.$formEvent.$emit('form-event', true);
    },

    // 打开编辑弹窗
    editRow(row) {
      this.formObj = {
        type: 'update',
        title: '编辑',
        dialogVisible: true,
        row: { ...row }, // 深拷贝避免直接修改表格数据
        params: {
          // 额外参数
          action: 'edit'
        }
      };
      this.$formEvent.$emit('form-event', true);
    },

    // 处理弹窗关闭
    listFormClose(visible) {
      this.formObj.dialogVisible = visible;
    },

    // 处理操作成功
    handleSuccess(data) {
      this.formObj.dialogVisible = false;
      this.$message.success('操作成功');
      this.getList(); // 刷新数据列表
    },

    // 处理取消操作
    handleCancel() {
      console.log('操作取消');
    },

    // 表单关闭事件
    formClose(visible) {
      this.formObj.dialogVisible = visible;
      this.getList(); // 关闭弹窗后刷新列表
    }
  }
};
</script>

动态加载的create.vue示例

<template>
  <el-form ref="form" :model="formData" label-width="100px">
    <!-- 表单内容 -->
    <el-form-item label="客户名称" prop="name">
      <el-input v-model="formData.name"></el-input>
    </el-form-item>
    <!-- 其他表单项 -->
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
    </div>
  </el-form>
</template>

<script>
export default {
  props: {
    formData: { type: Object, default: () => ({}) },
    params: { type: Object, default: () => ({}) }
  },
  methods: {
    handleSubmit() {
      this.$refs.form.validate(valid => {
        if (valid) {
          // 提交表单数据
          this.$emit('handleSuccess');
        }
      });
    },
    handleCancel() {
      this.$emit('cancel');
    }
  }
};
</script>

注意事项

  1. 确保在使用ListForm的目录下存在对应的create.vue和update.vue组件,或通过params.componentPath指定正确路径
  2. 动态加载组件支持自动路径和手动指定路径两种方式
  3. 组件加载失败时会有错误提示,可查看控制台获取详细错误信息
  4. 表单提交成功后,会自动触发success和handleSuccess事件
  5. 弹窗关闭时会重置组件引用和表单数据,避免内存泄漏
  6. 使用事件总线时,确保在组件销毁时移除事件监听器

高级用法

手动指定组件路径

当需要加载非当前路由目录下的组件时,可以通过params.componentPath手动指定:

this.formObj = {
  type: 'create',
  title: '创建',
  dialogVisible: true,
  params: {
    componentPath: 'projects/scrm/views/common'
  }
}

表单验证与反馈

子组件中可以进行表单验证,并将结果通过事件传递给父组件:

// 子组件
handleSubmit() {
  this.$refs.form.validate(valid => {
    if (valid) {
      // 模拟API请求
      setTimeout(() => {
        this.$emit('handleSuccess', this.formData);
        this.$message.success('提交成功');
      }, 1000);
    } else {
      this.$message.error('请填写必填项');
    }
  });
}

自定义弹窗样式

通过dialogWidth和top属性自定义弹窗样式:

<list-form
  :params="formObj.params"
  :type="formObj.type"
  :title="formObj.title"
  :dialogVisible="formObj.dialogVisible"
  :dialogWidth="'60%'"
  :top="'10vh'"
  @update:dialogVisible="listFormClose"
  @success="handleSuccess"
/>

多表单状态管理

在复杂场景下,可以管理多个表单状态:

data() {
  return {
    forms: {
      basic: {
        type: 'create',
        title: '基本信息',
        dialogVisible: false,
        params: {}
      },
      advanced: {
        type: 'update',
        title: '高级设置',
        dialogVisible: false,
        params: {}
      }
    }
  };
}
Prev
DdLevelTable 层级表格组件
Next
DdTable 组件使用文档