JavaScript / JQuery: $ (window) .resize cách kích hoạt SAU khi thay đổi kích thước hoàn tất?


235

Tôi đang sử dụng JQuery như vậy:

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

Tuy nhiên, có vẻ như nếu người đó tự thay đổi kích thước cửa sổ trình duyệt của họ bằng cách kéo cạnh cửa sổ để làm cho nó lớn hơn / nhỏ hơn, .resizesự kiện trên sẽ kích hoạt nhiều lần.

Câu hỏi: Làm thế nào để tôi gọi một chức năng SAU khi cửa sổ trình duyệt hoàn tất thay đổi kích thước (để sự kiện chỉ kích hoạt một lần)?


Xem câu trả lời này: stackoverflow.com/questions/667426/ Từ Nó liên quan đến việc sử dụng thời gian chờ để trì hoãn việc thực hiện chức năng của bạn.
Alastair Forge

Tôi không biết nếu điều đó có thể, bạn có thể dùng thử plugin này mặc dù benalman.com/projects/jquery-resize-plugin
BrunoLM

Nhân tiện, tôi nhận thấy điều này rất hữu ích trong các trình duyệt di động có xu hướng ẩn dần thanh địa chỉ khi người dùng cuộn xuống, do đó thay đổi kích thước màn hình. Tôi cũng dự kiến ​​thay đổi kích thước màn hình chỉ xảy ra trên máy tính để bàn ...
MakisH

Câu trả lời:


299

Đây là một sửa đổi của giải pháp CMS có thể được gọi ở nhiều nơi trong mã của bạn:

var waitForFinalEvent = (function () {
  var timers = {};
  return function (callback, ms, uniqueId) {
    if (!uniqueId) {
      uniqueId = "Don't call this twice without a uniqueId";
    }
    if (timers[uniqueId]) {
      clearTimeout (timers[uniqueId]);
    }
    timers[uniqueId] = setTimeout(callback, ms);
  };
})();

Sử dụng:

$(window).resize(function () {
    waitForFinalEvent(function(){
      alert('Resize...');
      //...
    }, 500, "some unique string");
});

Giải pháp của CMS là ổn nếu bạn chỉ gọi nó một lần, nhưng nếu bạn gọi nó nhiều lần, ví dụ: nếu các phần khác nhau của mã của bạn thiết lập các cuộc gọi lại riêng biệt để thay đổi kích thước cửa sổ, thì nó sẽ thất bại khi họ chia sẻ timerbiến.

Với sửa đổi này, bạn cung cấp một id duy nhất cho mỗi cuộc gọi lại và các ID duy nhất đó được sử dụng để tách biệt tất cả các sự kiện hết thời gian chờ.


2
Tôi <3 u, tôi đã kết hợp điều này trong khi thay đổi kích thước đồ thị Highcharts toàn màn hình (không phải html5) và hoạt động rất tốt.
Michael J. Calkins

Hoàn toàn không thể tin được!
Starkers

2
Vì tôi đã được hưởng lợi rất nhiều từ câu trả lời của bạn, tôi nghĩ rằng tôi đã chia sẻ một nguyên mẫu hoạt động của mã được cung cấp của bạn cho phần còn lại của cộng đồng: jsfiddle.net/h6h2pzpu/3 . Tận hưởng mọi người!
Jonas Stawski

1
Đây là tất cả hoàn hảo, NHƯNG nó trì hoãn việc thực hiện chức năng thực tế bằng lượng miliseconds (ms), có thể RẤT HIỂU.
Tomas M

Điều này chỉ là nó hoàn hảo, có cách nào để thay đổi kích thước cuối cùng và không phải chuyển tiếp trên những mili giây đó không? Dù sao điều này chỉ lưu lại ngày của tôi: ') Cảm ơn.
Leo

138

Tôi thích tạo một sự kiện:

$(window).bind('resizeEnd', function() {
    //do something, window hasn't changed size in 500ms
});

Đây là cách bạn tạo ra nó:

 $(window).resize(function() {
        if(this.resizeTO) clearTimeout(this.resizeTO);
        this.resizeTO = setTimeout(function() {
            $(this).trigger('resizeEnd');
        }, 500);
    });

Bạn có thể có điều này trong một tệp javascript toàn cầu ở đâu đó.


Tôi đã sử dụng giải pháp này. Nhưng về lâu dài tôi muốn thực hiện giống như giải pháp của brahn.
Bharat Patil

điều này cho phép bạn liên kết với sự kiện đó ở mọi nơi, không chỉ trong một chức năng, giả sử bạn có nhiều tệp / .js yêu cầu các phản ứng riêng biệt với khóa học
hanzolo

Điều này không hiệu quả với tôi nhưng câu trả lời của DusanV đã thực hiện công việc
lightbyte

123

Tôi sử dụng chức năng sau để trì hoãn các hành động lặp đi lặp lại, nó sẽ hoạt động cho trường hợp của bạn:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

Sử dụng:

$(window).resize(function() {
    delay(function(){
      alert('Resize...');
      //...
    }, 500);
});

Hàm gọi lại được truyền cho nó, sẽ chỉ thực hiện khi cuộc gọi trễ cuối cùng được thực hiện sau khoảng thời gian đã chỉ định, nếu không bộ hẹn giờ sẽ được đặt lại, tôi thấy điều này hữu ích cho các mục đích khác như phát hiện khi người dùng ngừng gõ, v.v. ..


5
Tôi nghĩ rằng cách tiếp cận này có thể thất bại nếu được sử dụng nhiều lần (ví dụ: nếu các phần khác nhau của các cuộc gọi lại thiết lập mã đến $(window).resize) bởi vì tất cả chúng sẽ chia sẻ timerbiến. Xem câu trả lời của tôi dưới đây cho giải pháp đề xuất.
brahn

Rất đẹp! Hoạt động như một lá bùa! Giống như câu trả lời của bạn ... đơn giản và thanh lịch!
Ông Pumpkin

74

Nếu bạn đã cài đặt Underscore.js, bạn có thể:

$(window).resize(_.debounce(function(){
    alert("Resized");
},500));

1
Ngay cả khi bạn không muốn bao gồm Underscore, ít nhất hãy lấy nguồn cho việc này: underscorejs.org/docs/underscore.html#section-67
tybro0103

Gỡ lỗi là kỹ thuật chính xác ở đây, nó chỉ là vấn đề thực hiện. Và đây là triển khai vượt trội nếu Underscore / Lodash đã là một phụ thuộc của dự án.
Nhân tố huyền bí

Đây là những gì tôi đang sử dụng,
Bharat Patil

20

Một số giải pháp được đề cập trước đây không hiệu quả với tôi, mặc dù chúng được sử dụng chung hơn. Ngoài ra, tôi đã tìm thấy cái này đã thực hiện thay đổi kích thước cửa sổ:

$(window).bind('resize', function(e){
    window.resizeEvt;
    $(window).resize(function(){
        clearTimeout(window.resizeEvt);
        window.resizeEvt = setTimeout(function(){
        //code to do after window is resized
        }, 250);
    });
});

1
Chỉ có ví dụ của bạn làm việc cho tôi ... những người khác ở trên đã không! Tôi không chắc tại sao câu trả lời của bạn không được chọn.
Mumbo Jumbo

Tôi không hiểu tại sao bắt sự kiện thay đổi kích thước bên trong sự kiện thay đổi kích thước, nhưng nó cũng hoạt động với tôi ...
lightbyte

Mumbo Jumbo, tôi nghĩ bởi vì những người khác tập trung vào khái quát hóa, tìm kiếm giải pháp cho bất kỳ vấn đề nào như vậy (nhiều cuộc gọi của một chức năng).
DusanV

lightbyte, đó là vì bạn phải dừng các sự kiện trước đó mỗi khi hàm được gọi.
DusanV

13

Rất cám ơn David Walsh, đây là một phiên bản vanilla của việc ra mắt gạch dưới.

Mã số:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Cách sử dụng đơn giản:

var myEfficientFn = debounce(function() {
    // All the taxing stuff you do
}, 250);

$(window).on('resize', myEfficientFn);

Tham chiếu: http://davidwalsh.name/javascript-debounce-f ghép


6

Thực tế, như tôi biết, bạn không thể thực hiện một số hành động chính xác khi tắt kích thước, đơn giản vì bạn không biết hành động của người dùng trong tương lai. Nhưng bạn có thể giả sử thời gian trôi qua giữa hai sự kiện thay đổi kích thước, vì vậy nếu bạn chờ thêm một chút so với thời gian này và không thực hiện thay đổi kích thước, bạn có thể gọi hàm của mình.
Ý tưởng là chúng tôi sử dụng setTimeoutvà đó là id để lưu hoặc xóa nó. Ví dụ: chúng ta biết rằng thời gian giữa hai sự kiện thay đổi kích thước là 500ms, do đó chúng ta sẽ đợi 750ms.

var a;
$(window).resize(function(){
  clearTimeout(a);
  a = setTimeout(function(){
    // call your function
  },750);
});


3

Tuyên bố người nghe bị trì hoãn trên toàn cầu:

var resize_timeout;

$(window).on('resize orientationchange', function(){
    clearTimeout(resize_timeout);

    resize_timeout = setTimeout(function(){
        $(window).trigger('resized');
    }, 250);
});

Và bên dưới sử dụng người nghe đến resizedsự kiện như bạn muốn:

$(window).on('resized', function(){
    console.log('resized');
});

Cảm ơn, đó là giải pháp tốt nhất hiện nay. Ngoài ra tôi đã kiểm tra rằng 250ms đang hoạt động một cách tốt nhất khi thay đổi kích thước cửa sổ.
AlexioVay


2

Plugin jQuery đơn giản cho sự kiện thay đổi kích thước cửa sổ bị trì hoãn.

Đồng bộ:

Thêm chức năng mới để thay đổi kích thước sự kiện

jQuery(window).resizeDelayed( func, delay, id ); // delay and id are optional

Xóa chức năng (bằng cách khai báo ID của nó) đã thêm trước đó

jQuery(window).resizeDelayed( false, id );

Xóa tất cả các chức năng

jQuery(window).resizeDelayed( false );

SỬ DỤNG:

// ADD SOME FUNCTIONS TO RESIZE EVENT
jQuery(window).resizeDelayed( function(){ console.log( 'first event - should run after 0.4 seconds'); }, 400,  'id-first-event' );
jQuery(window).resizeDelayed( function(){ console.log('second event - should run after 1.5 seconds'); }, 1500, 'id-second-event' );
jQuery(window).resizeDelayed( function(){ console.log( 'third event - should run after 3.0 seconds'); }, 3000, 'id-third-event' );

// LETS DELETE THE SECOND ONE
jQuery(window).resizeDelayed( false, 'id-second-event' );

// LETS ADD ONE WITH AUTOGENERATED ID(THIS COULDNT BE DELETED LATER) AND DEFAULT TIMEOUT (500ms)
jQuery(window).resizeDelayed( function(){ console.log('newest event - should run after 0.5 second'); } );

// LETS CALL RESIZE EVENT MANUALLY MULTIPLE TIMES (OR YOU CAN RESIZE YOUR BROWSER WINDOW) TO SEE WHAT WILL HAPPEN
jQuery(window).resize().resize().resize().resize().resize().resize().resize();

SỬ DỤNG ĐẦU RA:

first event - should run after 0.4 seconds
newest event - should run after 0.5 second
third event - should run after 3.0 seconds

CẮM VÀO:

jQuery.fn.resizeDelayed = (function(){

    // >>> THIS PART RUNS ONLY ONCE - RIGHT NOW

    var rd_funcs = [], rd_counter = 1, foreachResizeFunction = function( func ){ for( var index in rd_funcs ) { func(index); } };

    // REGISTER JQUERY RESIZE EVENT HANDLER
    jQuery(window).resize(function() {

        // SET/RESET TIMEOUT ON EACH REGISTERED FUNCTION
        foreachResizeFunction(function(index){

            // IF THIS FUNCTION IS MANUALLY DISABLED ( by calling jQuery(window).resizeDelayed(false, 'id') ),
            // THEN JUST CONTINUE TO NEXT ONE
            if( rd_funcs[index] === false )
                return; // CONTINUE;

            // IF setTimeout IS ALREADY SET, THAT MEANS THAT WE SHOULD RESET IT BECAUSE ITS CALLED BEFORE DURATION TIME EXPIRES
            if( rd_funcs[index].timeout !== false )
                clearTimeout( rd_funcs[index].timeout );

            // SET NEW TIMEOUT BY RESPECTING DURATION TIME
            rd_funcs[index].timeout = setTimeout( rd_funcs[index].func, rd_funcs[index].delay );

        });

    });

    // <<< THIS PART RUNS ONLY ONCE - RIGHT NOW

    // RETURN THE FUNCTION WHICH JQUERY SHOULD USE WHEN jQuery(window).resizeDelayed(...) IS CALLED
    return function( func_or_false, delay_or_id, id ){

        // FIRST PARAM SHOULD BE SET!
        if( typeof func_or_false == "undefined" ){

            console.log( 'jQuery(window).resizeDelayed(...) REQUIRES AT LEAST 1 PARAMETER!' );
            return this; // RETURN JQUERY OBJECT

        }

        // SHOULD WE DELETE THE EXISTING FUNCTION(S) INSTEAD OF CREATING A NEW ONE?
        if( func_or_false == false ){

            // DELETE ALL REGISTERED FUNCTIONS?
            if( typeof delay_or_id == "undefined" ){

                // CLEAR ALL setTimeout's FIRST
                foreachResizeFunction(function(index){

                    if( typeof rd_funcs[index] != "undefined" && rd_funcs[index].timeout !== false )
                        clearTimeout( rd_funcs[index].timeout );

                });

                rd_funcs = [];

                return this; // RETURN JQUERY OBJECT

            }
            // DELETE ONLY THE FUNCTION WITH SPECIFIC ID?
            else if( typeof rd_funcs[delay_or_id] != "undefined" ){

                // CLEAR setTimeout FIRST
                if( rd_funcs[delay_or_id].timeout !== false )
                    clearTimeout( rd_funcs[delay_or_id].timeout );

                rd_funcs[delay_or_id] = false;

                return this; // RETURN JQUERY OBJECT

            }

        }

        // NOW, FIRST PARAM MUST BE THE FUNCTION
        if( typeof func_or_false != "function" )
            return this; // RETURN JQUERY OBJECT

        // SET THE DEFAULT DELAY TIME IF ITS NOT ALREADY SET
        if( typeof delay_or_id == "undefined" || isNaN(delay_or_id) )
            delay_or_id = 500;

        // SET THE DEFAULT ID IF ITS NOT ALREADY SET
        if( typeof id == "undefined" )
            id = rd_counter;

        // ADD NEW FUNCTION TO RESIZE EVENT
        rd_funcs[id] = {
            func : func_or_false,
            delay: delay_or_id,
            timeout : false
        };

        rd_counter++;

        return this; // RETURN JQUERY OBJECT

    }

})();

1

Giả sử rằng con trỏ chuột sẽ quay trở lại tài liệu sau khi thay đổi kích thước cửa sổ, chúng ta có thể tạo một hành vi giống như gọi lại với sự kiện onmouseover. Đừng quên rằng giải pháp này có thể không hoạt động đối với màn hình hỗ trợ cảm ứng như mong đợi.

var resizeTimer;
var resized = false;
$(window).resize(function() {
   clearTimeout(resizeTimer);
   resizeTimer = setTimeout(function() {
       if(!resized) {
           resized = true;
           $(document).mouseover(function() {
               resized = false;
               // do something here
               $(this).unbind("mouseover");
           })
       }
    }, 500);
});

Tốt cho các trang web chỉ dành cho máy tính để bàn trên chuột nhưng sự kiện di chuột sẽ không bao giờ xảy ra nếu, ví dụ, người dùng đang sử dụng điện thoại di động và thay đổi từ ngang sang dọc hoặc nếu họ thay đổi kích thước cửa sổ trên màn hình cảm ứng.
dùng56reinstatemonica8

Bạn có thể thay đổi kích thước cửa sổ trình duyệt với sự trợ giúp của bàn phím trên các cửa sổ mới nhất như Win-Arrow-Left Win-Arrow-Right, v.v ...
Lu4

0

Đây là những gì tôi đã thực hiện:

$ (window) .resize (function () {setTimeout (someFunction, 500);});

chúng tôi có thể xóa setTimeout nếu chúng tôi muốn thay đổi kích thước xảy ra ít hơn500ms

Chúc may mắ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.