计算DIV元素的最大/最小高度 [英] Calculating the maximum/minimum height of a DIV element

查看:142
本文介绍了计算DIV元素的最大/最小高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:
给定一个固定高度的DIV元素,其中包含未知数量的相对于其高度大小的子元素,计算最大/最小高度



示例
查找最大/最小值的最大/最小值,



最小值:150像素



最大值:275px



  * {box-sizing:border-box;}。样式: border-width:1px 1px 1px 1px;}。{height:200px; width:200px;}。B {float:left; width:50%;身高:75% min-height:125px; max-height:225px; background:yellow;}。C {float:left; width:50%;身高:75% min-height:100px; max-height:250px; background:green;}。D {float:left; width:100%;身高:25% min-height:25px; max-height:50px; background:blue;}  

 < div class = border> < div class =B border> B< / div> < div class =C border> C< / div> < div class =D border> D< / div>< / div>  



附加信息:
我目前已经尝试使用一种算法,该算法遍历DIV的DOM树,并使用元素offset创建表示元素的空间定位的对象图。下面是一个初步的算法,检查元素的空间关系,允许边缘之间的10px扩展被认为是接触。



jQuery和其他库允许只要它们是开源的。



  var _isContentRoot = function(a,b){var aRect = a.innerRect; var bRect = b.outerRect; //检查子元素是否是根节点返回Math.abs(aRect.top  -  bRect.top)< = 10;} var _isLayoutSibling = function(a,b){var aRect = a.outerRect; var bRect = b.outerRect; //如果元素X具有与元素Y相交的边界,并且元素X位于元素Y之上,则元素Y是元素X的子节点if(Math.abs(aRect.bottom  -  bRect.top)< ; = 10){if(aRect.left< = bRect.left& aRect.right> = bRect.left || aRect.left< = bRect.right&& aRect.right> = bRect.right || aRect.left> = bRect.left&& aRect.right< = bRect.right || aRect.left< = bRect.left& a amp; aRect.right> = bRect。 right){return true; }} return false;}  



以下是更新的小提琴
http://jsfiddle.net/zqnscmo2/



编辑2:尝试在CSS / HTML的问题空间中想到这个更多的图形问题。想象一下,CSS和HTML用于描述每个DIV是一个顶点的图形。在两个顶点之间存在边缘



1。)如果HTML元素的边界rectA.top≈rectB.top OR
2.)存在边如果边界rectA.bottom≈rectB.top



每个顶点具有两个排他的边集,集A包含满足标准1的所有边。集B包含所有边满足条件2.因此你可以遍历图,找到最小和最大路径,应该是PARENT DIV的最大/最小高度。



这是我推荐的算法确定内容物的最大/最小高度。

解决方案

这是我在想什么:


  1. 查找具有显式高度的最近祖先

  2. 查找所有具有百分比高度的祖先,并计算最近的祖先的祖先找到可用的高度。允许调用祖先NAR和高度NARH。

  3. 查找元素距离其父元素的距离(使用getBoundingClientRect)。称为DT

  4. 从DT中减去NAR的上边界。请调用此A。

  5. 您的最大高度应为NARH-A



更新:Ohhhh kay,我实现了这个想法,它的工作原理!有很多废话,包括边距,边框,填充,滚动条(即使有自定义宽度),百分比宽度,最大高度/宽度和兄弟节点。查看这段代码:

  exports.findMaxHeight = function(domNode){
return findMaxDimension(domNode,'height' )
}
exports.findMaxWidth = function(domNode){
return findMaxDimension(domNode,'width')
}

//找到最大传递的domNode可以不超出其父节点的边界的高度/宽度(以px为单位)
// dimension - 'height'或'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
]

//找到具有显式高度/宽度的最近祖先,并捕获之间的所有祖先
//找到高度/宽度相对于那个祖先的祖先
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){//不是百分比和某种长度
var nearestAncestorWithExplicitDimension = x
var explicitLength = h
ancestorBottomBorder = parseInt(styles [outerBorderWidth])+ parseInt(styles [outerPaddingWidth])
if(hasScrollBars(x,axis,styles))
ancestorBottomBorder + = getScrollbarLength
break;
} else {
ancestry.push({node:x,styles:styles})
}
}

if(!nearestAncestorWithExplicitDimension)
return undefined //没有最大值

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.no​​de,otherAxis,styles))
moreBottomBorder + = getScrollbarLength(ancestorInfo.no​​de,otherDimension)

if(possibleNewDimension!== undefined&& (
newDimension!== undefined&& possibleNewDimension< newDimension ||
possibleNewDimension< maxAvailableDimension

){
maxAvailableDimension = possibleNewDimension
nodeToFindDistanceFrom = ancestorInfo.no​​de
// ancestorBottomBorder = moreBottomBorder
} else if(newDimension!== undefined){
maxAvailableDimension = newDimension
nodeToFindDistanceFrom = ancestorInfo.no​​de
/ / ancestorBottomBorder = moreBottomBorder
} else {

}

ancestorBottomBorder + = moreBottomBorder
})

//查找距离顶
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
}

//获取定义的值的像素长度真实绝对或相对测量(例如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)
}
}

//忽略'calc'的存在
function basicLengthToPixels(length,parentLength){
var lengthParts = length.match(/( - ?[0-9] +)(。*)/)
if(lengthParts!= null){
var number = parseInt(lengthParts [1])$ ​​b $ b var metric = lengthParts [2]
if (指标==='%'){
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)
}

返回转换*数字
}
}
}


// https://developer.mozilla.org/en-US/docs/Web/CSS/number
var number ='( ?:\\ + | - )?'+ //负数或正数运算符
'\\d *'+ //整数部分
'(?:\\.\\ \\\d *)?'+ //分数部分
'(?:e(?:\\ + | - )?\\d *)?'//科学记数法
// https://developer.mozilla.org/en-US/docs/Web/CSS/calc
var calcValue ='(?:'+
'('+ number +')'+ // length number
'([A-Za-z] + |%)?'+ //可选后缀(%或px / mm / etc)
'|'+
' (\\(。* \\))'+ //在括号中有更多的东西
')'
var calcSequence = calcValue +
'((\\s * '+
'(\\ * | / | \\ + | - )'+
'\\s *'+ calcValue +
')*)'
var calcSequenceItem ='\\ss''+
'(\\ * | / | \\ + | - )'+
'\\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]。长度)
}

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 ){
return caculateCalc(calcVal,parentLength)
} else if(suffix){
return basicLengthToPixels(number + suffix,parentLength)
} else {
return number
}
}

//通过任何方式(样式表,内联等)获取呈现的样式属性,但不是*计算值
// domNode - 获取
属性的节点//属性 - 可以是一个要提取的单个属性或一个要提取的属性数组
function getFinalStyle(domNode,properties){
if(! property 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
result [prop] = computedStyles [prop]
})

if(parent){
parent.style.display = originalDisplay
}

返回结果
}


//来自lostsource http://stackoverflow.com/questions/13382516/getting-scroll-bar-width-using -javascript
// dimension - 'width'或'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 // WinJS应用程序需要

domNode.parentNode.appendChild(outer)

var lengthNoScroll = outer [offsetDimension]

//强制滚动条两个css和一个更宽的内部div
var inner1 = document.createElement(div)
inner1.style [dimension] =120%//没有这个额外的内部div,一些浏览器可能决定不添加scoll bar
outer.appendChild(inner1)
outer.style.overflow =scroll

var inner2 = document.createElement(div)
inner2.style [dimension] =100%
outer.appendChild(inner2)//这必须在添加滚动条或浏览器是愚蠢的并且没有适当调整对象大小后添加返回调度程序?)

var lengthWithScroll = inner2 [offsetDimension]

domNode.parentNode.removeChild(outer)

返回lengthNoScroll - lengthWithScroll
}

// dimension - 'y'或'x'
// computedStyles - (可选)传入domNodes计算样式(如果已经有)听起来有点贵)
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]


//检查auto和visible值的overflow和overflowY属性
var cStyle = computedStyles || getComputedStyle(domNode)
return hasVScroll&& (cStyle [overflowDimension] ==visible
|| cStyle [overflowDimension] ==auto

|| cStyle [overflowDimension] ==scroll
}

一个npm / github模块导致它似乎应该天真地可用的东西,但不是,并采取shiteload的工作做正确。


The Problem: Given a DIV element with a fixed height, which contains an unknown number of child elements that are sized relative to its height, calculate the maximum/minimum height that the DIV could resize to, without violating any of the maximum/minimum values of its child elements.

Example Find the maximum/minimum height of DIV A

Answer

Minimum: 150px

Maximum: 275px

* {
  box-sizing: border-box;
}
.border {
  border-style: solid;
  border-width: 1px 1px 1px 1px;
}
.A {
  height: 200px;
  width: 200px;
}
.B {
  float: left;
  width: 50%;
  height: 75%;
  min-height: 125px;
  max-height: 225px;
  background: yellow;
}
.C {
  float: left;
  width: 50%;
  height: 75%;
  min-height: 100px;
  max-height: 250px;
  background: green;
}
.D{
  float: left;
  width: 100%;
  height: 25%;
  min-height: 25px;
  max-height: 50px;
  background: blue;
}

<div class="A border">
  <div class="B border">
    B
  </div>
  <div class="C border">
    C
  </div>
  <div class="D border">
    D
  </div>
</div>

Additional Information: I currently have tried using an algorithm that traverses the DIV's DOM tree and creates an object graph representing the spacial positioning of the elements, using the elements offset. Below is a rudimentary algorithm that examines the spacial relationship of the elements, allowing for a 10px spread between edges to be considered 'touching'.

jQuery and other libraries are allowed as long as they are open source.

var _isContentRoot = function(a,b){
    var aRect = a.innerRect;
    var bRect = b.outerRect;
    //Check if child element is a root node
    return Math.abs(aRect.top - bRect.top) <= 10;
}

var _isLayoutSibling = function(a,b){
    var aRect = a.outerRect;
    var bRect = b.outerRect;

    // If element X has a boundary that intersects element Y, and
    // element X is located above element Y, element Y is a child node of
    // element X
    if(Math.abs(aRect.bottom - bRect.top) <= 10) {
        if (aRect.left <= bRect.left && aRect.right >= bRect.left ||
            aRect.left <= bRect.right && aRect.right >= bRect.right ||
            aRect.left >= bRect.left && aRect.right <= bRect.right ||
            aRect.left <= bRect.left && aRect.right >= bRect.right) {

            return true;
        }
    }
    return false;
}

Edit: Fixed CSS error. Here is an updated Fiddle http://jsfiddle.net/zqnscmo2/

Edit 2: Try to think of this more of a graph problem in the problem space of CSS/HTML. Imagine the CSS and HTML are used to describe a graph where each DIV is a vertex. There exists an edge between the two vertices

1.) if the HTML element's bounding rectA.top ≈ rectB.top OR 2.) there exists an edge if the bounding rectA.bottom ≈ rectB.top

Each vertex has two exclusive sets of edges, set A contains all edges that meet criterion 1. Set B contains all edges that meet criterion 2. Therefor you can traverse the graph and find the minimal and maximal path and that should be the PARENT DIV's max/min height.

This is my proposed algorithm for determining the max/min height of the inner contents. I'm very much open to less complex solutions.

解决方案

This is what I'm thinking:

  1. Find the nearest ancestor with an explicit height
  2. Find all the ancestors with percentage heights and calculate the height of the nearest one of those ancestors to find the available height. Lets call that ancestor NAR and the height NARH.
  3. Find the distance your element is from the top of its parent (with getBoundingClientRect). Call it DT
  4. Subtract the top boundary of NAR from DT. Call this A.
  5. Your maximum height should be NARH-A

Something similar could be done for the minimum.

UPDATE: Ohhhh kay, I implemented this idea and it works! There's a lot of crap it takes into account including margins, borders, padding, scroll bars (even with custom widths), percentage widths, max-height/width, and sibling nodes. Check out this code:

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

I'll probably put this in an npm/github module cause it seems like something that should be available naively, but isn't and takes a shiteload of work to do right.

这篇关于计算DIV元素的最大/最小高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆