Làm thế nào để phát hiện kích thước của DIV thay đổi?


351

Tôi đã có mẫu html sau, có một DIV có chiều rộng 100%. Nó chứa một số yếu tố. Trong khi thực hiện thay đổi kích thước cửa sổ, các thành phần bên trong có thể được định vị lại và kích thước của div có thể thay đổi. Tôi đang hỏi liệu có thể kết nối sự kiện thay đổi kích thước của div không? và làm thế nào để làm điều đó? Tôi hiện đang liên kết chức năng gọi lại với sự kiện thay đổi kích thước jQuery trên DIV đích, tuy nhiên, không có nhật ký giao diện điều khiển nào được xuất ra, xem bên dưới:

Trước khi thay đổi kích thước nhập mô tả hình ảnh ở đây

<html>
<head>
    <script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
    <script type="text/javascript" language="javascript">
            $('#test_div').bind('resize', function(){
                console.log('resized');
            });
    </script>
</head>
<body>
    <div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
    </div>
</body>
</html>

7
Điều này sẽ không hoạt động bởi vì, bạn ràng buộc thay đổi kích thước sự kiện thành phần tử div được chỉ định. Nhưng sự kiện thay đổi kích thước sẽ kích hoạt cho cửa sổ không phải cho phần tử của bạn.
Fatih Acet

Bạn có thể sử dụng setIntervalở đây như là một giải pháp có thể. Bạn luôn có thể liên kết clearIntervalvới một nút bấm để dừng vòng lặp sau khi công việc của bạn hoàn thành.
Peter Darmis

1
Từ năm 2020, ResizeObserver hoạt động trong tất cả các trình duyệt chính (Chrome, Safari, Firefox, Edge) ngoại trừ IE. caniuse.com/#feat=resizeobserver
Dan

Câu trả lời:


264

Có một phương pháp rất hiệu quả để xác định xem kích thước của một phần tử đã được thay đổi hay chưa.

http://marcj.github.io/css-element-queries/

Thư viện này có một lớp ResizeSensorcó thể được sử dụng để phát hiện thay đổi kích thước.
Nó sử dụng một cách tiếp cận dựa trên sự kiện, vì vậy nó rất nhanh và không làm mất thời gian của CPU.

Thí dụ:

new ResizeSensor(jQuery('#divId'), function(){ 
    console.log('content dimension changed');
});

Vui lòng không sử dụng plugin onresize jQuery vì nó sử dụngsetTimeout() kết hợp với việc đọc DOM clientHeight/ clientWidththuộc tính trong một vòng lặp để kiểm tra các thay đổi.
Điều này là chậm đáng kinh ngạc và không chính xác vì nó gây ra bố cục đập .

Tiết lộ: Tôi liên kết trực tiếp với thư viện này.


8
@jake, hỗ trợ IE11 hiện đã được triển khai.
Marc J. Schmidt

15
@Aletheios bạn nên xem kỹ hơn. requestAnimationFrame không phải để phát hiện kích thước chậm mà hoàn toàn ngược lại: Nó làm mịn tất cả các số sự kiện cực đoan được kích hoạt bởi cảm biến thay đổi kích thước dựa trên sự kiện thực để tiết kiệm thời gian cpu. Xem các tài liệu được cập nhật tại github.com/marcj/css-element-queries/blob/master/src/ Kẻ
Marc J. Schmidt

6
@Aletheios Tôi đoán bạn bỏ lỡ một điểm: setTimeout không chỉ không chính xác mà còn chậm như địa ngục. Một requestAnimationFrame kiểm tra một boolean đơn giản là các đơn đặt hàng có cường độ nhanh hơn một setTimeout kiểm tra mọi lúc đối với các thuộc tính DOM. Bên cạnh đó setTimeout cũng được gọi cứ sau vài mili giây.
Marc J. Schmidt

9
@Orwellophile bạn rõ ràng không hiểu gì cả. Ngừng hạ thấp câu trả lời mà bạn không biết làm thế nào nó hoạt động trong nội bộ. Một lần nữa: css-Element-query: sử dụng một sự kiện thay đổi kích thước thực được kích hoạt mỗi khi kích thước thay đổi. Vì bạn nhận được quá nhiều sự kiện (ví dụ như drag'n'drop), nó đã thêm requestAnimationFrame kiểm tra một biến boolean đơn giản để làm mịn các sự kiện được kích hoạt xuống 1 / khung. plugin jquery: Sử dụng setTimeout kiểm tra tất cả các đạo cụ bố cục DOM (clientHeight, v.v.) trong đó mỗi lần kiểm tra rất chậm nhưng cần phải được kiểm tra thường xuyên để có cùng chức năng.
Marc J. Schmidt

9
@Aletheios, @Orwellophile và bất kỳ ai có thể đã bị họ đánh lừa: requestAnimationFramevs setTimeoutlà không liên quan, thư viện này không lặp . requestAnimationFramechỉ được sử dụng để gỡ lỗi / điều chỉnh tần số gọi lại cuộc gọi của bạn, nó không thăm dò ý kiến . Về mặt lý thuyết, MutingObserver có thể được sử dụng cho hiệu ứng tương tự nhưng không phải trong các trình duyệt cũ hơn, không giống như điều này. Điều này là thông minh nổi bật.
Han Seoul-Oh

251

Một tiêu chuẩn mới cho điều này là api Resize Observer, có sẵn trong Chrome 64.

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>

Thay đổi kích thước quan sát

Thông số: https://wicg.github.io/ResizeObserver

Polyfill: https://github.com/WICG/ResizeObserver/issues/3

Vấn đề về Firefox: https://ormszil.la/1272409

Vấn đề về Safari: http://wkb.ug/157743

Hỗ trợ hiện tại: http://caniuse.com/#feat=resizeobserver


3
chưa hữu ích cho các trang web sản xuất, vì hiện tại chỉ có Chrome hỗ trợ nó. Nhưng chắc chắn là giải pháp tốt nhất ở đây! btw, đây là một tổng quan nhanh về tình trạng triển khai: chromestatus.com/feature/5705346022637568
Philipp

8
@Philipp Có một polyfill.
Daniel Herr

2
Có vẻ như đây vẫn là một tính năng thử nghiệm trong tất cả các trình duyệt caniuse.com/#feat=resizeobserver
Francesc Rosas

5
Thậm chí 2 năm sau câu trả lời này, hỗ trợ trình duyệt vẫn ảm đạm: caniuse.com/#search=resizeobserver
Scrimothy 18/12/18

2
Hoạt động như một nét quyến rũ trong Chrome và FF mới nhất.
Klemen Tušar

32

Bạn phải ràng buộc resizesự kiện trênwindow đối tượng, không phải trên một phần tử html chung.

Sau đó, bạn có thể sử dụng này:

$(window).resize(function() {
    ...
});

và trong chức năng gọi lại, bạn có thể kiểm tra độ rộng mới của divcuộc gọi

$('.a-selector').width();

Vì vậy, câu trả lời cho câu hỏi của bạn là không , bạn không thể liên kết resizesự kiện với div.


124
Câu trả lời này không đủ tốt. thay đổi kích thước có thể xảy ra mà không thay đổi kích thước cửa sổ. ở tất cả.
vsync

9
ví dụ: khi bạn có một phần tử bộ chia hoặc chỉ nối thêm một số văn bản hoặc nội dung khác vào một phần tử.
Günter Zöchbauer

@anu không đúng, bạn có thể có sửa đổi DOM thông qua javascript khiến CSS áp dụng cho cấu trúc mới dẫn đến bố cục khác nhau - kích thước của mỗi vùng chứa.
Antoniossss

29

Về lâu dài, bạn sẽ có thể sử dụng ResizeObserver .

new ResizeObserver(callback).observe(element);

Thật không may, nó hiện không được hỗ trợ theo mặc định trong nhiều trình duyệt.

Trong thời gian trung bình, bạn có thể sử dụng chức năng như sau. Vì, phần lớn các thay đổi kích thước phần tử sẽ đến từ thay đổi kích thước cửa sổ hoặc từ thay đổi một cái gì đó trong DOM. Bạn có thể nghe thay đổi kích thước cửa sổ với sự kiện thay đổi kích thước của cửa sổ và bạn có thể nghe các thay đổi DOM bằng MutingObserver .

Dưới đây là ví dụ về chức năng sẽ gọi lại cho bạn khi kích thước của phần tử được cung cấp thay đổi do kết quả của một trong những sự kiện đó:

var onResize = function(element, callback) {
  if (!onResize.watchedElementData) {
    // First time we are called, create a list of watched elements
    // and hook up the event listeners.
    onResize.watchedElementData = [];

    var checkForChanges = function() {
      onResize.watchedElementData.forEach(function(data) {
        if (data.element.offsetWidth !== data.offsetWidth ||
            data.element.offsetHeight !== data.offsetHeight) {
          data.offsetWidth = data.element.offsetWidth;
          data.offsetHeight = data.element.offsetHeight;
          data.callback();
        }
      });
    };

    // Listen to the window's size changes
    window.addEventListener('resize', checkForChanges);

    // Listen to changes on the elements in the page that affect layout 
    var observer = new MutationObserver(checkForChanges);
    observer.observe(document.body, { 
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true 
    });
  }

  // Save the element we are watching
  onResize.watchedElementData.push({
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  });
};

1
Thật không may, có vẻ như MutingObserver không thể phát hiện các thay đổi trong Shadow DOM.
Ajedi32

@nkron, Thật không may, nếu bạn sử dụng thay đổi kích thước CSS3 , thay đổi kích thước có thể xảy ra khi người dùng thay đổi kích thước thủ công. Sự kiện này không thể bị bắt.
Pacerier

@ Ajedi32 Có, nhưng bạn có thể sử dụng MutingObserver bên trong ShadowDOM. Ý tôi là, thay vì xem bodynhư trong ví dụ này, bạn có thể xem một phần tử trực tiếp. Điều đó thực sự hiệu quả và hiệu quả hơn là xem toàn bộ cơ thể.
trusktr

@ Ajedi32 Chà, vấn đề duy nhất là, nếu cây Shadow DOM bị đóng, thì bạn sẽ không thể truy cập vào bên trong, nhưng tôi không nghĩ đó thường là việc bạn cần làm và nếu bạn cần quan sát một cây kín như thế thì có thể có một vấn đề trong thiết kế. Lý tưởng nhất, bạn chỉ cần quan sát các yếu tố của riêng bạn mà bạn có quyền truy cập. Thành phần Shadow-DOM yêu cầu bạn quan sát kích thước bên trong của nó có thể không được thiết kế đúng. Bạn có một ví dụ cụ thể? Nếu vậy, có lẽ tôi có thể giúp đề xuất một giải pháp (vì tôi cũng quan tâm đến nó, nhưng chưa có ví dụ nào).
trusktr

@trusktr Hiện tại tôi không có MCVE, nhưng về cơ bản, bất kỳ yếu tố Shadow DOM nào có thể thay đổi kích thước của nó do một số đầu vào của người dùng sẽ đủ để kích hoạt vấn đề này. Ví dụ, một hộp mở rộng với một số thông tin bổ sung khi nhấp vào. Lưu ý rằng tôi đang quan sát trang, không phải phần tử riêng lẻ, vì tôi muốn tự động cuộn xuống khi kích thước của trang tăng lên, bất kể lý do. Mở rộng phần tử Shadow DOM chỉ là một trong nhiều lý do có thể khiến trang có thể dài hơn.
Ajedi32

24

ResizeSensor.js là một phần của một thư viện khổng lồ, nhưng tôi đã giảm chức năng của nó xuống NÀY :

function ResizeSensor(element, callback)
{
    let zIndex = parseInt(getComputedStyle(element));
    if(isNaN(zIndex)) { zIndex = 0; };
    zIndex--;

    let expand = document.createElement('div');
    expand.style.position = "absolute";
    expand.style.left = "0px";
    expand.style.top = "0px";
    expand.style.right = "0px";
    expand.style.bottom = "0px";
    expand.style.overflow = "hidden";
    expand.style.zIndex = zIndex;
    expand.style.visibility = "hidden";

    let expandChild = document.createElement('div');
    expandChild.style.position = "absolute";
    expandChild.style.left = "0px";
    expandChild.style.top = "0px";
    expandChild.style.width = "10000000px";
    expandChild.style.height = "10000000px";
    expand.appendChild(expandChild);

    let shrink = document.createElement('div');
    shrink.style.position = "absolute";
    shrink.style.left = "0px";
    shrink.style.top = "0px";
    shrink.style.right = "0px";
    shrink.style.bottom = "0px";
    shrink.style.overflow = "hidden";
    shrink.style.zIndex = zIndex;
    shrink.style.visibility = "hidden";

    let shrinkChild = document.createElement('div');
    shrinkChild.style.position = "absolute";
    shrinkChild.style.left = "0px";
    shrinkChild.style.top = "0px";
    shrinkChild.style.width = "200%";
    shrinkChild.style.height = "200%";
    shrink.appendChild(shrinkChild);

    element.appendChild(expand);
    element.appendChild(shrink);

    function setScroll()
    {
        expand.scrollLeft = 10000000;
        expand.scrollTop = 10000000;

        shrink.scrollLeft = 10000000;
        shrink.scrollTop = 10000000;
    };
    setScroll();

    let size = element.getBoundingClientRect();

    let currentWidth = size.width;
    let currentHeight = size.height;

    let onScroll = function()
    {
        let size = element.getBoundingClientRect();

        let newWidth = size.width;
        let newHeight = size.height;

        if(newWidth != currentWidth || newHeight != currentHeight)
        {
            currentWidth = newWidth;
            currentHeight = newHeight;

            callback();
        }

        setScroll();
    };

    expand.addEventListener('scroll', onScroll);
    shrink.addEventListener('scroll', onScroll);
};

Làm thế nào để sử dụng nó:

let container = document.querySelector(".container");
new ResizeSensor(container, function()
{
    console.log("dimension changed:", container.clientWidth, container.clientHeight);
});

Đây là những gì biểu đồ js làm.
Antoniossss

Cảm ơn đã nén nó. Tôi sẽ dùng thử :)
Tony K.

Có một cái gì đó bị thiếu trong biểu thức nàyparseInt( getComputedStyle(element) )
GetFree

2
Tôi bối rối không biết làm thế nào là "let zIndex = parseInt (getComputingStyle (phần tử));" có hiệu lực? Tôi giả sử bạn có nghĩa là: "let zIndex = parseInt (getComputingStyle (phần tử) .z Index);
Ryan Badour

1
Giải pháp / mã ở trên không phát hiện tất cả các sự kiện thay đổi kích thước (ví dụ: nếu một container được thay đổi kích thước thành cố định với nó không phát hiện thay đổi kích thước cho các sự kiện con. Xem jsfiddle.net/8md2rfsy/1 ). Câu trả lời được chấp nhận hoạt động (bỏ ghi chú các dòng tương ứng).
newBee

21

Tôi KHÔNG khuyên bạn nên setTimeout()hack vì nó làm chậm hiệu suất! Thay vào đó, bạn có thể sử dụng trình quan sát đột biến DOM để nghe thay đổi kích thước Div.

JS:

var observer = new MutationObserver(function(mutations) {
    console.log('size changed!');
  });
  var target = document.querySelector('.mydiv');
  observer.observe(target, {
    attributes: true
  });

HTML:

<div class='mydiv'>
</div>

Đây là bí quyết
Hãy thử thay đổi kích thước div.


Bạn có thể tiếp tục bọc phương pháp của bạn trong debouncephương pháp để nâng cao hiệu quả. debouncesẽ kích hoạt phương thức của bạn sau mỗi x mili giây thay vì kích hoạt mỗi mili giây mà DIV đang được thay đổi kích thước.


9
Vấn đề duy nhất với vấn đề này là nó không báo cáo sự thay đổi trừ khi đột biến thực sự xảy ra với phần tử. Nếu phần tử thay đổi kích thước do các phần tử khác được thêm vào, phần tử này sẽ không hoạt động.
Tony K.

Tôi đồng ý với @TonyK., Đây là vấn đề duy nhất của tôi với MutingObserver và bây giờ tôi đang tìm kiếm một thư viện thay đổi kích thước phần tử
Murhaf Sousli

@JerryGidel Nó không hoạt động khi div chứa thẻ <img>. Trong trường hợp đầu tiên, hình ảnh không được tải và kích thước div được đặt là 0 và sau khi tải kích thước div được thay đổi, nhưng người quan sát không được kích hoạt
Santhosh

15

Giải pháp tốt nhất là sử dụng cái gọi là Element Queries . Tuy nhiên, chúng không phải là tiêu chuẩn, không có thông số kỹ thuật tồn tại - và tùy chọn duy nhất là sử dụng một trong các polyfill / thư viện có sẵn, nếu bạn muốn đi theo cách này.

Ý tưởng đằng sau các truy vấn phần tử là cho phép một vùng chứa nhất định trên trang đáp ứng với không gian được cung cấp cho nó. Điều này sẽ cho phép viết một thành phần một lần và sau đó thả nó vào bất cứ đâu trên trang, trong khi nó sẽ điều chỉnh nội dung của nó theo kích thước hiện tại của nó. Không có vấn đề kích thước cửa sổ là gì. Đây là sự khác biệt đầu tiên mà chúng ta thấy giữa các truy vấn phần tử và truy vấn phương tiện. Mọi người đều hy vọng rằng đến một lúc nào đó, một đặc tả sẽ được tạo ra để chuẩn hóa các truy vấn phần tử (hoặc một cái gì đó đạt được cùng một mục tiêu) và làm cho chúng trở nên tự nhiên, sạch sẽ, đơn giản và mạnh mẽ. Hầu hết mọi người đồng ý rằng các truy vấn Phương tiện khá hạn chế và không giúp ích cho thiết kế mô-đun và khả năng đáp ứng thực sự.

Có một vài polyfill / thư viện giải quyết vấn đề theo nhiều cách khác nhau (có thể được gọi là giải pháp thay vì giải pháp):

Tôi đã thấy các giải pháp khác cho các vấn đề tương tự được đề xuất. Thông thường họ sử dụng bộ hẹn giờ hoặc kích thước Cửa sổ / khung nhìn dưới mui xe, đây không phải là một giải pháp thực sự. Hơn nữa, tôi nghĩ lý tưởng là điều này nên được giải quyết chủ yếu bằng CSS, chứ không phải bằng javascript hoặc html.


+1 cho các truy vấn phần tử nhưng tôi không hy vọng sớm gặp chúng. Thậm chí không có một thông số kỹ thuật nào vào thời điểm này AFAIK ... có lẽ một trong số các bên quan tâm của chúng tôi nên kết hợp lại với nhau và gửi nó?
Rob Evans

1
Đó là một ý tưởng tốt tất nhiên. Sẽ mất một thời gian dài để đạt đến một phiên bản cuối cùng, rất nhiều sự chú ý cần phải được rút ra. Thiết kế này theo cách tốt dường như không tầm thường đối với tôi. Khả năng tương thích giữa nhiều trình duyệt, phụ thuộc vòng tròn, gỡ lỗi, dễ đọc và bảo trì, v.v. Vì vậy, hãy bắt đầu sớm nhất có thể :)
Stan

@Stan, tôi nghĩ rằng câu trả lời này có thể tốt hơn bằng cách thêm chi tiết hơn về những gì Element Query là tất cả về.
Pacerier

15

Tôi thấy thư viện này hoạt động khi giải pháp của MarcJ không:

https://github.com/sdecima/javascript-detect-element-resize

Nó rất nhẹ và phát hiện thay đổi kích thước tự nhiên thông qua CSS hoặc đơn giản là tải / kết xuất HTML.

Mẫu mã (lấy từ liên kết):

<script type="text/javascript" src="detect-element-resize.js"></script>
<script type="text/javascript">
  var resizeElement = document.getElementById('resizeElement'),
      resizeCallback = function() {
          /* do something */
      };
  addResizeListener(resizeElement, resizeCallback);
  removeResizeListener(resizeElement, resizeCallback);
</script>

Đây là nó. 147 dòng, sử dụng các sự kiện cuộn. Đọc qua mã này nếu bạn muốn câu trả lời đầy đủ và đúng về cách phát hiện tốt nhất các thay đổi kích thước div. Gợi ý: không phải "chỉ sử dụng thư viện này."
Seph Reed

1
Mọi người nên xem xét vấn đề này trước khi thử thư viện này.
Louis

13

Hãy xem http://benalman.com/code/projects/jquery-resize/examples/resize/ này

Nó có nhiều ví dụ khác nhau. Hãy thử thay đổi kích thước cửa sổ của bạn và xem cách các yếu tố bên trong các thành phần container được điều chỉnh.

Ví dụ với js fiddle để giải thích làm thế nào để nó hoạt động.
Hãy xem fiddle này http://jsfiddle.net/sgsqJ/4/

Trong đó sự kiện thay đổi kích thước () được liên kết với một phần tử có lớp "test" và cả đối tượng cửa sổ và gọi lại kích thước của đối tượng cửa sổ $ ('. Test'). Resize () được gọi.

ví dụ

$('#test_div').bind('resize', function(){
            console.log('resized');
});

$(window).resize(function(){
   $('#test_div').resize();
});

Hấp dẫn. Cái jsfiddle đó liên tục gặp sự cố chrome với thanh tra đang mở và tôi nhấp vào liên kết "Thêm văn bản". Firefox ném lỗi "quá nhiều đệ quy".
EricP

3
Vui lòng không sử dụng plugin thay đổi kích thước của jQuery. Nó thực sự chậm và cũng không chính xác. Xem câu trả lời của tôi để có được một giải pháp tốt hơn.
Marc J. Schmidt

24
Điều này KHÔNG trực tiếp phát hiện thay đổi kích thước. nó chỉ là sản phẩm phụ của người nghe thay đổi kích thước. một sự thay đổi kích thước có thể xảy ra theo nhiều cách khác nhau.
vsync

4
Điều gì xảy ra nếu thay đổi kích thước của div là từ thay đổi trong phong cách hoặc dom chứ không phải thay đổi kích thước cửa sổ?
kinh ngạc

9

Bạn có thể sử dụng iframehoặc objectsử dụng contentWindowhoặc contentDocumentthay đổi kích thước. Không có setIntervalhoặcsetTimeout

Các bước:

  1. Đặt vị trí phần tử của bạn thành relative
  2. Thêm vào bên trong một IFRAME ẩn tuyệt đối trong suốt
  3. Nghe IFRAME.contentWindow- onresizesự kiện

Một ví dụ về HTML:

<div style="height:50px;background-color:red;position:relative;border:1px solid red">
<iframe style=width:100%;height:100%;position:absolute;border:none;background-color:transparent allowtransparency=true>
</iframe>
This is my div
</div>

Javascript:

$('div').width(100).height(100);
$('div').animate({width:200},2000);

$('object').attr({
    type : 'text/html'
})
$('object').on('resize,onresize,load,onload',function(){
    console.log('ooooooooonload')
})

$($('iframe')[0].contentWindow).on('resize',function(){
    console.log('div changed')
})

Chạy ví dụ

JsFiddle: https://jsfiddle.net/qq8p470d/


Xem thêm:


1
Một lưu ý cho những người không sử dụng jquery, IFRAME.contentWindowkhông có sẵn cho đến khi onloadsự kiện bắt đầu trên iframe. Ngoài ra, bạn có thể muốn thêm kiểu visibility:hidden;, vì iframe có thể chặn đầu vào chuột vào các phần tử phía sau nó (dường như là "nổi" ít nhất trong IE).
James Wilkins

3
Mặc dù điều này hoạt động, nó là một giải pháp nặng với chi phí cao để tạo ra một bối cảnh duyệt hoàn toàn mới chỉ để quan sát sự thay đổi kích thước. Ngoài ra, trong một số trường hợp, việc thay đổi thuộc displaytính của phần tử là không lý tưởng hoặc không khả thi .
trusktr

đồng ý, đây là một giải pháp khủng khiếp như đã nêu ở trên
29er

Làm thế nào viết giải pháp khủng khiếp như vậy?
Aminadav Glickshtein

phương pháp này hoạt động tốt với trình phát video và trình phát âm thanh cần thay đổi kích thước nội dung động. Tôi đang sử dụng phương pháp này để thay đổi kích thước đầu ra waveurfer.js.
David Clews

8

Chỉ đối tượng cửa sổ tạo ra một sự kiện "thay đổi kích thước". Cách duy nhất tôi biết để làm những gì bạn muốn làm là chạy một bộ đếm thời gian định kỳ kiểm tra kích thước.


7

var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));

function checkResize (mutations) {
    var el = mutations[0].target;
    var w = el.clientWidth;
    var h = el.clientHeight;
    
    var isChange = mutations
      .map((m) => m.oldValue + '')
      .some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);

    if (!isChange)
      return;

    var event = new CustomEvent('resize', {detail: {width: w, height: h}});
    el.dispatchEvent(event);
}

var observer = new MutationObserver(checkResize); 
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>


7

Đáng ngạc nhiên là cũ như vấn đề này, đây vẫn là một vấn đề trong hầu hết các trình duyệt.

Như những người khác đã nói, Chrome 64+ hiện đã xuất xưởng với Resize Observes, tuy nhiên, thông số kỹ thuật vẫn đang được điều chỉnh tốt và Chrome hiện tại (kể từ 2019-01-29) đằng sau phiên bản mới nhất của thông số kỹ thuật .

Tôi đã thấy một vài polyfill ResizeObserver tốt ngoài tự nhiên, tuy nhiên, một số không tuân theo đặc điểm kỹ thuật và những người khác có một số vấn đề tính toán.

Tôi đang rất cần hành vi này để tạo ra một số thành phần web đáp ứng có thể được sử dụng trong bất kỳ ứng dụng nào. Để làm cho chúng hoạt động tốt, chúng cần phải biết kích thước của chúng mọi lúc, vì vậy ResizeObservers nghe có vẻ lý tưởng và tôi quyết định tạo ra một polyfill theo sát thông số kỹ thuật nhất có thể.

Repo: https://github.com/jugg/resize-observer

Bản trình diễn: https://codesandbox.io/s/myqzvpmmy9


Đây chắc chắn là câu trả lời tuyệt vời cho bất kỳ ai liên quan đến khả năng tương thích trình duyệt IE11 +.
ekfuhrmann

3

Sử dụng Clay.js ( https://github.com/zzarcon/clay ) khá đơn giản để phát hiện các thay đổi về kích thước phần tử:

var el = new Clay('.element');

el.on('resize', function(size) {
    console.log(size.height, size.width);
});

7
Vui lòng cung cấp thông tin phù hợp cho rằng đó là thư viện của bạn.
jhpratt ĐÁNG TIN CẬY GOFUNDME

Điều này làm việc cho tôi, nơi ResizeSensor không hoạt động, nó phá vỡ phong cách phương thức của tôi. Cảm ơn Zzarcon :)
Máxima Alekz

3

Bài đăng trên blog này đã giúp tôi phát hiện hiệu quả các thay đổi kích thước đối với các thành phần DOM.

http://www.backalleycoder.com/2013/03/18/cross-browser-event-basing-element-resize-detection/

Cách sử dụng mã này ...

AppConfig.addResizeListener(document.getElementById('id'), function () {
  //Your code to execute on resize.
});

Mã đóng gói được sử dụng bởi ví dụ ...

var AppConfig = AppConfig || {};
AppConfig.ResizeListener = (function () {
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function () {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function (fn) { return window.setTimeout(fn, 20); };
        return function (fn) { return raf(fn); };
    })();

    var cancelFrame = (function () {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
               window.clearTimeout;
        return function (id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function () {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function (fn) {
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    AppConfig.addResizeListener = function (element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position === 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    AppConfig.removeResizeListener = function (element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

Lưu ý: AppConfig là một không gian tên / đối tượng tôi sử dụng để tổ chức các chức năng có thể sử dụng lại. Hãy tìm kiếm và thay thế tên bằng bất cứ điều gì bạn muốn.


3

Plugin jQuery của tôi cho phép sự kiện "thay đổi kích thước" trên tất cả các thành phần không chỉ window.

https://github.com/dustinpoissant/ResizeTriggering

$("#myElement") .resizeTriggering().on("resize", function(e){
  // Code to handle resize
}); 

1
Liên kết của bạn đã được trỏ đến một vị trí không còn tồn tại. Tôi đã tìm kiếm tên của plugin và tìm thấy một trang tương ứng với mô tả của bạn. Vì bạn có vẻ là tác giả của plugin, tôi cũng đã chỉnh sửa ngôn ngữ câu trả lời của bạn để làm cho nó rõ ràng rằng đây là công việc của bạn. Các quy tắc của trang web này là khi bạn viết câu trả lời khuyên bạn nên sử dụng thứ gì đó bạn đã phát triển, bạn phải làm cho mối quan hệ rõ ràng.
Louis

Đây không phải là giải pháp tuyệt vời vì bạn chạy một số chức năng trong setTimer nhiều lần, điều đó có nghĩa là trình duyệt liên tục ghi CPU ngay cả khi không có gì xảy ra. Chủ sở hữu máy tính xách tay và điện thoại di động được hưởng lợi từ giải pháp chỉ sử dụng các sự kiện trình duyệt khi có một số hành động, như sử dụng sự kiện onScroll.
Roman Zenka

2

Bạn có thể thử mã trong đoạn mã sau, nó đáp ứng nhu cầu của bạn bằng cách sử dụng javascript đơn giản. ( chạy đoạn mã và nhấp vào liên kết toàn trang để kích hoạt cảnh báo rằng div được thay đổi kích thước nếu bạn muốn kiểm tra nó. ).

Dựa trên thực tế rằng đây là một setInterval 100 mili giây, tôi dám nói rằng PC của tôi không thấy CPU quá đói. (0,1% CPU đã được sử dụng làm tổng số cho tất cả các tab đã mở trong Chrome tại thời điểm được thử nghiệm.). Nhưng một lần nữa, đây chỉ là một div, nếu bạn muốn làm điều này cho một số lượng lớn các phần tử thì có, nó có thể rất đói CPU.

Bạn luôn có thể sử dụng một sự kiện nhấp để dừng việc đánh hơi thay đổi kích thước div .

var width = 0; 
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized div');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" />
        <input type="button" value="button 2" />
        <input type="button" value="button 3" />
</div>

Bạn có thể kiểm tra các câu đố cũng

CẬP NHẬT

var width = 0; 
function myInterval() {
var interval = setInterval(function(){
if(width <= 0){
width = document.getElementById("test_div").clientWidth;
} 
if(document.getElementById("test_div").clientWidth!==width) {   
  alert('resized');
  width = document.getElementById("test_div").clientWidth;
}    

}, 100);
return interval;
}
var interval = myInterval();
document.getElementById("clickMe").addEventListener( "click" , function() {
if(typeof interval!=="undefined") {
clearInterval(interval);
alert("stopped div-resize sniffing");
}
});
document.getElementById("clickMeToo").addEventListener( "click" , function() {
myInterval();
alert("started div-resize sniffing");
});
<div id="test_div" style="width: 100%; min-height: 30px; border: 1px dashed pink;">
        <input type="button" value="button 1" id="clickMe" />
        <input type="button" value="button 2" id="clickMeToo" />
        <input type="button" value="button 3" />
</div>

Cập nhật Fiddle


2

Đây gần như là một bản sao chính xác của câu trả lời hàng đầu, nhưng thay vì một liên kết, nó chỉ là một phần của mã quan trọng, được dịch thành IMO dễ đọc hơn và dễ hiểu hơn. Một vài thay đổi nhỏ khác bao gồm sử dụng cloneNode () và không đưa html vào chuỗi js. Những thứ nhỏ nhặt, nhưng bạn có thể sao chép và dán nó như hiện tại và nó sẽ hoạt động.

Cách thức hoạt động của nó là làm cho hai div vô hình lấp đầy phần tử bạn đang xem, sau đó đặt một bộ kích hoạt vào từng vị trí và đặt vị trí cuộn sẽ dẫn đến kích hoạt thay đổi cuộn nếu kích thước thay đổi.

Tất cả tín dụng thực sự thuộc về Marc J, nhưng nếu bạn chỉ tìm kiếm mã có liên quan, thì đây là:

    window.El = {}

    El.resizeSensorNode = undefined;
    El.initResizeNode = function() {
        var fillParent = "display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;";
        var triggerStyle = "position: absolute; left: 0; top: 0; transition: 0s;";

        var resizeSensor = El.resizeSensorNode = document.createElement("resizeSensor");
        resizeSensor.style = fillParent;

        var expandSensor = document.createElement("div");
        expandSensor.style = fillParent;
        resizeSensor.appendChild(expandSensor);

        var trigger = document.createElement("div");
        trigger.style = triggerStyle;
        expandSensor.appendChild(trigger);

        var shrinkSensor = expandSensor.cloneNode(true);
        shrinkSensor.firstChild.style = triggerStyle + " width: 200%; height: 200%";
        resizeSensor.appendChild(shrinkSensor);
    }


    El.onSizeChange = function(domNode, fn) {
        if (!domNode) return;
        if (domNode.resizeListeners) {
            domNode.resizeListeners.push(fn);
            return;
        }

        domNode.resizeListeners = [];
        domNode.resizeListeners.push(fn);

        if(El.resizeSensorNode == undefined)
            El.initResizeNode();

        domNode.resizeSensor = El.resizeSensorNode.cloneNode(true);
        domNode.appendChild(domNode.resizeSensor);

        var expand = domNode.resizeSensor.firstChild;
        var expandTrigger = expand.firstChild;
        var shrink = domNode.resizeSensor.childNodes[1];

        var reset = function() {
            expandTrigger.style.width = '100000px';
            expandTrigger.style.height = '100000px';

            expand.scrollLeft = 100000;
            expand.scrollTop = 100000;

            shrink.scrollLeft = 100000;
            shrink.scrollTop = 100000;
        };

        reset();

        var hasChanged, frameRequest, newWidth, newHeight;
        var lastWidth = domNode.offsetWidth;
        var lastHeight = domNode.offsetHeight;


        var onResized = function() {
            frameRequest = undefined;

            if (!hasChanged) return;

            lastWidth = newWidth;
            lastHeight = newHeight;

            var listeners = domNode.resizeListeners;
            for(var i = 0; listeners && i < listeners.length; i++) 
                listeners[i]();
        };

        var onScroll = function() {
            newWidth = domNode.offsetWidth;
            newHeight = domNode.offsetHeight;
            hasChanged = newWidth != lastWidth || newHeight != lastHeight;

            if (hasChanged && !frameRequest) {
                frameRequest = requestAnimationFrame(onResized);
            }

            reset();
        };


        expand.addEventListener("scroll", onScroll);
        shrink.addEventListener("scroll", onScroll);
    }

1

Giải pháp Javascript thuần túy, nhưng chỉ hoạt động nếu phần tử được thay đổi kích thước bằng nút thay đổi kích thước css :

  1. lưu trữ kích thước phần tử với offsetWidthoffsetHeight ;
  2. thêm một trình lắng nghe sự kiện onclick trên phần tử này;
  3. khi được kích hoạt, so sánh curent offsetWidthoffsetHeightvới các giá trị được lưu trữ và nếu khác nhau, hãy làm những gì bạn muốn và cập nhật các giá trị này.

1

Đây là phiên bản đơn giản hóa của giải pháp bởi @nkron, áp dụng cho một yếu tố duy nhất (thay vì một mảng các yếu tố trong câu trả lời của @ nkron, độ phức tạp tôi không cần).

function onResizeElem(element, callback) {    
  // Save the element we are watching
  onResizeElem.watchedElementData = {
    element: element,
    offsetWidth: element.offsetWidth,
    offsetHeight: element.offsetHeight,
    callback: callback
  };

  onResizeElem.checkForChanges = function() {
    const data = onResizeElem.watchedElementData;
    if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
      data.offsetWidth = data.element.offsetWidth;
      data.offsetHeight = data.element.offsetHeight;
      data.callback();
    }
  };

  // Listen to the window resize event
  window.addEventListener('resize', onResizeElem.checkForChanges);

  // Listen to the element being checked for width and height changes
  onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
  onResizeElem.observer.observe(document.body, {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  });
}

Người nghe và người quan sát sự kiện có thể được loại bỏ bằng cách:

window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();

0
jQuery(document).ready( function($) {

function resizeMapDIVs() {

// check the parent value...

var size = $('#map').parent().width();



if( $size < 640 ) {

//  ...and decrease...

} else {

//  ..or increase  as necessary

}

}

resizeMapDIVs();

$(window).resize(resizeMapDIVs);

});

0

sử dụng câu trả lời Bharat Patil chỉ cần trả về false bên trong hàm gọi lại liên kết của bạn để ngăn ngừa lỗi ngăn xếp tối đa, xem ví dụ bên dưới:

$('#test_div').bind('resize', function(){
   console.log('resized');
   return false;
});

0

Đây là một câu hỏi thực sự cũ, nhưng tôi nghĩ rằng tôi sẽ đăng giải pháp của mình cho vấn đề này.

Tôi đã cố gắng sử dụng ResizeSensorvì mọi người dường như có cảm tình với nó. Sau khi thực hiện, tôi nhận ra rằng trong phần mềm, Truy vấn phần tử yêu cầu phần tử được đề cập phải có vị trí relativehoặc absoluteáp dụng cho phần tử đó, điều này không hoạt động cho tình huống của tôi.

Tôi đã kết thúc việc xử lý việc này với một Rxjs intervalthay vì thẳng setTimeouthoặc requestAnimationFramegiống như các triển khai trước đó.

Điều tuyệt vời về hương vị có thể quan sát được của một khoảng là bạn có thể sửa đổi luồng tuy nhiên có thể xử lý mọi luồng khác. Đối với tôi, một triển khai cơ bản là đủ, nhưng bạn có thể phát điên và thực hiện tất cả các loại hợp nhất, v.v.

Trong ví dụ dưới đây, tôi đang theo dõi các thay đổi về chiều rộng của div bên trong (màu xanh lá cây). Nó có chiều rộng được đặt thành 50%, nhưng chiều rộng tối đa 200px. Kéo thanh trượt ảnh hưởng đến chiều rộng của trình bao bọc (màu xám). Bạn có thể thấy rằng chỉ có thể quan sát được kích hoạt khi chiều rộng của div bên trong thay đổi, điều này chỉ xảy ra nếu chiều rộng của div bên ngoài nhỏ hơn 400px.

const { interval } = rxjs;
const { distinctUntilChanged, map, filter } = rxjs.operators;


const wrapper = document.getElementById('my-wrapper');
const input = document.getElementById('width-input');




function subscribeToResize() {
  const timer = interval(100);
  const myDiv = document.getElementById('my-div');
  const widthElement = document.getElementById('width');
  const isMax = document.getElementById('is-max');
  
  /*
    NOTE: This is the important bit here 
  */
  timer
    .pipe(
      map(() => myDiv ? Math.round(myDiv.getBoundingClientRect().width) : 0),
      distinctUntilChanged(),
      // adding a takeUntil(), here as well would allow cleanup when the component is destroyed
    )
      .subscribe((width) => {        
        widthElement.innerHTML = width;
        isMax.innerHTML = width === 200 ? 'Max width' : '50% width';

      });
}

function defineRange() {
  input.min = 200;
  input.max = window.innerWidth;
  input.step = 10;
  input.value = input.max - 50;
}

function bindInputToWrapper() {
  input.addEventListener('input', (event) => {
    wrapper.style.width = `${event.target.value}px`;
  });
}

defineRange();
subscribeToResize();
bindInputToWrapper();
.inner {
  width: 50%;
  max-width: 200px;
}




/* Aesthetic styles only */

.inner {
  background: #16a085;
}

.wrapper {
  background: #ecf0f1;
  color: white;
  margin-top: 24px;
}

.content {
  padding: 12px;
}

body {
  
  font-family: sans-serif;
  font-weight: bold;
}
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>

<h1>Resize Browser width</h1>

<label for="width-input">Adjust the width of the wrapper element</label>
<div>
  <input type="range" id="width-input">
</div>

<div id="my-wrapper" class="wrapper">
  <div id="my-div" class="inner">
    <div class="content">
      Width: <span id="width"></span>px
      <div id="is-max"></div>  
    </div>
  </div>
</div>


-1

Chỉ Window.onResizetồn tại trong đặc tả, nhưng bạn luôn có thể sử dụng IFrameđể tạo Windowđối tượng mới bên trong DIV của mình.

Vui lòng kiểm tra câu trả lời này . Có một plugin jquery nhỏ mới , có thể mang theo và dễ sử dụng. Bạn luôn có thể kiểm tra mã nguồn để xem nó được thực hiện như thế nào.

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}

Đây là giải pháp rất kém hiệu quả nếu bạn có divs thay đổi kích thước.
xương rồng

-1

Tôi nghĩ rằng nó không thể được thực hiện nhưng sau đó tôi nghĩ về nó, bạn có thể thay đổi kích thước div một cách thủ công thông qua style = "resize: cả hai;" để làm điều đó, bạn phải nhấp vào nó để thêm chức năng onclick để kiểm tra chiều cao và chiều rộng của phần tử và nó đã hoạt động. Chỉ với 5 dòng javascript thuần túy (chắc chắn nó có thể ngắn hơn nữa) http://codepen.io/anon/pen/eNyyVN

<div id="box" style="
                height:200px; 
                width:640px;
                background-color:#FF0066;
                resize: both;
                overflow: auto;" 
                onclick="myFunction()">
    <p id="sizeTXT" style="
                font-size: 50px;">
       WxH
    </p>
    </div>

<p>This my example demonstrates how to run a resize check on click for resizable div.</p>

<p>Try to resize the box.</p>


<script>
function myFunction() {
var boxheight = document.getElementById('box').offsetHeight;
var boxhwidth = document.getElementById('box').offsetWidth;
var txt = boxhwidth +"x"+boxheight;
document.getElementById("sizeTXT").innerHTML = txt;
}
</script>

2
Điều này chỉ tính toán khi một sự kiện nhấp chuột được kích hoạt mà không phải là một phần của yêu cầu của câu hỏi.
Rob Evans
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.