Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 计算DIV元素的最大/最小高度_Javascript_Jquery_Html_Css - Fatal编程技术网

Javascript 计算DIV元素的最大/最小高度

Javascript 计算DIV元素的最大/最小高度,javascript,jquery,html,css,Javascript,Jquery,Html,Css,问题: 给定一个具有固定高度的DIV元素,该元素包含的子元素数量未知,且子元素的大小与其高度相关,请计算DIV可以调整大小的最大/最小高度,而不违反其子元素的任何最大/最小值 示例 查找A区的最大/最小高度 回答 最小值:150像素 最大值:275像素 *{ 框大小:边框框; } .边界{ 边框样式:实心; 边框宽度:1px 1px 1px; } .A{ 高度:200px; 宽度:200px; } .B{ 浮动:左; 宽度:50%; 身高:75%; 最小高度:125px; 最大高度:225px

问题: 给定一个具有固定高度的DIV元素,该元素包含的子元素数量未知,且子元素的大小与其高度相关,请计算DIV可以调整大小的最大/最小高度,而不违反其子元素的任何最大/最小值

示例 查找A区的最大/最小高度

回答

最小值:150像素

最大值:275像素

*{
框大小:边框框;
}
.边界{
边框样式:实心;
边框宽度:1px 1px 1px;
}
.A{
高度:200px;
宽度:200px;
}
.B{
浮动:左;
宽度:50%;
身高:75%;
最小高度:125px;
最大高度:225px;
背景:黄色;
}
C{
浮动:左;
宽度:50%;
身高:75%;
最小高度:100px;
最大高度:250px;
背景:绿色;
}
博士{
浮动:左;
宽度:100%;
身高:25%;
最小高度:25px;
最大高度:50px;
背景:蓝色;
}

B
C
D

如果我正确理解了你的问题,这行得通吗

// - I use two support functions that can probably be found in other JSes frameworks, and they're down below.
function calculateMySizes(someElement) {
    var childDiv = findChild(someElement, "DIV");

    var totalWidth = 0;
    var totalHeight = 0;
    var maxWidth = 0;       
    var maxHeight = 0;       

    do
    {
        if(childDiv.offsetLeft > maxWidth) {
            maxWidth = childDiv.offsetLeft;
            totalWidth += childDiv.offsetLeft;
        }

        if(childDiv.offsetTop > maxHeight) {
            maxHeight = childDiv.offsetTop;
            totalHeight += childDiv.offsetTop;
        }            
    }
    while (childDiv = nextElement(childDiv));

    alert("object's current width is: " + totalWidth + " and it's child's largest width is: " + maxWidth);
    alert("object's current height is: " + totalHeight + " and it's child's largest height is: " + maxHeight);
}

// - Returns the next Element of object
function nextElement(object) {
    var nextObject = object;
    while (nextObject = nextObject.nextSibling) {
        if (nextObject.nodeType == 1) {
            return nextObject;
        }
    }
    return nextObject;
}

// - Returns the first child of elementName found
function findChild(object, elementName) {
    for (var i = 0; i < object.childNodes.length; i++) {
        if (object.childNodes[i].nodeType == 1) {
            if (object.childNodes[i].nodeName.toUpperCase() == childName) {
                return object;
            }

            if (object.childNodes[i].hasChildNodes()) {
                var child = findChild(object.childNodes[i], childName, countMatch);
                if (child) {
                    return child;
                }
            }
        }
    }
}
/-我使用了两个可能在其他JSes框架中找到的支持函数,它们如下所示。
函数计算物理化(someElement){
var childDiv=findChild(someElement,“DIV”);
var totalWidth=0;
var totalHeight=0;
var maxWidth=0;
var maxHeight=0;
做
{
if(childDiv.offsetLeft>maxWidth){
maxWidth=childDiv.offsetLeft;
totalWidth+=childDiv.offsetLeft;
}
if(childDiv.offsetTop>maxHeight){
maxHeight=childDiv.offsetTop;
totalHeight+=childDiv.offsetTop;
}            
}
while(childDiv=nextElement(childDiv));
警报(“对象的当前宽度为:“+totalWidth+”,其子对象的最大宽度为:“+maxWidth”);
警报(“对象的当前高度为:“+totalHeight+”,其子对象的最大高度为:“+maxHeight”);
}
//-返回对象的下一个元素
函数nextElement(对象){
var nextObject=对象;
while(nextObject=nextObject.nextSibling){
if(nextObject.nodeType==1){
返回下一个对象;
}
}
返回下一个对象;
}
//-返回找到的elementName的第一个子项
函数findChild(对象,元素名){
对于(var i=0;i

我可以想象这样一种场景,在float或position:absolute元素的情况下,子对象的边界框比它自己的子对象小得多,并且为了解决需要对所有子对象进行递归调用的问题,除了此场景之外,这将根据孩子的大小为您提供任何元素的最小宽度/高度。

这是我能想到的最佳解决方案

首先,如果一个DIV依赖于它的子内容来确定它的大小,我给它一个选择器.childDependent,如果这个DIV可以垂直调整大小,我给它一个选择器.canResize


B
C
E
D

这就是我的想法:

  • 查找具有明确高度的最近祖先
  • 查找具有百分比高度的所有祖先,并计算其中最近一个祖先的高度以查找可用高度。我们称之为祖先NAR和高度NARH
  • 查找元素与其父元素顶部的距离(使用getBoundingClientRect)。叫它DT
  • 从DT中减去NAR的上边界。这叫A
  • 你的最大身高应该是NARH-A
  • 至少可以做类似的事情

    更新:哦,凯,我实现了这个想法,它的工作!它考虑了很多垃圾,包括边距、边框、填充、滚动条(即使使用自定义宽度)、百分比宽度、最大高度/宽度和同级节点。查看此代码:

    exports.findMaxHeight = function(domNode) {
        return findMaxDimension(domNode,'height')
    }
    exports.findMaxWidth = function(domNode) {
        return findMaxDimension(domNode,'width')
    }
    
    // finds the maximum height/width (in px) that the passed domNode can take without going outside the boundaries of its parent
    // dimension - either 'height' or 'width'
    function findMaxDimension(domNode, dimension) {
        if(dimension === 'height') {
            var inner = 'Top'
            var outer = 'Bottom'
            var axis = 'Y'
            var otherAxis = 'X'
            var otherDimension = 'width'
        } else {
            var inner = 'Left'
            var outer = 'Right'
            var axis = 'X'
            var otherAxis = 'Y'
            var otherDimension = 'height'
        }
    
        var maxDimension = 'max'+dimension[0].toUpperCase()+dimension.slice(1)
        var innerBorderWidth = 'border'+inner+'Width'
        var outerBorderWidth = 'border'+outer+'Width'
        var innerPaddingWidth = 'padding'+inner
        var outerPaddingWidth = 'padding'+outer
        var innerMarginWidth = 'margin'+inner
        var outerMarginWidth = 'margin'+outer
        var overflowDimension = 'overflow'+axis
    
        var propertiesToFetch = [
            dimension,maxDimension, overflowDimension,
            innerBorderWidth,outerBorderWidth,
            innerPaddingWidth,outerPaddingWidth,
            innerMarginWidth, outerMarginWidth
        ]
    
        // find nearest ancestor with an explicit height/width and capture all the ancestors in between
        // find the ancestors with heights/widths relative to that one
        var ancestry = [], ancestorBottomBorder=0
        for(var x=domNode.parentNode; x!=null && x!==document.body.parentNode; x=x.parentNode) {
            var styles = getFinalStyle(x,propertiesToFetch)
            var h = styles[dimension]
            if(h.indexOf('%') === -1 && h.match(new RegExp('\\d')) !== null) { // not a percentage and some kind of length
                var nearestAncestorWithExplicitDimension = x
                var explicitLength = h
                ancestorBottomBorder = parseInt(styles[outerBorderWidth]) + parseInt(styles[outerPaddingWidth])
                if(hasScrollBars(x, axis, styles))
                    ancestorBottomBorder+= getScrollbarLength(x,dimension)
                break;
            } else {
                ancestry.push({node:x, styles:styles})
            }
        }
    
        if(!nearestAncestorWithExplicitDimension)
            return undefined // no maximum
    
        ancestry.reverse()
    
        var maxAvailableDimension = lengthToPixels(explicitLength)
        var nodeToFindDistanceFrom = nearestAncestorWithExplicitDimension
        ancestry.forEach(function(ancestorInfo) {
            var styles = ancestorInfo.styles
            var newDimension = lengthToPixels(styles[dimension],maxAvailableDimension)
            var possibleNewDimension = lengthToPixels(styles[maxDimension], maxAvailableDimension)
    
            var moreBottomBorder = parseInt(styles[outerBorderWidth]) + parseInt(styles[outerPaddingWidth]) + parseInt(styles[outerMarginWidth])
            if(hasScrollBars(ancestorInfo.node, otherAxis, styles))
                moreBottomBorder+= getScrollbarLength(ancestorInfo.node,otherDimension)
    
            if(possibleNewDimension !== undefined && (
                    newDimension !== undefined && possibleNewDimension < newDimension ||
                    possibleNewDimension < maxAvailableDimension
                )
            ) {
                maxAvailableDimension = possibleNewDimension
                nodeToFindDistanceFrom = ancestorInfo.node
    //            ancestorBottomBorder = moreBottomBorder
            } else if(newDimension !== undefined) {
                maxAvailableDimension = newDimension
                nodeToFindDistanceFrom = ancestorInfo.node
    //            ancestorBottomBorder = moreBottomBorder
            } else {
    
            }
    
            ancestorBottomBorder += moreBottomBorder
        })
    
        // find the distance from the top
        var computedStyle = getComputedStyle(domNode)
        var verticalBorderWidth = parseInt(computedStyle[outerBorderWidth]) + parseInt(computedStyle[innerBorderWidth]) +
                                  parseInt(computedStyle[outerPaddingWidth]) + parseInt(computedStyle[innerPaddingWidth]) +
                                  parseInt(computedStyle[outerMarginWidth]) + parseInt(computedStyle[innerMarginWidth])
        var distanceFromSide = domNode.getBoundingClientRect()[inner.toLowerCase()] - nodeToFindDistanceFrom.getBoundingClientRect()[inner.toLowerCase()]
    
        return maxAvailableDimension-ancestorBottomBorder-verticalBorderWidth-distanceFromSide
    }
    
    // gets the pixel length of a value defined in a real absolute or relative measurement (eg mm)
    function lengthToPixels(length, parentLength) {
        if(length.indexOf('calc') === 0) {
            var innerds = length.slice('calc('.length, -1)
            return caculateCalc(innerds, parentLength)
        } else {
            return basicLengthToPixels(length, parentLength)
        }
    }
    
    // ignores the existences of 'calc'
    function basicLengthToPixels(length, parentLength) {
        var lengthParts = length.match(/(-?[0-9]+)(.*)/)
        if(lengthParts != null) {
            var number = parseInt(lengthParts[1])
            var metric = lengthParts[2]
            if(metric === '%') {
                return parentLength*number/100
            } else {
                if(lengthToPixels.cache === undefined) lengthToPixels.cache = {}//{px:1}
                var conversion = lengthToPixels.cache[metric]
                if(conversion === undefined) {
                    var tester = document.createElement('div')
                    tester.style.width = 1+metric
                    tester.style.visibility = 'hidden'
                    tester.style.display = 'absolute'
                    document.body.appendChild(tester)
                    conversion = lengthToPixels.cache[metric] = tester.offsetWidth
                    document.body.removeChild(tester)
                }
    
                return conversion*number
            }
        }
    }
    
    
    // https://developer.mozilla.org/en-US/docs/Web/CSS/number
    var number = '(?:\\+|-)?'+ // negative or positive operator
                 '\\d*'+       // integer part
                 '(?:\\.\\d*)?'+ // fraction part
                 '(?:e(?:\\+|-)?\\d*)?' // scientific notation
    // https://developer.mozilla.org/en-US/docs/Web/CSS/calc
    var calcValue = '(?:'+
                        '('+number+')'+   // length number
                        '([A-Za-z]+|%)?'+ // optional suffix (% or px/mm/etc)
                     '|'+
                        '(\\(.*\\))'+   // more stuff in parens
                    ')'
    var calcSequence = calcValue+
                       '((\\s*'+
                            '(\\*|/|\\+|-)'+
                            '\\s*'+calcValue+
                       ')*)'
    var calcSequenceItem = '\\s*'+
                           '(\\*|/|\\+|-)'+
                           '\\s*'+calcValue
    var caculateCalc = function(calcExpression, parentLength) {
        var info = calcExpression.match(new RegExp('^'+calcValue))
    
        var number = info[1]
        var suffix = info[2]
        var calcVal = info[3]
        var curSum = 0, curProduct = getCalcNumber(number, suffix, calcVal, parentLength), curSumOp = '+'
        var curCalcExpression = calcExpression.slice(info[0].length)
        while(curCalcExpression.length > 0) {
            info = curCalcExpression.match(new RegExp(calcSequenceItem))
    
            var op = info[1]
            number = info[2]
            suffix = info[3]
            calcVal = info[4]
    
            var length = getCalcNumber(number,suffix,calcVal, parentLength)
            if(op in {'*':1,'/':1}) {
                curProduct = calcSimpleExpr(curProduct,op,length)
            } else if(op === '+' || op === '-') {
                curSum = calcSimpleExpr(curSum,curSumOp,curProduct)
                curSumOp = op
                curProduct = length
            }
    
            curCalcExpression = curCalcExpression.slice(info[0].length)
        }
    
        curSum = calcSimpleExpr(curSum,curSumOp,curProduct)
        return curSum
    }
    function calcSimpleExpr(operand1, op, operand2) {
        if(op === '*') {
            return operand1 * operand2
        } else if(op === '/') {
            return operand1 / operand2
        } else if(op === '+') {
            return operand1 + operand2
        } else if(op === '-') {
            return operand1 - operand2
        } else {
            throw new Error("bad")
        }
    }
    function getCalcNumber(number, suffix, calcVal, parentLength) {
        if(calcVal) {
            return caculateCalc(calcVal, parentLength)
        } else if(suffix) {
            return basicLengthToPixels(number+suffix, parentLength)
        } else {
            return number
        }
    }
    
    // gets the style property as rendered via any means (style sheets, inline, etc) but does *not* compute values
    // domNode - the node to get properties for
    // properties - Can be a single property to fetch or an array of properties to fetch
    function getFinalStyle(domNode, properties) {
        if(!(properties instanceof Array)) properties = [properties]
    
        var parent = domNode.parentNode
        if(parent) {
            var originalDisplay = parent.style.display
            parent.style.display = 'none'
        }
        var computedStyles = getComputedStyle(domNode)
    
        var result = {}
        properties.forEach(function(prop) {
            result[prop] = computedStyles[prop]
        })
    
        if(parent) {
            parent.style.display = originalDisplay
        }
    
        return result
    }
    
    
    // from lostsource http://stackoverflow.com/questions/13382516/getting-scroll-bar-width-using-javascript
    // dimension - either 'width' or 'height'
    function getScrollbarLength(domNode, dimension) {
        if(dimension === 'width') {
            var offsetDimension = 'offsetWidth'
        } else {
            var offsetDimension = 'offsetHeight'
        }
    
        var outer = document.createElement(domNode.nodeName)
        outer.className = domNode.className
        outer.style.cssText = domNode.style.cssText
        outer.style.visibility = "hidden"
        outer.style.width = "100px"
        outer.style.height = "100px"
        outer.style.top = "0"
        outer.style.left = "0"
        outer.style.msOverflowStyle = "scrollbar" // needed for WinJS apps
    
        domNode.parentNode.appendChild(outer)
    
        var lengthNoScroll = outer[offsetDimension]
    
        // force scrollbars with both css and a wider inner div
        var inner1 = document.createElement("div")
        inner1.style[dimension] = "120%" // without this extra inner div, some browsers may decide not to add scoll bars
        outer.appendChild(inner1)
        outer.style.overflow = "scroll"
    
        var inner2 = document.createElement("div")
        inner2.style[dimension] = "100%"
        outer.appendChild(inner2) // this must be added after scroll bars are added or browsers are stupid and don't properly resize the object (or maybe they do after a return to the scheduler?)
    
        var lengthWithScroll = inner2[offsetDimension]
    
        domNode.parentNode.removeChild(outer)
    
        return lengthNoScroll - lengthWithScroll
    }
    
    // dimension - Either 'y' or 'x'
    // computedStyles - (Optional) Pass in the domNodes computed styles if you already have it (since I hear its somewhat expensive)
    function hasScrollBars(domNode, dimension, computedStyles) {
        dimension = dimension.toUpperCase()
        if(dimension === 'Y') {
            var length = 'Height'
        } else {
            var length = 'Width'
        }
    
        var scrollLength = 'scroll'+length
        var clientLength = 'client'+length
        var overflowDimension = 'overflow'+dimension
    
        var hasVScroll = domNode[scrollLength] > domNode[clientLength]
    
    
        // Check the overflow and overflowY properties for "auto" and "visible" values
        var cStyle = computedStyles || getComputedStyle(domNode)
        return hasVScroll && (cStyle[overflowDimension] == "visible"
                             || cStyle[overflowDimension] == "auto"
                             )
              || cStyle[overflowDimension] == "scroll"
    }
    
    exports.findMaxHeight=函数(domNode){
    返回findMaxDimension(domNode,'height')
    }
    exports.findMaxWidth=函数(domNode){
    返回findMaxDimension(domNode,'width')
    }
    //查找传递的domNode在不超出其父节点边界的情况下可以采用的最大高度/宽度(以px为单位)
    //尺寸-高度或宽度
    函数findMaxDimension(domNode,dimension){
    如果(尺寸=='高度'){
    内部变量='Top'
    外部变量='底部'
    变量轴='Y'
    var otherAxis='X'
    var otherDimension='width'
    }否则{
    内部变量='左'
    var outer='右'
    变量轴='X'
    var otherAxis='Y'
    var otherDimension='height'
    }
    变量maxDimension='max'+维度[0]。toUpperCase()+维度。切片(1)
    var innerBorderWidth='边框'+内部+'宽度'
    var outerBorderWidth='border'+outer+'Width'
    var innerPaddingWidth='padding'+内部
    var outerPaddingWidth='padding'+外部
    var innerMarginWidth='边距'+内部
    var outerMarginWidth=‘margin’+外部
    变量溢出维度='溢出'+轴
    var propertiesToFetch=[
    维度,最大维度,溢出维度,
    内边框宽度,外边框宽度,
    内部填充宽度,外部填充宽度,
    内边缘宽度,外边缘宽度
    ]
    //查找具有明确高度/宽度的最近祖先,并捕获中间的所有祖先
    //查找具有相对于该祖先的高度/宽度的祖先
    变量祖先=[],ancestorBottomBorder=0
    对于(var x=domNode.parentNode;x!=null&&x)