jQuery: Lấy chiều cao của phần tử ẩn trong jQuery


249

Tôi cần lấy chiều cao của một phần tử nằm trong div bị ẩn. Ngay bây giờ tôi hiển thị div, lấy chiều cao và ẩn div cha. Điều này có vẻ hơi ngớ ngẩn. Có cách nào tốt hơn?

Tôi đang sử dụng jQuery 1.4.2:

$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();

42
+1 Giải pháp ví dụ của bạn thực sự tốt hơn bất kỳ câu trả lời nào lol.
Tim Santeford

9
Tôi không đồng ý Tim. Với giải pháp này, có khả năng màn hình có thể nhấp nháy vì bạn thực sự đang hiển thị mục đó và sau đó ẩn nó. Mặc dù giải pháp Nicks phức tạp hơn, nó không có cơ hội nhấp nháy màn hình vì div cha không bao giờ được hiển thị.
Humphrey



5
Harry, thực sự những gì bạn phát hiện ra là mã của bạn không hoạt động trong IE, không phải giải pháp này. Đi gỡ lỗi mã của bạn :)
Gavin

Câu trả lời:


181

Bạn có thể làm một cái gì đó như thế này, một chút hacky, quên đi positionnếu nó đã tuyệt đối:

var previousCss  = $("#myDiv").attr("style");

$("#myDiv").css({
    position:   'absolute', // Optional if #myDiv is already absolute
    visibility: 'hidden',
    display:    'block'
});

optionHeight = $("#myDiv").height();

$("#myDiv").attr("style", previousCss ? previousCss : "");

17
Tôi hợp nhất mã trên vào một plugin jQ jsbin.com/ihakid/2 . Tôi cũng sử dụng một lớp và kiểm tra xem các phụ huynh cũng bị ẩn đi.
hitautodesturation

3
+1 Điều này hoạt động rất tốt. Chỉ cần ghi nhớ cha mẹ của các yếu tố phải được hiển thị là tốt. Điều này đã làm tôi bối rối trong vài phút. Ngoài ra, nếu yếu tố là position:relative, tất nhiên bạn sẽ muốn đặt nó sau thay vì static.
Michael Mior

6
Khi bạn sử dụng phương pháp này, phần tử đích thường có thể thay đổi hình dạng. Vì vậy, việc lấy chiều cao và / hoặc chiều rộng của div khi vị trí tuyệt đối của nó có thể không hữu ích lắm.
Jeremy Ricketts

2
@Gavin điều này ngăn chặn tính toán chỉnh lại dòng và bất kỳ nhấp nháy nào cho người dùng, vì vậy nó vừa rẻ hơn và ít xâm phạm hơn.
Nick Craver

2
@hitautodesturation, tôi đã sửa đổi plugin truy vấn của bạn để kiểm tra chỉ phần tử này thực sự bị ẩn. jsbin.com/ihakid/58
Prasad

96

Tôi gặp vấn đề tương tự với việc lấy chiều rộng phần tử ẩn, vì vậy tôi đã viết plugin này gọi jQuery Actual để sửa nó. Thay vì sử dụng

$('#some-element').height();

sử dụng

$('#some-element').actual('height');

sẽ cung cấp cho bạn giá trị phù hợp cho phần tử ẩn hoặc phần tử có cha mẹ ẩn.

Tài liệu đầy đủ xin vui lòng xem tại đây . Ngoài ra còn có một bản demo bao gồm trong trang.

Hy vọng điều này giúp đỡ :)


3
Có nó giúp! 2015 và nó vẫn giúp. Bạn nói "phiên bản cũ hơn của jquery" trên trang web Thực tế - tuy nhiên - nó vẫn được yêu cầu trong phiên bản 2.1, ít nhất là trong tình huống của tôi.
LpLrich 30/03/2015

Cảm ơn! Tôi đã sử dụng plugin này để đọc và thiết lập chiều cao của các yếu tố (việc này được thực hiện một cách linh hoạt) ban đầu được ẩn trong các hiệp ước
alds

Plugin tuyệt vời! Tôi đã thử mọi cách để có được chiều rộng của một div bên trong một phương thức khi được đặt thành 100% và không có gì hoạt động. thiết lập điều này trong 5 giây và hoạt động hoàn hảo!
Craig Howell

@ben Liên kết bị hỏng.
Sachin Prasad

39

Bạn đang nhầm lẫn hai kiểu CSS, kiểu hiển thịkiểu hiển thị .

Nếu phần tử bị ẩn bằng cách đặt kiểu css hiển thị, thì bạn sẽ có thể nhận được chiều cao bất kể phần tử có hiển thị hay không vì phần tử vẫn chiếm không gian trên trang .

Nếu phần tử bị ẩn bằng cách thay đổi kiểu css hiển thị thành "none", thì phần tử đó không chiếm dung lượng trên trang và bạn sẽ phải tạo cho nó một kiểu hiển thị sẽ khiến phần tử hiển thị trong một khoảng trắng, tại điểm nào, bạn có thể có được chiều cao.


cảm ơn vì điều đó. vấn đề của tôi liên quan đến một tế bào bảng và thiết lập visibilityđể hiddenkhông giải quyết vấn đề của tôi, nhưng nó đã cho tôi ý tưởng để thiết lập position: fixed; top: 100%và nó hoạt động như một cơ duyên!
Jayen

Bây giờ tôi hiểu tại sao chiều cao của nó không được hiển thị với màn hình: không có yếu tố nào. Cảm ơn rất nhiều cho lời giải thích tuyệt vời.
FrenkyB

30

Đôi khi tôi đã dùng đến một chút mánh khóe để giải quyết vấn đề này. Tôi đã phát triển một tiện ích thanh cuộn jQuery nơi tôi gặp phải vấn đề mà tôi không biết trước liệu nội dung có thể cuộn có phải là một phần của một phần đánh dấu ẩn hay không. Đây là những gì tôi đã làm:

// try to grab the height of the elem
if (this.element.height() > 0) {
    var scroller_height = this.element.height();
    var scroller_width = this.element.width();

// if height is zero, then we're dealing with a hidden element
} else {
    var copied_elem = this.element.clone()
                      .attr("id", false)
                      .css({visibility:"hidden", display:"block", 
                               position:"absolute"});
    $("body").append(copied_elem);
    var scroller_height = copied_elem.height();
    var scroller_width = copied_elem.width();
    copied_elem.remove();
}

Điều này hoạt động với hầu hết các phần, nhưng có một vấn đề rõ ràng có khả năng xảy ra. Nếu nội dung bạn đang nhân bản được tạo kiểu bằng CSS bao gồm các tham chiếu đến đánh dấu cha trong quy tắc của chúng, thì nội dung được sao chép sẽ không chứa kiểu dáng phù hợp và có thể sẽ có các phép đo hơi khác nhau. Để giải quyết vấn đề này, bạn có thể đảm bảo rằng đánh dấu mà bạn đang nhân bản có các quy tắc CSS được áp dụng cho nó không bao gồm các tham chiếu đến đánh dấu cha.

Ngoài ra, điều này không xuất hiện với tôi với tiện ích cuộn của tôi, nhưng để có được chiều cao phù hợp của phần tử nhân bản, bạn sẽ cần đặt chiều rộng thành cùng chiều rộng của phần tử cha. Trong trường hợp của tôi, độ rộng CSS luôn được áp dụng cho phần tử thực tế, vì vậy tôi không phải lo lắng về điều này, tuy nhiên, nếu phần tử không có chiều rộng được áp dụng cho phần tử đó, bạn có thể cần thực hiện một số loại đệ quy duyệt qua tổ tiên DOM của phần tử để tìm chiều rộng của phần tử cha thích hợp.


Điều này có một vấn đề thú vị mặc dù. Nếu phần tử đã là một phần tử khối, bản sao sẽ lấy toàn bộ chiều rộng cơ thể (ngoại trừ phần đệm cơ thể hoặc lề), khác với kích thước của nó trong một thùng chứa.
Meligy

16

Xây dựng thêm về câu trả lời của người dùng Nick và plugin hitautodesturation của người dùng trên JSBin, tôi đã tạo một plugin jQuery tương tự để lấy cả chiều rộng và chiều cao và trả về một đối tượng có chứa các giá trị này.

Nó có thể được tìm thấy ở đây: http://jsbin.com/ikogez/3/

Cập nhật

Tôi đã thiết kế lại hoàn toàn plugin nhỏ bé này vì hóa ra phiên bản trước (đã đề cập ở trên) không thực sự có thể sử dụng được trong môi trường thực tế nơi có nhiều thao tác DOM đang diễn ra.

Điều này đang hoạt động hoàn hảo:

/**
 * getSize plugin
 * This plugin can be used to get the width and height from hidden elements in the DOM.
 * It can be used on a jQuery element and will retun an object containing the width
 * and height of that element.
 *
 * Discussed at StackOverflow:
 * http://stackoverflow.com/a/8839261/1146033
 *
 * @author Robin van Baalen <robin@neverwoods.com>
 * @version 1.1
 * 
 * CHANGELOG
 *  1.0 - Initial release
 *  1.1 - Completely revamped internal logic to be compatible with javascript-intense environments
 *
 * @return {object} The returned object is a native javascript object
 *                  (not jQuery, and therefore not chainable!!) that
 *                  contains the width and height of the given element.
 */
$.fn.getSize = function() {    
    var $wrap = $("<div />").appendTo($("body"));
    $wrap.css({
        "position":   "absolute !important",
        "visibility": "hidden !important",
        "display":    "block !important"
    });

    $clone = $(this).clone().appendTo($wrap);

    sizes = {
        "width": $clone.width(),
        "height": $clone.height()
    };

    $wrap.remove();

    return sizes;
};

mã của bạn không đúng Bạn cần sizes = {"width": $wrap.width(), "height": $wrap.height()};tham chiếu thisđến mục gốc, không thể nhìn thấy.
jackJoe

@jackJoe Tôi đã sử dụng mã này khá lâu mà không gặp vấn đề gì. Tốt nhất tôi sẽ nói rằng tôi cần $ clone. Thong () thay vì 'this'. Không phải bọc $ vì tôi muốn kích thước của phần tử bên trong bọc. Wrapper có thể là 10000x10000px trong khi phần tử tôi muốn đo vẫn là 30x40px chẳng hạn.
Robin van Baalen

Ngay cả việc nhắm mục tiêu $wraplà ok (ít nhất là trong các thử nghiệm của tôi). Tôi đã thử với thisvà rõ ràng là nó sẽ không bắt được kích thước vì thisvẫn đề cập đến yếu tố ẩn.
jackJoe

1
Cảm ơn @jackJoe Tôi đã cập nhật ví dụ mã.
Robin van Baalen

12

Xây dựng thêm về câu trả lời của Nick:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});

Tôi thấy tốt hơn để làm điều này:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").removeAttr('style');

Đặt thuộc tính CSS sẽ chèn chúng nội tuyến, sẽ ghi đè lên bất kỳ thuộc tính nào khác bạn có trong tệp CSS của mình. Bằng cách xóa thuộc tính style trên thành phần HTML, mọi thứ trở lại bình thường và vẫn bị ẩn, vì nó bị ẩn ở vị trí đầu tiên.


1
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'}); optionHeight = $("#myDiv").height(); $("#myDiv").css({'position':'','visibility':'', 'display':''});
Aaron

9
... Trừ khi bạn đã có kiểu nội tuyến trên phần tử. Đó sẽ là trường hợp nếu bạn ẩn phần tử với jQuery.
Muhd

4

Bạn cũng có thể định vị div ẩn khỏi màn hình với lề âm thay vì sử dụng màn hình: không, giống như kỹ thuật thay thế hình ảnh thụt lề văn bản.

ví dụ.

position:absolute;
left:  -2000px;
top: 0;

Bằng cách này, chiều cao () vẫn có sẵn.


3

Tôi cố gắng tìm chức năng làm việc cho phần tử ẩn nhưng tôi nhận ra rằng CSS phức tạp hơn mọi người nghĩ. Có rất nhiều kỹ thuật bố cục mới trong CSS3 có thể không hoạt động cho tất cả các câu trả lời trước đó như hộp linh hoạt, lưới, cột hoặc thậm chí là phần tử bên trong phần tử cha phức tạp.

ví dụ flexibox nhập mô tả hình ảnh ở đây

Tôi nghĩ rằng giải pháp đơn giản và bền vững là kết xuất thời gian thực . Vào thời điểm đó, trình duyệt sẽ cung cấp cho bạn kích thước phần tử chính xác .

Đáng buồn thay, JavaScript không cung cấp bất kỳ sự kiện trực tiếp nào để thông báo khi phần tử được hiển thị hoặc ẩn. Tuy nhiên, tôi tạo một số chức năng dựa trên API sửa đổi thuộc tính DOM sẽ thực thi chức năng gọi lại khi khả năng hiển thị của phần tử bị thay đổi.

$('[selector]').onVisibleChanged(function(e, isVisible)
{
    var realWidth = $('[selector]').width();
    var realHeight = $('[selector]').height();

    // render or adjust something
});

Để biết thêm thông tin, vui lòng truy cập tại dự án GitHub của tôi.

https://github.com/Soul-Master/visible.event.js

bản demo: http://jsbin.com/ETiGIre/7


Cảm ơn câu trả lời của bạn. Nó cũng truyền cảm hứng cho tôi để sử dụng M mutObservers. Nhưng lưu ý rằng thư viện của bạn chỉ kiểm tra các thay đổi về mức độ hiển thị do thay đổi stylethuộc tính (xem dòng 59 tại đây ), trong khi thay đổi mức độ hiển thị cũng có thể được gây ra bởi các thay đổi trong classthuộc tính.
Ashraf Sabry

Bạn đúng. Câu lệnh đúng phải là e.attributionName! == 'style' && e.attributionName! == 'className'
Soul_Master

2

Theo giải pháp của Nick Craver, việc đặt mức độ hiển thị của thành phần cho phép nó có được kích thước chính xác. Tôi đã sử dụng giải pháp này rất thường xuyên. Tuy nhiên, phải thiết lập lại các kiểu thủ công, tôi đã tìm thấy sự cồng kềnh này, do việc sửa đổi định vị / hiển thị ban đầu của phần tử trong css của tôi thông qua quá trình phát triển, tôi thường quên cập nhật mã javascript liên quan. Đoạn mã sau không đặt lại kiểu cho mỗi lần nói, nhưng loại bỏ kiểu nội tuyến được thêm bởi javascript:

$("#myDiv")
.css({
    position:   'absolute',
    visibility: 'hidden',
    display:    'block'
});

optionHeight = $("#myDiv").height();
optionWidth = $("#myDiv").width();

$("#myDiv").attr('style', '');

Giả định duy nhất ở đây là không thể có các kiểu nội tuyến khác nếu không chúng sẽ bị xóa. Tuy nhiên, lợi ích ở đây là các kiểu của phần tử được trả về giá trị của chúng trong biểu định kiểu css. Kết quả là, bạn có thể viết nó lên như một hàm trong đó một phần tử được truyền qua và chiều cao hoặc chiều rộng được trả về.

Một vấn đề khác mà tôi đã tìm thấy khi đặt các kiểu nội tuyến qua js là khi xử lý các chuyển đổi qua css3, bạn bị buộc phải điều chỉnh các trọng số của quy tắc kiểu của mình mạnh hơn một kiểu nội tuyến, đôi khi có thể gây khó chịu.


1

Theo định nghĩa, một phần tử chỉ có chiều cao nếu nó hiển thị.

Chỉ tò mò: tại sao bạn cần chiều cao của một yếu tố ẩn?

Một cách khác là che giấu một yếu tố một cách hiệu quả bằng cách đặt nó phía sau (sử dụng chỉ mục z) một lớp phủ nào đó).


1
Tôi cần một chiều cao của một yếu tố, điều đó sẽ bị ẩn trong suốt thời gian tôi muốn chiều cao của nó. Tôi đang xây dựng một plugin và tôi cần thu thập một số dữ liệu khi tôi khởi tạo nó
mkoryak

2
một lý do khác là để định tâm mọi thứ với javascript có thể chưa hiển thị
Simon_Weaver

@cletus Nếu bạn chỉ tò mò viết bình luận, đó là tình huống rất thường gặp trong mã hóa frontend để lấy kích thước của một phần tử ẩn.
Rantiev

1

Trong hoàn cảnh của tôi, tôi cũng có một yếu tố ẩn khiến tôi không nhận được giá trị chiều cao, nhưng đó không phải là chính yếu tố đó mà là cha mẹ của nó ... vì vậy tôi chỉ cần kiểm tra một trong các plugin của mình để xem liệu nó có ẩn, khác tìm yếu tố ẩn gần nhất. Đây là một ví dụ:

var $content = $('.content'),
    contentHeight = $content.height(),
    contentWidth = $content.width(),
    $closestHidden,
    styleAttrValue,
    limit = 20; //failsafe

if (!contentHeight) {
    $closestHidden = $content;
    //if the main element itself isn't hidden then roll through the parents
    if ($closestHidden.css('display') !== 'none') { 
        while ($closestHidden.css('display') !== 'none' && $closestHidden.size() && limit) {
            $closestHidden = $closestHidden.parent().closest(':hidden');
            limit--;
        }
    }
    styleAttrValue = $closestHidden.attr('style');
    $closestHidden.css({
        position:   'absolute',
        visibility: 'hidden',
        display:    'block'
    });
    contentHeight = $content.height();
    contentWidth = $content.width();

    if (styleAttrValue) {
        $closestHidden.attr('style',styleAttrValue);
    } else {
        $closestHidden.removeAttr('style');
    }
}

Trên thực tế, đây là sự kết hợp các câu trả lời của Nick, Gregory và Mí mắt để cho bạn sử dụng phương pháp cải tiến của Gregory, nhưng sử dụng cả hai phương pháp trong trường hợp được cho là có một thứ gì đó trong thuộc tính phong cách mà bạn muốn đặt lại và tìm kiếm một phần tử cha.

Điều duy nhất của tôi với giải pháp của tôi là vòng lặp thông qua cha mẹ không hoàn toàn hiệu quả.


1

Một cách giải quyết khác là tạo div cha bên ngoài phần tử bạn muốn lấy chiều cao, áp dụng chiều cao '0' và ẩn bất kỳ tràn nào. Tiếp theo, lấy chiều cao của phần tử con và loại bỏ thuộc tính tràn của cha mẹ.

var height = $("#child").height();
// Do something here
$("#parent").append(height).removeClass("overflow-y-hidden");
.overflow-y-hidden {
  height: 0px;
  overflow-y: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="parent" class="overflow-y-hidden">
  <div id="child">
    This is some content I would like to get the height of!
  </div>
</div>


0

Đây là tập lệnh tôi đã viết để xử lý tất cả các phương thức thứ nguyên của jQuery cho các phần tử ẩn, thậm chí là hậu duệ của cha mẹ ẩn. Lưu ý rằng, tất nhiên, có một hiệu suất đạt được bằng cách sử dụng này.

// Correctly calculate dimensions of hidden elements
(function($) {
    var originals = {},
        keys = [
            'width',
            'height',
            'innerWidth',
            'innerHeight',
            'outerWidth',
            'outerHeight',
            'offset',
            'scrollTop',
            'scrollLeft'
        ],
        isVisible = function(el) {
            el = $(el);
            el.data('hidden', []);

            var visible = true,
                parents = el.parents(),
                hiddenData = el.data('hidden');

            if(!el.is(':visible')) {
                visible = false;
                hiddenData[hiddenData.length] = el;
            }

            parents.each(function(i, parent) {
                parent = $(parent);
                if(!parent.is(':visible')) {
                    visible = false;
                    hiddenData[hiddenData.length] = parent;
                }
            });
            return visible;
        };

    $.each(keys, function(i, dimension) {
        originals[dimension] = $.fn[dimension];

        $.fn[dimension] = function(size) {
            var el = $(this[0]);

            if(
                (
                    size !== undefined &&
                    !(
                        (dimension == 'outerHeight' || 
                            dimension == 'outerWidth') &&
                        (size === true || size === false)
                    )
                ) ||
                isVisible(el)
            ) {
                return originals[dimension].call(this, size);
            }

            var hiddenData = el.data('hidden'),
                topHidden = hiddenData[hiddenData.length - 1],
                topHiddenClone = topHidden.clone(true),
                topHiddenDescendants = topHidden.find('*').andSelf(),
                topHiddenCloneDescendants = topHiddenClone.find('*').andSelf(),
                elIndex = topHiddenDescendants.index(el[0]),
                clone = topHiddenCloneDescendants[elIndex],
                ret;

            $.each(hiddenData, function(i, hidden) {
                var index = topHiddenDescendants.index(hidden);
                $(topHiddenCloneDescendants[index]).show();
            });
            topHidden.before(topHiddenClone);

            if(dimension == 'outerHeight' || dimension == 'outerWidth') {
                ret = $(clone)[dimension](size ? true : false);
            } else {
                ret = $(clone)[dimension]();
            }

            topHiddenClone.remove();
            return ret;
        };
    });
})(jQuery);

Câu trả lời bằng mí mắt có vẻ hoàn hảo cho những gì tôi cần nhưng không hoạt động với jQuery Tôi đang chạy: 1.3.2 Nó khiến jQuery ném cái này. Clone (hoặc một cái gì đó rất gần) không phải là một chức năng. Bất cứ ai có bất kỳ ý tưởng về cách khắc phục nó?

0

Nếu bạn đã hiển thị phần tử trên trang trước đó, bạn chỉ cần lấy chiều cao trực tiếp từ phần tử DOM (có thể truy cập trong jQuery với .get (0)), vì nó được đặt ngay cả khi phần tử bị ẩn:

$('.hidden-element').get(0).height;

tương tự cho chiều rộng:

$('.hidden-element').get(0).width;

(cảm ơn Skeets O'Reilly đã sửa)


Trả vềundefined
Jake Wilson

1
Khá chắc chắn rằng điều này chỉ hoạt động nếu bạn đã hiển thị các yếu tố trên trang trước đó. Đối với các yếu tố đã luôn luôn display='none', điều này sẽ không hoạt động.
Xiên
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.