React Konva 开发基础速查手册

一份用于日常开发的 React Konva 核心语法速查表,涵盖画布搭建、图形绘制、事件处理、拖拽交互等常用场景。

核心层级关系与作用

  • Stage (舞台) :应用的最顶层根容器,所有内容的入口-1-4
  • Layer (图层) :Stage 下的直接子级,可看作是一张透明的"画布"。这是承载图形和进行性能优化的基本单位 ,也是事件检测的边界-1-9
  • Group (组) :这是图层下的一个逻辑容器 ,用于将多个Shape(图形)或其他Group组合在一起-2-5
  • Shape (图形) :实际绘制的图形元素,如 RectCircleLineText-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 前缀即可,如 onClickonMouseOveronDragEnd -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

相关推荐
小粉粉hhh2 小时前
Node.js(五)——编写接口
前端·javascript·node.js
进击切图仔2 小时前
SAM3 微调标注流水线和 Label Studio
java·服务器·前端
自然 醒2 小时前
前端如何实现在线预览office常见文件功能?
前端·vue.js
肉肉不吃 肉3 小时前
前端调试跨域如何解决
前端·vue.js
Liora_Yvonne3 小时前
为什么你写了3年前端还是搭不好一个项目
前端·架构
snow@li3 小时前
Java:后端项目会有一个类似前端node_modules的目录吗 / jar包在本地仓库 ~/.m2/repository 中按版本共存
java·开发语言·前端
weedsfly3 小时前
单例模式在前端中的正确打开方式
前端·javascript·面试
PedroQue993 小时前
uni-router新推useUniEventChannel,彻底解决页面通信难题
前端·uni-app
IT_陈寒3 小时前
Vite冷启动快?我遇到了个奇怪的依赖问题
前端·人工智能·后端