Skip to content

Commit 7d036b4

Browse files
committed
feat: add v-model support for Konva components. close #201
1 parent 9dabd96 commit 7d036b4

File tree

6 files changed

+531
-4
lines changed

6 files changed

+531
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ npm-debug.log*
66
yarn-debug.log*
77
yarn-error.log*
88
coverage/
9+
.claude
910

1011
# Editor directories and files
1112
.idea

src/components/KonvaNode.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
VNode,
1111
} from 'vue';
1212
import type { Node } from 'konva/lib/Node';
13-
import { applyNodeProps, findParentKonva, updatePicture, checkOrder } from '../utils';
13+
import { applyNodeProps, findParentKonva, updatePicture, checkOrder, syncVModelBindings, VMODEL_NAMESPACE } from '../utils';
1414
import { KonvaNodeConstructor } from '../types';
1515

1616
const EVENTS_NAMESPACE = '.vue-konva-event';
@@ -78,17 +78,20 @@ export default function (componentName: string, NodeConstructor: KonvaNodeConstr
7878
if (parentKonvaNode && 'add' in parentKonvaNode)
7979
(parentKonvaNode as { add: (node: Node) => void }).add(__konvaNode);
8080
updatePicture(__konvaNode);
81+
syncVModelBindings(__konvaNode, instance);
8182
});
8283

8384
onUnmounted(() => {
8485
updatePicture(__konvaNode);
8586
__konvaNode.destroy();
8687
__konvaNode.off(EVENTS_NAMESPACE);
88+
__konvaNode.off(VMODEL_NAMESPACE);
8789
});
8890

8991
onUpdated(() => {
9092
uploadKonva();
9193
checkOrder(instance.subTree, __konvaNode);
94+
syncVModelBindings(__konvaNode, instance);
9295
});
9396

9497
watch(() => props.config, uploadKonva, { deep: true });

src/components/Stage.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from 'vue';
1313
import KonvaModule from 'konva';
1414
import type { StageConfig } from 'konva/lib/Stage';
15-
import { applyNodeProps, checkOrder } from '../utils';
15+
import { applyNodeProps, checkOrder, syncVModelBindings } from '../utils';
1616

1717
const Stage = (KonvaModule as any).default?.Stage || KonvaModule.Stage;
1818

@@ -78,11 +78,13 @@ export default defineComponent({
7878
}
7979
uploadKonva();
8080
validateChildren();
81+
syncVModelBindings(__konvaNode, instance);
8182
});
8283

8384
onUpdated(() => {
8485
uploadKonva();
8586
checkOrder(instance.subTree, __konvaNode);
87+
syncVModelBindings(__konvaNode, instance);
8688
});
8789

8890
onBeforeUnmount(() => {

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,4 @@ export function checkOrder(subTree: VNode, konvaNode: Node) {
8888
}
8989

9090
export { updatePicture, applyNodeProps };
91+
export { default as syncVModelBindings, VMODEL_NAMESPACE } from './syncVModelBindings';

src/utils/syncVModelBindings.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { ComponentInternalInstance } from 'vue';
2+
import type { Node } from 'konva/lib/Node';
3+
4+
export const VMODEL_NAMESPACE = '.vue-konva-vmodel';
5+
const UPDATE_PREFIX = 'onUpdate:';
6+
7+
export default function syncVModelBindings(
8+
konvaNode: Node,
9+
instance: ComponentInternalInstance,
10+
) {
11+
konvaNode.off(VMODEL_NAMESPACE);
12+
const vnodeProps = instance.vnode.props || {};
13+
for (const key in vnodeProps) {
14+
if (key.startsWith(UPDATE_PREFIX)) {
15+
const propName = key.slice(UPDATE_PREFIX.length);
16+
const handler = vnodeProps[key];
17+
konvaNode.on(`${propName}Change${VMODEL_NAMESPACE}`, () => {
18+
handler(konvaNode.getAttr(propName));
19+
});
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)