html - 弹性盒调整大小

标签 html flexbox

我正在尝试提出一种定义嵌套 flexbox 并允许调整其大小的有效方法。我认为它几乎就在那里:

http://jsfiddle.net/6j10L3x2/1/

我使用三个自定义元素纯粹是为了使标记更具声明性:

flex, flex-item, flex-resizer

一个 flex 代表容器。 flex-item 表示容器内的一个元素,flex-resizer 表示一个 resizer 小部件,它可以放置在两个 flex-item 之间以在它们之间添加调整大小的功能。

这一切似乎都非常有效。但是,它只处理使用 flex-grow 调整大小的项目。如果定义了 flex-shrink 或 flex-basis,则计算根本不起作用。

任何人都可以提出一种修改方法以使其适用于所有情况吗?我意识到在如何在具有各种 flex 配置的项目之间共享空间方面存在一些歧义,但欢迎任何输入。

任何替代方法也将受到欢迎。谢谢。

最佳答案

哇。我对您如何使用“flexGrow”、出色的想法和代码使用 vanilla javascript 调整 flexbox 元素的大小印象深刻。
我已经通过几种方式改进了您的代码,并且运行良好。
我做了什么?
1.- 我简化了 HTML:

  • 不要使用 柔性 内的元素弹性项目 .
  • 使用 柔性 弹性项目 元素,永远!,在另一个里面
    柔性 元素。

  • 2.- 解决了!
    当可见的 flex-item 大小小于其内容大小时,拆分器的跳转。
    3.- 我添加了不同的游标来表示状态的变化(setupResizerEvents、onMouseUp)以提高可用性。
    4.- 我添加了代码来防止拖动时光标闪烁。
    5.- 在 manageResize() 与 scrollWidth 和 scrollHeight 中使用 offsetWidth 和 offsetHeight 来避免在弹性项目内容溢出(溢出:自动)时拆分器在调整大小时跳转。
    这是代码:

    function manageResize(md, sizeProp, posProp) {
        var r = md.target;
    
        var prev = r.previousElementSibling;
        var next = r.nextElementSibling;
        if (!prev || !next) {
            return;
        }
    
        md.preventDefault();
    
        var prevSize = prev[sizeProp];
        var nextSize = next[sizeProp];
        var sumSize = prevSize + nextSize;
        var prevGrow = Number(prev.style.flexGrow);
        var nextGrow = Number(next.style.flexGrow);
        var sumGrow = prevGrow + nextGrow;
        var lastPos = md[posProp];
    
        function onMouseMove(mm) {
            var pos = mm[posProp];
            var d = pos - lastPos;
            prevSize += d;
            nextSize -= d;
            if (prevSize < 0) {
                nextSize += prevSize;
                pos -= prevSize;
                prevSize = 0;
            }
            if (nextSize < 0) {
                prevSize += nextSize;
                pos += nextSize;
                nextSize = 0;
            }
    
            var prevGrowNew = sumGrow * (prevSize / sumSize);
            var nextGrowNew = sumGrow * (nextSize / sumSize);
    
            prev.style.flexGrow = prevGrowNew;
            next.style.flexGrow = nextGrowNew;
    
            lastPos = pos;
        }
    
        function onMouseUp(mu) {
            // Change cursor to signal a state's change: stop resizing.
            const html = document.querySelector('html');
            html.style.cursor = 'default';
    
            if (posProp === 'pageX') {
                r.style.cursor = 'ew-resize'; 
            } else {
                r.style.cursor = 'ns-resize';
            }
            
            window.removeEventListener("mousemove", onMouseMove);
            window.removeEventListener("mouseup", onMouseUp);
        }
    
        window.addEventListener("mousemove", onMouseMove);
        window.addEventListener("mouseup", onMouseUp);
    }
    
    function setupResizerEvents() {
        document.body.addEventListener("mousedown", function (md) {
    
            // Used to avoid cursor's flickering
            const html = document.querySelector('html');
            
            var target = md.target;
            if (target.nodeType !== 1 || target.tagName !== "FLEX-RESIZER") {
                return;
            }
            var parent = target.parentNode;
            var h = parent.classList.contains("h");
            var v = parent.classList.contains("v");
            if (h && v) {
                return;
            } else if (h) {
                // Change cursor to signal a state's change: begin resizing on H.
                target.style.cursor = 'col-resize';
                html.style.cursor = 'col-resize'; // avoid cursor's flickering
    
                // use offsetWidth versus scrollWidth (and clientWidth) to avoid splitter's jump on resize when a flex-item content overflow (overflow: auto).
                manageResize(md, "offsetWidth", "pageX");
                
            } else if (v) {
                // Change cursor to signal a state's change: begin resizing on V.
                target.style.cursor = 'row-resize';
                html.style.cursor = 'row-resize'; // avoid cursor's flickering
    
                manageResize(md, "offsetHeight", "pageY");
            }
        });
    }
    
    setupResizerEvents();
    body {
        /* margin:0; */
        border: 10px solid #aaa;
    }
    
    flex {
        display: flex;
        overflow: hidden;
    }
    
    /* flex-item > flex {
        position: absolute;
        width: 100%;
        height: 100%;
    } */
    
    flex.h {
        flex-direction: row;
    }
    
    flex.v {
        flex-direction: column;
    }
    
    flex-item {
        /* display: flex; */
        /* position: relative; */
        /* overflow: hidden; */
        overflow: auto;
    }
    
    flex > flex-resizer {
        flex: 0 0 10px;
        /* background: white; */
        background-color: #aaa;
        background-repeat: no-repeat;
        background-position: center;
    }
    
    flex.h > flex-resizer {
        cursor: ew-resize;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
    }
    
    flex.v > flex-resizer {
        cursor: ns-resize;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='30' height='10'><path d='M0 2 h30 M0 5 h30 M0 8 h30' fill='none' stroke='black'/></svg>");
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>flex-splitter</title>
        <link rel="stylesheet" href="./src/styles.css">
        <script src="./src/index.js" defer></script>
    </head>
    
    <body>
        <flex class="v" style="flex: 1; height: 500px;">
            <flex-item style="flex: 1;">Flex 1</flex-item>
            <flex-resizer></flex-resizer>
            <flex class="h" style="flex: 1;">
                <flex-item style="flex: 1; background-color: aqua;">
          
          <!-- 
            The next section is an example to test the splitter when there is content inside a flex-item
          -->
            <section>
                        <div>
                            <label for="CursorCoor" style="display: block;">showCursorCoor: </label>
                            <textarea id="CursorCoor" rows="6" cols="50" wrap="soft" readonly></textarea>
                        </div>
                    
                        <br />
                    
                        <div>
                            <label for="boxInfo" style="display: block;">showBoxInfo: </label>
                            <textarea id="boxInfo" rows="6" cols="50" wrap="soft" readonly></textarea>
                        </div>
                    </section>
            
          </flex-item>
                <flex-resizer></flex-resizer>
                <flex class="v" style="flex: 2; ">
                    <flex-item style="flex: 1; background: pink;">Flex 3</flex-item>
                    <flex-resizer></flex-resizer>
                    <flex class="h" style="flex: 1">
                        <flex-item style="flex: 1; background: green;">Flex 4</flex-item>
                        <flex-resizer></flex-resizer>
                        <flex-item style="flex: 2;">Flex 5</flex-item>
                        <!-- <flex-resizer></flex-resizer> -->
                        <flex-item style="flex: 3; background: darkorange;">Flex 6</flex-item>
                    </flex>
                </flex>
            </flex>
        </flex>
        
    </body>
    </html>

    或者在 Codesandbox 上查看:
    Edit sad-butterfly-1fwo4
    我希望它有帮助!

    关于html - 弹性盒调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28767221/

    相关文章:

    html - 是否可以将 amp-img 的尺寸移动到内联 css?

    html - 仅CSS的砌体布局

    html - flex-wrap:wrap;不能让他们工作

    javascript - 如何格式化 bootstrap 4 按钮以在按钮的不同位置显示部分文本

    html - CSS Sprite 定位在按钮内

    css - 如何使用 flexbox 溢出全高内容?

    html - 浏览器支持另一个 flexbox 内部的 Flexbox

    html - 为什么align-self 没有将我的div 与 flex 盒的底部对齐?

    php - 表中最后两行之间的空间

    html - 在嵌套表上使用 rvest 时出现问题