原生javascript实现上下左右中间八个点控制元素大小、旋转角度、拖拽位置功能

最近在接触一个简单的图形编辑器,要求是要实现web页面加载图标元素并可以通过上下左右中间八个点鼠标控制元素大小。拖拽功能比较简单,一般都比较容易实现,主要是旋转和八个点控制元素的大小,旋转是相对难理解一点,需要到一些数学问题,关于坐标系的知识。

整个demo源码下载地址: 点击下载源码

通过 Math.atan可以计算出反正切的值,从而推算出鼠标移动到哪个象限的时候的角度。四个点的拖拉也这个比较容易实现,自己想一下就可以了

运行结果如下:

部分主要代码如下:

Rotate.js代码

const $ = (str) => {
  return document.querySelector(str);
};
const setRotate = (dom, rotate) => {
  dom.style.webkitTransform = 'rotate(' + rotate + 'deg)';
};
let roateBox = $('#rotateBox');

// 旋转按钮代码
// 获取方形中心坐标点即坐标轴原点
let centerPointX = roateBox.getBoundingClientRect().left + roateBox.getBoundingClientRect().width / 2;
let centerPointY = roateBox.getBoundingClientRect().top + roateBox.getBoundingClientRect().height / 2;
// 鼠标移动事件
const moveEvent = (e) => {
  let X = e.clientX;
  let Y = e.clientY;
  e.stopPropagation();
  let oY = Math.abs(Y - centerPointY);
  let oX = Math.abs(X - centerPointX);
  // 避免水平和垂直位置的就相当于和坐标轴相交的时候设置除数为0或者不知道为360度还是180度
  (oY === 0) && (oY = 0.01);
  (oX === 0) && (oX = 0.01);
  let degEnd = Math.atan(oX / oY) / (2 * Math.PI) * 360;

  // 第一象限
  if (X > centerPointX && Y < centerPointY) {
    console.log('第一象限');
    setRotate(roateBox, degEnd);
  }
  // 第二象限
  if (X > centerPointX && Y > centerPointY) {
    console.log('第二象限');
    setRotate(roateBox, (180 - degEnd));
  }
  // 第三象限
  if (X < centerPointX && Y > centerPointY) {
    console.log('第三象限');
    setRotate(roateBox, (degEnd + 180));
  }
  // 第四象限
  if (X < centerPointX && Y < centerPointY) {
    console.log('第四象限');
    setRotate(roateBox, (360 - degEnd));
  }
};

$('#rotateBox .point').addEventListener('mousedown', function (e) {
  e.stopPropagation();
  document.addEventListener('mousemove', moveEvent, false);
}, false);

document.addEventListener('mouseup', function () {
  document.removeEventListener('mousemove', moveEvent);
}, false);

// 释放文档按下事件
document.onmouseup = function () {
  document.onmousemove = null;
};

// 右下角拉伸点
let startX, startY, owidth, oheight, oleft, otop;
const MAXWIDTH = 50;  // 限制最大宽度
const MAXHEIGHT = 50; // 限制最大高度
$('#rotateBox .rb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = moveX - startX;
    let mHeight = moveY - startY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = oleft + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左下角拉伸点
$('#rotateBox .lb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = startX - moveX;
    let mHeight = moveY - startY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左上角拉伸点
$('#rotateBox .lt-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = startX - moveX;
    let mHeight = startY - moveY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);


// 右上角拉伸点
$('#rotateBox .rt-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveX = e.clientX;
    let moveY = e.clientY;
    let mWidth = moveX - startX;
    let mHeight = startY - moveY;
    console.log(mWidth, mHeight);
    that.parentNode.style.left = oleft + 'px';
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);


// 中上拉伸点
$('#rotateBox .ct-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let mHeight = startY - moveY;
    that.parentNode.style.top = moveY + 'px';
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 中下拉伸点
$('#rotateBox .cb-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let mHeight = moveY - startY;
    that.parentNode.style.height = ((oheight + mHeight) > MAXHEIGHT ? (oheight + mHeight) : MAXHEIGHT) + 'px';
  };
}, false);

// 左中拉伸点
$('#rotateBox .cl-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let moveX = e.clientX;
    let mWidth = startX - moveX;
    that.parentNode.style.left = moveX + 'px';
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
  };
}, false);

// 右中拉伸点
$('#rotateBox .cr-point').addEventListener('mousedown', function (e) {
  let that = this;
  startX = e.clientX;
  startY = e.clientY;
  oleft = this.parentNode.getBoundingClientRect().left
  otop = this.parentNode.getBoundingClientRect().top
  owidth = this.parentNode.getBoundingClientRect().width;
  oheight = this.parentNode.getBoundingClientRect().height;
  e.stopPropagation();
  document.onmousemove = function (e) {
    let moveY = e.clientY;
    let moveX = e.clientX;
    let mWidth = moveX - startX;
    that.parentNode.style.width = (((owidth + mWidth) > MAXWIDTH) ? (owidth + mWidth) : MAXWIDTH) + 'px';
  };
}, false);

Dragble.js负责拖动元素位置

const $Dragble = {
  dom: '',
  isMove: false,
  left: '',
  top: '',
  mouseStartX: '',
  mouseStartY: '',
  positionType: '',
  mousemove: function(maxleft, maxtop) {
    $Dragble.dom.style.top = $Dragble.top + (window.event.pageY - $Dragble.mouseStartY) + 'px';
    $Dragble.dom.style.left = $Dragble.left + (window.event.pageX - $Dragble.mouseStartX) + 'px';
    // 这两行必须要有,为了移动的时候重置中心点的坐标
    centerPointX = $Dragble.dom.getBoundingClientRect().left + $Dragble.dom.getBoundingClientRect().width / 2;
    centerPointY = $Dragble.dom.getBoundingClientRect().top + $Dragble.dom.getBoundingClientRect().height / 2;
  },
  mouseup: function() {
    document.removeEventListener('mousemove', this.mousemove);
  },
  // 初始化数据
  intData: function(dom, type, maxLeft, maxTop) {
    this.dom = dom;
    this.isMove = true;
    this.positionType = type;
    this.dom.style.position = type;
    this.mouseStartX = window.event.pageX;
    this.mouseStartY = window.event.pageY;
    this.left = Number.parseFloat(this.dom.style.left);
    this.top = Number.parseFloat(this.dom.style.top);
    this.dom.style.left ? this.dom.style.left : this.dom.style.left = 0;
    this.dom.style.top ? this.dom.style.top : this.dom.style.top = 0;
  },
  mousedown: function(dom, type, maxLeft, maxTop) {
    this.intData(dom, type, maxLeft, maxTop);
    document.addEventListener('mousemove', this.mousemove, false);
    document.removeEventListener('mouseup', this.mousemove);
  }
};

html部分:

<!DOCTYPE html>
<html>
  <head>
    <link href="./css/Roate.css" rel="stylesheet" />
  </head>
  <body>
    <div 
      class="box"
      onmousedown="$Dragble.mousedown(this, 'relative')"
		  onmouseup="$Dragble.mouseup()"
      id="rotateBox"
      style="transform: rotate(0deg);left:0;top:0;"
    >
      正
      <!--img src="./img.png"/-->
      <div class="point" title="点击旋转"></div>
      <div class="lt-point" title="左上角"></div>
      <div class="rt-point" title="右上角"></div>
      <div class="rb-point" title="右下角"></div>
      <div class="lb-point" title="左下角"></div>
      <div class="ct-point" title="中上点"></div>
      <div class="cb-point" title="中下点"></div>
      <div class="cl-point" title="左中点"></div>
      <div class="cr-point" title="右中点"></div>
    </div>
    <script src="./js/Roate.js"></script>
    <script src="./js/Dragble.js"></script>
  </body>
</html>

CSS部分代码:

#rotateBox {
  position:relative;
  height: 200px;
  width: 200px;
  background:red;
  font-size:45px;
  color:#fff;
  line-height:200px;
  text-align:center;
  user-select: none;
  border:4px solid #AED271;
}
#rotateBox .point{
  position:absolute;
  left: 50%;
  top:-50px;
  margin-left:-10px;
  height:20px;
  width:20px;
  border-radius:20px;
  background: url('../img/rotate-icon.jpg') no-repeat center;
  background-size: 100%;
}
#rotateBox .rb-point,
.lb-point,
.lt-point,
.rt-point,
.ct-point,
.cb-point,
.cl-point,
.cr-point{
  height:14px;
  width:14px;
  background: #AED271;
  border-radius:20px;
  position:absolute;
  right: -10px;
  bottom:-10px;
  cursor: nw-resize;
}
#rotateBox .lb-point{
  left: -10px;
  bottom:-10px;
  cursor: sw-resize;
}
#rotateBox .lt-point{
  left: -10px;
  top:-10px;
  cursor: nw-resize;
}
#rotateBox .rt-point{
  right: -10px;
  top:-10px;
  cursor: sw-resize;
}
#rotateBox img {
  position:absolute;
  left: 0;
  height:100%;
  width:100%;
}
#rotateBox .ct-point {
  left: 50%;
  top: -10px;
  margin-left:-5px;
  cursor: s-resize;
}
#rotateBox .cb-point {
  left: 50%;
  bottom: -10px;
  margin-left:-5px;
  cursor: s-resize;
}
#rotateBox .cl-point {
  top: 50%;
  left: -10px;
  margin-top:-5px;
  cursor: w-resize;
}
#rotateBox .cr-point {
  top: 50%;
  right: -10px;
  margin-top:-5px;
  cursor: w-resize;
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要用原生 JavaScript 创建一个树型结构的表格,并且实现行的多选、拖拽、替换右键功能,可以按照以下步骤进行: 1. 构建 HTML 结构 首先需要构建基本的 HTML 结构,包含表格的基本结构和样式: ```html <table id="mytable"> <thead> <tr> <th>名称</th> <th>描述</th> <th>类型</th> </tr> </thead> <tbody> <tr data-id="1"> <td>节1</td> <td>描述1</td> <td>类型1</td> </tr> <tr data-id="2" data-parent-id="1"> <td>节2</td> <td>描述2</td> <td>类型2</td> </tr> <tr data-id="3" data-parent-id="1"> <td>节3</td> <td>描述3</td> <td>类型3</td> </tr> </tbody> </table> ``` 其中,每个行的唯一标识使用 `data-id` 属性来表示,每个行的父级标识使用 `data-parent-id` 属性来表示。 2. 添加样式 为了使表格更具有树形结构的特征,需要添加一些 CSS 样式: ```css #mytable td { padding-left: 20px; } #mytable tr[data-parent-id] { display: none; } #mytable tr[data-parent-id].expanded { display: table-row; } ``` 其中,`#mytable td` 用于设置每个单元格的左边距,`#mytable tr[data-parent-id]` 用于隐藏所有子节,`#mytable tr[data-parent-id].expanded` 用于显示已经展开的子节。 3. 添加多选功能 为了实现行的多选功能,可以使用以下代码: ```javascript var selectedRows = []; document.getElementById("mytable").addEventListener("click", function(event) { var target = event.target; if (target.tagName.toLowerCase() === "td") { var row = target.parentNode; if (selectedRows.indexOf(row) === -1) { selectedRows.push(row); row.classList.add("selected"); } else { selectedRows.splice(selectedRows.indexOf(row), 1); row.classList.remove("selected"); } } }); ``` 其中,`selectedRows` 用于存储选中的行,`document.getElementById("mytable").addEventListener("click", function(event) {...})` 用于监听表格的击事件,并且判断击的元素是否为单元格,如果是,则获取该行,并且将该行添加到 `selectedRows` 数组中,并且添加 `selected` 类名;如果已经存在于 `selectedRows` 中,则将该行从 `selectedRows` 数组中移除,并且移除 `selected` 类名。 4. 添加拖拽功能 为了实现行的拖拽功能,可以使用以下代码: ```javascript var draggingRow = null; document.getElementById("mytable").addEventListener("mousedown", function(event) { var target = event.target; if (target.tagName.toLowerCase() === "td") { draggingRow = target.parentNode; } }); document.getElementById("mytable").addEventListener("mousemove", function(event) { if (draggingRow !== null) { draggingRow.classList.add("dragging"); } }); document.getElementById("mytable").addEventListener("mouseup", function(event) { if (draggingRow !== null) { draggingRow.classList.remove("dragging"); draggingRow = null; } }); ``` 其中,`draggingRow` 用于存储正在拖拽的行,`document.getElementById("mytable").addEventListener("mousedown", function(event) {...})` 用于监听鼠标按下事件,如果按下的元素为单元格,则获取该行,并且将该行赋值给 `draggingRow`;`document.getElementById("mytable").addEventListener("mousemove", function(event) {...})` 用于监听鼠标移动事件,如果正在拖拽行,则为该行添加 `dragging` 类名;`document.getElementById("mytable").addEventListener("mouseup", function(event) {...})` 用于监听鼠标松开事件,如果正在拖拽行,则将 `draggingRow` 赋值为 null,并且移除 `dragging` 类名。 5. 添加替换右键功能 为了实现行的替换右键功能,可以使用以下代码: ```javascript document.getElementById("mytable").addEventListener("contextmenu", function(event) { var target = event.target; if (target.tagName.toLowerCase() === "td") { var row = target.parentNode; var parentId = row.getAttribute("data-parent-id"); if (parentId !== null) { event.preventDefault(); var parentRow = document.querySelector("[data-id='" + parentId + "']"); var nextSiblingRow = parentRow.nextElementSibling; if (nextSiblingRow !== null) { parentRow.parentNode.insertBefore(row, nextSiblingRow); } else { parentRow.parentNode.appendChild(row); } } } }); ``` 其中,`document.getElementById("mytable").addEventListener("contextmenu", function(event) {...})` 用于监听右键菜单事件,如果右键菜单的元素为单元格,则获取该行,并且获取该行的父级标识 `data-parent-id`,如果存在,则阻止右键菜单事件的默认行为,并且获取该行的父级行和下一个兄弟行,然后将该行插入到父级行和下一个兄弟行之间。 综上所述,以上步骤就是用原生 JavaScript 创建一个树型结构的表格,并且实现行的多选、拖拽、替换右键功能的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值