在添加到DOM之前的DOM元素宽度

30

我确定答案是否定的,但是在将元素添加到DOM之前确定元素的宽度是可能的吗?

一旦添加了元素,我知道可以使用offsetWidth和offsetHeight。

谢谢

7个回答

27

关键在于展示元素 (display:block),同时也隐藏它 (visibility:hidden),并将其位置设为绝对定位,以便不影响页面布局。

正如 Oscar 提到的那样,MooTools 的 Element.Measure 类可以实现这一点。


14

Oscar提到的Mootools Element.Measure功能非常棒。对于使用jQuery的人来说,这里有一个快速插件可以实现相同的功能:

$.fn.measure = (fn)->
  el = $(this).clone(false)
  el.css
    visibility: 'hidden'
    position:   'absolute'
  el.appendTo('body')
  result = fn.apply(el)
  el.remove()
  return result
你可以这样调用它,确保返回该值(感谢 Sam Fen 指出!):
width = $('.my-class-name').measure( function(){ return this.width() } )

1
我知道这篇文章发布已经很久了,但是对于像我这样尝试应用它的人来说,你需要在传递的函数中返回值。所以 'width = $('.my-class-name').measure( function(){ return this.width() } )' - Sam Fen
1
很棒的东西。目前正在使用RequireJS- https://gist.github.com/simonsmith/5135933 - Simon Smith
谢谢你的建议。我稍微修改了代码,这里提供一个纯JS的解决方案 https://dev59.com/anE85IYBdhLWcg3wJQCt#46707458。 - kashesandr
这个想法很好,但是仅仅将内容添加到 body 中是不够的。如果你需要获取元素的实际宽度,在某些情况下这种方法行不通,不要忘记考虑元素或其子元素的 __内边距__。 - Mehdi Dehghani

11

稍微修改了一下代码。这是一个纯JS解决方案:

function measure(el, fn) {
    var pV = el.style.visibility, 
        pP = el.style.position;
        
    el.style.visibility = 'hidden';
    el.style.position = 'absolute';
    
    document.body.appendChild(el);
    var result = fn(el);
    el.parentNode.removeChild(el);
    
    el.style.visibility = pV;
    el.style.position = pP;
    return result;
}

var div = document.createElement('div');
div.innerHTML = "<p>Hello</p><br/>";

alert(div.offsetHeight); // 0

alert(measure(div, function(el){return el.offsetHeight})); // 68


8

5

至少目前来说是不可能的,因为样式会影响这些属性,而它放置的位置决定了它的样式以及哪些规则会影响它。

例如,在页面中放置一个<p></p>元素,默认情况下如果将其作为子元素添加到body中,则其宽度将与body一致,但如果将其添加到一个<div style="width: 100px;"></div>中,那么你就会看到它很快就会改变大小。


4
+1,在当前 JavaScript 执行停止之前,该元素实际上不会被渲染。这意味着你可以追加、获取尺寸并再次删除,而没有任何可视化指示发生了任何事情。 - Andy E

3
/**
 * Get bounding client rect for an element (not exists at current DOM tree)
 * @param {!HTMLElement} el
 * @return {!Promise<!ClientRect>}
 */
function getElementRect(el) {
  return new Promise(resolve => {
    const element = el.cloneNode(true);
    element.style.visibility = "hidden";
    element.style.position = "absolute";
    document.body.appendChild(element);

    resolve(element.getBoundingClientRect());
    element.remove();
  });
}

const div = /** @type {!HTMLElement} */ (document.createElement("div"));
div.innerHTML = "<p>Hello</p><br/>";

// Execute
(async () => {
  const rect = await getElementRect(div);
  console.log(rect.width);
})();

演示


0
一个稍微不同的版本@kashesanders:将元素添加到div中,并将该div放入DOM中。
function getSizeOfNonDomElement(domElement)
{
  // setup
  let div = document.createElement("div");
  div.style.position = "absolute";
  div.style.visibility = "hidden";
  div.style.display = "block";

  div.appendChild (domElement);
  document.body.appendChild (div);

  // run
  let rect = domElement.getBoundingClientRect ();

  // cleanup
  document.body.removeChild (div);
  div.removeChild (domElement);

  return rect;
}

如果您想使其更加安全,请添加一个结构来检查它是否已经有父级和/或是否在DOM内部。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接