8

核心问题:我需要正确建立<div>嵌套在可调整大小的parent中的 child 的高度<div>。调整父级的大小时,子级不应超出父级的边界。父级本身应该受到限制,以免它缩小到超出子级的最小可滚动范围。

DEAD ENDS:通过数小时的研究,我了解到 CSS,即使使用该calc()函数,也无法动态设置 a 的高度和宽度<div>。此外,似乎为了防止子级<div>溢出其父级的尺寸,父级本身必须具有固定大小。在后一种情况下,样式height: auto; height: inherit;height: 100%;可能都产生相同的结果。

之前在这里提出过类似的问题,但我发现没有一个可以解决调整大小的问题。例如,为以下问题提供的解决方案无法正确解决我的问题。

防止子div溢出父div

在我的情况下,我有一个<div>将被用户调整大小和/或拖动到屏幕的任何部分的。<div>如有必要,其内容应自动滚动。<div>在任何情况下,它们都不应超过可调整大小的容器的尺寸。我的情况要求我不使用 jQuery,但欢迎使用 JavaScript 解决方案。(甚至 PERL 也可能值得,因为我将提供页面并通过 Perl 平台上的 AJAX 对其进行更新。)

下面包含一个完整的示例,它显示了<div>即使启用了滚动,子级如何超过其父级,并且无论父级如何<div>调整大小都会发生这种情况。(我已经在 Firefox 和 Safari 中测试过。)

请注意,在我的实际应用程序中,<div>每个用户从菜单中选择的内容将通过 AJAX 提供<select>,并且内容将具有不同的长度。无论返回的长度如何,容器/父级<div>都应根据用户自己的调整保持相同的大小。

<!DOCTYPE html>
<HTML lang="utf8">
<head>
<title>Example of Resizable/Draggable Container Div with Nested (Overflowing) Contents</title>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">

<style type="text/css">
.nested {
  background-color: #ffffcc;
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 720px;
  height: inherit;
  color: #000;
  text-align: left;
  font-weight: normal;
  } 
.resizable {
  background: white;
  min-width: 100px;
  min-height: 120px;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 80px;
  left: 60px;
display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.resizable .resizers{
  width: 100%;
  height: 100%;
  border: 3px solid #4286f4;
  box-sizing: border-box;
}
.resizable .resizers .resizer{
  width: 3px;
  height: 5px;
  border-radius: 50%;  /*magic to turn square into circle*/
  background: black;
  border: 3px solid #4286f4;
  position: absolute;
  }
.resizable .resizers .resizer.top-left {
  left: -2px;
  top: -2px;
  cursor: nwse-resize; /*resizer cursor*/
}
.resizable .resizers .resizer.top-right {
  right: -2px;
  top: -2px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-left {
  left: -2px;
  bottom: -2px;
  cursor: nesw-resize;
}
.resizable .resizers .resizer.bottom-right {
  right: -2px;
  bottom: -2px;
  cursor: nwse-resize;
}  
#dragselection {
    position: absolute;
    top: 6px;
    left: 3%;
    z-index: 8;
    background-color: #f1f1f1;
    border: 1px solid #d3d3d3;
display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.header {
    padding: 4px;
    margin-left: 2px;
    margin-right: 2px;
    margin-top: 4px;
    margin-bottom: 4px;
    text-align: center;
    cursor: move;
    z-index: 10;
    background-color: #2168a8;
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    }
#CV1 {
    min-width:150px; 
    min-height:150px; 
    }    
.top-banner {
display: inline-block; 
margin-top: 0px; 
margin-right: 7px; 
margin-left: 5px; 
margin-bottom: 7px; 
background-color: #afb; 
border-radius: 12px; 
opacity: 0.9; 
box-shadow: 3px 3px #878087; 
max-width: 100%; 
height: auto;
align: auto;
text-align: center;
    }     
</style>


</head>
<body onload="dragElement('dragselection');">

<div class="top-banner">
<p style="margin-top: 30px; margin-right: 60px; margin-left: 60px; margin-bottom: 30px; text-align:center; font-size: 2.0em; color:#fff;text-shadow: 2px 1px 2px #050050;">&#9840; Easy Text Reference &#9840;</p>
</div>

<form id="myform" name="nmyform" method="POST" accept-charset="utf-8" action="URL_for_CGI" >
<article>

<h1>Example:</h1>

<div id="flex-box" name="nflex-box" class="flex-container">

<div class="container" id="mainscreen" ondrop="drop(event)" ondragover="allowDrop(event)">
<div class="header flex-container-head" id="header-box" name="nheader-box">  

       
<div class='resizable' id="dragselection" style="border: 1px solid gray; font-size:18px; height: 250px; ">
  <div class='resizers'>
    <div class='resizer top-left'></div>
    <div class='resizer top-right'></div>
    <div class='resizer bottom-left'></div>
    <div class='resizer bottom-right'></div>
    
    <div id="dragselectionheader" class='header'>
    Your Text Selection
 
  <select id="get_text" name="nget_text"  onchange="getAjaxResult(['selection_text','recordnum'], 'POST'); ">
<option value="">---- Selection Menu ----</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
   
   </div>
    
  <div id="CV1" class="nested">
  A sample text:
  
  In the annals of human history, the growth of nations, the rise and fall of empires, appear as if dependent on the will and prowess of man; the shaping of events seems, to a great degree, to be determined by his power, ambition, or caprice. But in the word of God the curtain is drawn aside, and we behold, above, behind, and through all the play and counterplay of human interest and power and passions, the agencies of the All-merciful One, silently, patiently working out the counsels of His own will.  (Prophets and Kings, p. 499)
  </div>
  </div>
</div>


</div>
</div>

</div>

</article>

</form>


<script type="text/javascript">

/* Make the DIV element draggable: */
dragElement(document.getElementById(("dragselection")));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
    /* if present, the header is where you move the DIV from: */
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
    /* otherwise, move the DIV from anywhere inside the DIV: */
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    /* get the mouse cursor position at startup: */
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    /* call a function whenever the cursor moves: */
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    /* calculate the new cursor position: */
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    /* set the element's new position: */
    if ((elmnt.offsetTop - pos2) < 0) { 
         elmnt.style.top = '0px'
    } else {     
         elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    }     
    if ((elmnt.offsetLeft - pos1) < 0) {
         elmnt.style.left = '0px'
    } else {
         elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }
  }

  function closeDragElement() {
    /* stop moving when mouse button is released:*/
    document.onmouseup = null;
    document.onmousemove = null;    
  }
}

/* Modeled after: 
https://medium.com/the-z/making-a-resizable-div-in-js-is-not-easy-as-you-think-bda19a1bc53d 
*/

function makeResizableDiv(div) {
  const element = document.querySelector(div);
  const resizers = document.querySelectorAll(div + ' .resizer')
  const minimum_size = 120;
  var original_width = 0;
  var original_height = 0;
  var original_x = 0;
  var original_y = 0;
  var original_mouse_x = 0;
  var original_mouse_y = 0;

  for (var i = 0;i < resizers.length; i++) {
    const currentResizer = resizers[i];
    currentResizer.addEventListener('mousedown', function(e) {
      e.preventDefault()
      original_width = parseFloat(getComputedStyle(element, null).getPropertyValue('width').replace('px', ''));
      original_height = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
      original_x = element.getBoundingClientRect().left;
      original_y = element.getBoundingClientRect().top;
      original_mouse_x = e.pageX;
      original_mouse_y = e.pageY;
      window.addEventListener('mousemove', resize)
      window.addEventListener('mouseup', stopResize)
    })
    
    function resize(e) {
      if (currentResizer.classList.contains('bottom-right')) {
        const width = original_width + (e.pageX - original_mouse_x);     
        const height = original_height + (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x + 'px' 
        }
        if (height > minimum_size) {
          element.style.height = height + 'px'     
          element.style.top = original_y + 'px' 
        }
      }
      else if (currentResizer.classList.contains('bottom-left')) {
        const height = original_height + (e.pageY - original_mouse_y)     
        const width = original_width - (e.pageX - original_mouse_x)     
        if (height > minimum_size) {
          element.style.height = height + 'px'     
          element.style.top = original_y+'px' 
        }
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x+(e.pageX-original_mouse_x)+'px' 
        }
      }
      else if (currentResizer.classList.contains('top-right')) {
        const width = original_width + (e.pageX - original_mouse_x)     
        const height = original_height - (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x + 'px'
        }
        if (height > minimum_size) {
          if (original_y+(e.pageY-original_mouse_y) < 0 ) {
            element.style.top = '0px'
          } else {
            element.style.height = height + 'px'     
            element.style.top = original_y+(e.pageY-original_mouse_y)+'px' 
          }
        }
      }
      else {          /* top-left */
        const width = original_width - (e.pageX - original_mouse_x)     
        const height = original_height - (e.pageY - original_mouse_y)     
        if (width > minimum_size) {
          element.style.width = width + 'px'     
          element.style.left = original_x+(e.pageX-original_mouse_x)+'px' 
        }
        if (height > minimum_size) {
         if (original_y+(e.pageY-original_mouse_y) < 0 ) {
            element.style.top = '0px'
          } else {
            element.style.height = height + 'px'     
            element.style.top = original_y+(e.pageY-original_mouse_y)+'px' 
          }
        }
      }
    }
    
    function stopResize() {
      window.removeEventListener('mousemove', resize)
    }
  }
}
makeResizableDiv('.resizable')

</script>
</body>
</html>

更新:我已经调整了上面的代码以反映迄今为止提供的建议。不幸的是,我无法使用这种配置来限制父级的宽度。任何低于 100%(或自动)的东西都会被孩子继承,结果很不利。但是,我不希望父级占据屏幕的整个宽度,所以这个解决方案是不够的。

我现在想出了一个可以与 Firefox 一起使用的解决方法。我的 Safari 似乎不接受flex选项,所以仍然没有跨浏览器的解决方案。对于 Firefox,下面的 JavaScript 代码可以设置<div>页面加载后的位置,如下:

document.getElementById('dragselection').setAttribute("style","width:320px; height:240px; font-size:18px;");

我现在了解到,以下代码更能跨浏览器兼容,并导致 Safari 正确呈现它。

display: -webkit-box;   /* OLD - iOS 6-, Safari 3.1-6, BB7 */
display: -ms-flexbox;  /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */
display: flex;         /* NEW, Spec - Firefox, Chrome, Opera */
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;

我已经在示例脚本的两个地方更新了该代码。这在这一点上可能是可行的。

4

1 回答 1

5

你可以在这里使用 flexbox css。父 DIV 将是 flex, flex-direction: 列。

并且对于最小可拖动屏幕,父级高度为 120px,而子级最小高度为 150px,请从 #CV1 中删除样式。

您可以更新这些样式并检查吗?

.resizable .resizers{
  width: 100%;
  height: 100%;
  border: 3px solid #4286f4;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.nested {
  background-color: #ffffcc;
  overflow-y: auto;
  overflow-x: hidden;
  max-height: 720px;
  height: inherit;
  color: #000;
  text-align: left;
  font-weight: normal;
  }
于 2019-02-21T06:25:15.390 回答