如何根据js中的父位置动态调整div的大小

时间:2019-08-23 07:32:05

标签: javascript html css resize

我正在研究一个代码,该代码显示了如何动态调整div的大小。但是代码停留在1个元素上,我做了一些工作才能转换成多个div尺寸调整器。

现在,在调整大小时,鼠标和div之间会出现一个空格,我的目标是确保根据父位置准确地调整每个元素的大小,使其具有精确的鼠标位置。任何会改变我观点的方法都适用。不绑定到调整大小节点,而是直接保留div边框也是可能的。

到目前为止我已经完成的事情:

-通过鼠标位置调整了多个div的大小。

-在函数中保留第一个位置信息。

-父母与子女之间的累计差异。

我想要实现的目标:

-确保在调整大小时保持器位于鼠标位置下,而鼠标和div之间没有任何空间。

经过几次尝试调整大小后,我看到由父元素的页边距,填充...等引起的空间出现。 div开始调整大小,并在div和鼠标位置之间留出一个空格。

我需要一个递归解决方案来正确调整div的大小和位置。

可能是另一种方法,可以只计算父对象内部的x,y,w,h,但是我需要一些有关如何使用鼠标来实现这一点的解释...

function resizeable() {
  var resizers = document.querySelectorAll('.n, .s, .w, .e, .nw, .ne, .se, .sw');
  const min = 40;
  for (let i = 0; i < resizers.length; i++) {
    const currentResizer = resizers[i];
    const element = currentResizer.parentElement;
    const parent = currentResizer.parentElement.parentElement;
    let p;
    let c;
    let original_w = 0;
    let original_h = 0;
    let parent_x = 0;
    let parent_y = 0;
    let child_x = 0;
    let child_y = 0;
    let mouse_x = 0;
    let mouse_y = 0;
    let scale_x = 0;
    let scale_y = 0;
    // Mouse events
    currentResizer.addEventListener('mousedown', function(e) {
      first(e);
      document.addEventListener('mousemove', resize);
      document.addEventListener('mouseup', stopResize);
      e.preventDefault();
    });
    // Log
    function log(e){
      var str = 'original_w['+original_w+'] original_h['+original_h+'] \n'+
                'parent_x['+parent_x+'] parent_y['+parent_y+'] \n'+
                'child_x['+child_x+'] child_y['+child_y+'] \n'+
                'scale_x['+scale_x+'] scale_y['+scale_y+'] \n'+
                'mouse_x['+mouse_x+'] mouse_y['+mouse_y+'] \n'+
                'e.pageX['+e.pageX+'] e.pageY['+e.pageY+'] \n'+
                'obj.left['+element.style.left+'] obj.top['+element.style.top+']';
      console.log(str);
      /**/
      str = '<table>'+
          '<tr>'+
            '<th colspan="2">First Locations:</td>'+
          '</tr>'+
          '<tr>'+
            '<td>original_w['+original_w+']</td>'+
            '<td>original_h['+original_h+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>parent_x['+parent_x+']</td>'+
            '<td>parent_y['+parent_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>child_x['+child_x+']</td>'+
            '<td>child_y['+child_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>scale_x['+scale_x+']</td>'+
            '<td>scale_y['+scale_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>mouse_x['+mouse_x+']</td>'+
            '<td>mouse_y['+mouse_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>e.pageX['+e.pageX+']</td>'+
            '<td>e.pageY['+e.pageY+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>obj.left['+element.style.left+']</td>'+
            '<td>obj.top['+element.style.top+']</td>'+
          '</tr>'
      '</table>';
      var m = document.getElementById("nfo"); // Debug element
      m.innerHTML = str;
    }
    // First location & width
    function first(e) {
      c = element.getBoundingClientRect();
      child_y = c.top;
      child_x = c.left;
      p = parent.getBoundingClientRect();
      parent_y = p.top;
      parent_x = p.left;
      original_w = parseFloat(c.width).toFixed(2);
      original_h = parseFloat(c.height).toFixed(2);
      scale_y = parseFloat(c.height / element.offsetHeight).toFixed(2);
      scale_x = parseFloat(c.width / element.offsetWidth).toFixed(2);
      mouse_y = e.pageY;
      mouse_x = e.pageX;
      log(e);
    }
    // Resize process
    function resize(e) {
      element.style.position = "absolute";
      if (currentResizer.classList.contains('se')) {
        const width = e.pageX - child_x;
        const height = e.pageY - child_y;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('sw')) {
        const width = original_w - (e.pageX - child_x);
        const height = e.pageY - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
        if (width > min) {
          element.style.left = e.pageX - parent_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('ne')) {
        const width = e.pageX - child_x;
        const height = original_h - (e.pageY - mouse_y);
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top =  e.pageY - parent_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('nw')) {
        const width = original_w - (e.pageX - child_x);
        const height = original_h - (e.pageY - mouse_y);
        if (width > min) {
          element.style.left = e.pageX - parent_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - parent_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('e')) {
        const width = e.pageX - child_x;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('s')) {
        const height = e.pageY - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('w')) {
        const width = original_w - (e.pageX - child_x);
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
          element.style.left = (e.pageX - parent_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('n')) {
        const height = original_h - (e.pageY - mouse_y);
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - parent_y + 'px';
        }
      }
      log(e);
    }
    // When mouse released stop
    function stopResize(e) {
      first(e);
      document.removeEventListener('mousemove', resize);
    }
  }
}
resizeable();
.another_element_on_the_way {
  position: relative;
  width: 100px;
  height: 100px;
  float: left;
}
#nfo {
  position: relative;
  float: left;
}
div {
  position: absolute;
  background-color: grey;
}
.holder {
  float: left;
  clear: left;
  position: relative;
  margin: 20px;
  width: 550px;
  height: 600px;
}
.scaled:hover:before, .regular:hover:before {
  content: '';
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% - 6px);
  height: calc(100% - 6px);
  border: 6px solid #ccc;
}
.regular:nth-child(1){
  top: 5px;
  left: 5px;
  width: 120px;
  height: 120px;
  background-color: red;
}
.regular:nth-child(3){
  top: 270px;
  left: 60px;
  width: 240px;
  height: 180px;
  background-color: blue;
}
.scaled {
  top: 150px;
  left: 25px;
  width: 160px;
  height: 160px;
  transform: scale(0.6) translate(0, 0);
  transform-origin: top left 0px;
  background-color: green;
  overflow: visible;
}
.previewHeader {
  position: absolute;
  top: 10px;
  left: 10px;
  background-color: #eee;
  border: 1px solid #dedede;
}
.n, .s, .w, .e, .nw, .ne, .se, .sw {
  position: absolute;
  width: 18px;
  height: 18px;
  border: 1px solid grey;
  border-radius: 20px;
  background-color: #fff;
}
.n:hover, .s:hover, .w:hover, .e:hover,
.nw:hover, .ne:hover, .se:hover, .sw:hover {
  background-color: red;
}
.nw {
  top: -10px;
  left: -10px;
  cursor: nw-resize;
}
.ne {
  top: -10px;
  left: calc(100% - 10px);
  cursor: ne-resize;
}
.sw {
  top: calc(100% - 10px);
  left: -10px;
  cursor: sw-resize;
}
.se {
  top: calc(100% - 10px);
  left: calc(100% - 10px);
  cursor: se-resize;
}
.n {
  top: -10px;
  left: calc(50% - 10px);
  cursor: n-resize;
}
.w {
  top: calc(50% - 10px);
  left: -10px;
  cursor: w-resize;
}
.e {
  top: calc(50% - 10px);
  left:  calc(100% - 10px);
  cursor: e-resize;
}
.s {
  top: calc(100% - 10px);
  left: calc(50% - 10px);
  cursor: s-resize;
}
<div class="another_element_on_the_way">
</div>
<div class="another_element_on_the_way">
</div>
<div class="another_element_on_the_way">
</div>
<div class="another_element_on_the_way">
</div>
<div class="another_element_on_the_way">
</div>
<div class="another_element_on_the_way">
</div>
<div class="holder">
  <div class="regular">
      <div class="previewHeader">Resizable</div>
      <div class="nw"></div>
      <div class="ne"></div>
      <div class="sw"></div>
      <div class="se"></div>
      <div class="n"></div>
      <div class="s"></div>
      <div class="w"></div>
      <div class="e"></div>
  </div>
  <div class="scaled">
    <div class="previewHeader">Scaled</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
  <div class="regular">
    <div class="previewHeader">Resizable</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
</div>
<div id="nfo"> X & Y</div>

还有一个Codepen可以更清楚地显示它:https://codepen.io/BerkerYuceer/pen/gOYwqdb

2 个答案:

答案 0 :(得分:4)

您可以使用getComputedStyle通过正则表达式获取transform值,并将1 / scale值应用于所需的坐标。我只能解决East持有人的问题(我对坐标几何:P太傻了):

let match = getComputedStyle(element)
           .transform.match(/matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/);
let scale = 1; //for .regular folks
if (match && +match[1] != 0)
   scale = 1 / +match[1]; //because we need to unapply the transformation

示例:

function resizeable() {
  var resizers = document.querySelectorAll('.n, .s, .w, .e, .nw, .ne, .se, .sw');
  const min = 40;
  for (let i = 0; i < resizers.length; i++) {
    const currentResizer = resizers[i];
    const element = currentResizer.parentElement;
    const parent = currentResizer.parentElement.parentElement;
    let p;
    let c;
    let original_w = 0;
    let original_h = 0;
    let parent_x = 0;
    let parent_y = 0;
    let child_x = 0;
    let child_y = 0;
    let mouse_x = 0;
    let mouse_y = 0;
    let scale_x = 0;
    let scale_y = 0;
    let scroll_x = 0;
    let scroll_y = 0;
    // Mouse events
    currentResizer.addEventListener('mousedown', function(e) {
      first(e);
      document.addEventListener('mousemove', resize);
      document.addEventListener('mouseup', stopResize);
      e.preventDefault();
    });
    // Log
    function log(e){
      var str = 'original_w['+original_w+'] original_h['+original_h+'] \n'+
                'parent_x['+parent_x+'] parent_y['+parent_y+'] \n'+
                'scroll_x['+scroll_x+'] scroll_y['+scroll_y+'] \n'+
                'child_x['+child_x+'] child_y['+child_y+'] \n'+
                'scale_x['+scale_x+'] scale_y['+scale_y+'] \n'+
                'mouse_x['+mouse_x+'] mouse_y['+mouse_y+'] \n'+
                'e.pageX['+e.pageX+'] e.pageY['+e.pageY+'] \n'+
                'obj.left['+element.style.left+'] obj.top['+element.style.top+']';
      console.log(str);
      /**/
      str = '<table>'+
          '<tr>'+
            '<th colspan="2">First Locations:</td>'+
          '</tr>'+
          '<tr>'+
            '<td>original_w['+original_w+']</td>'+
            '<td>original_h['+original_h+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>parent_x['+parent_x+']</td>'+
            '<td>parent_y['+parent_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>scroll_x['+scroll_x+']</td>'+
            '<td>scroll_y['+scroll_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>child_x['+child_x+']</td>'+
            '<td>child_y['+child_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>scale_x['+scale_x+']</td>'+
            '<td>scale_y['+scale_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>mouse_x['+mouse_x+']</td>'+
            '<td>mouse_y['+mouse_y+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>e.pageX['+e.pageX+']</td>'+
            '<td>e.pageY['+e.pageY+']</td>'+
          '</tr>'+
          '<tr>'+
            '<td>obj.left['+element.style.left+']</td>'+
            '<td>obj.top['+element.style.top+']</td>'+
          '</tr>'
      '</table>';
      var m = document.getElementById("nfo"); // Debug element
      m.innerHTML = str;
    }
    // First location & width
    function first(e) {
      c = element.getBoundingClientRect();
      child_y = c.top;
      child_x = c.left;
      p = parent.getBoundingClientRect();
      parent_y = p.top;
      parent_x = p.left;
      scroll_y = window.scrollY;
      scroll_x = window.scrollX;
      original_w = parseFloat(c.width).toFixed(2);
      original_h = parseFloat(c.height).toFixed(2);
      scale_y = parseFloat(c.height / element.offsetHeight).toFixed(2);
      scale_x = parseFloat(c.width / element.offsetWidth).toFixed(2);
      mouse_y = e.pageY - scroll_y;
      mouse_x = e.pageX - scroll_x;
      log(e);
    }
    // Resize process
    function resize(e) {
      element.style.position = "absolute";
      if (currentResizer.classList.contains('se')) {
        const width = e.pageX - scroll_x - child_x ;
        const height = e.pageY - scroll_y - child_y ;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('sw')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        const height = e.pageY - scroll_y - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
        if (width > min) {
          element.style.left = e.pageX - scroll_x - parent_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('ne')) {
        const width = e.pageX - child_x - scroll_x;
        const height = original_h - (e.pageY - mouse_y - scroll_y);
        if (width > min) {
          element.style.width = (width / scale_x)  + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top =  e.pageY - parent_y - scroll_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('nw')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        const height = original_h - (e.pageY - scroll_y - mouse_y);
        if (width > min) {
          element.style.left = e.pageX - parent_x - scroll_x + 'px';
          element.style.width = (width / scale_x) + 'px';
        }
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - parent_y - scroll_y + 'px';
        }
      }
      else if (currentResizer.classList.contains('e')) {
        const width = e.pageX - scroll_x - child_x;
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('s')) {
        const height = e.pageY - scroll_y - child_y;
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
        }
      }
      else if (currentResizer.classList.contains('w')) {
        const width = original_w - (e.pageX - scroll_x - child_x);
        if (width > min) {
          element.style.width = (width / scale_x) + 'px';
          element.style.left = (e.pageX - scroll_x - parent_x) + 'px';
        }
      }
      else if (currentResizer.classList.contains('n')) {
        const height = original_h - (e.pageY - scroll_y - mouse_y);
        if (height > min) {
          element.style.height = (height / scale_y) + 'px';
          element.style.top = e.pageY - scroll_y - parent_y + 'px';
        }
      }
      log(e);
    }
    // When mouse released stop
    function stopResize(e) {
      first(e);
      document.removeEventListener('mousemove', resize);
    }
  }
}
resizeable();
body {
  width: 1200px;
}
.another_element_on_the_top {
  position: relative;
  float: left;
  margin: 10px;
  width: 100px;
  height: 100px;
}
.another_element_on_the_left {
  position: relative;
  float: left;
  clear: left;
  margin: 10px;
  width: 100px;
  height: 100px;
}
#nfo {
  position: relative;
  float: left;
}
div {
  position: absolute;
  background-color: grey;
}
.holder {
  float: left;
  position: relative;
  margin: -470px 20px 20px 20px;
  width: 550px;
  height: 600px;
}
.scaled:hover:before, .regular:hover:before {
  content: '';
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% - 6px);
  height: calc(100% - 6px);
  border: 6px solid #ccc;
}
.regular:nth-child(1){
  top: 5px;
  left: 5px;
  width: 120px;
  height: 120px;
  background-color: red;
}
.regular:nth-child(3){
  top: 270px;
  left: 60px;
  width: 240px;
  height: 180px;
  background-color: blue;
}
.scaled {
  top: 150px;
  left: 25px;
  width: 160px;
  height: 160px;
  transform: scale(0.6) translate(0, 0);
  transform-origin: top left 0px;
  background-color: green;
  overflow: visible;
}
.previewHeader {
  position: absolute;
  top: 10px;
  left: 10px;
  background-color: #eee;
  border: 1px solid #dedede;
}
.n, .s, .w, .e, .nw, .ne, .se, .sw {
  position: absolute;
  width: 18px;
  height: 18px;
  border: 1px solid grey;
  border-radius: 20px;
  background-color: #fff;
}
.n:hover, .s:hover, .w:hover, .e:hover,
.nw:hover, .ne:hover, .se:hover, .sw:hover {
  background-color: red;
}
.nw {
  top: -10px;
  left: -10px;
  cursor: nw-resize;
}
.ne {
  top: -10px;
  left: calc(100% - 10px);
  cursor: ne-resize;
}
.sw {
  top: calc(100% - 10px);
  left: -10px;
  cursor: sw-resize;
}
.se {
  top: calc(100% - 10px);
  left: calc(100% - 10px);
  cursor: se-resize;
}
.n {
  top: -10px;
  left: calc(50% - 10px);
  cursor: n-resize;
}
.w {
  top: calc(50% - 10px);
  left: -10px;
  cursor: w-resize;
}
.e {
  top: calc(50% - 10px);
  left:  calc(100% - 10px);
  cursor: e-resize;
}
.s {
  top: calc(100% - 10px);
  left: calc(50% - 10px);
  cursor: s-resize;
}
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>
<div class="another_element_on_the_top">
</div>

<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>
<div class="another_element_on_the_left">
</div>

<div class="holder">
  <div class="regular">
      <div class="previewHeader">Resizable</div>
      <div class="nw"></div>
      <div class="ne"></div>
      <div class="sw"></div>
      <div class="se"></div>
      <div class="n"></div>
      <div class="s"></div>
      <div class="w"></div>
      <div class="e"></div>
  </div>
  <div class="scaled">
    <div class="previewHeader">Scaled</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
  <div class="regular">
    <div class="previewHeader">Resizable</div>
    <div class="nw"></div>
    <div class="ne"></div>
    <div class="sw"></div>
    <div class="se"></div>
    <div class="n"></div>
    <div class="s"></div>
    <div class="w"></div>
    <div class="e"></div>
  </div>
</div>
<div id="nfo"> X & Y</div>

或在另一个问题中使用this方法。

   var element = document.querySelector('...');
   var scaleX = element.getBoundingClientRect().width / element.offsetWidth;
  

”之所以有效,是因为getBoundingClientRect返回实际尺寸   而offsetWidth / Height是未缩放的大小。“

编辑:窗口。已添加滚动X / Y。现在它可以在滚动页面中使用。

在页面的任何部分供以后参考,它均有效。即使对象已缩放。

答案 1 :(得分:3)

您是否考虑过使用可调整大小的jQuery O.O?这样可以节省很多时间和麻烦:)

在这里您可以检查它,这很简单:https://jsfiddle.net/maehy5tj/1/

这就是您需要做的一切:)

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Resizable - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <link rel="stylesheet" href="/resources/demos/style.css">
  <style>
  #resizable { width: 150px; height: 150px; padding: 0.5em; }
  #resizable h3 { text-align: center; margin: 0; }
  </style>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script>
  $( function() {
    $( "#resizable" ).resizable();
  } );
  </script>
</head>
<body>

<div id="resizable" class="ui-widget-content">
  <h3 class="ui-widget-header">Resizable</h3>
</div>


</body>
</html>