如何在Ember中实现类似谷歌反馈的矩形高亮工具?
用Ember实现谷歌风格矩形高亮工具
要实现谷歌官网反馈功能里的矩形高亮工具,核心是在页面上层构建一个可交互的遮罩图层,通过监听全局鼠标事件完成矩形的绘制、调整和管理。以下是基于Ember的具体实现方案:
核心组件拆分
把工具拆分为两个核心组件,贴合Ember的组件化设计思路:
highlight-tool:主组件,负责管理所有高亮矩形的状态、全局鼠标事件监听、工具的激活/关闭逻辑。highlight-rect:单个高亮矩形组件,处理矩形的拖拽、调整大小和删除(若需求简单,也可合并到主组件中简化实现)。
关键实现步骤
1. 主组件初始化与事件绑定
主组件需要监听全局鼠标事件(绑定到document),同时维护高亮矩形数组、绘制状态等跟踪属性:
// app/components/highlight-tool.js import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; export default class HighlightToolComponent extends Component { @tracked highlights = []; @tracked isDrawing = false; @tracked currentRect = null; @tracked startX = 0; @tracked startY = 0; didInsertElement() { // 绑定全局鼠标事件 document.addEventListener('mousedown', this.handleMouseDown); document.addEventListener('mousemove', this.handleMouseMove); document.addEventListener('mouseup', this.handleMouseUp); } willDestroyElement() { // 组件销毁时解绑事件,避免内存泄漏 document.removeEventListener('mousedown', this.handleMouseDown); document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); } }
2. 实现矩形绘制逻辑
通过mousedown、mousemove、mouseup事件的联动,完成矩形的绘制流程:
// 继续在highlight-tool.js中添加以下action @action handleMouseDown(event) { // 仅在遮罩层上点击时启动绘制 if (event.target.classList.contains('highlight-mask')) { this.isDrawing = true; this.startX = event.pageX; this.startY = event.pageY; this.currentRect = { x: this.startX, y: this.startY, width: 0, height: 0 }; } } @action handleMouseMove(event) { if (!this.isDrawing) return; const currentX = event.pageX; const currentY = event.pageY; // 处理从右下往左上拖拽的情况,确保矩形坐标正确 this.currentRect = { x: Math.min(this.startX, currentX), y: Math.min(this.startY, currentY), width: Math.abs(currentX - this.startX), height: Math.abs(currentY - this.startY) }; } @action handleMouseUp() { // 过滤掉过小的误操作矩形 if (this.isDrawing && this.currentRect.width > 10 && this.currentRect.height > 10) { this.highlights = [...this.highlights, this.currentRect]; } this.isDrawing = false; this.currentRect = null; }
3. 渲染遮罩层与高亮矩形
在组件模板中添加全屏遮罩层,渲染已完成的高亮矩形和绘制中的临时矩形:
{{! app/templates/components/highlight-tool.hbs }} {{#if @isActive}} {{! 全屏遮罩层,半透明背景 }} <div class="highlight-mask" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.3); pointer-events: auto;"></div> {{! 渲染已保存的高亮矩形 }} {{#each this.highlights as |highlight index|}} <div class="highlight-rect" style="position: fixed; left: {{highlight.x}}px; top: {{highlight.y}}px; width: {{highlight.width}}px; height: {{highlight.height}}px; background: rgba(255,255,0,0.5); border: 2px solid #ffeb3b; cursor: move;" {{on "click" (fn this.removeHighlight index)}}> </div> {{/each}} {{! 渲染绘制中的临时矩形 }} {{#if this.currentRect}} <div class="highlight-rect" style="position: fixed; left: {{this.currentRect.x}}px; top: {{this.currentRect.y}}px; width: {{this.currentRect.width}}px; height: {{this.currentRect.height}}px; background: rgba(255,255,0,0.5); border: 2px solid #ffeb3b;"> </div> {{/if}} {{/if}}
4. 添加删除与调整功能
给每个高亮矩形添加删除逻辑,如需拖拽调整大小,可以扩展highlight-rect组件添加控制点和对应的事件处理:
// 在highlight-tool.js中添加删除action @action removeHighlight(index) { this.highlights = this.highlights.filter((_, i) => i !== index); }
5. 集成到应用中
在需要使用工具的路由模板中,通过开关状态控制工具的显示:
{{! 示例页面模板 }} <button {{on "click" (fn (mut this.showHighlightTool) true)}}>开启高亮工具</button> <HighlightTool @isActive={{this.showHighlightTool}} />
细节优化
- 坐标兼容性:使用
pageX/pageY而非clientX/clientY,避免页面滚动导致的坐标偏移。 - 交互隔离:工具激活时,遮罩层设置
pointer-events: auto,底层页面可临时设置pointer-events: none,防止误操作。 - 样式精细化:调整高亮矩形的透明度、边框样式,使其更接近谷歌的视觉效果;添加调整控制点(如四个角的小方块)提升交互体验。
内容的提问来源于stack exchange,提问作者agustinvaca
相关产品推荐
相关产品推荐

