Acara pengubahan ukuran jendela JavaScript

618

Bagaimana saya bisa menghubungkan ke acara pengubahan ukuran jendela browser?

Ada cara jQuery untuk mendengarkan acara ukuran tetapi saya lebih suka untuk tidak membawanya ke proyek saya hanya untuk persyaratan yang satu ini.

Akun mati
sumber
8
Terimakasih semuanya. Saya tidak peduli tentang IE, saya berpikir lebih banyak tentang mengubah ukuran untuk opera di ponsel.
Akun mati

Jawaban:

640

jQuery hanya membungkus resizeacara DOM standar , misalnya.

window.onresize = function(event) {
    ...
};

jQuery dapat melakukan beberapa pekerjaan untuk memastikan bahwa acara pengubahan ukuran dipecat secara konsisten di semua browser, tapi saya tidak yakin apakah ada browser yang berbeda, tetapi saya mendorong Anda untuk menguji di Firefox, Safari, dan IE.

olliej
sumber
226
Salah satu potensi gotcha dengan metode ini adalah bahwa Anda mengesampingkan acara dan karenanya Anda tidak dapat melampirkan beberapa tindakan ke suatu acara. Combo addEventListener / attachEvent adalah cara terbaik untuk membuat javascript Anda ramah dengan skrip lain yang mungkin dijalankan pada halaman.
MyItchyChin
4
var onresize = window.onresize; window.onresize = function (event) {if (typeof onresize === 'function') onresize (); / ** ... * /}
SubOne
230
window.addEventListener('resize', function(){}, true);
WebWanderer
16
@ SubOne, contoh sempurna tentang bagaimana seseorang seharusnya tidak pernah melakukannya.
Eugene Pankov
28
ECMAScript 6 : window.onresize = () => { /* code */ };atau lebih baik:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman
561

Pertama, saya tahu addEventListenermetode ini telah disebutkan dalam komentar di atas, tetapi saya tidak melihat kode apa pun. Karena ini pendekatan yang disukai, ini dia:

window.addEventListener('resize', function(event){
  // do stuff here
});

Ini sampel yang berfungsi .

Jondlm
sumber
63
Ini adalah jawaban yang paling mudah.
jacoviza
7
Kedengarannya seperti jawaban terbaik karena Anda tidak menimpa acara window.onresize :-)
James Harrington
27
Banyak orang menambahkan pendengar acara anonim seperti yang Anda lakukan dalam contoh ini, tetapi ini bukan praktik yang sangat baik, karena pendekatan ini tidak memungkinkan untuk menghapus pendengar ini nanti. Ini dulunya tidak ada masalah karena halaman web berumur pendek, tapi di hari ini dan usia AJAX dan RIA dan SPA itu menjadi satu. Kami membutuhkan cara untuk mengelola siklus hidup pendengar acara. Dengan demikian, akan lebih baik untuk memfaktorkan keluar fungsi pendengar ke dalam fungsi yang terpisah sehingga dapat dihapus nanti dengan removeEventListener.
Stijn de Witt
6
mengapa bisa tidak semua orang jawaban seperti ini tanpa semua bulu yang
quemeful
2
Saya pikir ada kebenaran untuk jawaban Stijn de Witt dan quemeful di sini. Terkadang Anda peduli untuk menghapus pendengar acara, tetapi jika Anda tidak melakukannya, menambahkan semua kode tambahan seperti dalam contoh di atas tidak diperlukan dan keduanya dapat membengkak dan kurang mudah dibaca. Menurut pendapat saya, jika Anda tidak membayangkan alasan untuk menghapus pendengar, pendekatan ini adalah solusi terbaik. Anda selalu dapat menulis ulang nanti jika perlu. Dalam pengalaman saya, kebutuhan ini hanya muncul dalam situasi tertentu.
cazort
524

Jangan pernah menimpa fungsi window.onresize.

Sebaliknya, buat fungsi untuk menambahkan Event Listener ke objek atau elemen. Ini memeriksa dan memetikan pendengar tidak bekerja, maka mengesampingkan fungsi objek sebagai upaya terakhir. Ini adalah metode yang disukai yang digunakan di perpustakaan seperti jQuery.

object: elemen atau objek jendela
type: ubah ukuran, gulir (jenis peristiwa)
callback: referensi fungsi

var addEvent = function(object, type, callback) {
    if (object == null || typeof(object) == 'undefined') return;
    if (object.addEventListener) {
        object.addEventListener(type, callback, false);
    } else if (object.attachEvent) {
        object.attachEvent("on" + type, callback);
    } else {
        object["on"+type] = callback;
    }
};

Maka gunakan seperti ini:

addEvent(window, "resize", function_reference);

atau dengan fungsi anonim:

addEvent(window, "resize", function(event) {
  console.log('resized');
});
Alex V
sumber
100
Ini seharusnya jawaban yang diterima. Mengesampingkan onresize adalah praktik buruk.
Tiberiu-Ionuț Stan
8
hah, ada apa dengan semua cek nol tambahan? mencoba bekerja di IE 4.5 atau sesuatu?
FlavourScape
1
Dan Anda bertanya-tanya bagaimana cara saya memanggil fungsi ini untuk menerima event ukuran jendela? Begini caranya: addEvent (window, "resize", function_reference); :)
oabarca
6
Perhatikan bahwa pada IE 11, attachEventtidak lagi didukung. Cara yang disukai untuk masa depan adalah addEventListener.
Lukas
6
Hati-hati dengan elem == undefined. Mungkin (walaupun tidak mungkin) bahwa "tidak terdefinisi" didefinisikan secara lokal sebagai sesuatu yang lain. stackoverflow.com/questions/8175673/…
Luke
32

Acara pengubahan ukuran tidak boleh digunakan secara langsung karena dipecat secara terus-menerus sebagaimana kita mengubah ukuran.

Gunakan fungsi debounce untuk mengurangi kelebihan panggilan.

window.addEventListener('resize',debounce(handler, delay, immediate),false);

Berikut ini adalah debounce umum yang melayang di sekitar net, meskipun mencari yang lebih maju sebagai featuerd di lodash.

const debounce = (func, wait, immediate) => {
    var timeout;
    return () => {
        const context = this, args = arguments;
        const later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        const callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Ini dapat digunakan seperti ...

window.addEventListener('resize', debounce(() => console.log('hello'),
200, false), false);

Itu tidak akan pernah menembak lebih dari sekali setiap 200 ms.

Untuk perubahan orientasi seluler gunakan:

window.addEventListener('orientationchange', () => console.log('hello'), false);

Ini perpustakaan kecil yang saya kumpulkan untuk merawatnya dengan rapi.

frontsideup
sumber
Saya menghargai informasi tentang: debounce (sekarang tampaknya konsep / fungsi yang sangat berharga meskipun saya sebelumnya menolak menggunakan batas waktu dengan cara ini), lodash (meskipun saya pribadi tidak yakin) dan menyelesaikan ambiguitas tentang apakah menggunakan addEvent sebagai cadangan.
menambahkan addventventener
5
FYI karena Anda menggunakan notasi fungsi panah ES6, fungsi bagian dalam perlu memiliki (...arguments) => {...}(atau ...argsuntuk lebih sedikit kebingungan) karena argumentsvariabel tidak lagi tersedia cakupannya.
coderatchet
Saya sepenuhnya sadar, cuplikan itu bukan kode saya, itu hanya sebagai contoh.
frontsideup
Jawaban bagus, masalah perf dengan ukuran perlu diatasi! Debouncing adalah sebuah opsi, yang lain adalah pelambatan sederhana (yang mungkin merupakan cara untuk pergi jika Anda perlu UI untuk mengubah ukuran dalam "langkah"). Lihat bencentra.com/code/2015/02/27/optimizing-window-resize.html untuk contoh
Robin Métral
24

Solusi untuk 2018+:

Anda harus menggunakan ResizeObserver . Ini adalah solusi browser-asli yang memiliki kinerja yang jauh lebih baik daripada menggunakan resizeacara tersebut. Selain itu, tidak hanya mendukung acara di documenttetapi juga sewenang-wenang elements.

var ro = new ResizeObserver( entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

Saat ini, Firefox, Chrome, dan Safari mendukungnya . Untuk peramban lain (dan yang lebih lama), Anda harus menggunakan polyfill .

str
sumber
Masih jawaban terbaik di tahun 2020 imo
Jesse Reza Khorasanee
16

Saya percaya bahwa jawaban yang benar telah disediakan oleh @Alex V, namun jawabannya memang memerlukan beberapa modernisasi karena sudah lebih dari lima tahun sekarang.

Ada dua masalah utama:

  1. Jangan pernah gunakan objectsebagai nama parameter. Itu adalah kata yang dipulihkan. Dengan demikian, fungsi yang disediakan @Alex V tidak akan berfungsi strict mode.

  2. The addEventfungsi yang disediakan oleh @ Alex V tidak mengembalikan event objectjika addEventListenermetode yang digunakan. Parameter lain harus ditambahkan ke addEventfungsi untuk memungkinkan ini.

CATATAN: Parameter baru addEventtelah dibuat opsional sehingga migrasi ke versi fungsi baru ini tidak akan memutuskan panggilan sebelumnya ke fungsi ini. Semua penggunaan lawas akan didukung.

Berikut adalah addEventfungsi yang diperbarui dengan perubahan ini:

/*
    function: addEvent

    @param: obj         (Object)(Required)

        -   The object which you wish
            to attach your event to.

    @param: type        (String)(Required)

        -   The type of event you
            wish to establish.

    @param: callback    (Function)(Required)

        -   The method you wish
            to be called by your
            event listener.

    @param: eventReturn (Boolean)(Optional)

        -   Whether you want the
            event object returned
            to your callback method.
*/
var addEvent = function(obj, type, callback, eventReturn)
{
    if(obj == null || typeof obj === 'undefined')
        return;

    if(obj.addEventListener)
        obj.addEventListener(type, callback, eventReturn ? true : false);
    else if(obj.attachEvent)
        obj.attachEvent("on" + type, callback);
    else
        obj["on" + type] = callback;
};

Contoh panggilan ke addEventfungsi baru :

var watch = function(evt)
{
    /*
        Older browser versions may return evt.srcElement
        Newer browser versions should return evt.currentTarget
    */
    var dimensions = {
        height: (evt.srcElement || evt.currentTarget).innerHeight,
        width: (evt.srcElement || evt.currentTarget).innerWidth
    };
};

addEvent(window, 'resize', watch, true);
WebWanderer
sumber
Saya berpendapat bahwa attachEvent tidak lagi relevan pada tahun 2017.
Vlad Nicula
@Vladicicula saya setuju, tapi jawaban ini sudah dua tahun.
WebWanderer
12

Terima kasih telah merujuk posting blog saya di http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Meskipun Anda hanya dapat terhubung ke acara pengubahan ukuran jendela standar, Anda akan menemukan bahwa di IE, acara tersebut dipecat satu kali untuk setiap X dan sekali untuk setiap gerakan sumbu Y, menghasilkan satu ton peristiwa yang dipecat yang mungkin memiliki kinerja berdampak pada situs Anda jika rendering adalah tugas yang intensif.

Metode saya melibatkan batas waktu singkat yang dibatalkan pada acara berikutnya sehingga acara tersebut tidak menggelembung ke kode Anda sampai pengguna selesai mengubah ukuran jendela.

Steven
sumber
7
window.onresize = function() {
    // your code
};
saravanakumar
sumber
22
Seperti banyak komentar di atas katakan, yang terbaik adalah tidak menimpa fungsi onresize; bukan menambahkan acara baru. Lihat jawaban Jondlm.
Luke
6

Posting blog berikut ini mungkin berguna bagi Anda: Memperbaiki acara mengubah ukuran jendela di IE

Ini menyediakan kode ini:

Sys.Application.add_load(function(sender, args) {
    $addHandler(window, 'resize', window_resize);
});

var resizeTimeoutId;

function window_resize(e) {
     window.clearTimeout(resizeTimeoutId);
     resizeTimeoutId = window.setTimeout('doResizeCode();', 10);
}
lakshmanaraj
sumber
6
Yang satu ini hanya berlaku untuk aplikasi ASP.NET
Evgeny Gorb
2

Solusi yang disebutkan di atas akan bekerja jika semua yang Anda ingin lakukan hanya mengubah ukuran jendela dan jendela saja. Namun, jika Anda ingin agar ukurannya disebarkan ke elemen anak, Anda harus menyebarkan acara itu sendiri. Berikut beberapa contoh kode untuk melakukannya:

window.addEventListener("resize", function () {
  var recResizeElement = function (root) {
    Array.prototype.forEach.call(root.childNodes, function (el) {

      var resizeEvent = document.createEvent("HTMLEvents");
      resizeEvent.initEvent("resize", false, true);
      var propagate = el.dispatchEvent(resizeEvent);

      if (propagate)
        recResizeElement(el);
    });
  };
  recResizeElement(document.body);
});

Perhatikan bahwa elemen anak dapat memanggil

 event.preventDefault();

pada objek acara yang dilewatkan sebagai Arg pertama dari ukuran peristiwa. Sebagai contoh:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});
rysama
sumber
1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>
Rob Herring
sumber
1
var EM = new events_managment();

EM.addEvent(window, 'resize', function(win,doc, event_){
    console.log('resized');
    //EM.removeEvent(win,doc, event_);
});

function events_managment(){
    this.events = {};
    this.addEvent = function(node, event_, func){
        if(node.addEventListener){
            if(event_ in this.events){
                node.addEventListener(event_, function(){
                    func(node, event_);
                    this.events[event_](win_doc, event_);
                }, true);
            }else{
                node.addEventListener(event_, function(){
                    func(node, event_);
                }, true);
            }
            this.events[event_] = func;
        }else if(node.attachEvent){

            var ie_event = 'on' + event_;
            if(ie_event in this.events){
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                    this.events[ie_event]();
                });
            }else{
                node.attachEvent(ie_event, function(){
                    func(node, ie_event);
                });
            }
            this.events[ie_event] = func;
        }
    }
    this.removeEvent = function(node, event_){
        if(node.removeEventListener){
            node.removeEventListener(event_, this.events[event_], true);
            this.events[event_] = null;
            delete this.events[event_];
        }else if(node.detachEvent){
            node.detachEvent(event_, this.events[event_]);
            this.events[event_] = null;
            delete this.events[event_];
        }
    }
}
THE AMAZING
sumber