Vue 整合 Vue Flow:從零構建交互式流程圖

目錄

  • 引言
  • 目的
  • 適用場景
  • 環境準備
  • 基礎組件 (index.vue)
  • 自定義組件 (矩形、菱形等)
    • RectangleNode.vue (矩形節點):
    • DiamondNode.vue (菱形節點):
    • ImageNode(自定義圖片節點):
  • 操作實現 (#操作實現)
    • ?????拖拽節點 (#拖拽節點)
    • ?????連線 (多連接點)
    • ?????刪除節點
    • ?????保存為 JSON
    • ?????導入 JSON
  • 性能優化建議
  • 常見問題與解決
  • 總結
  • `demo見:`

引言

????????Vue Flow 是一個基于 Vue 的流程圖庫,結合 Vue.js 的組件化優勢,可用于創建交互式、可視化的流程圖。本文將逐步引導你整合 Vue Flow,涵蓋從環境配置到自定義節點、拖拽、連線、刪除、JSON 管理和優化,適合初學者和高級開發者。

目的

?本文旨在提供一個全面的指南,幫助開發者:

  • 理解 Vue Flow 的核心功能和集成流程。
  • 實現交互式流程圖,包括拖拽、連線和節點管理。
  • 掌握數據持久化(保存和導入 JSON),提升項目實用性。
  • 優化性能并解決常見問題,確保生產環境穩定。

適用場景

  • 工作流管理:設計審批或任務流程。
  • 數據可視化:展示組織結構或網絡拓撲。
  • 工業自動化:模擬設備連接和生產流程。
  • 教育工具:可視化算法或邏輯步驟。
  • 說明插圖:繪制一個工業流程圖,包含 “設備1”, “工序1”, “設備2” 節點和連接線。

環境準備

  • 項目初始化:使用 Vue 3 + Vite 創建項目。

  • 依賴安裝:

npm install @vue-flow/core @vue-flow/background @vue-flow/controls @vue-flow/minimap ant-design-vue

@vue-flow/core:核心庫。
@vue-flow/background:背景網格。
@vue-flow/controls:交互控制。
@vue-flow/minimap:畫布概覽。
ant-design-vue:用于按鈕樣式。
在這里插入圖片描述

基礎組件 (index.vue)

創建 src/components/FlowChart.vue 作為流程圖容器。

<template><div class="flow-container"><div class="layout"><!-- 左側可選項區域 --><div class="sidebar"><h3>可拖拽節點</h3><divv-for="option in nodeOptions":key="option.type"class="draggable-node":data-type="option.type"draggable="true"@dragstart="onDragStart"><div class="node-label">{{ option.label }}</div><div class="node-preview-wrapper"><div :class="['inner-shape', option.shapeClass]"><div class="label">{{ option.label }}</div></div></div></div></div><!-- 右側 Vue Flow 畫布 --><div class="flow-area"><div class="toolbar"><a-button type="primary" @click="addRandomNode">添加隨機節點</a-button>
<!--          <a-button type="danger" @click="deleteSelected">刪除選中節點</a-button>--><a-button type="default" @click="exportJson">導出 JSON</a-button><a-button type="default" @click="saveExportJson">保存流程圖</a-button></div><VueFlowv-model:nodes="nodes"v-model:edges="edges":node-types="nodeTypes":default-edge-options="{type: 'smoothstep',animated: true,markerEnd: { type: 'arrowclosed', color: '#ff0000' },style: { stroke: '#ff0000', strokeWidth: 2, strokeDasharray: 'none' },}":connection-line-style="{ stroke: '#ff0000', strokeWidth: 2, strokeDasharray: 'none' }":fit-view-on-init="true":connectable="true"@drop="onDrop"@dragover.prevent@connect="onConnect"@node-click="onNodeClick"@node-drag-start="onNodeDragStart"@node-drag-stop="onNodeDragStop"@pane-click="onPaneClick"><Background variant="dots" :gap="20" /><Controls /><MiniMap /></VueFlow></div></div></div>
</template><script setup lang="ts">
import {ref, markRaw, onMounted} from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import type { NodeTypesObject } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
import { message } from 'ant-design-vue'
import DiamondNode from './DiamondNode.vue'
import CircleNode from './CircleNode.vue'
import ImageNode from './ImageNode.vue'
import DeviceNode from './DeviceNode.vue'
import UserNode from './UserNode.vue'
import RoundedRectangleNode from './RoundedRectangleNode.vue'
import { editingNodeId } from './store'
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'
import '../style/node-styles.css'const nodes = ref([])
const edges = ref<any>([])const nodeTypes: NodeTypesObject = {diamond: markRaw(DiamondNode),circle: markRaw(CircleNode),image: markRaw(ImageNode),user: markRaw(UserNode),device: markRaw(DeviceNode),roundedRectangle: markRaw(RoundedRectangleNode),
}const { addNodes, getNodes, deleteElements,removeNodes } = useVueFlow()const nodeOptions = ref([{ type: 'circle', label: '開始節點', shapeClass: 'node-circle' },{ type: 'circle', label: '結束節點', shapeClass: 'node-circle' },// { type: 'image', label: '圖片節點', shapeClass: 'node-image' }, // 新增圖片節點// { type: 'device', label: '設備節點', shapeClass: 'node-device' }, // 新增設備節點// { type: 'user', label: '人員節點', shapeClass: 'node-user' }, // 新增人員節點// { type: 'roundedRectangle', label: '圓角長方形節點', shapeClass: 'node-rounded-rectangle' },])function initData(){return [{ type: 'device', label: '設備節點', shapeClass: 'node-device',id:1,code:'123' },{ type: 'device', label: '工序1', shapeClass: 'node-device',id:1,code:'123' },{ type: 'device', label: '工序2', shapeClass: 'node-device',id:1,code:'123' },{ type: 'device', label: '工序3', shapeClass: 'node-device',id:1,code:'123' },]
}
function getData(){nodes.value = [{"":""}];edges.value = [{"":""}];onMounted(() => {let data  =initData();nodeOptions.value = [...nodeOptions.value, ...data];getData();
})
// Drag-and-drop handlers
function onDragStart(event: DragEvent) {if (event.dataTransfer && event.target instanceof HTMLElement) {const type = event.target.dataset.typeif (type) {event.dataTransfer.setData('application/vueflow-node-type', type)}}
}function onDrop(event: DragEvent) {const type = event.dataTransfer?.getData('application/vueflow-node-type')if (!type) returnconst bounds = (event.currentTarget as HTMLElement).getBoundingClientRect()const position = {x: event.clientX,y: event.clientY,}const label = type === 'diamond' ? '判斷節點' : type === 'circle' ? '開始節點' : '圓角長方形節點'addNodes([{id: `${type}-${Date.now()}`,type,position,data: { label },},])
}// Connection handler
function onConnect(params: any) {edges.value = [...edges.value,{...params,id: `edge-${params.source}-${params.target}`,type: 'smoothstep',animated: true,markerEnd: { type: 'arrowclosed', color: '#ff0000' },style: { stroke: '#ff0000', strokeWidth: 2, strokeDasharray: 'none' },},]
}// Node interaction handlers
function onNodeClick(event: any, node: any) {nodes.value = nodes.value.map(n => ({...n,selected: n.id === node.id ? true : false,}))// if (node.type === 'circle') {//   editingNodeId.value = node.id // 僅對圓形節點啟用編輯模式// }
}function onNodeDragStart(event: any, node: any) {console.log('Node drag started:', node)
}function onNodeDragStop(event: any, node: any) {console.log('Node drag stopped:', node)
}function onPaneClick() {nodes.value = nodes.value.map(n => ({ ...n, selected: false }))editingNodeId.value = null // 退出編輯模式
}// Add a random node
function addRandomNode() {const types = ['diamond', 'circle', 'roundedRectangle','image','user','device']const type = types[Math.floor(Math.random() * types.length)]const label = type === 'diamond' ? '判斷節點' : type === 'circle' ? '圓形節點' : '圓角長方形節點'addNodes([{id: `${type}-${Date.now()}`,type,position: { x: Math.random() * 500, y: Math.random() * 500 },data: { label },},])
}// Delete selected nodes
function deleteSelected() {const selectedIds = getNodes.value.filter(n => n.selected).map(n => n.id)if (selectedIds.length === 0) {message.warning('請先選中一個節點')return}removeNodes({ selectedIds })message.success('節點刪除成功')editingNodeId.value = null // 退出編輯模式
}function saveExportJson(){//todo 保存到數據庫
}
// Export JSON
function exportJson() {const json = JSON.stringify({ nodes: nodes.value ,edges: edges.value }, null, 2)const blob = new Blob([json], { type: 'application/json' })const url = window.URL.createObjectURL(blob)const a = document.createElement('a')a.href = urla.download = 'flowchart.json'a.click()window.URL.revokeObjectURL(url)message.success('JSON 文件已導出')
}// 更新節點標簽
function updateNodeLabel(nodeId: string, newLabel: string) {nodes.value = nodes.value.map(n =>n.id === nodeId ? { ...n, data: { ...n.data, label: newLabel } } : n)editingNodeId.value = null // 編輯完成后退出編輯模式
}
</script>

???????說明:基礎組件包含側邊欄(拖拽源)、工具欄(操作按鈕)和 VueFlow 畫布,綁定了節點和邊數據。

自定義組件 (矩形、菱形等)

定義不同形狀的節點,添加多連接點。

RectangleNode.vue (矩形節點):

<template><div class="node rectangle"><Handle type="target" position="top" id="top-target" /><Handle type="source" position="top" id="top-source" /><Handle type="target" position="bottom" id="bottom-target" /><Handle type="source" position="bottom" id="bottom-source" /><Handle type="target" position="left" id="left-target" /><Handle type="source" position="left" id="left-source" /><Handle type="target" position="right" id="right-target" /><Handle type="source" position="right" id="right-source" /><div class="label">{{ data.label }}</div></div>
</template><script setup>
import { Handle } from '@vue-flow/core'
defineProps({ data: Object })
</script><style scoped>
.node {width: 100px;height: 60px;border: 1px solid #333;display: flex;align-items: center;justify-content: center;
}
.label { text-align: center; }
</style>

DiamondNode.vue (菱形節點):

<template><div class="diamond-node"><!-- 頂部連接點:source 和 target --><Handle type="target" position="top" class="handle" id="top-target" /><Handle type="source" position="top" class="handle" id="top-source" /><!-- 左側連接點:source 和 target --><Handle type="target" position="left" class="handle" id="left-target" /><Handle type="source" position="left" class="handle" id="left-source" /><!-- 右側連接點:source 和 target --><Handle type="target" position="right" class="handle" id="right-target" /><Handle type="source" position="right" class="handle" id="right-source" /><!-- 底部連接點:source 和 target --><Handle type="target" position="bottom" class="handle" id="bottom-target" /><Handle type="source" position="bottom" class="handle" id="bottom-source" /><!-- 節點本體 --><div class="diamond"><div class="label">{{ data.label }}</div></div></div>
</template><script setup>
import { Handle } from '@vue-flow/core'defineProps({data: Object,
})
</script><style scoped>
.diamond-node {position: relative;width: 80px;height: 80px;overflow: visible;
}.diamond {width: 100%;height: 100%;background: #2ec4b6;transform: rotate(45deg);display: flex;align-items: center;justify-content: center;border: 2px solid #333;color: white;font-weight: bold;box-sizing: border-box;z-index: 1;
}.label {transform: rotate(-45deg);text-align: center;pointer-events: none;font-size: 12px;padding: 4px;max-width: 90%;word-break: break-all;
}.handle {width: 10px;height: 10px;background: #ff0000;border-radius: 50%;position: absolute;z-index: 2;
}:deep(.vue-flow__handle-top) {top: -10px; /* 增加偏移量,使點移到頂部外部 */left: 50%;transform: translateX(-50%);
}:deep(.vue-flow__handle-bottom) {bottom: -10px; /* 增加偏移量,使點移到底部外部 */left: 50%;transform: translateX(-50%);
}:deep(.vue-flow__handle-left) {left: -10px; /* 增加偏移量,使點移到左側外部 */top: 50%;transform: translateY(-50%);
}:deep(.vue-flow__handle-right) {right: -10px; /* 增加偏移量,使點移到右側外部 */top: 50%;transform: translateY(-50%);
}
</style>

說明:每個節點包含上下左右的 target 和 source 連接點,允許多向連接。

ImageNode(自定義圖片節點):

<template><div class="image-node"><!-- 頂部連接點:source 和 target --><Handle type="target" position="top" class="handle" id="top-target" /><Handle type="source" position="top" class="handle" id="top-source" /><!-- 左側連接點:source 和 target --><Handle type="target" position="left" class="handle" id="left-target" /><Handle type="source" position="left" class="handle" id="left-source" /><!-- 右側連接點:source 和 target --><Handle type="target" position="right" class="handle" id="right-target" /><Handle type="source" position="right" class="handle" id="right-source" /><!-- 底部連接點:source 和 target --><Handle type="target" position="bottom" class="handle" id="bottom-target" /><Handle type="source" position="bottom" class="handle" id="bottom-source" /><!-- 節點本體 --><div class="image-container"><img :src="imageSrc" alt="Image Node" class="node-image" /></div></div>
</template><script setup>
import { Handle } from '@vue-flow/core'
import { computed } from 'vue'defineProps({data: Object,
})const imageSrc = computed(() => {return new URL('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQ5LjEgKDUxMTQ3KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Hcm91cCAyPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+CiAgICAgICAgPGNpcmNsZSBpZD0icGF0aC0xIiBjeD0iMzYiIGN5PSIzNiIgcj0iMzYiPjwvY2lyY2xlPgogICAgICAgIDxmaWx0ZXIgeD0iLTkuNyUiIHk9Ii02LjklIiB3aWR0aD0iMTE5LjQlIiBoZWlnaHQ9IjExOS40JSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iZmlsdGVyLTIiPgogICAgICAgICAgICA8ZmVPZmZzZXQgZHg9IjAiIGR5PSIyIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIj48L2ZlT2Zmc2V0PgogICAgICAgICAgICA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyIiBpbj0ic2hhZG93T2Zmc2V0T3V0ZXIxIiByZXN1bHQ9InNoYWRvd0JsdXJPdXRlcjEiPjwvZmVHYXVzc2lhbkJsdXI+CiAgICAgICAgICAgIDxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIj48L2ZlQ29tcG9zaXRlPgogICAgICAgICAgICA8ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAgIDAgMCAwIDAgMCAgIDAgMCAgIDAgMCAwIDAgMCAgMCAwIDAgMC4wNCAwIiB0eXBlPSJtYXRyaXgiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIj48L2ZlQ29sb3JNYXRyaXg+CiAgICAgICAgPC9maWx0ZXI+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0i5Z+656GA5rWB56iL5Zu+LTAxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTA2LjAwMDAwMCwgLTkzLjAwMDAwMCkiPgogICAgICAgICAgICA8ZyBpZD0iR3JvdXAtMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTEwLjAwMDAwMCwgOTUuMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iT3ZhbCI+CiAgICAgICAgICAgICAgICAgICAgPHVzZSBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIxIiBmaWx0ZXI9InVybCgjZmlsdGVyLTIpIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgICAgICAgICA8dXNlIGZpbGwtb3BhY2l0eT0iMC49MiIgZmlsbD0iI2NjY2M5OThjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgc3Ryb2tlPSIjY2NjYzMzYzkiIHN0cm9rZS13aWR0aD0iMSIgY3g9IjM2IiBjeT0iMzYiIHI9IjM1LjUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPHRleHQgaWQ9Iue7k+adn+iKgueCuSIgZm9udC1mYW1pbHk9IlBpbmdGYW5nU0MtUmVndWxhciwgUGluZ0ZhbmcgU0MiIGZvbnQtc2l6ZT0iMTIiIGZvbnQtd2VpZ2h0PSJub3JtYWwiIGxpbmUtc3BhY2luZz0iMTIiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMC42NSI+CiAgICAgICAgICAgICAgICAgICAgPHRzcGFuIHg9IjEyIiB5PSI0MSI+57uT5p2f6IqC54K5PC90c3Bhbj4KICAgICAgICAgICAgICAgIDwvdGV4dD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+', import.meta.url).href
})
</script><style scoped>
.image-node {position: relative;width: 50px; /* 調整為適合圖片的尺寸 */height: 50px; /* 調整為適合圖片的尺寸 */overflow: visible;
}.image-container {width: 100%;height: 100%;border-radius: 50%;border: 2px solid #333;display: flex;align-items: center;justify-content: center;color: white;font-weight: bold;box-sizing: border-box;
}.node-image {max-width: 50px;max-height: 50px;overflow: visible;position: relative;}.handle {width: 10px;height: 10px;background: #ff0000;border-radius: 50%;position: absolute;z-index: 2;
}:deep(.vue-flow__handle-top) {top: -5px; /* 移到外部 */left: 50%;transform: translateX(-50%);
}:deep(.vue-flow__handle-bottom) {bottom: -5px; /* 移到外部 */left: 50%;transform: translateX(-50%);
}:deep(.vue-flow__handle-left) {left: -5px; /* 移到外部 */top: 50%;transform: translateY(-50%);
}:deep(.vue-flow__handle-right) {right: -5px; /* 移到外部 */top: 50%;transform: translateY(-50%);
}
</style>

在這里插入圖片描述

操作實現 (#操作實現)

?????拖拽節點 (#拖拽節點)

原理: 使用 draggable 和 onDrop,從側邊欄拖動節點到畫布。
代碼: 見 index.vue 中的 onDragStart 和 onDrop。
效果:拖動 “開始” 或 “決策” 到畫布,生成對應節點,位置基于鼠標坐標。

使用 draggable 和 onDrop,從側邊欄拖動節點到畫布。
代碼:見 index.vue 中的 onDragStart 和 onDrop。
效果:拖動 “開始” 或 “決策” 到畫布,生成對應節點,位置基于鼠標坐標。

?????連線 (多連接點)

原理:@connect 捕獲連接,Handle 定義多連接點,smoothstep 提供平滑線。
代碼:見 index.vue 中的 onConnect。
效果:點擊節點任意連接點拖動,生成紅線連接,箭頭指向目標。
在這里插入圖片描述

?????刪除節點

原理:@node-click 選中,deleteSelected 調用 removeElements。
代碼:見 index.vue 中的 onNodeClick 和 deleteSelected。
效果:點擊節點高亮,點擊刪除按鈕移除節點及相關邊。

在這里插入圖片描述

?????保存為 JSON

原理:exportJson 序列化 nodes 和 edges,生成下載文件。
代碼:見 index.vue 中的 exportJson。

unction exportJson() {const json = JSON.stringify({ nodes: nodes.value ,edges: edges.value }, null, 2)const blob = new Blob([json], { type: 'application/json' })const url = window.URL.createObjectURL(blob)const a = document.createElement('a')a.href = urla.download = 'flowchart.json'a.click()window.URL.revokeObjectURL(url)message.success('JSON 文件已導出')
}

效果:點擊按鈕下載 flowchart.json,包含當前結構。
在這里插入圖片描述

?????導入 JSON

原理:importJson 解析上傳文件,更新 nodes 和 edges。
代碼:見 index.vue 中的 importJson。
效果:上傳 JSON 文件,畫布還原節點和邊。

性能優化建議

  • 限制節點數量:使用虛擬列表優化大規模節點渲染。
  • 防抖處理:對 onDrop 和 onConnect 添加防抖,減少頻繁更新。
  • 懶加載:大圖節點時,延遲加載圖片資源。

常見問題與解決

  • 拖拽位置偏移:檢查 bounds 計算,調整 event.clientX - bounds.left。
  • 連接點無效:確保 Handle ID 唯一,檢查 connectable 屬性。
  • JSON 解析錯誤:驗證文件格式,添加錯誤處理:
reader.onload = (e: any) => {try {const data = JSON.parse(e.target.result)nodes.value = data.nodes || []edges.value = data.edges || []message.success('導入成功')} catch (error) {message.error('JSON 格式錯誤')}
}

總結

??????通過 Vue 整合 Vue Flow,開發者可構建功能豐富的交互式流程圖。本文從環境準備到自定義節點、拖拽、連線、刪除和 JSON 管理,提供了完整指南。Vue Flow 的靈活性使其適用于工作流、數據可視化等場景,建議根據需求優化性能并處理異常。

demo見:

????????https://gitee.com/codingtodie/vue-integration-with-vue-flow

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88090.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88090.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88090.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C# WPF - Prism 學習篇:搭建項目(一)

一、前期準備開發工具&#xff1a;Visual Studio 2022二、創建項目1、創建WPF 應用“WpfApp.StudyDemo”&#xff1a;2、項目結構如下&#xff1a; 三、安裝 Prism1、選中項目“WpfApp.PrismDemo”&#xff0c;在右鍵菜單中選擇“管理 NuGet 程序包(N)...”。2、在搜索框中輸入…

單片機 基于rt-thread 系統 使用 CCM內存

一、開發環境 開發板&#xff1a;野火stm32f407 系統&#xff1a;rt-thread V4.1.1 二、鏈接腳本配置 ; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ****************************…

【UnityAssetBundle】AB包卸載資源

AB包的卸載高效穩定游戲開發的強制要求&#xff0c;它解決了資源管理中的內存泄漏問題&#xff0c;為動態的內容加載、熱更新、大型世界的構建提供了內存保障&#xff0c;最終提升了游戲性能、穩定性和用戶體驗。卸載資源方式一&#xff08;推薦使用&#xff09;&#xff1a;卸…

【萬字長文】深度學習2 yolov5修改為自己的數據集

數據預處理 使用labelme可以直接導出適用于yolo模型的txt文本數據&#xff0c;也可以直接導出默認的json數據結構&#xff0c;后面我會提供代碼進行轉換。自行進行標注&#xff0c;圖片與標注一一對應&#xff0c;更多要求不贅述。因為我做最簡單的檢索模型&#xff0c;不做切…

ubuntu18編譯RealSense SDK 2.0

參考文章&#xff1a;https://dev.intelrealsense.com/docs/compiling-librealsense-for-linux-ubuntu-guide1、安裝依賴 sudo apt-get update && sudo apt-get upgrade && sudo apt-get dist-upgrade sudo apt-get install libssl-dev libusb-1.0-0-dev libud…

算法學習筆記:9.Kruskal 算法——從原理到實戰,涵蓋 LeetCode 與考研 408 例題

在圖論的眾多算法中&#xff0c;Kruskal 算法以其簡潔高效的特性&#xff0c;成為求解最小生成樹&#xff08;Minimum Spanning Tree&#xff0c;MST&#xff09;的經典方法。無論是在通信網絡的優化設計、電路布線的成本控制&#xff0c;還是在計算機考研 408 的備考過程中&am…

Vue+Openlayers加載OSM、加載天地圖

文章目錄1. 介紹2. 加載底圖2.1 加載默認OSM地圖2.2 加載天地圖1. 介紹 Openlayers官網&#xff1a;https://openlayers.org/ 安裝依賴&#xff1a;npm i ol 2. 加載底圖 參考博客&#xff1a; vueopenlayers環境配置&#xff1a;https://blog.csdn.net/cuclife/article/det…

Python處理電子表格文件庫之pyexcel使用詳解

概要 pyexcel是一個功能強大的Python第三方庫,專門用于處理各種格式的電子表格文件。核心價值在于提供了統一的接口來讀取、寫入和操作Excel、CSV、ODS等多種電子表格格式,極大簡化了數據處理工作流程。與傳統的單一格式處理庫不同,pyexcel采用了插件化架構,使開發者能夠通…

【網絡安全】惡意 Python 包“psslib”仿冒 passlib,可導致 Windows 系統關閉

文章目錄惡意 Python 包“psslib”仿冒 passlib如何避免psslib的威脅惡意 Python 包“psslib”仿冒 passlib Socket 的威脅研究團隊發現了一個名為 psslib 的惡意 Python 包&#xff0c;旨在以提供密碼安全功能為幌子突然關閉 Windows 系統。 該軟件包由威脅行為者使用別名 u…

ai之對接電信ds后端服務,通過nginx代理轉發https為http,對外請求,保持到達第三方后請求頭不變

前置環境&#xff1a; 在微信小程序中嵌入H5頁面&#xff08;智能客服&#xff09;&#xff0c;需要讓h5頁面在https的域名服務器上。即通過 nginx 部署成web服務&#xff0c;還得配置域名和端口443訪問。電信的第三方deepseek服務 &#xff0c;只接收http請求&#xff0c;暫未…

第十四節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - Flask 后端 生產部署講解

Vben5 系列文章目錄 ?? 基礎篇 ? 第一節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 ? 第二節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - Python Flask 后端開發詳解(附源碼) ? 第三節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

Unity開發如何解決iOS閃退問題

一、iOS閃退常見原因及排查方法1. 內存問題&#xff08;最常見原因&#xff09; 癥狀表現&#xff1a; 設備發熱后閃退 加載大型場景時崩潰 控制臺出現EXC_RESOURCE RESOURCE_TYPE_MEMORY日志 解決方案&#xff1a; // 內存監控代碼 void Update() { Debug.Log($"內存使用…

【機器學習筆記 Ⅲ】5 強化學習

強化學習&#xff08;Reinforcement Learning, RL&#xff09; 強化學習是機器學習的一個分支&#xff0c;其核心思想是讓智能體&#xff08;Agent&#xff09;通過與環境&#xff08;Environment&#xff09;的交互學習最優策略&#xff08;Policy&#xff09;&#xff0c;以最…

pytorch深度學習-卷積神經網絡CNN-MNIST-gpu加速

一、為什么需要 CNN&#xff1f;從圖像識別的 “麻煩” 說起假設你想讓電腦識別一張圖片里有沒有貓。 如果用傳統神經網絡&#xff1a;一張 100100 的彩色圖片&#xff0c;有 100100330000 個像素點&#xff0c;每個像素點都是一個輸入神經元。傳統網絡需要每個輸入神經元和隱藏…

【阿里巴巴JAVA開發手冊】IDE的text file encoding設置為UTF-8; IDE中文件的換行符使用Unix格式,不要使用Windows格式。

問題&#xff1a;當使用 IDEA SSH 遠程開發時&#xff0c;SFTP 同步的 Windows 本地編輯的 config/plugin_config 文件文本內容中 “換行符”與 Unix、Linux 的文件文本內容換行符字符集不一致&#xff0c;導致 docker 容器中自定義 /opt/seatunnel/bin/install_plugin 在執行以…

自動駕駛ROS2應用技術詳解

自動駕駛ROS2應用技術詳解 目錄 自動駕駛ROS2節點工作流程自動駕駛感知融合技術詳解多傳感器數據同步技術詳解ROS2多節點協作與自動駕駛系統最小節點集 1. 自動駕駛ROS2節點工作流程 1.1 感知輸出Topic的后續處理 在自動駕駛系統中&#xff0c;感知節點輸出的各種Topic會被…

Redis底層實現原理之訂閱發布機制

文章目錄1. 通知類型2. 實現原理2.1 Pub/Sub2.1.1 基礎知識點2.1.2 頻道和訂閱者的存儲通知原理2.1.3 鍵空間通知2.1.4 客戶端消費2.1.5 缺陷2.2 Redis Stream2.2.1 基礎知識點2.2.2 基礎數據結構2.2.3 消費者組管理2.2.4 消息和消費者持久化2.2.5 消息生產和消費2.2.6 消費者拉…

【MATLAB代碼】AOA與TDOA混合定位例程,自適應基站數量,二維,可調節錨點數量。訂閱專欄后,可直接查看matlab源代碼

本文給出一個matlab代碼,用于在二維平面上,使用AOA的角度測量和TDOA的到達時間差的測量,來達到對未知點的精確定位。最后輸出定位示意圖、真實點坐標、僅AOA定位坐標與誤差、僅TDOA定位的坐標與誤差、AOA+TDOA混合定位的坐標與誤差。訂閱專欄后可直接查看源代碼,粘貼到MATL…

Node.js 所有主要版本的發布時間、穩定版本(Stable)和長期支持版本(LTS) 的整理

以下是 Node.js 所有主要版本的發布時間、穩定版本&#xff08;Stable&#xff09;和長期支持版本&#xff08;LTS&#xff09; 的整理&#xff0c;涵蓋從早期版本到當前最新版本的信息。 &#x1f4c5; Node.js 版本發布規律 每 6 個月發布一個新主版本&#xff08;偶數月&am…

【牛客刷題】小紅的v三元組

文章目錄 一、題目介紹1.1 題目描述1.2 輸入描述1.3 輸出描述1.4 示例二、解題思路2.1 核心算法設計2.2 性能優化關鍵2.3 算法流程圖三、算法實現四、算法分析4.1 時間復雜度4.2 空間復雜度4.3 正確性證明五、為什么選擇離散化+樹狀數組的解法?5.1 問題本質分析5.2 解法設計思…