refactor(nodes): reduce nodewrapper re-render
# What's changed? * use v-model for computed pos * remove computed from style and class getters
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { useVueFlow, useDrag } from '../../composables'
|
||||
import { NodeComponent, SnapGrid } from '../../types'
|
||||
import { NodeComponent, SnapGrid, XYZPosition } from '../../types'
|
||||
import { NodeId } from '../../context'
|
||||
import { getConnectedEdges, getHandleBounds, getXYZPos } from '../../utils'
|
||||
|
||||
const { id, type, name, draggable, selectable, connectable, snapGrid } = defineProps<{
|
||||
const { id, type, name, draggable, selectable, connectable, snapGrid, ...props } = defineProps<{
|
||||
id: string
|
||||
modelValue: XYZPosition
|
||||
draggable: boolean
|
||||
selectable: boolean
|
||||
connectable: boolean
|
||||
@@ -15,6 +15,11 @@ const { id, type, name, draggable, selectable, connectable, snapGrid } = defineP
|
||||
name: string
|
||||
}>()
|
||||
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
let computedPosition = $(useVModel(props, 'modelValue', emit))
|
||||
|
||||
provide(NodeId, id)
|
||||
|
||||
const {
|
||||
@@ -95,7 +100,7 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => observer.stop())
|
||||
|
||||
watch(
|
||||
[() => node.position, () => parentNode?.computedPosition, () => node.selected, () => parentNode?.selected],
|
||||
[() => node.position, () => parentNode?.computedPosition],
|
||||
([pos, parent]) => {
|
||||
const xyzPos = {
|
||||
...pos,
|
||||
@@ -103,14 +108,14 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
node.computedPosition = getXYZPos(parent, xyzPos)
|
||||
computedPosition = getXYZPos(parent, xyzPos)
|
||||
} else {
|
||||
node.computedPosition = xyzPos
|
||||
computedPosition = xyzPos
|
||||
}
|
||||
|
||||
node.handleBounds = getHandleBounds(nodeElement.value, viewport.zoom)
|
||||
},
|
||||
{ deep: true, flush: 'post' },
|
||||
{ immediate: true, deep: true, flush: 'post' },
|
||||
)
|
||||
})
|
||||
|
||||
@@ -160,35 +165,19 @@ const onSelectNode = (event: MouseEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getClass = computed(() => {
|
||||
const extraClass = node.class instanceof Function ? node.class(node) : node.class
|
||||
return [
|
||||
'vue-flow__node',
|
||||
`vue-flow__node-${name}`,
|
||||
noPanClassName,
|
||||
{
|
||||
dragging,
|
||||
selected: node.selected,
|
||||
selectable,
|
||||
},
|
||||
extraClass,
|
||||
]
|
||||
})
|
||||
const getClass = () => {
|
||||
return node.class instanceof Function ? node.class(node) : node.class
|
||||
}
|
||||
|
||||
const getStyle = computed(() => {
|
||||
const getStyle = () => {
|
||||
const styles = (node.style instanceof Function ? node.style(node) : node.style) || {}
|
||||
const width = node.width instanceof Function ? node.width(node) : node.width
|
||||
const height = node.height instanceof Function ? node.height(node) : node.height
|
||||
if (width) styles.width = typeof width === 'string' ? width : `${width}px`
|
||||
if (height) styles.height = typeof height === 'string' ? height : `${height}px`
|
||||
|
||||
return {
|
||||
zIndex: node.computedPosition.z,
|
||||
transform: `translate(${node.computedPosition.x}px,${node.computedPosition.y}px)`,
|
||||
pointerEvents: selectable || draggable ? 'all' : 'none',
|
||||
...styles,
|
||||
} as CSSProperties
|
||||
})
|
||||
return styles
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -201,8 +190,23 @@ export default {
|
||||
<template>
|
||||
<div
|
||||
ref="nodeElement"
|
||||
:class="getClass"
|
||||
:style="getStyle"
|
||||
:class="[
|
||||
'vue-flow__node',
|
||||
`vue-flow__node-${name}`,
|
||||
noPanClassName,
|
||||
{
|
||||
dragging,
|
||||
selected: node.selected,
|
||||
selectable,
|
||||
},
|
||||
getClass(),
|
||||
]"
|
||||
:style="{
|
||||
zIndex: node.computedPosition.z ? node.computedPosition.z : node.selected ? 1000 : 0,
|
||||
transform: `translate(${node.computedPosition.x}px,${node.computedPosition.y}px)`,
|
||||
pointerEvents: selectable || draggable ? 'all' : 'none',
|
||||
...getStyle(),
|
||||
}"
|
||||
:data-id="node.id"
|
||||
@mouseenter="onMouseEnter"
|
||||
@mousemove="onMouseMove"
|
||||
|
||||
@@ -23,9 +23,9 @@ const selectable = (s?: boolean) => (typeof s === 'undefined' ? elementsSelectab
|
||||
const connectable = (c?: boolean) => (typeof c === 'undefined' ? nodesConnectable : c)
|
||||
const hasSnapGrid = (sg?: SnapGrid) => (sg ?? snapToGrid ? snapGrid : undefined)
|
||||
|
||||
const getType = (node: GraphNode) => {
|
||||
const name = node.type || 'default'
|
||||
let nodeType = node.template ?? getNodeTypes[name]
|
||||
const getType = (type?: string, template?: GraphNode['template']) => {
|
||||
const name = type || 'default'
|
||||
let nodeType = template ?? getNodeTypes[name]
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
if (typeof nodeType === 'string') {
|
||||
@@ -40,7 +40,7 @@ const getType = (node: GraphNode) => {
|
||||
|
||||
const slot = slots?.[`node-${name}`]
|
||||
if (!slot?.({})) {
|
||||
console.warn(`[vueflow]: Node type "${node.type}" not found and no node-slot detected. Using fallback type "default".`)
|
||||
console.warn(`[vueflow]: Node type "${type}" not found and no node-slot detected. Using fallback type "default".`)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ export default {
|
||||
v-for="node of getNodes"
|
||||
:id="node.id"
|
||||
:key="node.id"
|
||||
:type="getType(node)"
|
||||
v-model="node.computedPosition"
|
||||
:type="getType(node.type, node.template)"
|
||||
:name="node.type || 'default'"
|
||||
:draggable="draggable(node.draggable)"
|
||||
:selectable="selectable(node.selectable)"
|
||||
|
||||
Reference in New Issue
Block a user