js 實現上下改變父 div 的高度,左右上下動態分割孩子的寬高

1. 需求

實現父 div 裏面 左右,上下動態分割 div,並上下改變父 div 的高度,並且寬和高都是按百分比(如圖) 。

2. 實現原理

2.1 父佈局

<div class='hj-wrap'>
        <div class="arrow"></div>
    </div>
  • 首先一個父 div 爲 hj-wrap,相對定位 。
  • 一個改變父 div 高度的 arrow,用於上下拖動 , 不能佔有位置,所以要絕對定位,並定位到最右下角。
  • 上下拖動的 arrow,當上拖動時,arrow 的父 div 的高度變小,當下拖動時,arrow 的父 div 的高度變大。

2.2 橫向佈局

<div class='hj-wrap'>
        <div class="hj-transverse-split-div">
            橫 向
            <label class="hj-transverse-split-label"></label>
        </div>
        <div class="hj-transverse-split-div">橫 向 2
            <label class="hj-transverse-split-label"></label>
        </div>
        <div class="hj-transverse-split-div">橫 向 3
            <label class="hj-transverse-split-label"></label>
        </div>
        <div class="hj-transverse-split-div">橫 向 4
            <label class="hj-transverse-split-label"></label>
        </div>
        <div class="hj-transverse-split-div">橫 向 5
        </div>
        <div class="arrow"></div>
    </div>
  • 每一個橫向的 div 爲 hj-transverse-split-div 並相對定位,裏面有一個拖動改變左右的 label 爲 hj-transverse-split-label ,不能佔有位置,所以要絕對定位,並定位到最右邊並高爲 100%,最後一個橫向的 div 不用 hj-transverse-split-label 。
  • 拖動改變左右的 label 時,向左時,label 的父 div 的寬變小,label 的父 div 相鄰的 右邊的 div 寬度變大。

2.3 豎向佈局

<div class='hj-wrap verticals'>
        <div class="hj-vertical-split-div">上
            <label class="hj-vertical-split-label"></label>
        </div>
        <div class="hj-vertical-split-div">中
            <label class="hj-vertical-split-label"></label>
        </div>
        <div class="hj-vertical-split-div">下</div>
        <div class="arrow"></div>
    </div>
  • 每一個橫向的 div 爲 hj-vertical-split-div 並相對定位,裏面有一個拖動改變左右的 label 爲 hj-vertical-split-label ,不能佔有位置,所以要絕對定位,並定位到最下邊並寬爲 100%,最後一個豎向的 div 不用再放 hj-vertical-split-label 的 label 。
  • 拖動改變上下的 label 時,向上時,label 的父 div 的高度變小,label 的父 div 相鄰的下邊的 div 高度變大。

3. js 實現

代碼:

/**
 * name:   split.js
 * author:  biaochen
 * date:    2018-12-26
 *
 */
$(function() {
    //鼠標橫向、豎向、和改變父高度的上下 操作對象
    var thisTransverseObject, thisVerticalObject, thisArrowObject;
    //文檔對象
    var doc = document;
    //橫向分割欄
    var transverseLabels = $(".hj-wrap").find(".hj-transverse-split-label");
    //豎向分割欄
    var verticalLabels = $(".hj-wrap").find(".hj-vertical-split-label");
    // 改變父高度的 箭頭 div
    var parentArrow = $(".hj-wrap").find(".arrow");

    // 設置寬
    function setWidth(type) {
        if (type === "init") {
            var length = $(".hj-wrap").length;
            if (length > 0) {
                for (var i = 0; i < length; i++) {
                    var width = $($(".hj-wrap")[i])[0].offsetWidth;
                    var hjDivNums = $($(".hj-wrap")[i]).children(".hj-transverse-split-div");
                    // var defaultWidth = Math.floor(100 / hjDivNums.length);
                    var defaultWidth = Math.floor(width / hjDivNums.length);
                    $($(".hj-wrap")[i])
                        .children(".hj-transverse-split-div")
                        .width(defaultWidth + "px");
                    // .width(defaultWidth + "%");
                }
            }
        } else {
            // 設置百分比
            var transverseDivs = $(".hj-transverse-split-div")
            var widthLength = transverseDivs.length
            for (var i = 0; i < widthLength; i++) {
                var width = $(transverseDivs[i]).width();
                var parentWidth = $(transverseDivs[i])
                    .parent()
                    .width();
                var rate = (width / parentWidth) * 100 + "%";
                $(transverseDivs[i]).css({ width: rate });
            }
        }
    }

    // 設置高
    function setHeight(type) {
        if (type === "init") {
            var verticalsParentDivs = $(".verticals");
            var parentLengths = verticalsParentDivs.length;
            for (var i = 0; i < parentLengths; i++) {
                var parentHeight = $(verticalsParentDivs[i]).height();
                var childrenNum = $(verticalsParentDivs[i]).children(
                    ".hj-vertical-split-div"
                ).length;
                var defaultHeight = Math.floor(parentHeight / childrenNum);
                // var rate = Math.floor((height / parentHeight)* 100)  + '%'
                var defaultHeight = Math.floor(100 / childrenNum);
                $(verticalsParentDivs[i])
                    .children(".hj-vertical-split-div")
                    .height(defaultHeight + "%");
                // .height(defaultHeight + "px");
            }
        } else {
            // 設置百分比
            var verticalsDivs = $(".hj-vertical-split-div");
            var heightLength = verticalsDivs.length;
            for (var i = 0; i < heightLength; i++) {
                var height = $(verticalsDivs[i]).height();
                var parentHeight = $(verticalsDivs[i])
                    .parent()
                    .height();
                var rate = (height / parentHeight) * 100 + "%";
                $(verticalsDivs[i]).css({ height: rate });
            }
        }
    }

    setWidth('init')
    setHeight("init");

    //定義一個對象
    function PointerObject() {
        this.el = null; //當前鼠標選擇的對象
        this.clickX = 0; //鼠標橫向初始位置
        this.clickY = 0; //鼠標豎向初始位置
        this.transverseDragging = false; //判斷鼠標可否橫向拖動
        this.verticalDragging = false; //判斷鼠標可否豎向拖動
    }
    //橫向分隔欄綁定事件
    transverseLabels.bind("mousedown", function(e) {
        thisTransverseObject = new PointerObject();
        thisTransverseObject.transverseDragging = true; //鼠標可橫向拖動
        thisTransverseObject.el = this;
        thisTransverseObject.clickX = e.pageX; //記錄鼠標橫向初始位置
    });

    //豎向分隔欄綁定事件
    verticalLabels.bind("mousedown", function(e) {
        //console.log("mousedown");
        thisVerticalObject = new PointerObject();
        thisVerticalObject.verticalDragging = true; //鼠標可豎向拖動
        thisVerticalObject.el = this;
        thisVerticalObject.clickY = e.pageY; //記錄鼠標豎向初始位置
    });
    //上下綁定事件
    parentArrow.bind("mousedown", function(e) {
        //console.log("mousedown");
        thisArrowObject = new PointerObject();
        // thisArrowObject.transverseDragging = true; //鼠標可橫向拖動
        thisArrowObject.verticalDragging = true; //鼠標可豎向拖動
        thisArrowObject.el = this;
        thisArrowObject.clickY = e.pageY; //記錄鼠標豎向初始位置
    });

    doc.onmousemove = function(e) {
        //鼠標橫向拖動
        if (thisTransverseObject != null) {
            if (thisTransverseObject.transverseDragging) {
                var changeDistance = 0;
                if (thisTransverseObject.clickX >= e.pageX) {
                    //鼠標向左移動
                    changeDistance =
                        Number(thisTransverseObject.clickX) - Number(e.pageX);
                    if (
                        $(thisTransverseObject.el)
                        .parent()
                        .width() -
                        changeDistance <
                        20
                    ) {} else {
                        $(thisTransverseObject.el)
                            .parent()
                            .width(
                                $(thisTransverseObject.el)
                                .parent()
                                .width() - changeDistance
                            );
                        $(thisTransverseObject.el)
                            .parent()
                            .next()
                            .width(
                                $(thisTransverseObject.el)
                                .parent()
                                .next()
                                .width() + changeDistance
                            );
                        thisTransverseObject.clickX = e.pageX;
                        $(thisTransverseObject.el).offset({ left: e.pageX });
                    }
                } else {
                    //鼠標向右移動
                    changeDistance =
                        Number(e.pageX) - Number(thisTransverseObject.clickX);
                    if (
                        $(thisTransverseObject.el)
                        .parent()
                        .next()
                        .width() -
                        changeDistance <
                        20
                    ) {} else {
                        $(thisTransverseObject.el)
                            .parent()
                            .width(
                                $(thisTransverseObject.el)
                                .parent()
                                .width() + changeDistance
                            );
                        $(thisTransverseObject.el)
                            .parent()
                            .next()
                            .width(
                                $(thisTransverseObject.el)
                                .parent()
                                .next()
                                .width() - changeDistance
                            );
                        thisTransverseObject.clickX = e.pageX;
                        $(thisTransverseObject.el).offset({ left: e.pageX });
                    }
                }
                $(thisTransverseObject.el).width(2);
            }
        }
        //鼠標豎向拖動
        if (thisVerticalObject != null) {
            if (thisVerticalObject.verticalDragging) {
                var changeDistance = 0;
                if (thisVerticalObject.clickY >= e.pageY) {
                    //鼠標向上移動
                    changeDistance = Number(thisVerticalObject.clickY) - Number(e.pageY);
                    if (
                        $(thisVerticalObject.el)
                        .parent()
                        .height() -
                        changeDistance <
                        20
                    ) {} else {
                        $(thisVerticalObject.el)
                            .parent()
                            .height(
                                $(thisVerticalObject.el)
                                .parent()
                                .height() - changeDistance
                            );
                        $(thisVerticalObject.el)
                            .parent()
                            .next()
                            .height(
                                $(thisVerticalObject.el)
                                .parent()
                                .next()
                                .height() + changeDistance
                            );
                        thisVerticalObject.clickY = e.pageY;
                        $(thisVerticalObject.el).offset({ top: e.pageY });
                    }
                } else {
                    //鼠標向下移動
                    changeDistance = Number(e.pageY) - Number(thisVerticalObject.clickY);
                    if (
                        $(thisVerticalObject.el)
                        .parent()
                        .next()
                        .height() -
                        changeDistance <
                        20
                    ) {} else {
                        $(thisVerticalObject.el)
                            .parent()
                            .height(
                                $(thisVerticalObject.el)
                                .parent()
                                .height() + changeDistance
                            );
                        $(thisVerticalObject.el)
                            .parent()
                            .next()
                            .height(
                                $(thisVerticalObject.el)
                                .parent()
                                .next()
                                .height() - changeDistance
                            );
                        thisVerticalObject.clickY = e.pageY;
                        $(thisVerticalObject.el).offset({ top: e.pageY });
                    }
                }
                $(thisVerticalObject.el).height(2);
            }
        }
        // 改變父的 高度
        if (thisArrowObject != null) {
            //鼠標豎向拖動
            if (thisArrowObject.verticalDragging) {
                var changeDistance = 0;
                if (thisArrowObject.clickY >= e.pageY) {
                    //鼠標向上移動
                    changeDistance = Number(thisArrowObject.clickY) - Number(e.pageY);
                    if (
                        $(thisArrowObject.el)
                        .parent()
                        .height() -
                        changeDistance <
                        50
                    ) {} else {
                        $(thisArrowObject.el)
                            .parent()
                            .height(
                                $(thisArrowObject.el)
                                .parent()
                                .height() - changeDistance
                            );
                        thisArrowObject.clickY = e.pageY;
                        $(thisArrowObject.el).offset({ bottom: e.pageY });
                    }
                } else {
                    //鼠標向下移動
                    changeDistance = Number(e.pageY) - Number(thisArrowObject.clickY);
                    $(thisArrowObject.el)
                        .parent()
                        .height(
                            $(thisArrowObject.el)
                            .parent()
                            .height() + changeDistance
                        );
                    thisArrowObject.clickY = e.pageY;
                    $(thisArrowObject.el).offset({ bottom: e.pageY });
                }
                $(thisArrowObject.el).height(10);
            }
        }
    };

    $(doc).mouseup(function(e) {
        setHeight("setHeight");
        setWidth("setWidth");
        // 鼠標彈起時設置不能拖動
        if (thisTransverseObject != null) {
            thisTransverseObject.transverseDragging = false;
            thisTransverseObject = null;
        }
        if (thisVerticalObject != null) {
            thisVerticalObject.verticalDragging = false;
            thisVerticalObject = null;
        }
        if (thisArrowObject != null) {
            thisArrowObject.verticalDragging = false;
            thisArrowObject = null;
        }

        e.cancelBubble = true;
    });
});

4. 完整代碼與效果

效果圖:

split.gif

項目地址:https://github.com/biaochenxuying/split
效果體驗地址: https://biaochenxuying.github.io/split/index.html

初始代碼是從網上來的,不過網上的並不完整,父 div 的高也不能改變,並且孩子的寬高並不是百分比的,佈局也並不合理,所以修改成這樣子。

5. 最後

微信公衆號:BiaoChenXuYing
分享 前端、後端開發等相關的技術文章,熱點資源,隨想隨感,全棧程序員的成長之路。

關注公衆號並回復 福利 便免費送你視頻資源,絕對乾貨。

福利詳情請點擊: 免費資源分享--Python、Java、Linux、Go、node、vue、react、javaScript

BiaoChenXuYing

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章