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

时间:2017-10-25 11:22:08

标签: javascript html css css-grid

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

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

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

我很抱歉,如果问题是noobish,我是Web开发新手,之前只使用过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>

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;
}

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

3 个答案:

答案 0 :(得分:29)

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

以下是代码输出的快速屏幕抓取:

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

  • 使用.addEventListener进行事件绑定。在这种情况下,我们将使用mousedownmouseupmousemove的组合来确定用户是否正在拖动元素
  • CSS flexbox layout

解决方案的描述

使用CSS的初始布局

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

.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;
}

收听拖动互动

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

var handler = document.querySelector('.handler');
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;
  }

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

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

计算方框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;

工作示例

&#13;
&#13;
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;
});
&#13;
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;
}
&#13;
<div class="wrapper">
  <div class="box">A</div>
  <div class="handler"></div>
  <div class="box">B</div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

以下是拖动事件处理的示例,但使用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()
  }
}
#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;
}
<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>

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

答案 2 :(得分:1)

我更改了,因此您可以添加更多的“水平”和“垂直”滑块。 test1.html:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="test1.css">
        <script src=  "test1.js" > </script>
    </head>
    <body>
        <div id="page" onmouseup="EndDrag()" onmousemove="OnDrag(event)">
            <div id="header">
                Header asdlkj flkdfj sdflkksdjf sd;flsdjf sd;flkjsd;fljsd;flsdj;fjsd f;sdlfj;sdlfj
            </div>
            <div id="leftcol">
                Left Col
            </div>
            <div id="leftdragbar" onmousedown="StartHDrag(1)"></div>
            <div id="tabs">
                Tabs
            </div>
            <div id="topdragbar" onmousedown="StartVDrag(2)"></div>
            <div id="tabpages">
                Tab Pages
            </div>
            <div id="rightdragbar" onmousedown="StartHDrag(3)"></div>
            <div id="rightcol">
                Rightcol
            </div>
            <div id="botdragbar" onmousedown="StartVDrag(4)"></div>
            <div id="footer">
                Footer
            </div>
        </div>
        <div id= 'status'></div>
    </body>
</html>

test1.css

body {
}

#page {
    height: 100vh;
    background-color: pink;
    display: grid;
    grid-template-areas:
        'header header header header header'
        'leftcol leftdragbar tabs tabs tabs'
        'leftcol leftdragbar topdragbar topdragbar topdragbar'
        'leftcol leftdragbar tabpages rightdragbar rightcol'
        'botdragbar botdragbar botdragbar botdragbar botdragbar'
        'footer footer footer footer footer';
    grid-template-rows: min-content 1fr 6px 9fr 6px 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;
}

#topdragbar {
    background-color: black;
    grid-area: topdragbar;
    cursor: ns-resize;
}

#botdragbar {
    background-color: black;
    grid-area: botdragbar;
    cursor: ns-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;
}

test1.js

let isHDragging = false;
let isVDragging = false;

let cols = ['2fr','6px','6fr','6px','2fr'];  //grid-template-columns: 2fr 6px 6fr 6px 2fr;
let colns = ['leftcol','','tabpages','','rightcol'];
let Tcols = [];

let rows = ['min-content','1fr','6px','9fr','6px','1fr'];  //grid-template-rows: min-content 1fr 6px 9fr 1fr
let rowns = ['header','tabs','','tabpages','','footer'];
let Trows = []
let CLfactor ;
let CRfactor ;
let gWcol = -1;
let gWrow = -1;

function StartHDrag(pWcol) {
    isHDragging = true;
    SetCursor("ew-resize");
    CLfactor = parseFloat(cols[pWcol-1]) / document.getElementById(colns[pWcol-1]).clientWidth;
    CRfactor = parseFloat(cols[pWcol+1]) / document.getElementById(colns[pWcol+1]).clientWidth;
    Tcols = cols.map(parseFloat);
    gWcol = pWcol;
}

function StartVDrag(pRow) {
    isVDragging = true;
    SetCursor("ns-resize");
    CLfactor = parseFloat(rows[pRow-1]) / document.getElementById(rowns[pRow-1]).clientHeight;
    CRfactor = parseFloat(rows[pRow+1]) / document.getElementById(rowns[pRow+1]).clientHeight;
    Trows = rows.map(parseFloat);
    gWrow = pRow;
}

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

function EndDrag() {
    isHDragging = false;
    isVDragging = false;
    SetCursor("auto");
}

function OnDrag(event) {
    if(isHDragging) {
        Tcols[gWcol-1] +=  (CLfactor * event.movementX);
        Tcols[gWcol+1] -=  (CLfactor * event.movementX);
        
        cols[gWcol-1]  = Math.max(Tcols[gWcol-1],0.01) + "fr";
        cols[gWcol+1]  = Math.max(Tcols[gWcol+1],0.01) + "fr";
        let newColDefn = cols.join(" ");
        page.style.gridTemplateColumns = newColDefn;
        
    } else if (isVDragging) {
        Trows[gWrow-1] +=  (CLfactor * event.movementY);
        Trows[gWrow+1] -=  (CLfactor * event.movementY);
        
        rows[gWrow-1]  = Math.max(Trows[gWrow-1],0.01) + "fr";
        rows[gWrow+1]  = Math.max(Trows[gWrow+1],0.01) + "fr";
        let newRowDefn = rows.join(" ");
        page.style.gridTemplateRows = newRowDefn;
        document.getElementById("footer").innerHTML = newRowDefn;
    }
    event.preventDefault()
}