Skip to content

增加拖拽操作按钮

在二开场景中,你可能希望给画布上的组件增加“额外的快捷操作”,例如:一键高亮、快速生成联动、绑定业务数据、打开自定义弹窗配置等。本文讲清楚在设计器中如何在组件右下角的操作区新增一个按钮,并通过事件把“目标组件规则(rule)”传递出去执行自定义逻辑。

你可以把它理解为:仿照已有的 copy / delete,新增一个 custom(或任意名称)的“组件操作”事件。

你需要了解

  • 画布上每个组件都会被 DragTool 包一层,用于渲染“移动/复制/删除”等操作按钮

  • DragTool 只负责 $emit(...) 抛事件,真正的“复制/删除”等逻辑在 FcDesigner.vuehandleToolCopy / handleToolDelete 中实现

你要改哪些地方?

增加一个“组件操作按钮”通常涉及 2 个文件:

  • 操作按钮 UI 与事件抛出src/designer/DragTool.vue
    • 新增一个按钮
    • 增加对应的 emits 事件名
  • 事件接收与执行自定义逻辑src/designer/FcDesigner.vue
    • 在构造 DragTool 节点时补齐 on: { custom: ... } 的监听
    • 新增一个 handleToolCustom(命名自定)方法,统一拿到 targetRule 并执行自定义操作

参考样例:copy / delete 的完整链路

在源码中,copy/delete 的链路非常典型:

1. DragTool.vue 里只做 $emit

copy/delete 按钮点击后,直接触发:

  • $emit('copy')
  • $emit('delete')

你新增按钮时沿用这个模式即可。

2. FcDesigner.vue 里把事件映射到处理函数

FcDesigner.vue 在把组件规则包装成 DragTool 时,会在 on 中绑定事件处理:

  • copy: ({ self }) => methods.handleToolCopy({ self, inside: true/false })
  • delete: ({ self }) => methods.handleToolDelete({ self, inside: true/false })

3. handleToolCopy/handleToolDelete 统一拿到 targetRule

关键点在于:同一个按钮事件,需要兼容两种包装模式

  • inside === trueDragTool 在规则的 children 内(“内嵌模式”)
  • inside === falseDragTool 是外层 wrapper(“外包裹模式”)

所以源码里会用同样的判断统一得到“真正被操作的规则”:

  • targetRule = inside ? methods.getParent(self).parent : self.children[0]

新增自定义操作,也建议复用这一套 targetRule 计算方式。

方案设计与约定

事件命名建议

  • 按钮事件名建议用语义清晰、可扩展的名字,例如:
    • custom(通用)
    • highlight(高亮)
    • bind(绑定)
    • linkage(联动)

显隐与权限

DragTool.vuecopy/delete 的显示控制包含两层:

  • 按钮白名单:通过 handleBtn(数组)控制显示哪些按钮(例如 ['copy','delete']
  • 权限对象:通过 permission.xxx !== false 控制某个按钮是否允许

新增按钮时建议也按同样方式接入(这样业务方可以用“配置/权限”控制按钮显隐,而不是写死在源码里)。

实现步骤

下面以新增一个 custom 操作为例(你可以替换成任意事件名)。

1. 在 DragTool.vue 新增按钮并抛出事件

文件:src/designer/DragTool.vue

1.1 增加 emits 声明

custom 加到 emits 数组中(示例):

js
emits: ['create', 'copy', 'addChild', 'delete', 'custom', 'active', 'action', 'fc.el'],

1.2 在操作区增加按钮

参照 copy/delete 的写法,新增一段按钮(示例用 icon-setting,你也可以换成你们的业务图标):

vue
<div
  class="_fd-drag-btn"
  @click.stop
  v-if="permission.custom !== false && (btns === true || btns.indexOf('custom') > -1)"
  @click="$emit('custom')"
>
  <i class="fc-icon icon-setting"></i>
</div>

建议

如果你希望按钮只在“选中激活”时显示,不需要额外处理:DragTool 已有样式逻辑,会在 active/hover 时显示按钮。

2. 在 FcDesigner.vue 接收事件并执行自定义逻辑

文件:src/designer/FcDesigner.vue

2.1 在 DragTool 的事件映射里补齐 custom

在构造 DragTool 的两处 on: { ... } 里都加上(inside: trueinside: false 各一处):

js
custom: ({ self }) => methods.handleToolCustom({ self, inside: true }),
js
custom: ({ self }) => methods.handleToolCustom({ self, inside: false }),

2.2 增加处理函数 handleToolCustom

仿照 handleToolCopy/handleToolDelete,统一拿到 targetRule 后执行你的业务操作。最推荐的方式是:

  • FcDesigner 内部完成“默认行为”(例如弹窗、改规则、写入扩展字段等)
  • 同时对外 emit('custom', targetRule),让集成项目可监听(按需)

示例(伪代码):

js
handleToolCustom({ self, inside }) {
  const targetRule = inside ? methods.getParent(self).parent : self.children[0];

  // 1) 执行你的自定义逻辑(示例:给规则打标记)
  targetRule.props = targetRule.props || {};
  targetRule.props.__bizTagged = true;

  // 2) 如果影响了右侧面板/画布展示,可按需刷新
  if (data.activeRule === targetRule) {
    methods.updateRuleFormData();
  }

  // 3) 对外抛事件(按需:让集成项目接管)
  vm.emit('custom', targetRule);
},

2.3(可选)把 custom 加到组件的 emits 列表

如果你希望在集成项目里这样监听:

vue
<FcDesigner @custom="onCustomTool" />

那么需要把 custom 加到 FcDesigner.vueemits: [...] 中(与 copy/delete/create 同级)。

常见问题排查

1. 按钮显示了,但点击没有反应

  • 最可能原因DragTool.vue 里只新增了按钮,但没有把事件名加入 emits,导致 Vue 丢弃事件
  • 定位路径src/designer/DragTool.vueemits: [...]
  • 修复方式:把 custom 加入 emits

2. 点击触发了,但拿到的 rule 不对(删错/改错组件)

  • 最可能原因:没有按 inside 区分取 targetRule
  • 定位路径src/designer/FcDesigner.vuehandleToolCopy/handleToolDelete(对照它们的取值方式)
  • 修复方式:使用统一写法
    targetRule = inside ? methods.getParent(self).parent : self.children[0]

3. 集成项目监听不到 @custom

  • 最可能原因FcDesigner.vueemits 列表没加入 custom
  • 定位路径src/designer/FcDesigner.vue 顶部 emits: [...]
  • 修复方式:加入 custom,并在 handleToolCustomvm.emit('custom', targetRule)

附录:相关文件路径速查

  • 工具栏组件:src/designer/DragTool.vue
  • 工具栏事件处理:src/designer/FcDesigner.vue