react vite 基础worker
vitejs.cn/guide/asset…

index.ts
import { useEffect, useRef } from 'react'
import MyWorker from './index.worker.ts?worker'
const ListDemo = () => {
const worker = new MyWorker()
const canvasOneRef = useRef<HTMLCanvasElement>(null)
const canvasOneRef1 = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasOneRef.current
const displayCanvas = canvasOneRef1.current
if (!canvas || !displayCanvas) return
// 设置canvas尺寸
const dpr = window.devicePixelRatio
canvas.width = 300 * dpr
canvas.height = 300 * dpr
canvas.style.width = '300px'
canvas.style.height = '300px'
const offScreenCanvas = canvas.transferControlToOffscreen()
worker.postMessage({
type: 'init',
canvas: offScreenCanvas,
width: 600,
height: 600
}, [offScreenCanvas])
const handleCanvasClick = (e: MouseEvent) => { // 明确事件类型
const rect = displayCanvas.getBoundingClientRect()
const pos = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
console.log(pos)
worker.postMessage({
type: 'click',
position: pos
})
}
displayCanvas.addEventListener('click', handleCanvasClick)
worker.onmessage = (e: MessageEvent) => { // 明确事件类型
const { data } = e
console.log(data)
if (data.type === 'render') {
if (displayCanvas && data.bitmap) {
const ctx = displayCanvas.getContext('2d')
if (ctx) {
ctx.drawImage(data.bitmap, 0, 0)
data.bitmap.close()
}
}
}
}
return () => {
canvas.removeEventListener('click', handleCanvasClick)
}
}, [])
return (
<div>
<canvas ref={canvasOneRef} width={300} height={300} style={{ display: 'none' }}></canvas>
<canvas ref={canvasOneRef1} width={300} height={300}></canvas>
</div>
)
}
export default ListDemo
index.worker.ts
// 保存点击记录和渲染状态
let clickCount = 0
let ctx: OffscreenCanvasRenderingContext2D
// 初始化画布
function init(canvas: OffscreenCanvas, width: number, height: number) {
canvas.width = width
canvas.height = height
ctx = canvas.getContext('2d')!
render()
}
// 处理点击事件
function handleClick(x: number, y: number) {
clickCount++
render(x, y)
}
// 渲染函数
function render(clickX?: number, clickY?: number) {
// 清空画布
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
// 绘制背景
ctx.fillStyle = '#f0f0f0'
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)
// 绘制当前点击次数
ctx.fillStyle = '#333'
ctx.font = '24px Arial'
ctx.textAlign = 'center'
ctx.fillText(`已点击: ${clickCount}次`, ctx.canvas.width / 2, 40)
// 如果有新点击,绘制标记
if (clickX !== undefined && clickY !== undefined) {
ctx.fillStyle = '#e74c3c'
ctx.beginPath()
ctx.arc(clickX, clickY, 10, 0, Math.PI * 2)
ctx.fill()
// 在点击点旁边显示序号
ctx.fillStyle = '#fff'
ctx.font = '12px Arial'
ctx.fillText(clickCount.toString(), clickX, clickY - 15)
}
// 将渲染结果传回主线程
const bitmap = ctx.canvas.transferToImageBitmap()
(self as any).postMessage({
type: 'render',
bitmap: bitmap
}, [bitmap])
}
// 监听主线程消息
self.onmessage = (e: MessageEvent) => {
const data = e.data
switch (data.type) {
case 'init':
init(data.canvas, data.width, data.height)
break
case 'click':
handleClick(data?.position?.x, data?.position?.y)
break
}
}