JavaScript / JQuery: $ (หน้าต่าง) .resize วิธีการยิงหลังจากการปรับขนาดเสร็จสมบูรณ์?


235

ฉันใช้ JQuery เป็นเช่นนี้:

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

อย่างไรก็ตามปรากฏว่าหากบุคคลนั้นปรับขนาดหน้าต่างเบราว์เซอร์ด้วยตนเองโดยการลากขอบหน้าต่างเพื่อทำให้ใหญ่ขึ้น / เล็กลง.resizeเหตุการณ์ดังกล่าวจะเริ่มต้นขึ้นหลายครั้ง

คำถาม:ฉันจะเรียกฟังก์ชั่นได้อย่างไรหลังจากหน้าต่างปรับขนาดเบราว์เซอร์เสร็จสมบูรณ์ (เพื่อให้เหตุการณ์เริ่มทำงานเพียงครั้งเดียว)


ดูคำตอบนี้: stackoverflow.com/questions/667426/…มันเกี่ยวข้องกับการใช้ timeouts เพื่อหน่วงเวลาการเรียกใช้ฟังก์ชันของคุณ
Alastair Pitts

ฉันไม่ทราบว่าเป็นไปได้หรือไม่คุณสามารถลองใช้ปลั๊กอินนี้ได้แม้ว่าbenalman.com/projects/jquery-resize-plugin
BrunoLM

โดยวิธีการที่ฉันสังเกตเห็นว่ามีประโยชน์มากในเบราว์เซอร์มือถือที่มีแนวโน้มที่จะค่อยๆซ่อนแถบที่อยู่เมื่อผู้ใช้เลื่อนลงจึงปรับขนาดหน้าจอ ฉันยังคาดว่าการปรับขนาดหน้าจอที่จะเกิดขึ้นเฉพาะบนเดสก์ทอป ...
MakisH

คำตอบ:


299

นี่คือการแก้ไขโซลูชัน CMS ที่สามารถเรียกได้หลายแห่งในรหัสของคุณ:

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);
  };
})();

การใช้งาน:

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

วิธีการแก้ปัญหาของ CMS ดีถ้าคุณจะเรียกมันว่าครั้งเดียว แต่ถ้าคุณเรียกมันหลายครั้งเช่นถ้าชิ้นส่วนที่แตกต่างกันของรหัสของคุณตั้งค่าการเรียกกลับที่แยกต่างหากเพื่อปรับขนาดหน้าต่างแล้วมันจะล้มเหลว B / C พวกเขาส่วนใหญ่มีtimerตัวแปร

ด้วยการปรับเปลี่ยนนี้คุณจะต้องระบุรหัสที่ไม่ซ้ำสำหรับการโทรกลับแต่ละครั้งและ ID ที่ไม่ซ้ำเหล่านั้นจะถูกใช้เพื่อแยกกิจกรรมการหมดเวลาทั้งหมด


2
ฉัน <3 คุณฉันรวมสิ่งนี้ในขณะที่ปรับขนาดแบบเต็มหน้าจอ (ไม่ใช่ html5) กราฟแสดงแผนที่และใช้งานได้ดี
Michael J. Calkins

เหลือเชื่ออย่างแน่นอน!
ตา

2
ตั้งแต่ฉันได้รับประโยชน์อย่างมากจากคำตอบของคุณผมคิดว่าผมใช้ร่วมกันต้นแบบการทำงานของรหัสที่ให้ไว้ของคุณสำหรับส่วนที่เหลือของชุมชน: jsfiddle.net/h6h2pzpu/3 สนุกกับทุกคน!
Jonas Stawski

1
นี่คือทั้งหมดที่สมบูรณ์แบบ แต่มันล่าช้าการดำเนินการของฟังก์ชั่นที่เกิดขึ้นจริงโดยจำนวนมิลลิวินาที (ms) ซึ่งอาจเป็น VERY UNDESIRABLE
Tomas M

เพียงแค่นี้มันจะสมบูรณ์แบบหรือไม่มีวิธีที่จะคว้าการปรับขนาดครั้งสุดท้ายและไม่ต้องถ่ายทอดในมิลลิวินาทีเหล่านั้นหรือไม่ อย่างไรก็ตามนี่เพิ่งบันทึกวันของฉัน: ') ขอบคุณ
Leo

138

ฉันชอบที่จะสร้างกิจกรรม:

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

นี่คือวิธีที่คุณสร้างขึ้น:

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

คุณสามารถมีสิ่งนี้ในไฟล์จาวาสคริปต์ทั่วโลกที่ไหนสักแห่ง


ฉันใช้วิธีนี้ แต่ในระยะยาวฉันต้องการใช้เช่นเดียวกับโซลูชันของ brahn
Bharat Patil

สิ่งนี้ช่วยให้คุณสามารถเชื่อมโยงกับเหตุการณ์นั้นได้ทุกที่ไม่ใช่แค่ในฟังก์ชั่นเดียวสมมติว่าคุณมีไฟล์หลายหน้า / .js ที่ต้องการการตอบสนองแบบแยกต่างหากแน่นอน
hanzolo

สิ่งนี้ไม่ได้ผลสำหรับฉัน แต่คำตอบของ DusanV ทำงานได้ดี
lightbyte

123

ฉันใช้ฟังก์ชั่นต่อไปนี้สำหรับการชะลอการกระทำซ้ำ ๆ มันจะทำงานกับกรณีของคุณ:

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

การใช้งาน:

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

ฟังก์ชั่นการโทรกลับถูกส่งไปยังมันจะทำงานเฉพาะเมื่อมีการโทรล่าช้าครั้งสุดท้ายหลังจากระยะเวลาที่กำหนดมิฉะนั้นตัวจับเวลาจะถูกรีเซ็ตฉันพบว่ามีประโยชน์สำหรับวัตถุประสงค์อื่นเช่นการตรวจจับเมื่อผู้ใช้หยุดพิมพ์เป็นต้น ..


5
ฉันคิดว่าวิธีการนี้อาจล้มเหลวหากใช้หลายครั้ง (เช่นหากส่วนต่าง ๆ ของการตั้งค่าการเรียกกลับรหัส$(window).resize) เพราะพวกเขาจะแบ่งปันtimerตัวแปร ดูคำตอบของฉันด้านล่างสำหรับวิธีแก้ปัญหาที่เสนอ
brahn

ดีมาก! ทำงานเหมือนจับใจ! ชอบคำตอบของคุณ ... เรียบง่ายและสง่างาม!
Mr. Pumpkin

74

หากคุณติดตั้ง Underscore.js คุณสามารถ:

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

1
แม้ว่าคุณไม่ต้องการรวม Underscore อย่างน้อยก็คว้าแหล่งที่มาสำหรับสิ่งนี้: underscorejs.org/docs/underscore.html#section-67
tybro0103

Debounce เป็นเทคนิคที่ถูกต้องที่นี่เป็นเพียงเรื่องของการใช้งาน และนี่คือการใช้งานที่ยอดเยี่ยมหาก Underscore / Lodash เป็นที่พึ่งของโครงการอยู่แล้ว
ปัจจัย Mystic

นี่คือสิ่งที่ฉันกำลังใช้อยู่
Bharat Patil

20

วิธีแก้ปัญหาที่กล่าวถึงบางข้อไม่ได้ผลสำหรับฉันแม้ว่าจะเป็นการใช้งานทั่วไปมากกว่า อีกวิธีหนึ่งฉันได้พบหนึ่งนี้ที่ปรับขนาดงานบนหน้าต่าง:

$(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
มีเพียงตัวอย่างของคุณที่เหมาะกับฉัน ... คนอื่น ๆ ข้างต้นไม่ได้! ฉันไม่แน่ใจว่าทำไมคำตอบของคุณไม่ถูกเลือก
Mumbo Jumbo

ผมไม่เข้าใจว่าทำไมจะจับเหตุการณ์ที่ปรับขนาดด้านในเหตุการณ์การปรับขนาด แต่มันทำงานสำหรับฉันเกินไป ...
lightbyte

Mumbo Jumbo ฉันคิดว่าเพราะคนอื่น ๆ มุ่งเน้นไปที่ลักษณะทั่วไปมองหาวิธีแก้ไขปัญหาดังกล่าว (ฟังก์ชั่นการโทรหลายสาย)
DusanV

lightbyte เป็นเพราะคุณต้องหยุดกิจกรรมก่อนหน้านี้ทุกครั้งที่เรียกใช้ฟังก์ชัน
DusanV

13

ขอบคุณ David Walsh มากนี่คือการหักล้างขีดล่างแบบวนิลา

รหัส:

// 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);
    };
};

การใช้งานง่าย:

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

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

Ref: http://davidwalsh.name/javascript-debounce-function


6

ที่จริงแล้วฉันรู้ว่าคุณไม่สามารถดำเนินการบางอย่างได้อย่างแน่นอนเมื่อปรับขนาดถูกปิดเพียงเพราะคุณไม่รู้การกระทำของผู้ใช้ในอนาคต แต่คุณสามารถสมมติเวลาที่ผ่านไประหว่างเหตุการณ์การปรับขนาดสองเหตุการณ์ดังนั้นหากคุณรอมากกว่าเวลานี้เล็กน้อยและไม่มีการปรับขนาดคุณสามารถเรียกใช้ฟังก์ชันของคุณได้
แนวคิดคือเราใช้setTimeoutและเป็นรหัสเพื่อบันทึกหรือลบ ตัวอย่างเช่นเรารู้ว่าเวลาระหว่างกิจกรรมปรับขนาดสองเหตุการณ์คือ 500ms ดังนั้นเราจะรอ 750 มิลลิวินาที

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


3

ประกาศผู้ฟังที่ล่าช้าทั่วโลก:

var resize_timeout;

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

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

และด้านล่างใช้ฟังเพื่อresizedกิจกรรมตามที่คุณต้องการ:

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

ขอบคุณนั่นเป็นทางออกที่ดีที่สุดในขณะนี้ นอกจากนี้ฉันได้ทดสอบว่า 250ms ใช้งานได้ดีที่สุดเมื่อปรับขนาดหน้าต่าง
Alexio

3

มันใช้งานได้สำหรับฉัน ดูวิธีแก้ปัญหานี้ - https://alvarotrigo.com/blog/firing-resize-event-only-once-when-resizing-is-finished/

var resizeId;
$(window).resize(function() {
    clearTimeout(resizeId);
    resizeId = setTimeout(doneResizing, 500);
});
function doneResizing(){
    //whatever we want to do 
}


2

ปลั๊กอิน jQuery แบบง่ายสำหรับเหตุการณ์การปรับขนาดหน้าต่างที่ล่าช้า

SYNTAX:

เพิ่มฟังก์ชั่นใหม่เพื่อปรับขนาดกิจกรรม

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

ลบฟังก์ชั่น (โดยการประกาศ ID) เพิ่มก่อนหน้านี้

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

ลบฟังก์ชั่นทั้งหมด

jQuery(window).resizeDelayed( false );

การใช้:

// 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();

การใช้ผลลัพธ์:

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

เสียบเข้าไป:

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

สมมติว่าเคอร์เซอร์ของเมาส์ควรกลับไปที่เอกสารหลังจากปรับขนาดหน้าต่างเราสามารถสร้างพฤติกรรมการโทรกลับด้วยเหตุการณ์ onmouseover อย่าลืมว่าวิธีนี้อาจใช้ไม่ได้กับหน้าจอที่เปิดใช้งานแบบสัมผัสตามที่คาดไว้

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);
});

ใช้ได้ดีกับไซต์บนเดสก์ท็อปที่ใช้เมาส์เท่านั้น แต่เหตุการณ์การวางเมาส์จะไม่เกิดขึ้นหากผู้ใช้อยู่บนมือถือและเปลี่ยนจากแนวนอนเป็นแนวตั้งหรือหากพวกเขาปรับขนาดหน้าต่างบนเดสก์ท็อปหน้าจอสัมผัส
user56reinstatemonica8

คุณสามารถปรับขนาดหน้าต่างเบราว์เซอร์ด้วยความช่วยเหลือของแป้นพิมพ์ในหน้าต่างล่าสุดเช่น Win-Arrow-Left Win-Arrow-Right ฯลฯ ...
Lu4

0

นี่คือสิ่งที่ฉันได้ดำเนินการ:

$ (หน้าต่าง) .resize (function () {setTimeout (someFunction, 500);});

เราสามารถล้าง setTimeoutหากเราคาดว่าการปรับขนาดจะเกิดขึ้นน้อยกว่า500ms

โชคดี...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.