ToolJet Map 组件深度解析:属性、事件、组件特定动作与源码级实现原理
2026/9/10 1:38:49 网站建设 项目流程

ToolJet Map 组件深度解析:属性、事件、组件特定动作与源码级实现原理

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

本文以 ToolJet 的 Map(地图)组件为主线,完整覆盖其属性配置、事件体系、组件特定动作(CSA)、暴露变量与样式控制,并结合frontend/src/AppBuilder/Widgets/Map/下的实际源码,剖析其底层基于@react-google-maps/api的实现机制、动态值(fx)解析流程以及自托管部署时GOOGLE_MAPS_API_KEY环境变量的配置方式。读完本文,你将能够独立配置并编程化控制 Map 组件,在业务应用中展示商家、门店或用户位置,并通过事件与变量实现地图交互闭环。

一、组件定位与典型场景

Map 组件用于在应用中显示一张地图,支持展示或选择单个/多个地理位置。文档中给出的典型场景包括:展示企业、门店或餐厅的位置,展示用户在地图上的位置,以及允许终端用户与地图界面交互、点击选取兴趣点。

从源码结构看,Map 是 ToolJet 前端 WidgetManager 中注册的一个标准组件。其注册配置文件 map.js 声明了组件元数据,其中默认尺寸为宽 16 列、高 420 像素(defaultSize: { width: 16, height: 420 }),组件标识为Map,描述为 "Display map locations"。组件的实际渲染逻辑位于 Map.jsx。

二、自托管部署前提:配置 Google Maps API Key

原文档明确提示:若使用 ToolJet 自托管(self-hosted)版本,必须将 Google Maps API key 配置为环境变量,否则地图无法正常加载。

这一点在源码中得到印证:Map.jsx 中地图脚本通过如下方式加载:

<LoadScript googleMapsApiKey={window.public_config.GOOGLE_MAPS_API_KEY} libraries={['places'}}> <GoogleMap ... /> </LoadScript>

即组件依赖window.public_config.GOOGLE_MAPS_API_KEY这一前端全局配置项来初始化 Google Maps JS SDK,并同时加载places库(Places 库是"地点搜索"能力的前提,详见第四节)。环境变量GOOGLE_MAPS_API_KEY的官方说明见 env-vars.md 中的 "Google maps configuration (optional)" 章节:

variabledescription
GOOGLE_MAPS_API_KEYGoogle maps API key

三、Properties 属性详解

Map 组件提供 5 个专属属性。以下在继承原文档说明的基础上,结合 map.js 中的配置补充了默认值与校验规则。

属性说明期望取值
Initial location应用初始加载时的默认位置。包含latitudelongitude键值对的对象。例:{{ {"lat": 40.7128, "lng": -73.935242} }}
Default markers地图上应显示的标记点数量(即初始标记点集合)。包含坐标的对象数组。例:{{ [{"lat": 40.7128, "lng": -73.935242}, {"lat": 40.7128, "lng": -73.935242}] }}
Polygon points使用给定坐标在地图上创建多边形。包含坐标的对象数组。例:{{ [{"lat": 40.7128, "lng": -73.935242}, {"lat": 40.7128, "lng": -73.935242}] }}
Add new markers点击地图时在对应位置添加新标记。默认On。切换为off可禁用"点击加标记"行为。点击fx可动态设置{{true}}/{{false}}
Search for places启用后在地图左上角显示地点搜索框。默认On。切换为off可禁用搜索框。点击fx可动态设置{{true}}/{{false}}

源码层面有三个值得注意的细节:

  1. 前三个属性均为code类型编辑器。map.js 中initialLocationdefaultMarkerspolygonPoints均配置为type: 'code'mode: 'javascript',校验 schema 为union,即"对象或对象数组"(schemas: [{ type: 'array', element: { type: 'object' } }, { type: 'object' }])。这意味着这三个字段不仅接受静态坐标对象,还支持 fx 动态表达式,例如{{ JSON.parse(query1.data) }}之类的查询结果。
  2. 两个开关属性的默认值均为trueaddNewMarkerscanSearchdefaultValue均为true),与文档"默认 On"的说明一致。
  3. 渲染时的兜底逻辑:Map.jsx 中,initialLocation缺失时回退到{ lat: 0, lng: 0 }addNewMarkerscanSearch缺失时回退到falsepolygonPointsdefaultMarkers缺失时回退到空数组。

多边形渲染的附加条件:Map.jsx 中,仅当polygonPoints.length > 1时才会渲染<Polygon>,且样式是硬编码的——描边色#4d72fa、线宽 2、填充色#4d72fa、填充不透明度 0.5,因此多边形外观不支持属性级自定义。

四、Events 事件体系

事件名触发时机
On bounds change地图可视边界(bounding area)发生变化后触发,此时bounds暴露变量已更新。
On create marker向地图添加新标记点时触发。
On marker click用户点击地图上任意标记点时触发。
On polygon click用户点击地图上的多边形时触发。

这四个事件在 map.js 的events段注册,并与 Map.jsx 中的四处fireEvent调用一一对应:

  • onBoundsChange:由 handleBoundsChange 触发,绑定在地图的onDragEnd上(即用户拖拽地图结束)。该函数通过gmap.getBounds()取出northEast/southWest两个角点,连同新的center一并写入暴露变量,最后才fireEvent('onBoundsChange')——这保证了事件处理函数内读取boundscenter时拿到的一定是新值。
  • onCreateMarker:由 handleMapClick 触发。若canAddNewMarkers为假则直接返回;否则从点击事件的e.latLng中取出经纬度,追加进markers状态、更新暴露变量,再触发事件。
  • onMarkerClick:由 handleMarkerClick 触发,先将被点击的标记写入selectedMarker暴露变量再触发事件。
  • onPolygonClick:直接绑定在<Polygon>onClick上。

关于 ToolJet 全部可用 Actions 的更多信息,可参考 Actions 参考文档,以及在 RunJS 查询中执行动作的用法见 run-action-from-runjs.md。

五、Component Specific Actions(CSA)

Map 组件当前对外暴露一个组件特定动作,可在任意事件处理函数中通过 RunJS 查询编程化调用:

动作说明调用方式
setLocation通过经度、纬度参数在地图上设置标记点位置。在 RunJS 查询中执行:component.map1.setLocation(40.7128, -73.935242)

动作定义见 map.js:handlesetLocation,接收lat(Latitude)与lng(Longitude)两个参数。

其实现机制在 Map.jsx 的初始化useEffect中:组件挂载时通过setExposedVariables将一个闭包函数注入到组件的暴露变量对象上:

const exposedVariables = { setLocation: async function (lat, lng) { if (lat && lng) setMapCenter(resolveWidgetFieldValue({ lat, lng })); }, center: addMapUrlToJson(resolvedCenter), markers: defaultMarkers, };

也就是说,setLocation本质上是一个被挂到components.<id>命名空间下的异步函数:它经resolveWidgetFieldValue解析参数(因此参数位置同样支持 fx 表达式),再调用setMapCenter把地图中心平移到目标坐标。

六、Exposed Variables 暴露变量

暴露变量用于从组件中读取运行时数据,完整清单如下:

变量说明访问方式
center持有纬度、经度及 Google Maps URL 三个值。
center.latMap 组件上标记点的纬度值。{{components.map1.center.lat}}
center.lngMap 组件上标记点的经度值。{{components.map1.center.lng}}
center.googleMapUrl中心标记点位置的 Google Maps URL。{{components.map1.center.googleMapUrl}}
markers仅在启用add new markers属性后持有值;每个标记为含latlng键的对象。{{components.map1.markers[1].lat}}
selectedMarker用户所选标记点构成的对象。
bounds由西南角与东北角两点构成的矩形(地图可视范围)。
bounds.northEast矩形东北角的经纬度。{{components.map1.bounds.northEast.lat}}{{components.map1.bounds.northEast.lng}}
bounds.southWest矩形西南角的经纬度。{{components.map1.bounds.southWest.lat}}{{components.map1.bounds.southWest.lng}}

源码印证了各变量的写入时机与结构:

  • center / googleMapUrl:addMapUrlToJson 在中心坐标对象上追加一个可直接打开的 URL 字段:https://www.google.com/maps/@?api=1&map_action=map&center=<lat>,<lng>center在地图onLoad、拖拽结束(handleBoundsChange)以及initialLocation变化时都会刷新(见 Map.jsx)。
  • markers:初始值来自defaultMarkers属性(Map.jsx 中监听defaultMarkers变化同步状态);用户点击地图新增标记后,handleMapClick会即时将最新数组写入markers暴露变量。
  • selectedMarkerhandleMarkerClick中执行setExposedVariable('selectedMarker', markers[index]),即当前点击索引对应的完整标记对象。
  • boundshandleBoundsChange中由getBounds().getNorthEast().toJSON()getSouthWest().toJSON()构造,故northEast/southWest各含latlng两个子字段。

一个实用的组合用法:在onBoundsChange事件处理中读取components.map1.bounds,即可在用户平移/缩放地图后,用边界坐标作为参数去执行一条查询(例如只加载当前可视范围内的门店数据)。

七、动态值解析与交互实现原理

7.1 fx 动态值的统一解析入口

Map 属性中所有{{ ... }}表达式最终都经过 resolveWidgetFieldValue 解析:

export function resolveWidgetFieldValue(prop, _default = [], customResolveObjects = {}) { const widgetFieldValue = prop; try { const state = {}; // getCurrentState(); return resolveReferences(widgetFieldValue, state, _default, customResolveObjects); } catch (err) { console.log(err); } return widgetFieldValue; }

在 Map.jsx 中可以看到该函数的三类典型用法:解析initialLocation得到地图初始中心(第 48 行useState(() => resolveWidgetFieldValue(center)));解析styles.visibility得到可见性布尔值(第 41 行);解析setLocation的入参坐标(第 150 行)。解析失败时回退原值并打印日志,保证组件不会因表达式异常而白屏。

7.2 地图交互细节

从 Map.jsx 的渲染结构看:

  • 地图实例<GoogleMap>固定zoom={12},关闭街景与地图类型控件(streetViewControl: falsemapTypeControl: false),允许拖拽(draggable: true)。
  • 地点搜索:仅当canSearch为真时渲染<Autocomplete>(第 196-204 行),用户选定搜索结果后onPlaceChanged会把地图中心移动到所选地点的geometry.location,并顺带触发一次handleBoundsChange(刷新bounds/center并触发onBoundsChange事件)。搜索框的占位文本走 i18n 翻译键globals.search
  • 标记点markers数组逐项渲染为<Marker>,支持可选的label字段,点击回调携带索引以便写入selectedMarker
  • 深色模式:当darkMode为真时应用 styles.js 中的darkModeStyles(Google Maps 主题化样式集);styles.scss 则隐藏了 Places 自动补全的默认面板(.pac-container { display: none !important; }),因为组件使用的是onPlaceChanged回调而非下拉面板交互。
  • 编辑态装饰:编辑器画布中地图上叠加了一个中心大头针图标(assets/images/icons/marker.svg)作为组件可视化标记,仅用于设计态辨识。

八、通用能力:Devices 与 Styles

Devices(设备可见性)

属性说明期望取值
Show on desktop组件在桌面视图中可见。可用开关按钮设置,或点击fx输入逻辑表达式动态控制。
Show on mobile组件在移动视图中可见。可用开关按钮设置,或点击fx输入逻辑表达式动态控制。

源码中对应mapConfig.others段的两个 toggle 属性 showOnDesktop / showOnMobile;注意组件定义里二者的出厂默认值分别为{{true}}{{false}}(map.js),即新建的 Map 组件默认只在桌面端显示。

General — Tooltip

Tooltip 用于在用户鼠标悬停组件时展示附加说明信息:一旦设置了 Tooltip 值,悬停时即显示指定字符串。

Styles(样式)

属性说明期望取值
Visibility开关组件的可见性。点击旁边的fx按钮可编程修改。设为{{false}}时,应用发布后组件不可见。默认{{true}}
Disable默认off;切换为on时锁定组件、使其不可交互。也可通过fx按钮编程设置。设为{{true}}后组件被锁定不可用。默认{{false}}
Box shadow提供 X、Y、Blur、Spread 与 Color 值,为组件添加阴影效果。也可通过fx按钮编程设置。例:{{"x": 0, "y": 0, "blur": 0, "spread": 0, "color": "#000000"}}

源码中visibility直接决定外层容器display: none(Map.jsx 中style={{ height, display: parsedWidgetVisibility ? '' : 'none', boxShadow: styles.boxShadow }});disabledState则写入data-disabled属性供编辑器渲染锁定态;boxShadow原样作用于容器内联样式。

九、小结与延伸阅读

Map 组件通过"属性(位置/标记/多边形/开关)+ 事件(边界/标记/多边形交互)+ CSA(setLocation)+ 暴露变量(center/markers/selectedMarker/bounds)"四层机制构成完整的地图交互闭环,其底层由@react-google-maps/api驱动,所有动态值统一经resolveWidgetFieldValue解析。自托管环境下务必先配置GOOGLE_MAPS_API_KEY环境变量。相关路径一览:

  • 组件文档源文件:docs/docs/widgets/map.md
  • 组件注册与默认值:frontend/src/AppBuilder/WidgetManager/widgets/map.js
  • 组件渲染实现:frontend/src/AppBuilder/Widgets/Map/Map.jsx
  • 深色模式样式:frontend/src/AppBuilder/Widgets/Map/styles.js
  • 环境变量说明:docs/docs/setup/env-vars.md
  • Actions 参考目录:docs/docs/actions/

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询