使用vue3 写法 拖拽节点成功后 配置当前节点自定义属性值
在 Vue3 中,当拖拽节点成功后配置自定义属性值,主要有两种方式:一种是在拖拽时通过 startDrag方法直接传入初始属性,另一种是在节点被添加到画布后通过事件监听来动态设置属性。下面是一个清晰的
在 Vue3 中更新 LogicFlow 节点名称有多种方式,下面我为你详细介绍几种常用方法。
updateText方法(推荐)这是最直接的方式,通过节点 ID 更新文本内容:
<template>
<div>
<div ref="container" style="width: 100%; height: 500px;"></div>
<button @click="updateNodeName">更新节点名称</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import LogicFlow from '@logicflow/core';
import '@logicflow/core/dist/style/index.css';
const container = ref(null);
const lf = ref(null);
const selectedNodeId = ref('');
onMounted(() => {
lf.value = new LogicFlow({
container: container.value,
grid: true,
});
// 示例数据
lf.value.render({
nodes: [
{
id: 'node_1',
type: 'rect',
x: 100,
y: 100,
text: '原始名称'
}
]
});
// 监听节点点击,获取选中节点ID
lf.value.on('node:click', ({ data }) => {
selectedNodeId.value = data.id;
});
});
// 更新节点名称
const updateNodeName = () => {
if (!selectedNodeId.value) {
alert('请先点击选择一个节点');
return;
}
const newName = prompt('请输入新的节点名称', '新名称');
if (newName) {
// 使用 updateText 方法更新节点文本
lf.value.updateText(selectedNodeId.value, newName);
}
};
</script>
setProperties方法更新这种方法可以同时更新文本和其他属性:
// 更新节点属性,包括名称
const updateNodeWithProperties = () => {
if (!selectedNodeId.value) return;
const newNodeName = '更新后的节点名称';
// 获取节点当前属性
const nodeModel = lf.value.getNodeModelById(selectedNodeId.value);
const currentProperties = nodeModel.properties || {};
// 更新属性
lf.value.setProperties(selectedNodeId.value, {
...currentProperties,
nodeName: newNodeName,
updatedAt: new Date().toISOString()
});
// 同时更新显示文本
lf.value.updateText(selectedNodeId.value, newNodeName);
};
实现双击节点直接进入编辑模式:
// 监听双击事件
lf.value.on('node:dblclick', ({ data }) => {
const currentNode = lf.value.getNodeModelById(data.id);
const currentText = currentNode.text?.value || '';
const newText = prompt('编辑节点名称:', currentText);
if (newText !== null) {
lf.value.updateText(data.id, newText);
}
});
结合 Menu 插件实现右键菜单编辑:
import { Menu } from '@logicflow/extension';
import '@logicflow/extension/lib/style/index.css';
// 初始化时注册菜单插件
lf.value = new LogicFlow({
container: container.value,
plugins: [Menu],
});
// 配置右键菜单
lf.value.extension.menu.setMenuConfig({
nodeMenu: [
{
text: '编辑名称',
callback: (node) => {
const currentText = node.text || '';
const newText = prompt('编辑节点名称:', currentText);
if (newText) {
lf.value.updateText(node.id, newText);
}
}
},
{
text: '删除',
callback: (node) => {
lf.value.deleteNode(node.id);
}
}
]
});
对于自定义节点,可以重写文本相关方法:
import { RectNode, RectNodeModel } from '@logicflow/core';
class CustomNodeModel extends RectNodeModel {
// 自定义文本样式
getTextStyle() {
const style = super.getTextStyle();
return {
...style,
fontSize: 14,
fontWeight: 'bold',
fill: '#1e40af',
};
}
// 初始化节点数据
initNodeData(data) {
super.initNodeData(data);
// 确保文本格式正确
this.text = {
x: data.x,
y: data.y + this.height / 2 + 10,
value: data.text || '默认节点'
};
}
}
// 注册自定义节点
lf.value.register({
type: 'custom-node',
view: RectNode,
model: CustomNodeModel
});
// 批量更新所有节点名称
const batchUpdateNodeNames = () => {
const graphData = lf.value.getGraphData();
const updatedNodes = graphData.nodes.map(node => ({
...node,
text: `${node.text}(已更新)`
}));
// 重新渲染
lf.value.render({
nodes: updatedNodes,
edges: graphData.edges
});
};
// 按条件更新节点
const updateNodesByCondition = () => {
const graphData = lf.value.getGraphData();
const updatedNodes = graphData.nodes.map(node => {
if (node.type === 'rect') {
return {
...node,
text: `矩形节点-${node.id}`
};
}
return node;
});
lf.value.render({
nodes: updatedNodes,
edges: graphData.edges
});
};
// 监听文本变化并自动保存
lf.value.on('node:text-update', ({ data }) => {
console.log('节点文本已更新:', data);
saveToBackend(lf.value.getGraphData());
});
// 实现撤销重做功能
const undo = () => {
lf.value.undo();
};
const redo = () => {
lf.value.redo();
};
// 启用历史记录
lf.value = new LogicFlow({
container: container.value,
grid: true,
history: true, // 启用历史记录
historySize: 100 // 设置历史记录大小
});
{value: '文本', x: 100, y: 100}
lf.render()之后再进行更新操作// 安全的更新函数
const safeUpdateNodeName = (nodeId, newName) => {
if (!lf.value) {
console.error('LogicFlow 实例未初始化');
return false;
}
const nodeModel = lf.value.getNodeModelById(nodeId);
if (!nodeModel) {
console.error(`节点 ${nodeId} 不存在`);
return false;
}
try {
lf.value.updateText(nodeId, newName);
return true;
} catch (error) {
console.error('更新节点名称失败:', error);
return false;
}
};
这些方法涵盖了 Vue3 中 LogicFlow 节点名称更新的主要场景,你可以根据具体需求选择合适的方式。
// 方法1: 使用filter保留奇数下标元素
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// 删除偶数下标(0, 2, 4, 6, 8...),保留奇数下标
const result1 = arr.filter((_, index) => index % 2 !== 0);
console.log(result1); // [1, 3, 5, 7, 9]
// 或删除奇数下标,保留偶数下标
const result2 = arr.filter((_, index) => index % 2 === 0);
console.log(result2); // [0, 2, 4, 6, 8]
// 方法2: 从后向前遍历,原地删除
function removeEvenIndexes(arr) {
// 从后向前遍历,避免索引错乱
for (let i = arr.length - 1; i >= 0; i--) {
if (i % 2 === 0) { // 删除偶数下标
arr.splice(i, 1);
}
}
return arr;
}
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(removeEvenIndexes(arr)); // [1, 3, 5, 7, 9]
console.log(arr); // 原数组也被修改
// 方法3: 使用reduce
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = arr.reduce((acc, cur, index) => {
if (index % 2 !== 0) { // 只保留奇数下标
acc.push(cur);
}
return acc;
}, []);
console.log(result); // [1, 3, 5, 7, 9]
// 方法4: 遍历奇数下标创建新数组
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function removeEvenIndexes(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (i % 2 !== 0) { // 只取奇数下标
result.push(arr[i]);
}
}
return result;
}
console.log(removeEvenIndexes(arr)); // [1, 3, 5, 7, 9]
// 方法5: 使用while循环
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function removeEvenIndexes(arr) {
let i = 0;
while (i < arr.length) {
if (i % 2 === 0) { // 删除偶数下标
arr.splice(i, 1);
} else {
i++; // 只有不删除时才递增
}
}
return arr;
}
console.log(removeEvenIndexes(arr)); // [1, 3, 5, 7, 9]
// 方法6: 高性能版本,避免splice
function removeEvenIndexesOptimized(arr) {
const result = [];
const length = arr.length;
// 从第一个奇数下标开始,步长为2
for (let i = 1; i < length; i += 2) {
result.push(arr[i]);
}
return result;
}
// 测试大数据量
const largeArr = Array.from({ length: 1000000 }, (_, i) => i);
console.time('优化版');
const optimizedResult = removeEvenIndexesOptimized(largeArr);
console.timeEnd('优化版'); // 大约 5-10ms
console.log('结果长度:', optimizedResult.length); // 500000
function removeEvenIndexesInPlace(arr) {
let writeIndex = 0;
for (let readIndex = 0; readIndex < arr.length; readIndex++) {
if (readIndex % 2 !== 0) { // 只保留奇数下标
arr[writeIndex] = arr[readIndex];
writeIndex++;
}
}
// 截断数组
arr.length = writeIndex;
return arr;
}
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(removeEvenIndexesInPlace(arr)); // [1, 3, 5, 7, 9]
console.log(arr); // 原数组被修改
<template>
<div>
<h3>原始数组: {{ originalArray }}</h3>
<h3>处理后: {{ processedArray }}</h3>
<button @click="processArray">删除偶数下标</button>
<button @click="resetArray">重置数组</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 原始响应式数组
const originalArray = ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
// 计算属性:删除偶数下标
const processedArray = computed(() => {
return originalArray.value.filter((_, index) => index % 2 !== 0)
})
// 方法处理
const processArray = () => {
// 方法1: 创建新数组(推荐,不修改原数组)
originalArray.value = originalArray.value.filter((_, index) => index % 2 !== 0)
// 方法2: 原地修改(会触发响应式更新)
// let writeIndex = 0
// for (let i = 0; i < originalArray.value.length; i++) {
// if (i % 2 !== 0) {
// originalArray.value[writeIndex] = originalArray.value[i]
// writeIndex++
// }
// }
// originalArray.value.length = writeIndex
}
const resetArray = () => {
originalArray.value = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}
</script>
// 工具函数集合
const ArrayUtils = {
/**
* 删除偶数下标元素
* @param {Array} arr - 输入数组
* @param {boolean} inPlace - 是否原地修改
* @returns {Array} 处理后的数组
*/
removeEvenIndexes: function(arr, inPlace = false) {
if (!Array.isArray(arr)) {
throw new TypeError('输入必须是数组')
}
if (inPlace) {
return this._removeEvenIndexesInPlace(arr)
} else {
return this._removeEvenIndexesNew(arr)
}
},
/**
* 创建新数组(不修改原数组)
*/
_removeEvenIndexesNew: function(arr) {
return arr.filter((_, index) => index % 2 !== 0)
},
/**
* 原地修改
*/
_removeEvenIndexesInPlace: function(arr) {
let writeIndex = 0
for (let i = 0; i < arr.length; i++) {
if (i % 2 !== 0) {
arr[writeIndex] = arr[i]
writeIndex++
}
}
arr.length = writeIndex
return arr
},
/**
* 删除奇数下标元素
*/
removeOddIndexes: function(arr, inPlace = false) {
if (inPlace) {
let writeIndex = 0
for (let i = 0; i < arr.length; i++) {
if (i % 2 === 0) {
arr[writeIndex] = arr[i]
writeIndex++
}
}
arr.length = writeIndex
return arr
} else {
return arr.filter((_, index) => index % 2 === 0)
}
},
/**
* 删除指定下标的元素
* @param {Array} arr - 输入数组
* @param {Function} condition - 条件函数,返回true则删除
*/
removeByIndexCondition: function(arr, condition, inPlace = false) {
if (inPlace) {
let writeIndex = 0
for (let i = 0; i < arr.length; i++) {
if (!condition(i)) {
arr[writeIndex] = arr[i]
writeIndex++
}
}
arr.length = writeIndex
return arr
} else {
return arr.filter((_, index) => !condition(index))
}
}
}
// 使用示例
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// 删除偶数下标
console.log(ArrayUtils.removeEvenIndexes(arr)) // [1, 3, 5, 7, 9]
console.log(arr) // 原数组不变 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// 原地修改
console.log(ArrayUtils.removeEvenIndexes(arr, true)) // [1, 3, 5, 7, 9]
console.log(arr) // 原数组被修改 [1, 3, 5, 7, 9]
// 删除奇数下标
const arr2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(ArrayUtils.removeOddIndexes(arr2)) // [0, 2, 4, 6, 8]
// 自定义条件
const arr3 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(ArrayUtils.removeByIndexCondition(
arr3,
index => index % 3 === 0
)) // 删除下标是3的倍数的元素
// 使用生成器函数
function* filterByIndex(arr, condition) {
for (let i = 0; i < arr.length; i++) {
if (condition(i)) {
yield arr[i]
}
}
}
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
const result = [...filterByIndex(arr, i => i % 2 !== 0)]
console.log(result) // [1, 3, 5, 7, 9]
// 使用箭头函数和三元运算符
const removeEvenIndexes = arr => arr.filter((_, i) => i % 2 ? arr[i] : null).filter(Boolean)
// 使用位运算(性能更好)
const removeEvenIndexesBit = arr => {
const result = []
for (let i = 1; i < arr.length; i += 2) {
result.push(arr[i])
}
return result
}
// 使用 Array.from
const removeEvenIndexesFrom = arr =>
Array.from(
{ length: Math.ceil(arr.length / 2) },
(_, i) => arr[i * 2 + 1]
).filter(Boolean)
// TypeScript 类型安全的版本
class ArrayProcessor {
/**
* 删除偶数下标元素
* @param arr 输入数组
* @param inPlace 是否原地修改
* @returns 处理后的数组
*/
static removeEvenIndexes<T>(arr: T[], inPlace: boolean = false): T[] {
if (inPlace) {
return this.removeEvenIndexesInPlace(arr)
} else {
return this.removeEvenIndexesNew(arr)
}
}
private static removeEvenIndexesNew<T>(arr: T[]): T[] {
return arr.filter((_, index) => index % 2 !== 0)
}
private static removeEvenIndexesInPlace<T>(arr: T[]): T[] {
let writeIndex = 0
for (let i = 0; i < arr.length; i++) {
if (i % 2 !== 0) {
arr[writeIndex] = arr[i]
writeIndex++
}
}
arr.length = writeIndex
return arr
}
/**
* 泛型方法:根据下标条件过滤数组
*/
static filterByIndex<T>(
arr: T[],
predicate: (index: number) => boolean
): T[] {
return arr.filter((_, index) => predicate(index))
}
}
// 使用示例
const numbers: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
const strings: string[] = ['a', 'b', 'c', 'd', 'e', 'f']
console.log(ArrayProcessor.removeEvenIndexes(numbers)) // [1, 3, 5, 7, 9]
console.log(ArrayProcessor.filterByIndex(strings, i => i % 2 === 0)) // ['a', 'c', 'e']
// 性能测试
function testPerformance() {
const largeArray = Array.from({ length: 1000000 }, (_, i) => i)
// 测试 filter 方法
console.time('filter')
const result1 = largeArray.filter((_, i) => i % 2 !== 0)
console.timeEnd('filter')
// 测试 for 循环
console.time('for loop')
const result2 = []
for (let i = 1; i < largeArray.length; i += 2) {
result2.push(largeArray[i])
}
console.timeEnd('for loop')
// 测试 while 循环
console.time('while loop')
const arrCopy = [...largeArray]
let i = 0
while (i < arrCopy.length) {
if (i % 2 === 0) {
arrCopy.splice(i, 1)
} else {
i++
}
}
console.timeEnd('while loop')
// 测试 reduce
console.time('reduce')
const result4 = largeArray.reduce((acc, cur, i) => {
if (i % 2 !== 0) acc.push(cur)
return acc
}, [])
console.timeEnd('reduce')
}
testPerformance()
// 结果通常: for loop 最快, filter 次之, reduce 较慢, while+splice 最慢
最简洁:filter方法
arr.filter((_, i) => i % 2 !== 0)
最高性能:for循环
const result = []
for (let i = 1; i < arr.length; i += 2) {
result.push(arr[i])
}
原地修改:使用写指针
let writeIndex = 0
for (let i = 0; i < arr.length; i++) {
if (i % 2 !== 0) {
arr[writeIndex] = arr[i]
writeIndex++
}
}
arr.length = writeIndex
splice会改变数组长度,容易出错splice和 filter链式调用i % 2 === 0
i % 3 === 0删除3的倍数下标i >= 2 && i <= 5
**