制作一个拖动栏来调整CSS网格中的div

Aqu*_*azi 22 html javascript css css-grid

我在一个独特的容器div(下面的代码和小提琴)中有2个盒子和一个垂直div线.

我正在使用CSS网格将我的元素放在容器中

我想要完成的是使用垂直线根据垂直线的位置水平调整两个框的大小.

我很抱歉,如果问题是noobish,我是网络开发的新手,之前只使用过Python,已经尝试过google和stackoverflow搜索,但所有解决方案看起来都过于复杂,而且通常需要额外的库,我只是寻找更简单的东西和JS.

HTML:

<div class="wrapper">
  <div class="box a">A</div>
  <div class="handler"></div>
  <div class="box b">B</div>
</div>
Run Code Online (Sandbox Code Playgroud)

CSS:

body {
  margin: 40px;
}

.wrapper {
  display: grid;
  grid-template-columns: 200px 8px 200px;
  grid-gap: 10px;
  background-color: #fff;
  color: #444;
}

.box {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
  resize: both;
}

.handler{
    width: 3px;
    height: 100%;
    padding: 0px 0;
    top: 0;
    background: red;
    draggable: true;
}
Run Code Online (Sandbox Code Playgroud)

https://jsfiddle.net/gv8Lwckh/6/

Ter*_*rry 47

你打算用CSS flexbox做什么 - 不需要使用CSS网格.坏消息是,HTML + CSS是不是非常聪明,声明resizedraggable将布局通过用户交互灵活可调.为此,您将不得不使用JS.好消息是,这实际上并不太复杂.

这是一个快速屏幕抓取输出代码如下:

但是,为了让您了解我将在下面发布的代码,您必须熟悉:

  • 事件绑定使用.addEventListener.在这种情况下,我们将使用组合mousedown,mouseupmousemove确定用户是否正在拖动元素
  • CSS flexbox布局

解决方案的描述

使用CSS的初始布局

首先,您需要使用CSS flexbox布局您的盒子.我们只是display: flex在父对象上声明,然后使用flex: 1 1 auto(转换为"让元素增长,让元素缩小,并具有相等的宽度).此布局仅在页面的初始呈现时有效:

.wrapper {
  /* Use flexbox */
  display: flex;
}

.box {
  /* Use box-sizing so that element's outerwidth will match width property */
  box-sizing: border-box;

  /* Allow box to grow and shrink, and ensure they are all equally sized */
  flex: 1 1 auto;
}
Run Code Online (Sandbox Code Playgroud)

听听拖动互动

您想要侦听可能源自您的.handler元素的鼠标事件,并且您想要一个记住用户是否正在拖动的全局标志:

var handler = document.querySelector('.handler');
var isHandlerDragging = false;
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用以下逻辑来检查用户是否正在拖动:

document.addEventListener('mousedown', function(e) {
  // If mousedown event is fired from .handler, toggle flag to true
  if (e.target === handler) {
    isHandlerDragging = true;
  }
});

document.addEventListener('mousemove', function(e) {
  // Don't do anything if dragging flag is false
  if (!isHandlerDragging) {
    return false;
  }

  // Set boxA width properly
  // [...more logic here...]
});

document.addEventListener('mouseup', function(e) {
  // Turn off dragging flag when user mouse is up
  isHandlerDragging = false;
});
Run Code Online (Sandbox Code Playgroud)

计算方框A的宽度

现在剩下的就是计算方框A的宽度(插入[...more logic here...]上面代码中的占位符),以便它与鼠标移动的宽度相匹配.Flexbox将确保框B将填满剩余空间:

// Get offset
var containerOffsetLeft = wrapper.offsetLeft;

// Get x-coordinate of pointer relative to container
var pointerRelativeXpos = e.clientX - containerOffsetLeft;

// Resize box A
// * 8px is the left/right spacing between .handler and its inner pseudo-element
// * Set flex-grow to 0 to prevent it from growing
boxA.style.width = (pointerRelativeXpos - 8) + 'px';
boxA.style.flexGrow = 0;
Run Code Online (Sandbox Code Playgroud)

工作实例

var handler = document.querySelector('.handler');
var wrapper = handler.closest('.wrapper');
var boxA = wrapper.querySelector('.box');
var isHandlerDragging = false;

document.addEventListener('mousedown', function(e) {
  // If mousedown event is fired from .handler, toggle flag to true
  if (e.target === handler) {
    isHandlerDragging = true;
  }
});

document.addEventListener('mousemove', function(e) {
  // Don't do anything if dragging flag is false
  if (!isHandlerDragging) {
    return false;
  }

  // Get offset
  var containerOffsetLeft = wrapper.offsetLeft;

  // Get x-coordinate of pointer relative to container
  var pointerRelativeXpos = e.clientX - containerOffsetLeft;
  
  // Arbitrary minimum width set on box A, otherwise its inner content will collapse to width of 0
  var boxAminWidth = 60;

  // Resize box A
  // * 8px is the left/right spacing between .handler and its inner pseudo-element
  // * Set flex-grow to 0 to prevent it from growing
  boxA.style.width = (Math.max(boxAminWidth, pointerRelativeXpos - 8)) + 'px';
  boxA.style.flexGrow = 0;
});

document.addEventListener('mouseup', function(e) {
  // Turn off dragging flag when user mouse is up
  isHandlerDragging = false;
});
Run Code Online (Sandbox Code Playgroud)
body {
  margin: 40px;
}

.wrapper {
  background-color: #fff;
  color: #444;
  /* Use flexbox */
  display: flex;
}

.box {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
  
  /* Use box-sizing so that element's outerwidth will match width property */
  box-sizing: border-box;
  
  /* Allow box to grow and shrink, and ensure they are all equally sized */
  flex: 1 1 auto;
}

.handler {
  width: 20px;
  padding: 0;
  cursor: ew-resize;
  flex: 0 0 auto;
}

.handler::before {
  content: '';
  display: block;
  width: 4px;
  height: 100%;
  background: red;
  margin: 0 auto;
}
Run Code Online (Sandbox Code Playgroud)
<div class="wrapper">
  <div class="box">A</div>
  <div class="handler"></div>
  <div class="box">B</div>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 如果仅坚持使用网格而不切换到使用flex,那将是一个完美的答案。OP说他正在使用CSS网格。 (4认同)
  • 我更喜欢这个答案,因为它使用 flexbox 而不是 CSS 网格(更好的支持),即使问题标题首先指的是 CSS 网格 (3认同)
  • 是否可以设置框 A 的初始宽度? (2认同)

小智 27

这是拖动事件处理的示例,但使用 CSS 网格

诀窍是在网格容器上设置网格模板列(或行)而不是网格项的大小

let isLeftDragging = false;
let isRightDragging = false;

function ResetColumnSizes() {
  // when page resizes return to default col sizes
  let page = document.getElementById("pageFrame");
  page.style.gridTemplateColumns = "2fr 6px 6fr 6px 2fr";
}

function SetCursor(cursor) {
  let page = document.getElementById("page");
  page.style.cursor = cursor;
}

function StartLeftDrag() {
  // console.log("mouse down");
  isLeftDragging = true;

  SetCursor("ew-resize");
}

function StartRightDrag() {
  // console.log("mouse down");
  isRightDragging = true;

  SetCursor("ew-resize");
}

function EndDrag() {
  // console.log("mouse up");
  isLeftDragging = false;
  isRightDragging = false;

  SetCursor("auto");
}

function OnDrag(event) {
  if (isLeftDragging || isRightDragging) {
    // console.log("Dragging");
    //console.log(event);

    let page = document.getElementById("page");
    let leftcol = document.getElementById("leftcol");
    let rightcol = document.getElementById("rightcol");

    let leftColWidth = isLeftDragging ? event.clientX : leftcol.clientWidth;
    let rightColWidth = isRightDragging ? page.clientWidth - event.clientX : rightcol.clientWidth;

    let dragbarWidth = 6;

    let cols = [
      leftColWidth,
      dragbarWidth,
      page.clientWidth - (2 * dragbarWidth) - leftColWidth - rightColWidth,
      dragbarWidth,
      rightColWidth
    ];

    let newColDefn = cols.map(c => c.toString() + "px").join(" ");

    // console.log(newColDefn);
    page.style.gridTemplateColumns = newColDefn;

    event.preventDefault()
  }
}
Run Code Online (Sandbox Code Playgroud)
#page {
  height: 100%;
  background-color: pink;
  display: grid;
  grid-template-areas: 'header header header header header' 'leftcol leftdragbar tabs tabs tabs' 'leftcol leftdragbar tabpages rightdragbar rightcol' 'leftcol leftdragbar footer footer footer';
  grid-template-rows: min-content 1fr 9fr 1fr;
  grid-template-columns: 2fr 6px 6fr 6px 2fr;
}


/*****************************/

#header {
  background-color: lightblue;
  overflow: auto;
  grid-area: header;
}

#leftcol {
  background-color: #aaaaaa;
  overflow: auto;
  grid-area: leftcol;
}

#leftdragbar {
  background-color: black;
  grid-area: leftdragbar;
  cursor: ew-resize;
}

#tabs {
  background-color: #cccccc;
  overflow: auto;
  grid-area: tabs;
}

#tabpages {
  background-color: #888888;
  overflow: auto;
  grid-area: tabpages;
}

#rightdragbar {
  background-color: black;
  grid-area: rightdragbar;
  cursor: ew-resize;
}

#rightcol {
  background-color: #aaaaaa;
  overflow: auto;
  grid-area: rightcol;
}

#footer {
  background-color: lightblue;
  overflow: auto;
  grid-area: footer;
}
Run Code Online (Sandbox Code Playgroud)
<body onresize="ResetColumnSizes()">
  <div id="page" onmouseup="EndDrag()" onmousemove="OnDrag(event)">
    <div id="header">
      Header
    </div>
    <div id="leftcol">
      Left Col
    </div>
    <div id="leftdragbar" onmousedown="StartLeftDrag()"></div>
    <div id="tabs">
      Tabs
    </div>
    <div id="tabpages">
      Tab Pages
    </div>
    <div id="rightdragbar" onmousedown="StartRightDrag()"></div>
    <div id="rightcol">
      Rightcol
    </div>
    <div id="footer">
      Footer
    </div>
  </div>
</body>
Run Code Online (Sandbox Code Playgroud)

https://codepen.io/lukerazor/pen/GVBMZK

  • 不错的工作!我获取了您的代码并将其扩展为适用于垂直分离器以及水平分离器。我通过从网格容器中动态添加和删除 onmouseup 和 onmousemove 事件处理程序来做到这一点:https://jsfiddle.net/zabh8jev/ (2认同)