Thay đổi kích thước trên phần tử div


80

jQuery có resize()- sự kiện, nhưng nó chỉ hoạt động với window.

jQuery(window).resize(function() { /* What ever */ });

Điều này hoạt động tốt! Nhưng khi tôi muốn thêm sự kiện vào một phần tử div thì nó không hoạt động.

Ví dụ

jQuery('div').resize(function() { /* What ever */ });

Tôi muốn bắt đầu gọi lại khi kích thước của phần tử div đã thay đổi. Tôi không muốn bắt đầu một sự kiện có thể thay đổi kích thước - chỉ là một sự kiện để kiểm tra xem kích thước của phần tử div có thay đổi hay không.

Có giải pháp nào để làm điều này?


2
các sự kiện thay đổi kích thước chỉ được kích hoạt trên (các) đối tượng cửa sổ (và có thể là iframe?).
BiAiB


Điều này có thể hữu ích: resizeObserver. developer.mozilla.org/en-US/docs/Web/API/ResizeObserver . Được hỗ trợ bởi Chrome 64, Firefox 69 ...
Captain puget

Câu trả lời:


35

DIVkhông kích hoạt một resizesự kiện, vì vậy bạn sẽ không thể thực hiện chính xác những gì bạn đã mã hóa, nhưng bạn có thể xem xét giám sát các thuộc tính DOM .

Nếu bạn thực sự đang làm việc với một cái gì đó như có thể thay đổi kích thước và đó là cách duy nhất để div thay đổi kích thước, thì plugin thay đổi kích thước của bạn có thể sẽ triển khai một lệnh gọi lại của riêng nó.


Bạn có thể kích hoạt sự kiện thay đổi kích thước cửa sổ với $ (window) .trigger ("thay đổi kích thước");
Laurent

32

Tôi chỉ quan tâm đến trình kích hoạt khi chiều rộng của một phần tử bị thay đổi (tôi không quan tâm đến chiều cao), vì vậy tôi đã tạo một sự kiện jquery thực hiện chính xác điều đó, bằng cách sử dụng phần tử iframe ẩn.

$.event.special.widthChanged = {
  remove: function() {
      $(this).children('iframe.width-changed').remove();
  },
  add: function () {
      var elm = $(this);
      var iframe = elm.children('iframe.width-changed');
      if (!iframe.length) {
          iframe = $('<iframe/>').addClass('width-changed').prependTo(this);
      }
      var oldWidth = elm.width();
      function elmResized() {
          var width = elm.width();
          if (oldWidth != width) {
              elm.trigger('widthChanged', [width, oldWidth]);
              oldWidth = width;
          }
      }

      var timer = 0;
      var ielm = iframe[0];
      (ielm.contentWindow || ielm).onresize = function() {
          clearTimeout(timer);
          timer = setTimeout(elmResized, 20);
      };
  }
}

Nó yêu cầu css sau:

iframe.width-changed {
    width: 100%;
    display: block;
    border: 0;
    height: 0;
    margin: 0;
}

Bạn có thể thấy nó hoạt động ở đây widthChanged fiddle


Đây là câu trả lời đúng. Việc đính kèm sự kiện vào cửa sổ iframe ít khó hơn nhiều so với một khoảng thời gian.
Kevin Beal

1
Đây là hoàn hảo! Tôi làm tôi hoàn toàn js dựa bằng cách thêm các stylesheet động: var ss = document.createElement('style'); ss.type = "text/css"; ss.innerHTML = "iframe.width-changed {width: 100%;display: block;border: 0;height: 0;margin: 0;}"; document.body.appendChild(ss);
sroskelley

Đây là thiên tài thuần túy.
Thomas

Tôi sắp sử dụng nó nhưng tôi tự hỏi: vai trò của bộ đếm thời gian và setTimeout là gì? nó giống như một "debounce" / ga để ngăn quá nhiều thay đổi kích thước được phát hiện khi người dùng thay đổi kích thước phần tử?
Mathieu

Có nó là để ngăn chặn cách gọi quá nhiều lần so với "widthChanged" cò
Panos Theof

22
// this is a Jquery plugin function that fires an event when the size of an element is changed
// usage: $().sizeChanged(function(){})

(function ($) {

$.fn.sizeChanged = function (handleFunction) {
    var element = this;
    var lastWidth = element.width();
    var lastHeight = element.height();

    setInterval(function () {
        if (lastWidth === element.width()&&lastHeight === element.height())
            return;
        if (typeof (handleFunction) == 'function') {
            handleFunction({ width: lastWidth, height: lastHeight },
                           { width: element.width(), height: element.height() });
            lastWidth = element.width();
            lastHeight = element.height();
        }
    }, 100);


    return element;
};

}(jQuery));

7

Tôi đã tạo jquery plugin jquery.resize nó sử dụng resizeObserver nếu được hỗ trợ hoặc giải pháp dựa trên sự kiện cuộn marcj / css-element-queries , không có setTimeout / setInterval.

Bạn chỉ sử dụng

 jQuery('div').on('resize', function() { /* What ever */ });

hoặc dưới dạng plugin chỉnh sửa

jQuery('div').resizer(function() { /* What ever */ });

Tôi đã tạo điều này cho jQuery Terminal và trích xuất thành gói repo và npm riêng biệt, nhưng trong thời gian ngắn tôi đã chuyển sang iframe ẩn vì tôi gặp vấn đề với việc thay đổi kích thước nếu phần tử nằm bên trong iframe. Tôi có thể cập nhật plugin cho phù hợp. Bạn có thể xem plugin chỉnh sửa khung dựa trên iframe trong mã nguồn jQuery Terminal .

CHỈNH SỬA : phiên bản mới sử dụng iframe và thay đổi kích thước trên đối tượng cửa sổ của nó vì các giải pháp trước đó không hoạt động khi trang bên trong iframe.

EDIT2 : Vì iframe sử dụng dự phòng nên bạn không thể sử dụng nó với các điều khiển biểu mẫu hoặc hình ảnh, bạn cần thêm nó vào phần tử trình bao bọc.

EDIT3:: có giải pháp tốt hơn bằng cách sử dụng polyfill resizeObserver sử dụng trình quan sát đột biến (nếu resizeObserver không được hỗ trợ) và hoạt động ngay cả trong IE. Nó cũng có kiểu chữ TypeScript.


Đó là một ý tưởng tuyệt vời. Làm tốt lắm.
Marco Luzzara

6

cái này thì sao:

divH = divW = 0;
jQuery(document).ready(function(){
    divW = jQuery("div").width();
    divH = jQuery("div").height();
});
function checkResize(){
    var w = jQuery("div").width();
    var h = jQuery("div").height();
    if (w != divW || h != divH) {
        /*what ever*/
        divH = h;
        divW = w;
    }
}
jQuery(window).resize(checkResize);
var timer = setInterval(checkResize, 1000);

BTW Tôi khuyên bạn nên thêm một id vào div và thay đổi $ ("div") thành $ ("# yourid"), nó sẽ nhanh hơn và nó sẽ không bị hỏng khi sau này bạn thêm các div khác


Tất nhiên - đó chỉ là một ví dụ - tất nhiên tôi sử dụng id và các lớp để chọn các phần tử của mình. Tôi thích ý tưởng của bạn - tôi nghĩ nó sẽ thành công! Cảm ơn rất nhiều. Tôi sẽ thử sau vài phút và sẽ đưa ra phản hồi.
TJR

Điều này giám sát DIV để biết các thay đổi về kích thước bất cứ khi nào resizesự kiện của cửa sổ được kích hoạt. Có thể hình dung được rằng kích thước của div sẽ thay đổi mà không ngay sau đó là cửa sổ thay đổi kích thước, trong trường hợp đó, /* what ever */phần này sẽ không được đánh giá.
David Hedlund

Đúng! Và đây là vấn đề trong dự án của tôi. Phần tử div nằm trong một trình bao bọc bên ngoài có thuộc tính css Overflow: hidden - vì vậy cửa sổ không thay đổi kích thước. Nhưng theo những cách khác, ví dụ sẽ hoạt động tốt - tôi vừa thử nghiệm nó.
TJR

@Timo: $(window).resizelắng nghe hành động thay đổi kích thước vật lý của cửa sổ trình duyệt bằng cách kéo góc dưới cùng bên phải. Không có sự kiện DOM nào có thể kích hoạt sự kiện này overflow:hiddenhay không. Câu trả lời này không giải quyết vấn đề của bạn. Sẽ có ý nghĩa hơn nếu chạy mã này trong một bộ đếm thời gian, hơn là được gắn vào một trình lắng nghe sự kiện ngẫu nhiên có khả năng không bao giờ được kích hoạt. Sẽ tốt hơn nếu bạn có thể sử dụng theo dõi thuộc tính DOM và quay trở lại bộ đếm thời gian (hoặc tăng một số sự kiện theo cách thủ công ở những nơi mà kích thước div có thể thay đổi).
David Hedlund

đã thêm mã cho setInterval. Bạn cần phải tinh chỉnh nó, vì 1000ms có thể là quá nhiều đối với bạn, mặt khác, một con số quá thấp có thể dễ dàng giết chết CPU của bạn. Nếu bạn biết rằng bạn không cần nghe nữa thì hãy gọi: clearInterval (bộ đếm thời gian)!
Gavriel

5

Có một plugin thực sự đẹp, dễ sử dụng, nhẹ (sử dụng các sự kiện trình duyệt gốc để phát hiện) cho cả JavaScript cơ bản và jQuery đã được phát hành trong năm nay. Nó hoạt động hoàn hảo:

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


1
bạn nói nó không thăm dò ý kiến liên tục, nhưng nó, nó sử dụng requestAnimationFrame: github.com/sdecima/javascript-detect-element-resize/blob/master/...
Muhammad Umer

1
Thú vị: dự án GitHub được tham chiếu được lấy cảm hứng từ bài đăng trên blog này: backalleycoder.com/2013/03/18/… Nhưng mã trong bài đăng đã được thay đổi đáng kể sau đó, trong khi dự án GitHub dường như sử dụng cách tiếp cận cũ hơn. Vì vậy, đáng để xem xét cả hai trước khi bạn quyết định sử dụng cái gì.
CF


0

Để tích hợp bản đồ google, tôi đang tìm cách phát hiện khi div đã thay đổi kích thước. Vì bản đồ google luôn yêu cầu kích thước thích hợp, ví dụ chiều rộng và chiều cao để hiển thị đúng.

Giải pháp mà tôi đưa ra là ủy quyền một sự kiện, trong trường hợp của tôi là nhấp vào tab. Tất nhiên, đây có thể là một thay đổi kích thước cửa sổ, ý tưởng vẫn như cũ:

if (parent.is(':visible')) {
    w = parent.outerWidth(false);
    h = w * mapRatio /*9/16*/;
    this.map.css({ width: w, height: h });
} else {
    this.map.closest('.tab').one('click', function() {
        this.activate();
    }.bind(this));
}

this.maptrong trường hợp này là div bản đồ của tôi. Vì cha mẹ của tôi ẩn khi tải nên chiều rộng và chiều cao được tính là 0 hoặc không khớp. Bằng cách sử dụng, .bind(this)tôi có thể ủy quyền việc thực thi tập lệnh ( this.activate) cho một sự kiện ( click).

Bây giờ tôi tin rằng điều tương tự cũng áp dụng cho các sự kiện thay đổi kích thước.

$(window).one('resize', function() {
    this.div.css({ /*whatever*/ });
}.bind(this));

Hy vọng nó sẽ giúp bất cứ ai!


0

Chỉ cần thử func này (nó có thể hoạt động không chỉ với div):

function resized(elem, func = function(){}, args = []){
    elem = jQuery(elem);
    func = func.bind(elem);
    var h = -1, w = -1;
    setInterval(function(){
        if (elem.height() != h || elem.width() != w){
            h = elem.height();
            w = elem.width();
            func.apply(null, args);
        }
    }, 100);
}

Bạn có thể sử dụng nó như thế này

resized(/*element*/ '.advs-columns-main > div > div', /*callback*/ function(a){
    console.log(a);
    console.log(this); //for accessing the jQuery element you passed
}, /*callback arguments in array*/ ['I\'m the first arg named "a"!']);

CẬP NHẬT: Bạn cũng có thể sử dụng bộ theo dõi liên tục hơn (nó có thể hoạt động với mọi đối tượng, không chỉ các phần tử DOM):

function changed(elem, propsToBeChanged, func = function(){}, args = [], interval = 100){
        func = func.bind(elem);
        var currentVal = {call: {}, std: {}};
        $.each(propsToBeChanged, (property, needCall)=>{
            needCall = needCall ? 'call' : 'std';
            currentVal[needCall][property] = new Boolean(); // is a minimal and unique value, its equivalent comparsion with each other will always return false
        });
        setInterval(function(){
            $.each(propsToBeChanged, (property, needCall)=>{
                try{
                    var currVal = needCall ? elem[property]() : elem[property];
                } catch (e){ // elem[property] is not a function anymore
                    var currVal = elem[property];
                    needCall = false;
                    propsToBeChanged[property] = false;
                }
                needCall = needCall ? 'call' : 'std';
                if (currVal !== currentVal[needCall][property]){
                    currentVal[needCall][property] = currVal;
                    func.apply(null, args);
                }
            });
        }, interval);
    }

Hãy thử nó:

var b = '2',
    a = {foo: 'bar', ext: ()=>{return b}};
changed(a, {
// prop name || do eval like a function?
    foo:        false,
    ext:        true
}, ()=>{console.log('changed')})

Nó sẽ ghi 'thay đổi' mỗi khi bạn thay đổi trực tiếp b, a.foo hoặc a.ext


setIntervalcó thể nhận được khá đắt tiền như nó vẫn không ngừng cố gắng để thay đổi kích cỡ
tấn

@ton: Tôi nghĩ bạn không hoàn toàn đúng. Điều này chỉ xảy ra trong trường hợp cố gắng thay đổi kích thước một phần tử trong khi nó đã thay đổi kích thước. : / Hay bạn lo lắng về hiệu suất? Trên các trình duyệt mới nhất của nó hoạt động hoàn hảo ngay cả trên các trang web "nặng"
KaMeHb

Nếu bạn sẽ thêm một đơn giản console.logngay trước khi $.each, bạn sẽ thấy nó in tất cả 100ms, như bạn đã thiết lập tronginterval
tấn

@ton: Bạn hiểu tôi sai rồi. Tôi biết rõ cách thức setIntervalhoạt động. Nó giống như một e-mail "còn sống" - máy chủ liên tục ping. Tôi biết điều đó. Vậy thì sao? Hiệu suất? Đọc bình luận của tôi ở trên. Lo lắng về điều gì khác? Viết cho tôi, bạn của tôi.
KaMeHb

0

Bạn có thể thay đổi văn bản hoặc Nội dung hoặc Thuộc tính của mình tùy thuộc vào Kích thước màn hình: HTML:

<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>

Javascript:

<script>
const changeText = document.querySelector('.change');
function resize() {
  if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
    changeText.textContent="FAQ";
  } else {
    changeText.textContent="Frequently Asked Questions (FAQ)";
  }
}
window.onresize = resize;
</script>

-2

Nếu bạn chỉ muốn thay đổi kích thước của chính div, bạn cần chỉ định điều đó trong kiểu css. Bạn cần thêm thuộc tính trànthay đổi kích thước .

Dưới đây là đoạn mã của tôi

#div1 {
        width: 90%;
        height: 350px;
        padding: 10px;
        border: 1px solid #aaaaaa;
        overflow: auto;
        resize: both;
    }

<div id="div1">

</div>

Câu trả lời này không áp dụng cho bài viết gốc. Cuộc thảo luận rộng ở đây là về việc lắng nghe các thay đổi đối với kích thước của một phần tử (và thực hiện một hành động sau đó), chứ không phải thiết lập kích thước của phần tử.
MarsAndBack
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.