Sự kiện thay đổi kích thước cửa sổ JavaScript


618

Làm thế nào tôi có thể nối vào một sự kiện thay đổi kích thước cửa sổ trình duyệt?

một cách nghe jQuery để thay đổi kích thước các sự kiện nhưng tôi không muốn đưa nó vào dự án của mình chỉ vì một yêu cầu này.


8
Cảm ơn mọi người. Tôi không quan tâm đến IE, tôi đã suy nghĩ nhiều hơn về việc thay đổi kích thước cho opera trên điện thoại di động.
Tài khoản chết

Câu trả lời:


640

jQuery chỉ gói resizegọn sự kiện DOM tiêu chuẩn , vd.

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

jQuery có thể thực hiện một số công việc để đảm bảo rằng sự kiện thay đổi kích thước được kích hoạt một cách nhất quán trong tất cả các trình duyệt, nhưng tôi không chắc liệu có bất kỳ trình duyệt nào khác nhau không, nhưng tôi khuyến khích bạn nên thử nghiệm trên Firefox, Safari và IE.


226
Một vấn đề tiềm năng với phương pháp này là bạn đang ghi đè sự kiện và vì vậy bạn không thể đính kèm nhiều hành động vào một sự kiện. Combo addEventListener / AttachEvent là cách tốt nhất để làm cho javascript của bạn chơi thân thiện với bất kỳ tập lệnh nào khác có thể đang thực thi trên trang.
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 là một ví dụ hoàn hảo về cách người ta không bao giờ nên làm điều đó.
Eugene Pankov

28
ECMAScript 6 : window.onresize = () => { /* code */ };hoặc tốt hơn:window.addEventListener('resize', () => { /* code */ });
Derk Jan Speelman

561

Trước hết, tôi biết addEventListenerphương pháp đã được đề cập trong các ý kiến ​​trên, nhưng tôi không thấy bất kỳ mã nào. Vì đó là cách tiếp cận ưa thích, nên đây là:

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

Đây là một mẫu làm việc .


63
Đây là câu trả lời đơn giản nhất.
jacoviza

7
Nghe có vẻ như câu trả lời hay nhất vì bạn không ghi đè lên sự kiện window.onresize :-)
James Harrington

27
Nhiều người thêm người nghe sự kiện ẩn danh như bạn làm trong ví dụ này, nhưng nó không thực sự tốt, bởi vì cách tiếp cận này làm cho không thể loại bỏ những người nghe này sau này. Điều này từng không có vấn đề gì vì dù sao các trang web cũng tồn tại trong một thời gian ngắn, nhưng trong thời đại của AJAX và RIAs và SPA, nó đã trở thành một. Chúng ta cần một cách để quản lý vòng đời của người nghe sự kiện. Vì vậy, sẽ tốt hơn nếu đưa yếu tố chức năng nghe vào một chức năng riêng biệt để có thể loại bỏ nó sau này removeEventListener.
Stijn de Witt

6
Tại sao mọi người không thể trả lời như thế này mà không có tất cả những
câu chuyện vớ vẩn

2
Tôi nghĩ rằng có sự thật cho cả câu trả lời của Stijn de Witt và câu đố ở đây. Đôi khi bạn quan tâm đến việc loại bỏ các trình lắng nghe sự kiện, nhưng trong trường hợp bạn không, việc thêm tất cả các mã bổ sung như trong ví dụ trên là không cần thiết và có thể vừa phình to và ít đọc hơn. Theo tôi, nếu bạn không hình dung ra một lý do cần loại bỏ người nghe, phương pháp này là giải pháp tốt nhất. Bạn luôn có thể viết lại sau nếu cần thiết. Theo kinh nghiệm của tôi, những nhu cầu này chỉ phát sinh trong các tình huống cụ thể.
cazort

524

Không bao giờ ghi đè chức năng window.onresize.

Thay vào đó, hãy tạo một hàm để thêm Trình lắng nghe sự kiện vào đối tượng hoặc thành phần. Điều này kiểm tra và khiến người nghe không làm việc, sau đó nó ghi đè chức năng của đối tượng như là phương sách cuối cùng. Đây là phương thức ưa thích được sử dụng trong các thư viện như jQuery.

object: phần tử hoặc đối tượng cửa sổ
type: thay đổi kích thước, cuộn (loại sự kiện)
callback: tham chiếu hàm

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

Sau đó sử dụng là như thế này:

addEvent(window, "resize", function_reference);

hoặc với chức năng ẩn danh:

addEvent(window, "resize", function(event) {
  console.log('resized');
});

100
Đây phải là câu trả lời được chấp nhận. Ghi đè onresize chỉ là thực hành xấu.
Tiberiu-Ionuț Stan

8
hah, những gì với tất cả các kiểm tra null thêm? cố gắng làm việc trong IE 4.5 hay cái gì đó?
FlavorScape

1
Và bạn đang tự hỏi làm thế nào để tôi gọi chức năng này để nhận các sự kiện thay đổi kích thước cửa sổ? Đây là cách thực hiện: addEvent (cửa sổ, "thay đổi kích thước", hàm numference); :)
oabarca

6
Lưu ý rằng kể từ IE 11, attachEventkhông còn được hỗ trợ. Cách ưa thích cho tương lai là addEventListener.
Lu-ca

6
Hãy cẩn thận với elem == undefined. Có thể (mặc dù không chắc) rằng "không xác định" được định nghĩa cục bộ là một cái gì đó khác. stackoverflow.com/questions/8175673/ hy
Luke

32

Sự kiện thay đổi kích thước không bao giờ được sử dụng trực tiếp vì nó được kích hoạt liên tục khi chúng ta thay đổi kích thước.

Sử dụng chức năng gỡ lỗi để giảm thiểu các cuộc gọi dư thừa.

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

Đây là một bản phát hành phổ biến trôi nổi trên mạng, mặc dù vậy, hãy tìm những bản nâng cao hơn như featuerd trong 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);
    };
};

Điều này có thể được sử dụng như vậy ...

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

Nó sẽ không bao giờ bắn hơn 200ms một lần.

Đối với thay đổi định hướng di động, sử dụng:

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

Đây là một thư viện nhỏ tôi tập hợp lại để chăm sóc nó gọn gàng.


Tôi đánh giá cao thông tin về: gỡ lỗi (hiện tại có vẻ như là một khái niệm / chức năng vô giá mặc dù trước đây tôi đã chống lại việc sử dụng thời gian chờ theo cách này), lodash (mặc dù cá nhân tôi không bị thuyết phục) và giải quyết sự mơ hồ về việc có nên sử dụng addEvent làm dự phòng không để addEventListener (chỉ vì các câu trả lời cũ hơn không thực sự giải quyết rõ ràng các ý kiến ​​liên quan đến vấn đề này)
wunth

5
FYI vì bạn đang sử dụng ký hiệu func mũi tên ES6, hàm bên trong cần phải có (...arguments) => {...}(hoặc ...argsít nhầm lẫn hơn) vì argumentsbiến không còn khả dụng trong phạm vi của chúng.
coderatchet

Tôi hoàn toàn biết rằng đoạn mã đó không phải là mã của tôi, nó chỉ là một ví dụ.
frontsideup

Câu trả lời tuyệt vời, các vấn đề hoàn hảo với thay đổi kích thước cần phải được giải quyết! Nợ là một tùy chọn, một cách khác là điều chỉnh đơn giản (có thể là cách để đi nếu bạn cần UI của mình thay đổi kích thước trong "các bước"). Xem bencentra.com/code/2015/02/27/optimizing-window-resize.html để biết ví dụ
Robin Métral

24

Giải pháp cho năm 2018+:

Bạn nên sử dụng ResizeObserver . Đây là một giải pháp dựa trên trình duyệt có hiệu suất tốt hơn nhiều so với sử dụng resizesự kiện. Ngoài ra, nó không chỉ hỗ trợ sự kiện trên documentmà còn tùy ý 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);

Hiện tại, Firefox, Chrome và Safari hỗ trợ nó . Đối với các trình duyệt khác (và cũ hơn), bạn phải sử dụng một polyfill .


Vẫn là câu trả lời hay nhất năm 2020 imo
Jesse Reza Khorasanee


16

Tôi tin rằng câu trả lời đúng đã được cung cấp bởi @Alex V, tuy nhiên câu trả lời yêu cầu một số hiện đại hóa vì nó đã hơn năm tuổi.

Có hai vấn đề chính:

  1. Không bao giờ sử dụng objectnhư một tên tham số. Đó là một từ được lưu trữ lại. Với điều này đang được nói, chức năng được cung cấp của @Alex V sẽ không hoạt động strict mode.

  2. Các addEventchức năng được cung cấp bởi @ Alex V không trả lại event objectnếu addEventListenerphương pháp được sử dụng. Một tham số khác nên được thêm vào addEventhàm để cho phép điều này.

LƯU Ý: Tham số mới addEventđã được thực hiện tùy chọn để việc di chuyển sang phiên bản chức năng mới này sẽ không phá vỡ bất kỳ cuộc gọi trước nào đến chức năng này. Tất cả các sử dụng di sản sẽ được hỗ trợ.

Đây là addEventchức năng được cập nhật với những thay đổi sau:

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

Một ví dụ gọi addEventhàm mới :

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

Tôi sẽ lập luận rằng Đính kèm không còn phù hợp trong năm 2017.
Vlad Nicula 17/03/2017

@VladNicula Tôi đồng ý, nhưng câu trả lời này đã được hai tuổi.
WebWanderer 17/03/2017

12

Cảm ơn bạn đã tham khảo bài viết trên blog của tôi tại http://mbccs.blogspot.com/2007/11/fixing-window-resize-event-in-ie.html .

Mặc dù bạn có thể kết nối với sự kiện thay đổi kích thước cửa sổ tiêu chuẩn, nhưng bạn sẽ thấy rằng trong IE, sự kiện này được kích hoạt một lần cho mỗi X và một lần cho mỗi chuyển động trục Y, dẫn đến một tấn sự kiện có thể có hiệu suất tác động đến trang web của bạn nếu kết xuất là một nhiệm vụ chuyên sâu.

Phương pháp của tôi liên quan đến thời gian chờ ngắn bị hủy trong các sự kiện tiếp theo để sự kiện không bị lỗi với mã của bạn cho đến khi người dùng hoàn tất thay đổi kích thước cửa sổ.


7
window.onresize = function() {
    // your code
};

22
Như nhiều ý kiến ​​trên cho biết, tốt nhất không nên ghi đè chức năng onresize; thay vì thêm một sự kiện mới. Xem câu trả lời của Jondlm.
Lu-ca

6

Bài đăng blog sau đây có thể hữu ích cho bạn: Sửa lỗi thay đổi kích thước cửa sổ trong IE

Nó cung cấp mã này:

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

6
Ứng dụng này chỉ áp dụng cho các ứng dụng ASP.NET
Evgeny Gorb

2

Các giải pháp đã được đề cập ở trên sẽ hoạt động nếu tất cả những gì bạn muốn làm là chỉ thay đổi kích thước cửa sổ và cửa sổ. Tuy nhiên, nếu bạn muốn thay đổi kích thước được truyền đến các phần tử con, bạn sẽ cần phải tự truyền bá sự kiện. Dưới đây là một số mã ví dụ để làm điều đó:

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

Lưu ý rằng một phần tử con có thể gọi

 event.preventDefault();

trên đối tượng sự kiện được truyền vào dưới dạng Arg đầu tiên của sự kiện thay đổi kích thước. Ví dụ:

var child1 = document.getElementById("child1");
child1.addEventListener("resize", function (event) {
  ...
  event.preventDefault();
});

1
<script language="javascript">
    window.onresize = function() {
    document.getElementById('ctl00_ContentPlaceHolder1_Accordion1').style.height = '100%';
} 

</script>

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_];
        }
    }
}
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.