我正在研究一个代码,该代码显示了如何动态调整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
答案 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>