文章目錄
- 一、前言
- 二、Konva.js 介紹
- 三、創建 React 畫板項目
- 3.1 安裝依賴
- 3.2 創建 `CanvasBoard` 組件
- 四、增加畫布控制功能
- 4.1 清空畫布
- 4.2 撤銷 & 重做功能
- 五、增加顏色和畫筆大小選擇
- 5.1 選擇顏色
- 5.2 選擇畫筆大小
- 六、最終效果
- 七、總結
一、前言
在線畫板是許多應用(如白板協作工具、手寫筆記、繪圖軟件)中的重要組件。我們可以使用 React
+ Konva.js
結合 react-konva
來實現一個功能豐富的畫板。
本教程將帶你實現一個支持 自由繪制、清空畫布、撤銷/重做 的 React 畫板組件。
二、Konva.js 介紹
Konva.js 是一個基于 Canvas API 的 2D 圖形庫,支持高性能的繪圖操作,如路徑、形狀、文本、圖片等。它具有以下優點:
- 更高性能:相比 DOM 操作,Canvas 渲染更加流暢;
- 提供豐富的圖形 API(直線、多邊形、貝塞爾曲線等);
- 支持事件監聽,如
click
、drag
、touch
等。
react-konva
是 Konva.js 的 React 封裝庫,使其可以在 React 中更方便地使用。
三、創建 React 畫板項目
3.1 安裝依賴
在 React 項目中,安裝 react-konva
和 konva
:
{bash}
npm install react-konva konva
{bash}
3.2 創建 CanvasBoard
組件
新建 CanvasBoard.js
,并使用 react-konva
組件創建一個可繪制的 Canvas。
// CanvasBoard.js
import React, { useRef, useState } from "react";
import { Stage, Layer, Line } from "react-konva";const CanvasBoard = () => {const [lines, setLines] = useState([]);const [isDrawing, setIsDrawing] = useState(false);const stageRef = useRef(null);// 開始繪制const handleMouseDown = (event) => {setIsDrawing(true);const { x, y } = event.target.getStage().getPointerPosition();setLines([...lines, { points: [x, y] }]);};// 畫線const handleMouseMove = (event) => {if (!isDrawing) return;const { x, y } = event.target.getStage().getPointerPosition();const newLines = [...lines];newLines[newLines.length - 1].points.push(x, y);setLines(newLines);};// 結束繪制const handleMouseUp = () => {setIsDrawing(false);};return (<div><Stagewidth={800}height={500}ref={stageRef}onMouseDown={handleMouseDown}onMousemove={handleMouseMove}onMouseup={handleMouseUp}style={{ border: "1px solid #ccc", background: "#fff" }}><Layer>{lines.map((line, index) => (<Line key={index} points={line.points} stroke="black" strokeWidth={3} tension={0.5} lineCap="round" />))}</Layer></Stage></div>);
};export default CanvasBoard;
四、增加畫布控制功能
4.1 清空畫布
我們可以添加一個“清空”按鈕,點擊后清除所有線條。
const handleClearCanvas = () => {setLines([]);
};
{javascript}并在 `CanvasBoard` 組件中添加按鈕:{javascript}
<button onClick={handleClearCanvas}>清空畫布</button>
4.2 撤銷 & 重做功能
為了實現 撤銷/重做,我們需要一個狀態棧來存儲歷史操作。
修改 CanvasBoard.js
:
const [history, setHistory] = useState([]);
const [redoStack, setRedoStack] = useState([]);const handleUndo = () => {if (lines.length > 0) {setRedoStack([...redoStack, lines[lines.length - 1]]);setLines(lines.slice(0, -1));}
};const handleRedo = () => {if (redoStack.length > 0) {setLines([...lines, redoStack[redoStack.length - 1]]);setRedoStack(redoStack.slice(0, -1));}
};
并在 CanvasBoard
組件中添加按鈕:
<button onClick={handleUndo}>撤銷</button>
<button onClick={handleRedo}>重做</button>
五、增加顏色和畫筆大小選擇
我們可以添加選擇顏色和畫筆大小的功能,使畫板更豐富。
5.1 選擇顏色
在 CanvasBoard.js
中添加顏色選擇器:
const [color, setColor] = useState("black");<input type="color" value={color} onChange={(e) => setColor(e.target.value)} />
并修改 Line
組件,讓它支持動態顏色:
<Line key={index} points={line.points} stroke={line.color || "black"} strokeWidth={3} />
{javascript}當鼠標按下時,將顏色存入 `lines`:{javascript}
setLines([...lines, { points: [x, y], color }]);
5.2 選擇畫筆大小
在 CanvasBoard.js
添加畫筆大小選擇器:
const [strokeWidth, setStrokeWidth] = useState(3);<input type="range" min="1" max="10" value={strokeWidth} onChange={(e) => setStrokeWidth(e.target.value)} />
{javascript}修改 `Line` 組件,讓它支持動態畫筆大小:{javascript}
<Line key={index} points={line.points} stroke={line.color || "black"} strokeWidth={line.strokeWidth || 3} />
當鼠標按下時,將 strokeWidth
存入 lines
:
setLines([...lines, { points: [x, y], color, strokeWidth }]);
六、最終效果
最終,我們的在線畫板具備以下功能:
? 支持自由繪制
? 支持清空畫布
? 支持撤銷/重做
? 支持顏色選擇
? 支持畫筆大小調整
你可以將 CanvasBoard
組件導入 App.js
進行測試:
// App.js
import React from "react";
import CanvasBoard from "./CanvasBoard";function App() {return (<div className="App"><h1>React 畫板</h1><CanvasBoard /></div>);
}export default App;
七、總結
本篇文章介紹了如何使用 React
+ Konva
實現一個 在線畫板組件,并添加了 撤銷/重做、顏色選擇、畫筆大小調整 等功能。Konva
提供了高效的 Canvas API,使得 React 處理復雜的繪圖操作變得更加輕松。
你可以在此基礎上繼續擴展,比如:
- 添加橡皮擦功能
- 支持圖像導入與導出
- 多人協作(結合 WebSocket)
到這里,這篇文章就和大家說再見啦!我的主頁里還藏著很多 篇 前端 實戰干貨,感興趣的話可以點擊頭像看看,說不定能找到你需要的解決方案~
創作這篇內容花了很多的功夫。如果它幫你解決了問題,或者帶來了啟發,歡迎:
點個贊?? 讓更多人看到優質內容
關注「前端極客探險家」🚀 每周解鎖新技巧
收藏文章?? 方便隨時查閱
📢 特別提醒:
轉載請注明原文鏈接,商業合作請私信聯系
感謝你的閱讀!我們下篇文章再見~ 💕