Javascript 计算DIV元素的最大/最小高度
问题: 给定一个具有固定高度的DIV元素,该元素包含的子元素数量未知,且子元素的大小与其高度相关,请计算DIV可以调整大小的最大/最小高度,而不违反其子元素的任何最大/最小值 示例 查找A区的最大/最小高度 回答 最小值:150像素 最大值:275像素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
*{
框大小:边框框;
}
.边界{
边框样式:实心;
边框宽度: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
这就是我的想法:
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)