一份用于日常开发的 React Konva 核心语法速查表,涵盖画布搭建、图形绘制、事件处理、拖拽交互等常用场景。
核心层级关系与作用
Stage(舞台) :应用的最顶层根容器,所有内容的入口-1-4。Layer(图层) :Stage 下的直接子级,可看作是一张透明的"画布"。这是承载图形和进行性能优化的基本单位 ,也是事件检测的边界-1-9。Group(组) :这是图层下的一个逻辑容器 ,用于将多个Shape(图形)或其他Group组合在一起-2-5。Shape(图形) :实际绘制的图形元素,如Rect、Circle、Line、Text等-3-4。它们是构成画面的"原子"。
js
import React from 'react';
import { Stage, Layer, Group, Rect, Circle, Text } from 'react-konva';
function KonvaDemo() {
return (
{/* 第1层:Stage - 整个画布(展示墙) */}
<Stage width={800} height={500} style={{ background: '#f0f0f0' }}>
{/* 第2层:Layer - 透明图层(亚克力板) */}
<Layer>
{/* 背景装饰图形(直接在Layer下) */}
<Rect x={0} y={0} width={800} height={500} fill="#fafafa" />
<Text x={20} y={20} text="Stage → Layer → Group → Shape" fontSize={18} fill="#333" />
{/* 第3层:Group - 逻辑分组(磁力贴组合) */}
<Group x={50} y={80} draggable>
{/* 第4层:Shape - 具体图形(磁力贴) */}
<Rect
x={0}
y={0}
width={150}
height={100}
fill="#4A90D9"
cornerRadius={8}
shadowColor="rgba(0,0,0,0.2)"
shadowBlur={10}
/>
<Circle x={75} y={50} radius={30} fill="#FF6B6B" />
<Text x={50} y={40} text="组" fontSize={16} fill="white" />
</Group>
{/* 第3层:另一个Group - 独立的组合 */}
<Group x={300} y={120} draggable>
<Rect
x={0}
y={0}
width={200}
height={120}
fill="#2ECC71"
cornerRadius={8}
shadowColor="rgba(0,0,0,0.2)"
shadowBlur={10}
/>
<Circle x={60} y={60} radius={40} fill="#F39C12" />
<Circle x={140} y={60} radius={40} fill="#E74C3C" />
<Text x={40} y={100} text="另一个组" fontSize={14} fill="white" />
</Group>
{/* 第3层:嵌套Group - 组合里套组合 */}
<Group x={50} y={280}>
<Rect
x={0}
y={0}
width={450}
height={150}
fill="#F8F9FA"
stroke="#DEE2E6"
strokeWidth={2}
cornerRadius={12}
/>
<Text x={20} y={15} text="嵌套 Group 示例" fontSize={16} fill="#333" />
{/* 内层Group 1 */}
<Group x={30} y={50}>
<Rect x={0} y={0} width={100} height={70} fill="#E3F2FD" cornerRadius={6} />
<Text x={20} y={28} text="子组1" fontSize={14} fill="#1565C0" />
</Group>
{/* 内层Group 2 */}
<Group x={160} y={50}>
<Rect x={0} y={0} width={100} height={70} fill="#FCE4EC" cornerRadius={6} />
<Text x={20} y={28} text="子组2" fontSize={14} fill="#C62828" />
</Group>
{/* 内层Group 3 */}
<Group x={290} y={50}>
<Rect x={0} y={0} width={100} height={70} fill="#E8F5E9" cornerRadius={6} />
<Text x={20} y={28} text="子组3" fontSize={14} fill="#2E7D32" />
</Group>
</Group>
</Layer>
</Stage>
);
}
export default KonvaDemo;
一、快速上手
1.1 安装
js
npm install react-konva konva --save
1.2 最简示例
js
import React from 'react';
import { Stage, Layer, Rect, Text } from 'react-konva';
function App() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Text text="Hello Canvas" fontSize={20} x={10} y={10} />
<Rect x={20} y={50} width={100} height={100} fill="red" />
</Layer>
</Stage>
);
}
export default App;
核心概念:Stage 是画布容器(相当于
div),Layer 是实际画布层(相当于canvas元素),图形组件放在 Layer 内部 -1-8。
二、常用图形组件
| 组件名 | 说明 | 核心属性 |
|---|---|---|
Rect |
矩形 | x, y, width, height, fill, stroke, cornerRadius |
Circle |
圆形 | x, y, radius, fill, stroke |
Ellipse |
椭圆 | x, y, radiusX, radiusY, fill |
Line |
线条/多边形 | points={[x1,y1,x2,y2,...]}, closed, fill, stroke, tension |
Text |
文字 | x, y, text, fontSize, fontFamily, fill |
Image |
图片 | image, x, y, width, height |
Path |
SVG路径 | data="M...Z", fill, stroke |
RegularPolygon |
正多边形 | x, y, sides, radius, fill |
Star |
星形 | x, y, numPoints, innerRadius, outerRadius |
Label / Tag |
标签组合 | 用于带背景的文字标签 |
所有 react-konva 组件与 Konva 组件同名,属性也一一对应 -1-4。
基础图形示例
js
import { Stage, Layer, Rect, Circle, Line, Text } from 'react-konva';
function ShapesDemo() {
return (
<Stage width={600} height={400}>
<Layer>
<Text text="基础图形示例" fontSize={18} x={10} y={10} fill="#333" />
{/* 矩形 */}
<Rect x={20} y={50} width={100} height={80} fill="#00D2FF" stroke="black" strokeWidth={2} cornerRadius={8} />
{/* 圆形 */}
<Circle x={200} y={90} radius={40} fill="green" stroke="black" strokeWidth={2} />
{/* 多边形(三角形) */}
<Line x={280} y={50} points={[0, 0, 60, 80, -60, 80]} closed fill="orange" stroke="black" strokeWidth={2} />
</Layer>
</Stage>
);
}
三、事件处理
react-konva 支持所有 Konva 事件,事件名加 on 前缀即可,如 onClick、onMouseOver、onDragEnd -2-6。
3.1 鼠标事件
| 事件 | 说明 |
|---|---|
onClick |
单击 |
onDblClick |
双击 |
onMouseOver / onMouseOut |
悬停进入/离开 |
onMouseDown / onMouseUp |
按下/释放 |
onMouseMove |
鼠标移动 |
3.2 触摸事件
| 事件 | 说明 |
|---|---|
onTouchStart / onTouchEnd |
触摸开始/结束 |
onTap / onDblTap |
轻击/双击 |
3.3 事件示例
js
import { useState } from 'react';
import { Stage, Layer, Rect, Text } from 'react-konva';
function EventDemo() {
const [msg, setMsg] = useState('悬停或点击图形试试');
return (
<Stage width={600} height={300}>
<Layer>
<Text text={msg} x={10} y={10} fontSize={16} fill="#333" />
<Rect
x={50}
y={60}
width={120}
height={80}
fill="#00D2FF"
stroke="black"
strokeWidth={2}
onClick={() => setMsg('点击了矩形!')}
onMouseOver={() => setMsg('鼠标进入矩形')}
onMouseOut={() => setMsg('鼠标离开矩形')}
/>
<Circle
x={280}
y={100}
radius={45}
fill="red"
stroke="black"
strokeWidth={2}
onClick={() => setMsg('点击了圆形!')}
onMouseOver={() => setMsg('鼠标进入圆形')}
onMouseOut={() => setMsg('鼠标离开圆形')}
/>
</Layer>
</Stage>
);
}
四、拖拽交互
4.1 基础拖拽
给任意图形添加 draggable 属性即可拖拽:
js
<Rect
x={50}
y={50}
width={100}
height={80}
fill="blue"
draggable
onDragStart={() => console.log('开始拖拽')}
onDragMove={(e) => console.log('位置:', e.target.x(), e.target.y())}
onDragEnd={(e) => console.log('拖拽结束:', e.target.x(), e.target.y())}
/>
4.2 使用 ref 获取 Konva 实例
通过 ref 可以获取图形或 Stage 的原生 Konva 实例,调用其方法 -1-2。
js
import { useRef, useEffect } from 'react';
import { Stage, Layer, Circle } from 'react-konva';
function RefDemo() {
const circleRef = useRef(null);
const stageRef = useRef(null);
useEffect(() => {
// 获取 Konva 实例
console.log(circleRef.current); // Konva.Circle 实例
// 获取鼠标位置
const pos = stageRef.current?.getPointerPosition();
console.log('鼠标位置:', pos);
}, []);
return (
<Stage ref={stageRef} width={600} height={400}>
<Layer>
<Circle ref={circleRef} x={200} y={150} radius={50} fill="green" draggable />
</Layer>
</Stage>
);
}
4.3 组内任意位置拖拽
如果想让 Group 内的任意位置点击都能拖拽整个组,可以使用透明背景矩形 + startDrag() 方法 -11:
js
import { useRef } from 'react';
import { Group, Rect, Circle, Text } from 'react-konva';
function DraggableGroup() {
const groupRef = useRef(null);
return (
<Group ref={groupRef}>
{/* 透明背景:点击任何位置都可拖拽 */}
<Rect
width={200}
height={150}
fill="transparent"
draggable
onDragStart={() => groupRef.current.startDrag()}
/>
<Rect x={10} y={10} width={180} height={50} fill="#4A90D9" cornerRadius={5} />
<Text text="点击任意位置拖拽" x={20} y={25} fill="white" fontSize={14} />
<Circle x={100} y={110} radius={20} fill="#FF6B6B" />
</Group>
);
}
4.4 Stage 整体拖拽(中键/右键)
通过 dragButtons 配置可以指定用哪个鼠标按键拖拽画布 -9:
js
// 鼠标中键拖拽画布
<Stage
width={window.innerWidth}
height={window.innerHeight}
draggable={true}
dragButtons={[1]} // 1 = 中键
>
{/* 内容 */}
</Stage>
按键对应关系:0 = 左键,1 = 中键,2 = 右键 -9。
五、高级图形绘制
5.1 自定义形状(Shape)
当内置形状无法满足需求时,可以使用 Shape 组件配合 sceneFunc 自定义绘制逻辑 -10:
js
import { Stage, Layer, Shape } from 'react-konva';
function CustomShape() {
return (
<Stage width={600} height={400}>
<Layer>
<Shape
x={100}
y={50}
width={200}
height={150}
fill="#FF6B6B"
stroke="black"
strokeWidth={2}
sceneFunc={(context, shape) => {
context.beginPath();
// 绘制箭头形状
context.moveTo(0, shape.height() / 2);
context.lineTo(shape.width() - 30, shape.height() / 2);
context.lineTo(shape.width() - 30, 0);
context.lineTo(shape.width(), shape.height() / 2);
context.lineTo(shape.width() - 30, shape.height());
context.lineTo(shape.width() - 30, shape.height() / 2);
context.closePath();
// 由 Konva 处理填充和描边
context.fillStrokeShape(shape);
}}
/>
</Layer>
</Stage>
);
}
5.2 路径图形(Path)
使用 SVG 路径语法绘制复杂图形:
js
import { Stage, Layer, Path } from 'react-konva';
function PathDemo() {
return (
<Stage width={600} height={400}>
<Layer>
{/* SVG 路径语法:M=移动, L=直线, C=贝塞尔曲线, Z=闭合 */}
<Path
data="M50,50 C100,20 150,80 200,50 L180,150 Z"
fill="#4A90D9"
stroke="black"
strokeWidth={2}
/>
</Layer>
</Stage>
);
}
六、状态管理与数据驱动
react-konva 的优势在于可以用 React 的 state 驱动图形变化:
js
import { useState } from 'react';
import { Stage, Layer, Rect, Text } from 'react-konva';
import Konva from 'konva';
function StateDrivenDemo() {
const [color, setColor] = useState('#00D2FF');
const [position, setPosition] = useState({ x: 50, y: 50 });
const [size, setSize] = useState({ width: 120, height: 80 });
const randomColor = () => {
setColor(Konva.Util.getRandomColor());
};
const handleDragEnd = (e) => {
setPosition({ x: e.target.x(), y: e.target.y() });
};
return (
<Stage width={600} height={400}>
<Layer>
<Text text="点击矩形变色,拖拽后位置会记录" x={10} y={10} fontSize={14} />
<Rect
x={position.x}
y={position.y}
width={size.width}
height={size.height}
fill={color}
stroke="black"
strokeWidth={2}
draggable
onClick={randomColor}
onDragEnd={handleDragEnd}
/>
<Text text={`位置: (${Math.round(position.x)}, ${Math.round(position.y)})`} x={10} y={360} fontSize={14} />
</Layer>
</Stage>
);
}
七、图片加载与渲染
7.1 使用 Konva.Image 加载图片
js
import { useState, useEffect } from 'react';
import { Stage, Layer, Image } from 'react-konva';
function ImageDemo() {
const [image, setImage] = useState(null);
useEffect(() => {
const img = new window.Image();
img.src = 'https://example.com/image.png';
img.onload = () => setImage(img);
}, []);
return (
<Stage width={600} height={400}>
<Layer>
{image && (
<Image
image={image}
x={50}
y={50}
width={200}
height={150}
draggable
/>
)}
</Layer>
</Stage>
);
}
7.2 使用 useImage Hook(需安装 react-konva-utils)
npm install react-konva-utils
js
import { useImage } from 'react-konva-utils';
import { Stage, Layer, Image } from 'react-konva';
function ImageWithHook() {
const [image] = useImage('https://example.com/image.png');
return (
<Stage width={600} height={400}>
<Layer>
{image && <Image image={image} x={50} y={50} width={200} height={150} draggable />}
</Layer>
</Stage>
);
}
八、严格模式(Strict Mode)
默认情况下 react-konva 以非严格模式 运行:用户交互(如拖拽)修改的属性不会被 render 覆盖 -1-2。
js
// 全局开启严格模式
import { useStrictMode } from 'react-konva';
useStrictMode(true);
// 或仅对单个组件开启
<Rect x={20} y={50} width={100} height={100} fill="red" _useStrictMode />
何时使用:如果需要 render 中的属性强制覆盖用户交互结果(如游戏中的位置重置),开启严格模式。
九、Next.js 使用注意事项
react-konva 仅客户端运行,在 Next.js 中需避免服务端渲染 -2:
js
'use client';
import dynamic from 'next/dynamic';
const Canvas = dynamic(() => import('../components/Canvas'), {
ssr: false,
});
export default function Page() {
return <Canvas />;
}
十、与 DOM 元素的交互
react-konva-utils 提供了 Html 组件,可在 Canvas 上层叠加 DOM 元素 -5:
js
import { Html } from 'react-konva-utils';
<Stage width={600} height={400}>
<Layer>
<Rect x={50} y={50} width={100} height={100} fill="blue" />
<Html>
<div style={{ position: 'absolute', top: 180, left: 50, background: 'white', padding: 8, borderRadius: 4 }}>
这是 DOM 元素
</div>
</Html>
</Layer>
</Stage>
十一、快速检查清单
| 场景 | 用法 |
|---|---|
| 创建画布 | <Stage> + <Layer> |
| 绘制矩形 | <Rect x={} y={} width={} height={} fill={} /> |
| 绘制圆形 | <Circle x={} y={} radius={} fill={} /> |
| 绘制线条/多边形 | <Line points={[]} closed fill={} /> |
| 显示文字 | <Text text={} fontSize={} /> |
| 显示图片 | <Image image={} x={} y={} /> |
| 点击事件 | onClick={handler} |
| 悬停事件 | onMouseOver={handler} / onMouseOut={handler} |
| 拖拽 | draggable + onDragEnd |
| 获取 Konva 实例 | ref={ref} |
| 自定义形状 | <Shape sceneFunc={...} /> |
| 获取鼠标位置 | stageRef.current.getPointerPosition() |
十二、常用命令
bash
复制
下载
bash
# 安装
npm install react-konva konva --save
# 安装工具库(可选)
npm install react-konva-utils
💡 提示 :
react-konva实际是 Konva 框架的 React 绑定,理解 Konva 本身的概念会更方便。官方文档地址:konvajs.org