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

news2024/11/28 4:53:00

画一个矩形,可以选中高亮,删除自己效果的实现,后期会丰富下细节,拖动及拖动调整矩形大小

实现效果

请添加图片描述

代码实现

class Draw {
  constructor() {
    this.x = 0
    this.y = 0
    this.disX = 0
    this.disY = 0
    this.startX = 0
    this.startY = 0

    this.mouseDown = this.mouseDown.bind(this)
    this.mouseMove = this.mouseMove.bind(this)
    this.mouseUp = this.mouseUp.bind(this)
    this.zIndex = 0
    this.shadowBox = document.createElement('div')
    this.init()
  }

  init() {
    this.draw()
  }
  draw() {
    window.addEventListener('mousedown', this.mouseDown)
  }
  mouseDown(e) {
    console.log('🚀 ~ Draw ~ mouseDown ~ e:', e)
    if (e.target.className == 'delete-btn') return
    // 校验点击的是不是画的的元素
    if (e.target.className == 'draw-rect') {
      // 改变边框颜色
      this.changeBorderColor(e.target)
      return false
    } else {
      this.x = e.clientX
      this.y = e.clientY
      document.addEventListener('mousemove', this.mouseMove)
      document.addEventListener('mouseup', this.mouseUp)
    }
  }
  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.clientY
    this.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() {
    document.removeEventListener('mousemove', this.mouseMove)
    document.removeEventListener('mouseup', this.mouseUp)
    this.drawRect()
    this.shadowBox && this.shadowBox.remove()
  }
  drawShadeRect(startX, startY) {
    // console.log('🚀 ~ Draw ~ drawRect', this)
    // const div = document.createElement('div')
    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() {
    const div = document.createElement('div')
    div.className = 'draw-rect'
    div.style = `width: ${this.disX}px;height: ${this.disY}px;border:1px solid red;position: absolute;left: ${this.startX}px;top: ${this.startY}px`
    div.appendChild(this.addDeleteBtn())
    document.body.appendChild(div)
  }
  changeBorderColor(target) {
    target.style.border = '1px solid blue'
  }
  // 动态添加一个删除按钮
  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
  }
}

const d = new Draw()
d.init()

当前高亮

请添加图片描述

constructor里面新增

this.allRect = []
drawRect() {
    const div = document.createElement('div')
    div.className = 'draw-rect'
    div.style = `width: ${this.disX}px;height: ${this.disY}px;border:1px solid #ccc;position: absolute;left: ${this.startX}px;top: ${this.startY}px`
    div.appendChild(this.addDeleteBtn())
    document.body.appendChild(div)
    // 收集所有的rect
    this.allRect.push(div)
    this.setCurrentBorderColor(div)
  }
changeBorderColor(target) {
    console.log('🚀 ~ Draw ~ changeBorderColor ~ target:', target)
    this.nowMoveTarget = target
    this.setCurrentBorderColor(target)
    // 改变鼠标指针
    target.style.cursor = 'move'
  }

setCurrentBorderColor方法

setCurrentBorderColor(target) {
  // 改变边框颜色,当前选中的高亮
  this.allRect.forEach((item) => {
    if (item != target) {
      item.style.border = '1px solid #ccc'
    }
  })
  target.style.border = '1px solid blue'
}


添加元素拖动效果

请添加图片描述

class Draw {
  constructor() {
    // ...
    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)
    // ...
  }
  mouseDown(e) {
    console.log('🚀 ~ Draw ~ mouseDown ~ e:', e)
    if (e.target.className == 'delete-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)
    }
  }
  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() {
    const div = document.createElement('div')
    div.className = 'draw-rect'
    div.style = `width: ${this.disX}px;height: ${this.disY}px;border:1px solid #ccc;position: absolute;left: ${this.startX}px;top: ${this.startY}px`
    div.appendChild(this.addDeleteBtn())
    document.body.appendChild(div)

    this.allRect.push(div)
    this.setCurrentBorderColor(div)
  }
  handleRectDown(e) {
    this.startX = e.clientX
    this.startY = e.clientY
    this.offsetX = e.clientX - this.nowMoveTarget.offsetLeft
    this.offsetY = e.clientY - this.nowMoveTarget.offsetTop
    const that = this
    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() {
    const that = this
    console.log('🚀 ~ Draw ~ handleRectUp ~ that:', that)
    document.removeEventListener('mousemove', this.handleRectMove)
    document.removeEventListener('mouseup', this.handleRectUp)
  }
}

const d = new Draw()
d.init()

总结

  • 鼠标事件的熟练运动
  • 下步会丰富下拖动调整矩形大小的功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

12 —— Webpack中向前端注入环境变量

环境变量的作用&#xff1a;根据不同环境&#xff0c;执行不同的配置 需求&#xff1a;开发模式下打印语句生效&#xff0c;生产模式下打印语句失效 —— 使用Webpack内置的DefinePlugin插件 const webpack require(webpack) module.exports { plugins: [ new webpack.Def…

Learn Git Branching 学习笔记

网址&#xff1a;Learn Git Branching 一、基础篇 1.1 git commit 1.1.1 示例&#xff08;git commit&#xff09; git commit 1.1.2 题目&#xff08;两次提交记录&#xff09; git commit git commit 前 后 1.2 git branch 1.2.1 示例&#xff08;git branch <>、git …

Unity类银河战士恶魔城学习总结(P145 Save Skill Tree 保存技能树)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了技能树的保存 警告&#xff01;&#xff01;&#xff01; 如果有LoadData&#xff08;&#xff09;和SaveData(&#xff09;…

从 App Search 到 Elasticsearch — 挖掘搜索的未来

作者&#xff1a;来自 Elastic Nick Chow App Search 将在 9.0 版本中停用&#xff0c;但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为&#xff0c;激励开发人员创造更具活力、更直观、更引人入…

社团管理新工具:SpringBoot框架

3系统分析 3.1可行性分析 通过对本社团管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本社团管理系统采用SSM框架&#xff0c;JAVA作为开发语言&#…

Vue3 源码解析(三):静态提升

什么是静态提升 Vue3 尚未发布正式版本前&#xff0c;尤大在一次关于 Vue3 的分享中提及了静态提升&#xff0c;当时笔者就对这个亮点产生了好奇&#xff0c;所以在源码阅读时&#xff0c;静态提升也是笔者的一个重点阅读点。 那么什么是静态提升呢&#xff1f;当 Vue 的编译器…

8款Pytest插件助力Python自动化测试

当测试用例变得复杂&#xff0c;或者需要处理大量测试数据时&#xff0c;插件通过使测试更加简洁和结构化而变得非常有用。Python凭借其简洁性和多功能性&#xff0c;成为自动化测试的热门选择&#xff0c;而pytest是最广泛使用的测试框架之一。虽然pytest本身功能强大&#xf…

【spark-spring boot】学习笔记

目录 说明RDD学习RDD介绍RDD案例基于集合创建RDDRDD存入外部文件中 转换算子 操作map 操作说明案例 flatMap操作说明案例 filter 操作说明案例 groupBy 操作说明案例 distinct 操作说明案例 sortBy 操作说明案例 mapToPair 操作说明案例 mapValues操作说明案例 groupByKey操作说…

Spring Boot 3 集成 Spring Security(2)授权

文章目录 授权配置 SecurityFilterChain基于注解的授权控制自定义权限决策 在《Spring Boot 3 集成 Spring Security&#xff08;1&#xff09;》中&#xff0c;我们简单实现了 Spring Security 的认证功能&#xff0c;通过实现用户身份验证来确保系统的安全性。Spring Securit…

Apache OFBiz xmlrpc XXE漏洞(CVE-2018-8033)

目录 1、漏洞描述 2、EXP下载地址 3、EXP利用 1、漏洞描述 Apache OFBiz是一套企业资源计划&#xff08;ERP&#xff09;系统。它提供了广泛的功能&#xff0c;包括销售、采购、库存、财务、CRM等。 Apache OFBiz还具有灵活的架构和可扩展性&#xff0c;允许用户根据业务需求…

【Android】ARouter的使用及源码解析

文章目录 简介介绍作用 原理关系 使用添加依赖和配置初始化SDK添加注解在目标界面跳转界面不带参跳转界面含参处理返回结果 源码基本流程getInstance()build()navigation()_navigation()Warehouse ARouter初始化init帮助类根帮助类组帮助类 completion 总结 简介 介绍 ARouter…

springboot整合hive

springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

IntelliJ IDEA 中,自动导包功能

在 IntelliJ IDEA 中&#xff0c;自动导包功能可以极大地提高开发效率&#xff0c;减少手动导入包所带来的繁琐和错误。以下是如何在 IntelliJ IDEA 中设置和使用自动导包功能的详细步骤&#xff1a; 一、设置自动导包 打开 IntelliJ IDEA&#xff1a; 启动 IntelliJ IDEA 并打…

【MySQL课程学习】:MySQL安装,MySQL如何登录和退出?MySQL的简单配置

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;MySQL课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 MySQL在Centos 7环境下的安装&#xff1a; 卸载…

Easyexcel(7-自定义样式)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09;Easyexcel&#xff08;6-单…

(计算机网络)期末

计算机网络概述 物理层 信源就是发送方 信宿就是接收方 串行通信--一次只发一个单位的数据&#xff08;串行输入&#xff09; 并行通信--一次可以传输多个单位的数据 光纤--利用光的反射进行传输 传输之前&#xff0c;要对信源进行一个编码&#xff0c;收到信息之后要进行一个…

uniapp跨域问题解决方案

uniapp跨域问题解决方案 引言 在使用 uni-app 本地开发 H5> 平台时&#xff0c;需要使用浏览器进行调试&#xff0c;而浏览器会有跨域的问题。比如直接通过本地IP地址去访问开发中的页面&#xff0c;同时这个页面会调一些现有的接口时&#xff0c;就面临着跨域的问题。 解决…

Android 基于Camera2 API进行摄像机图像预览

前言 近期博主准备编写一个基于Android Camera2的图像采集并编码为h.264的应用&#xff0c;准备分为三个阶段来完成&#xff0c;第一阶段实现Camera2的摄像机预览&#xff0c;第二阶段完成基于MediaCodec H.264编码&#xff0c;第三阶段完成基于MediaCodec H.264解码,针对不同…

设计模式:11、迭代器模式(游标)

目录 0、定义 1、迭代器模式的四种角色 2、迭代器模式的UML类图 3、示例代码 4、迭代器的next()方法与集合的get(int index)方法的效率对比&#xff08;LinkedList为例&#xff09; 0、定义 提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不需要暴露该对象…

UE5连接VR(pico,quest)进行PC VR开发(没有废话全是干货)

一、PICO VR连接UE 首先picoVR&#xff0c;不管是pico neo3还是pico4&#xff0c;用到的软件就只有三个 分别是pico互联助手PICO 互联 | PICO (picoxr.com)、steam VR&#xff0c;虚幻引擎5 pico互联助手 在pico互联助手中你需要选择两种连接方式&#xff08;推荐USB连接&a…