【es6】原生js在页面上画矩形添加选中状态高亮及显示调整大小控制框(三)

ops/2024/11/27 19:27:52/

接上篇文章,这篇实现下选中当前元素显示调整大小的控制框,点击document取消元素的选中高亮状态效果。

实现效果

请添加图片描述

代码逻辑

  • 动态生成控制按钮矩形,并设置响应的css
// 动态添加一个调整位置的按钮addScaleBtn(target) {const w = target.offsetWidth;const h = target.offsetHeight;const lt = document.createElement("div");lt.className = "scale-btn";lt.style = `position: absolute;left: -5px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lt);const lm = document.createElement("div");lm.className = "scale-btn";lm.style = `position: absolute;top: ${(h - 5) / 2}px;left: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lm);const lb = document.createElement("div");lb.className = "scale-btn";lb.style = `position: absolute;bottom: -5px;left: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lb);const tm = document.createElement("div");tm.className = "scale-btn";tm.style = `position: absolute;left: ${(w - 5) / 2}px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(tm);const bm = document.createElement("div");bm.className = "scale-btn";bm.style = `position: absolute;left: ${(w - 5) / 2}px;bottom: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(bm);const rt = document.createElement("div");rt.className = "scale-btn";rt.style = `position: absolute;right: -5px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rt);const rm = document.createElement("div");rm.className = "scale-btn";rm.style = `position: absolute;top: ${(h - 5) / 2}px;right: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rm);const rb = document.createElement("div");rb.className = "scale-btn";rb.style = `position: absolute;right: -5px;bottom: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rb);}
  • 点击document恢复样式
resetAllBorderColor(target) {// 改变边框颜色,当前选中的高亮this.allRect.forEach((item) => {item.style.border = "1px solid #ccc";item.querySelectorAll(".scale-btn").forEach((i) => {i.remove();});});}
  • 点击当前元素显示控制框按钮,其他的都隐藏
setCurrentBorderColor(target) {// 改变边框颜色,当前选中的高亮this.allRect.forEach((item) => {if (item != target) {item.style.border = "1px solid #ccc";// 删除8个调整位置的按钮,只保留当前的元素的8个调整位置的按钮item.querySelectorAll(".scale-btn").forEach((i) => {i.remove();});}});target.style.border = "1px solid blue";}
  • 在每次画完矩形和拖动矩形后,都要重置下数据,不然会导致直接画出一个莫名其妙的新矩形
// 画完后重置初始化数据reset() {this.x = 0;this.y = 0;this.disX = 0;this.disY = 0;this.startX = 0;this.startY = 0;}
  • 完整代码
class Draw {constructor() {this.x = 0;this.y = 0;this.disX = 0;this.disY = 0;this.startX = 0;this.startY = 0;this.offsetX = 0;this.offsetY = 0;this.nowMoveTarget = null;this.mouseDown = this.mouseDown.bind(this);this.mouseMove = this.mouseMove.bind(this);this.mouseUp = this.mouseUp.bind(this);this.handleRectMove = this.handleRectMove.bind(this);this.handleRectUp = this.handleRectUp.bind(this);this.zIndex = 0;this.allRect = [];this.shadowBox = document.createElement("div");this.init();}init() {this.draw();}draw() {document.addEventListener("mousedown", this.mouseDown, false);}mouseDown(e) {console.log("🚀 ~ Draw ~ mouseDown ~ e:", e);if (e.target.className == "delete-btn" || e.target.className == "scale-btn")return;// 校验点击的是不是画的的元素if (e.target.className == "draw-rect") {// 改变边框颜色this.changeBorderColor(e.target);this.handleRectDown(e);return false;} else {this.x = e.clientX;this.y = e.clientY;document.addEventListener("mousemove", this.mouseMove);document.addEventListener("mouseup", this.mouseUp);// 清除所有选中的边框颜色,恢复默认边框颜色,及8个选中按钮this.allRect.forEach((item) => {this.resetAllBorderColor(item);});}}mouseMove(e) {// 不要选中文字e.preventDefault();// this.disX = e.clientX - this.x// this.disY = e.clientY - this.y// const startX = e.clientX < this.x ? e.clientX : this.x// const startY = e.clientY < this.y ? e.clientY : this.y// this.disX = e.clientX > this.x ? e.clientX - this.x : this.x - e.clientX// this.disY = e.clientY > this.y ? e.clientY - this.y : this.y - e.clientYthis.startX = Math.min(e.clientX, this.x);this.startY = Math.min(e.clientY, this.y);this.disX = Math.abs(e.clientX - this.x);this.disY = Math.abs(e.clientY - this.y);// console.log('🚀 ~ Draw ~ mouseMove ~ e:', this.disX, this.disY)this.drawShadeRect();}mouseUp(e) {document.removeEventListener("mousemove", this.mouseMove);document.removeEventListener("mouseup", this.mouseUp);this.drawRect();this.shadowBox && this.shadowBox.remove();}drawShadeRect(startX, startY) {this.shadowBox.style = `width: ${this.disX}px;height: ${this.disY}px;border:1px solid red;background:rgba(94,243,243,.5);position: absolute;left: ${this.startX}px;top: ${this.startY}px;z-index:${this.zIndex++}`;document.body.appendChild(this.shadowBox);}drawRect() {if (this.disX < 20 || this.disY < 20) return;const div = document.createElement("div");div.className = "draw-rect";div.style = `position:relative;width: ${this.disX}px;height: ${this.disY}px;border:1px solid #ccc;position: absolute;left: ${this.startX}px;top: ${this.startY}px;z-index:${this.zIndex++};background:greenyellow`;div.appendChild(this.addDeleteBtn());document.body.appendChild(div);this.allRect.push(div);this.setCurrentBorderColor(div);this.reset();}// 画完后重置初始化数据reset() {this.x = 0;this.y = 0;this.disX = 0;this.disY = 0;this.startX = 0;this.startY = 0;}handleRectDown(e) {this.startX = e.clientX;this.startY = e.clientY;this.offsetX = e.clientX - this.nowMoveTarget.offsetLeft;this.offsetY = e.clientY - this.nowMoveTarget.offsetTop;document.addEventListener("mousemove", this.handleRectMove);document.addEventListener("mouseup", this.handleRectUp);}handleRectMove(e) {this.disX = e.clientX - this.offsetX;this.disY = e.clientY - this.offsetY;this.nowMoveTarget.style.left = `${this.disX}px`;this.nowMoveTarget.style.top = `${this.disY}px`;}handleRectUp() {document.removeEventListener("mousemove", this.handleRectMove);document.removeEventListener("mouseup", this.handleRectUp);this.reset();}changeBorderColor(target) {this.nowMoveTarget = target;this.setCurrentBorderColor(target);// 改变鼠标指针target.style.cursor = "move";target.style.zIndex = ++this.zIndex;// 当前元素没有添加8个调整位置的按钮,则添加if (!target.querySelector(".scale-btn")) {this.addScaleBtn(target);}}// 动态添加一个调整位置的按钮addScaleBtn(target) {const w = target.offsetWidth;const h = target.offsetHeight;const lt = document.createElement("div");lt.className = "scale-btn";lt.style = `position: absolute;left: -5px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lt);const lm = document.createElement("div");lm.className = "scale-btn";lm.style = `position: absolute;top: ${(h - 5) / 2}px;left: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lm);const lb = document.createElement("div");lb.className = "scale-btn";lb.style = `position: absolute;bottom: -5px;left: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(lb);const tm = document.createElement("div");tm.className = "scale-btn";tm.style = `position: absolute;left: ${(w - 5) / 2}px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(tm);const bm = document.createElement("div");bm.className = "scale-btn";bm.style = `position: absolute;left: ${(w - 5) / 2}px;bottom: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(bm);const rt = document.createElement("div");rt.className = "scale-btn";rt.style = `position: absolute;right: -5px;top: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rt);const rm = document.createElement("div");rm.className = "scale-btn";rm.style = `position: absolute;top: ${(h - 5) / 2}px;right: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rm);const rb = document.createElement("div");rb.className = "scale-btn";rb.style = `position: absolute;right: -5px;bottom: -5px;width: 10px;height: 10px;background:red;cursor:resize`;target.appendChild(rb);}// 动态添加一个删除按钮addDeleteBtn() {const btn = document.createElement("button");btn.innerHTML = "删除";btn.className = "delete-btn";btn.style = `position: absolute;right: 0px;bottom: -25px`;// 绑定事件btn.onclick = function () {this.parentElement.remove();};return btn;}setCurrentBorderColor(target) {// 改变边框颜色,当前选中的高亮this.allRect.forEach((item) => {if (item != target) {item.style.border = "1px solid #ccc";// 删除8个调整位置的按钮,只保留当前的元素的8个调整位置的按钮item.querySelectorAll(".scale-btn").forEach((i) => {i.remove();});}});target.style.border = "1px solid blue";}resetAllBorderColor(target) {// 改变边框颜色,当前选中的高亮this.allRect.forEach((item) => {item.style.border = "1px solid #ccc";item.querySelectorAll(".scale-btn").forEach((i) => {i.remove();});});}
}const d = new Draw();
d.init();

总结

  • 要注意控制按钮的显示时机,最好是点击按钮时显示,因为矩形未画完,我们无法获得矩形的宽高,来定位控制矩形的位置
  • 下步实现拖动控制点来调整矩形的大小

http://www.ppmy.cn/ops/137152.html

相关文章

自动驾驶系统研发系列—智能驾驶新高度:解析ESS驾驶员转向辅助系统

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中一起航行,共同成长,探索技术的无限可能。 🚀 探索专栏:学…

Apache Maven Assembly 插件简介

Apache Maven Assembly 插件是一个强大的工具&#xff0c;允许您以多种格式&#xff08;如 ZIP、TAR 和 JAR&#xff09;创建项目的分发包。 该插件特别适用于将项目与其依赖项、配置文件和其他必要资源一起打包。 通过使用 Maven Assembly 插件&#xff0c;您可以将项目作为…

如何利用ChatGPT加速开发与学习:以BPMN编辑器为例

在现代开发中&#xff0c;开发者经常会遇到各种需要编写和学习新技术的任务。ChatGPT作为一种强大的自然语言处理工具&#xff0c;不仅可以辅助编写代码&#xff0c;还可以帮助学习新的编程概念和解决开发中的难题。本文将以开发一个BPMN&#xff08;业务流程建模与标注&#x…

【es6进阶】如何使用Proxy实现自己的观察者模式

观察者模式&#xff08;Observer mode&#xff09;指的是函数自动观察数据对象&#xff0c;一旦对象有变化&#xff0c;函数就会自动执行。这里&#xff0c;我们是使用es6的proxy及reflect来实现这个效果。 实现效果 业务分析 源数据 const object2 {name: "张三"…

python语言基础

1. 基础语法 Q: Python 中的变量与数据类型有哪些&#xff1f; A: Python 支持多种数据类型&#xff0c;包括数字&#xff08;整数 int、浮点数 float、复数 complex&#xff09;、字符串 str、列表 list、元组 tuple、字典 dict 和集合 set。每种数据类型都有其特定的用途和…

【es6】原生js在页面上画矩形及删除的实现方法

画一个矩形&#xff0c;可以选中高亮&#xff0c;删除自己效果的实现&#xff0c;后期会丰富下细节&#xff0c;拖动及拖动调整矩形大小 实现效果 代码实现 class Draw {constructor() {this.x 0this.y 0this.disX 0this.disY 0this.startX 0this.startY 0this.mouseDo…

获 2023 年度浙江省科学技术进步奖一等奖 | 网易数智日报

11 月 22 日&#xff0c;加快建设创新浙江因地制宜发展新质生产力动员部署会暨全省科学技术奖励大会在杭州隆重召开。浙江大学、网易数智等单位联合研发的“大规模结构化数据智能计算平台及产业化”项目获得 2023 年度浙江省科学技术进步奖一等奖。 加快建设创新浙江因地制宜发…

微信万能门店小程序系统存在任意文件读取漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…