【问题标题】:How to scale multiple divs and stay inside of container?如何缩放多个 div 并留在容器内?
【发布时间】:2017-06-20 23:46:28
【问题描述】:

我正在构建一个网格 UI,用户应该能够在其中单击单元格来缩放它们。

期望的行为:

  • 单元格不应超出容器并被裁剪*。
  • 单元格可以与其他单元格重叠(缩放时)。
  • (一次只需要缩放一个单元格。这不是我们最关心的问题)。

*左:不受欢迎的行为(部分单元格 O 消失了)。 右:期望的行为

我的方法:

显然,我可以同时transform: scale() translate(),以达到预期的效果。 您可以通过 cell N (translateY(22px)) 看到这一点。

问题:

这种方法不能很好地扩展到 9 个单元(更不用说 90 个,这是我的实际用例)。

容器必须overflow: hidden。滚动等不是一种选择。

我的问题:

这感觉像是一个非常粗暴的尝试,试图解决某人必须已经以编程方式解决的问题。

有没有更好的方法来构建这样的 UI?(我对插件或其他方法持开放态度)。

如果没有,用 jQuery 编写脚本的好方法是什么?

$(function() {
$(".cell").click(function() {
    $(this).toggleClass("zoom-in");
  });
});
.grid {
  width: 300px;
  height: 300px;
  background: gray;
  overflow: hidden;
}

.cell {
  background: tomato;
  width: 30%;
  height: 30%;
  margin: 5px;
  float: left;
  text-align: center;
  z-index: 999;
  transition: all 0.2s ease-in-out;
}

.zoom-in {
  transform: scale(2);
  transition: all 0.2s ease-in-out; 
}

#nord {
  background-color: white;
}
#nord.zoom-in {
  transform: scale(2) translateY(22px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div> Click white and red cells to scale. Click again to revert.</div>
<div class="grid">
  <div class="cell">NW</div>
  <div id="nord" class="cell">N</div>
  <div class="cell">NO</div>
  <div class="cell">W</div>
  <div class="cell">C</div>
  <div class="cell">O</div>
  <div class="cell">SW</div>
  <div class="cell">S</div>
  <div class="cell">SO</div>
</div>

【问题讨论】:

  • 感谢@Akshay,它有效。不幸的是,它禁用了第二次点击(完全恢复scale)。

标签: jquery html css scale css-transforms


【解决方案1】:

我创建了类似的东西作为概念证明。我认为这可能有助于为您指明正确的方向。在此处查看演示:https://codepen.io/RTakes/pen/aWejOy

这就是我在缩放时处理居中的方式。它从当前位置计算动画到的位置。

function computeCenterPosition(element, sizeFactor = 0) {
  const screenCenter = {
    x: window.innerWidth / 2,
    y: window.innerHeight / 2
  };

  const elCenter = {
    x: (element.offsetWidth / 2) + element.offsetLeft,
    y: (element.offsetHeight / 2) + element.offsetTop
  };

  return {
    x: (elCenter.x - screenCenter.x) * -1,
    y: (elCenter.y - screenCenter.y) * -1
  }
}

【讨论】:

  • 感谢@RickTakes!模态对话框的问题在于,它们不断地打断用户交互……必须有更直观的方式。
【解决方案2】:

我已经设置了一个函数来评估单元格是否靠近网格的边界(任何边界)。如果是这种情况,请在单元格上注入一个样式,设置一个变换样式属性,使其在缩放时沿与边框相反的方向移动。

这是一种快速而肮脏的方法,显然还有改进的余地。

$(function() {
$(".cell").click(function() {
    $(this).toggleClass("zoom-in");
  });
});

document.addEventListener('DOMContentLoaded', setEvent, false);

function setEvent () {
    var elements = document.getElementsByClassName('cell');
    var grid = elements[0].parentElement;

    var gridWidth = grid.clientWidth;
    var gridHeight = grid.clientHeight;
    var maxGrid = {
        right: gridWidth,
        bottom: gridHeight
    }

    

    for (var n = 0; n < elements.length; n++) {
        evaluate (elements[n], maxGrid);
    }
}

function evaluate (element, maxGrid) {

    var transOrigin = "";

    var left = element.offsetLeft;
    if (left < element.clientWidth) {
        transOrigin += 'left ';
    }
    if (left + element.clientWidth > maxGrid.right - element.clientWidth) {
        transOrigin += 'right ';
    }


    var top = element.offsetTop;
    if (top < element.clientHeight) {
        transOrigin += 'top';
    }
    if (top + element.clientHeight > maxGrid.bottom - element.clientHeight) {
        transOrigin += 'bottom';
    }


    element.style.transformOrigin = transOrigin;
}
.grid {
  width: 300px;
  height: 300px;
  background: gray;
  overflow: hidden;
  position: relative; /* important to have this */
}

.cell {
  background: tomato;
  width: 30%;
  height: 30%;
  margin: 5px;
  float: left;
  text-align: center;
  z-index: 999;
  transition: all 0.2s ease-in-out;
}

.zoom-in {
  transform: scale(2);
  transition: all 0.2s ease-in-out; 
}

#nord {
  background-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div> Click white and red cells to scale. Click again to revert.</div>
<div class="grid">
  <div class="cell">NW</div>
  <div id="nord" class="cell">N</div>
  <div class="cell">NO</div>
  <div class="cell">W</div>
  <div class="cell">C</div>
  <div class="cell">O</div>
  <div class="cell">SW</div>
  <div class="cell">S</div>
  <div class="cell">SO</div>
</div>

【讨论】:

  • 谢谢你,@vals!将.clientWidth/.clientHeight.offset... 属性一起使用是个好主意。问题是单元格C。它与+= 'bottom' 一起转换,即使它在中间。
  • 现在工作正常。我使用 offsetTop 来获取相对于网格的顶部坐标,这需要定位网格。添加位置:相对于它解决问题
  • 我能够根据我的用例调整您的方法(添加少量内容),再次感谢@vals。
  • @vals 非常抱歉,我错误地投了反对票,现在无法更改我的投票。您能否添加一个简单的修改,以便我再次投票?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-05
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
相关资源
最近更新 更多