- 前端
- UI组件
【免费下载链接】vue-flow
A highly customizable Flowchart component for Vue 3. Features seamless zoom & pan 🔎, additional components like a Minimap 🗺 and utilities to interact with state and graph.
Vue Flow 的图状态(节点、边、视口、选中态等)并非散落在各个组件里,而是由一个基于 Provide/Inject 机制的集中式 store 统一管理。本篇指南以官方文档 state.md 为骨架,结合仓库源码,讲透如何通过useVueFlow组合式函数访问、注入、创建与操作内部状态,如何在组件树之外读写状态,以及如何通过applyDefault关闭自动变更、实现完全受控的流程图。
读完本文,你将掌握:useVueFlow的注入与创建两条路径、跨组件共享状态的正确姿势、Options API 下的兼容用法,以及从"自动应用变更"到"手动应用变更"的完整受控流方案。
一、状态架构:Provide/Inject + 全局 Storage
Vue Flow 的状态管理建立在 Vue 3 的 Provide/Inject 机制之上:<VueFlow>组件在挂载时会把自己的 store 实例 provide 到组件树中,子树中的任何组件都可以通过useVueFlow注入到这份状态。
注入所用的 InjectionKey 定义在 context/index.ts:
export const VueFlow: InjectionKey<VueFlowStore> = Symbol('vueFlow')除了依赖注入之外,Vue Flow 还维护了一个全局的Storage单例(实现见 utils/storage.ts),用Map<string, VueFlowStore>按 id 登记所有已创建的 store 实例,并挂载到appContext.app的全局属性上。这样即使在没有注入上下文的场景(例如 Options API 的beforeMount生命周期),只要传入正确的 id,依然能按 id 从 Storage 中取回同一个实例。
值得注意的一点是:store 状态是响应式的。Storage.create通过reactive(state)创建响应式状态(见 utils/storage.ts),因此任何对状态的修改(如新增节点、拖动改变位置)都会实时反映到图上。文档中的示例展示了这一点:
<script setup> import { useVueFlow } from '@vue-flow/core' const { getNodes, onPaneReady } = useVueFlow() // event handler onPaneReady((i) => i.fitView()) // watch the stored nodes watch(getNodes, (nodes) => console.log('nodes changed', nodes)) </script>getNodes是一个computedref(见 getters.ts),可以像普通 ref 一样被watch,从而在节点集合变化时触发回调。
二、useVueFlow:注入已有 store 还是创建新实例
useVueFlow是整个状态访问体系的入口,它的完整实现位于 composables/useVueFlow.ts,支持两种调用签名:
export function useVueFlow(id?: string): VueFlowStore export function useVueFlow(options?: FlowOptions): VueFlowStore其查找逻辑按以下优先级进行:
- 从当前上下文注入:如果当前处于某个 setup 作用域内,尝试
inject(VueFlow)获取组件树中已提供的 store;若传入了 id 或当前 scope 带有vueFlowId,还会校验注入实例的 id 是否匹配(见 useVueFlow.ts)。 - 从全局 Storage 查找:注入失败时,若有 id(显式传入或来自当前 scope 的
vueFlowId),则从 Storage 中按 id 取回(见 useVueFlow.ts)。 - 创建新实例:两步都找不到、或找到的实例 id 与传入 id 不符时,调用
storage.create(name, options)创建全新 store 并注册进 Storage(见 useVueFlow.ts)。
无论走哪条路径,最终都会把取到的 storeprovide回当前上下文并记录vueFlowId(见 useVueFlow.ts),保证后续调用能稳定命中同一个实例。另外,若以 options 对象形式传入,且当前不在<VueFlow>组件内部,会触发ErrorCode.USEVUEFLOW_OPTIONS错误提示——因为带 options 的调用语义是"创建新实例",在已存在上下文中这样做容易造成实例混乱(见 useVueFlow.ts)。
store 实例本身是一个包含三部分能力的聚合对象(见 utils/storage.ts):
- hooks:
onNodesChange、onConnect、onPaneReady等全部事件钩子; - getters:
getNodes、getEdges、getSelectedNodes等只读计算属性; - actions:
addNodes、removeNodes、applyNodeChanges、setViewport等操作方法。
三、在组件树外部访问状态:跨组件共享实战
组合式 API 的最大红利在于:store 实例一旦创建,就可以脱离当前组件上下文被任意传递,从而规避 props 逐层透传(prop drilling)的问题。
文档中的经典场景是:根组件里同时渲染<Sidebar>和<VueFlow>,Sidebar 需要"全选所有节点"的能力。
首先在 Container 中提前初始化store 实例(关键是必须在 Sidebar 初始化之前执行):
<script> // Container.vue import { useVueFlow } from '@vue-flow/core' // initialize a store instance in this context, so it is available when calling inject(VueFlow) useVueFlow() </script> <template> <div> <Sidebar /> <div class="wrapper"> <VueFlow :nodes="nodes" :edges="edges" /> </div> </div> </template>接着 Sidebar 组件里直接注入同一份状态,无需任何 props:
<script setup> import { useVueFlow } from '@vue-flow/core' const { nodesSelectionActive, addSelectedNodes, getNodes } = useVueFlow() const selectAll = () => { addSelectedNodes(getNodes.value) nodesSelectionActive.value = true } </script> <template> <aside> <div class="description"> This is an example of how you can access the internal state outside of the Vue VueFlow component. </div> <div class="selectall"> <button @click="selectAll">select all nodes</button> </div> </aside> </template>addSelectedNodes的实现会基于节点 id 集合生成 selection change,并通过state.hooks.nodesChange.trigger(...)通知所有监听者(见 actions.ts);在非多选模式下还会同时取消边的选中态。由于默认applyDefault为true,这些变更会被默认处理器自动应用到节点与边上。
::: tip 如果同一上下文中存在多个 store 实例(例如在一个页面里渲染多个相互独立的<VueFlow>),务必为每个实例指定唯一的 id。否则useVueFlow会注入它在当前上下文中找到的第一个实例——通常是最后被注入的那个,容易拿错状态。 :::
四、多实例与唯一 id
为 store 指定 id 有两种方式:调用useVueFlow({ id: 'my-flow' })或在<VueFlow>组件上传idprop。当显式传入 id 时,useVueFlow的查找会校验injectedState.id === vueFlowId,并优先从 Storage 按 id 精确取回对应实例(见 useVueFlow.ts),从而避免拿到"第一个碰到的实例"。
不传 id 时,Storage.getId()会生成自增 id(格式vue-flow-0、vue-flow-1...,见 storage.ts)。也就是说,文档中的"多实例必须唯一 id"建议,本质上是为了绕过"注入默认取最后一个实例"的歧义,改用精确寻址。
五、状态更新与 applyDefault:从自动到受控
5.1 默认行为:自动应用变更
默认情况下,删除元素、更新位置、选择/取消选择等交互产生的状态变更会被自动应用。applyDefault的默认值在 store/state.ts 中定义为true。
这份"自动应用"的接线发生在useVueFlow创建实例时:它通过watch(state.applyDefault, ...)注册默认的 nodes/edges 变更处理器(见 useVueFlow.ts):
const nodesChangeHandler = (changes: NodeChange[]) => { state.applyNodeChanges(changes) } const edgesChangeHandler = (changes: EdgeChange[]) => { state.applyEdgeChanges(changes) }当shouldApplyDefault为真时,处理器被挂到onNodesChange/onEdgesChange上;为假时则从 hooks 上摘除,同时在作用域销毁时清理,避免内存泄漏。这段逻辑注释里特别说明:必须在<VueFlow>组件挂载之前注册默认 hooks,否则在组件未挂载时调用addNodes将不会触发任何变更。
5.2 关闭自动应用
如果你希望完全掌控状态变更(例如先校验再落地),把applyDefault设为false:
<template> <VueFlow :nodes="nodes" :edges="edges" :apply-default="false" /> </template>applyDefault是<VueFlow>的合法 prop(定义见 VueFlow.vue),组件挂载后会通过 props 监听同步到 store(见 useWatchProps.ts),因此无论用 prop 还是useVueFlow({ applyDefault: false })都有效。
5.3 变更事件与手动应用
状态变更统一通过onNodesChange/onEdgesChange事件对外暴露,事件参数是变更数组(NodeChange[]/EdgeChange[])。即使开启了自动应用,这两个事件也照常触发,你可以用它来监听,也可以用applyNodeChanges/applyEdgeChanges手动应用。
手动应用函数定义在 actions.ts:
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => { return applyChanges(changes, state.nodes) } const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => { const changedEdges = applyChanges(changes, state.edges) updateConnectionLookup(state.connectionLookup, edgeLookup.value, changedEdges) return changedEdges }关于"变更"的边界:这里的 change 专指交互或 API 触发的增删改(
add、remove、select、position、dimensions),不包括缩放、平移等视口变化,也不包括直接修改节点data对象。Vue Flow 不会替你追踪 nodes/edges 数组的任意变化——直接filter掉一个节点不会触发任何 change 事件,必须走removeNodes()或applyNodeChanges()这类 API。
完整的受控流方案(禁用自动应用 → 监听变更 → 校验 → 手动应用,如"删除节点前弹确认框")请参阅仓库文档 controlled-flow.md;若需要把内部状态与自己的 state 双向同步,还可以使用v-model:nodes与v-model:edges。
六、在 Options API 中访问状态
useVueFlow虽为组合式 API 设计,但 Options API 同样可用,前提是必须传入唯一 id——否则查找会失败,Vue Flow 会在组件挂载时新建一个实例,导致你拿到的状态与<VueFlow>渲染用的状态不是同一个。
官方完整示例:
<script> import { VueFlow, useVueFlow } from '@vue-flow/core' const { addEdges, onConnect } = useVueFlow({ id: 'options-api' }) export default defineComponent({ components: { VueFlow }, data() { return { nodes: [ { id: '1', position: { x: 0, y: 0}, data: { label: 'Node 1' } } ], edges: [], } }, methods: { // regular event handler handleConnect: (params) => { addEdges([params]) } }, beforeMount() { // Register your event handler, can technically be called in any lifecycle phase // Skip this if you're using regular event handlers onConnect((params) => addEdges([params])) } }) </script> <template> <VueFlow id="options-api" :nodes="nodes" :edges="edges" @connect="handleConnect" /> </template>要点拆解:
- id 一致性:
useVueFlow({ id: 'options-api' })与模板里的id="options-api"必须对应,useVueFlow才会在beforeMount阶段从 Storage 中按 id 命中同一个实例; - 两种事件订阅方式二选一:通过
@connect="handleConnect"模板监听走的是组件事件,而onConnect((params) => addEdges([params]))走的是 store hooks——hooks 注册理论上可在任意生命周期调用,但必须在事件发生前完成; - 文档注释明确说明:"Skip this if you're using regular event handlers",即两者同时使用时注意避免重复添加。
七、状态 API 速查
useVueFlow返回的 store 覆盖了完整的状态操作面,按职责划分如下:
| 类别 | 代表性成员 | 源码位置 |
|---|---|---|
| 事件钩子 | onNodesChange、onEdgesChange、onConnect、onPaneReady、onNodeClick、onMove等 40+ 钩子 | hooks.ts |
| 只读 getters | getNodes、getEdges、getSelectedNodes、getSelectedEdges、getNodeTypes、getEdgeTypes | getters.ts |
| 变更应用 | applyNodeChanges、applyEdgeChanges | actions.ts |
| 增删改 | addNodes、addEdges、removeNodes、updateNode、updateNodeData | actions.ts |
| 选择操作 | addSelectedNodes、addSelectedEdges、removeSelectedNodes | actions.ts |
| 状态属性 | nodesSelectionActive、applyDefault、viewport、zoom等全部响应式 ref | state.ts |
其中getNodes/getEdges在开启onlyRenderVisibleElements时只返回视口内可见元素(见 getters.ts),适合大图性能优化场景。
八、小结
Vue Flow 的状态体系可以用一句话概括:集中式响应式 store + Provide/Inject 注入 + 全局 Storage 按 id 寻址。useVueFlow是唯一入口,它既能"注入已有状态",也能"创建新状态";默认开启的applyDefault让日常使用零成本,关闭后则配合onNodesChange/onEdgesChange与applyNodeChanges/applyEdgeChanges实现完全受控的流程图。理解这条链路后,无论是跨组件共享状态、多实例隔离还是 Options API 集成,都能准确地拿到"同一个"状态实例。
继续深入可阅读:composables.md(更多组合式函数)、controlled-flow.md(受控流完整指南)、state.ts(全部状态字段与默认值)。
- 前端
- UI组件
【免费下载链接】vue-flow
A highly customizable Flowchart component for Vue 3. Features seamless zoom & pan 🔎, additional components like a Minimap 🗺 and utilities to interact with state and graph.
相关推荐
Vue Flow状态管理终极指南:使用组合式API掌控复杂流程图
Vue Flow状态管理终极指南:使用组合式API掌控复杂流程图 Vue Flow是一个高度可定制的流程图组件,专为Vue 3设计。它通过强大的 状态管理 系统
前端UI组件电子课本下载:粘贴课本链接,PDF 批量存到本地
电子课本下载:粘贴课本链接,PDF 批量存到本地 想把国家中小学智慧教育平台上的教材存到本地,却只能对着预览页一张张截图?tchMaterial parser
网页爬虫教育Vue Flow 3 Composables 完全指南:useVueFlow 状态管理、连接查询与自定义 Handle 的响应式交互
Vue Flow 3 Composables 完全指南:useVueFlow 状态管理、连接查询与自定义 Handle 的响应式交互 在 Vue Flow( @
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考