react-konva实现元素超出容器范围时外部区域模糊效果
React-Konva实现元素超出容器时外部区域模糊效果
核心思路是把目标元素拆成两个部分渲染:容器内的清晰区域,和容器外的模糊区域,通过裁剪路径和滤镜组合实现效果,下面是具体实现步骤和代码:
实现步骤
- 定义容器的位置与尺寸,作为可视边界
- 对目标元素做两个副本:
- 第一个副本用裁剪路径只保留容器内的部分,不添加滤镜,保持清晰
- 第二个副本添加模糊滤镜,并用反向裁剪只保留容器外的部分
- 绑定拖拽事件,同步两个副本的位置(如果有缩放/旋转也要同步对应属性)
完整代码示例
import React, { useState } from "react"; import { render } from "react-dom"; import { Stage, Layer, Rect, Circle, Transformer } from "react-konva"; import { Blur } from "konva/lib/filters/Blur"; const App = () => { const [circlePos, setCirclePos] = useState({ x: 150, y: 150 }); // 容器的位置和尺寸 const container = { x: 50, y: 50, width: 200, height: 200 }; // 裁剪出容器内的区域 const clipInside = (ctx) => { ctx.rect(container.x, container.y, container.width, container.height); }; // 裁剪出容器外的区域(利用evenodd规则实现反向裁剪) const clipOutside = (ctx) => { // 先画整个舞台范围 ctx.rect(0, 0, 400, 400); // 再画容器范围,evenodd规则会把两个区域的差值保留 ctx.rect(container.x, container.y, container.width, container.height); ctx.clip("evenodd"); }; return ( <Stage width={400} height={400}> <Layer> {/* 容器背景 */} <Rect x={container.x} y={container.y} width={container.width} height={container.height} fill="#eee" stroke="#ddd" /> {/* 下层:模糊的外部区域 */} <Circle x={circlePos.x} y={circlePos.y} radius={50} fill="red" clipFunc={clipOutside} filters={[Blur]} blurRadius={5} /> {/* 上层:清晰的内部区域,绑定拖拽事件 */} <Circle className="konva-circle" x={circlePos.x} y={circlePos.y} radius={50} fill="red" clipFunc={clipInside} draggable onDragEnd={(e) => { setCirclePos({ x: e.target.x(), y: e.target.y() }); }} /> {/* 拖拽控制器 */} <Transformer node={document.querySelector(".konva-circle")} enabledAnchors={["top-left", "top-right", "bottom-left", "bottom-right"]} /> </Layer> </Stage> ); }; render(<App />, document.getElementById("root"));
关键细节说明
- 裁剪路径(clipFunc):通过Canvas的
clip方法和evenodd填充规则,实现反向裁剪,精准保留容器外的区域 - 图层叠加顺序:模糊元素放在下层,清晰元素在上层,视觉上就会呈现“内部清晰、外部模糊”的效果
- 性能优化提示:模糊滤镜会消耗一定性能,如果是复杂场景,可以考虑只在元素拖拽过程中启用模糊,静止时关闭,或者使用离屏Canvas预渲染模糊区域
内容的提问来源于stack exchange,提问作者thitbachi
相关产品推荐
相关产品推荐

