Làm cách nào để kích hoạt một sự kiện khi thay đổi lớp bằng jQuery?


91

Tôi muốn có một cái gì đó như:

$('#myDiv').bind('class "submission ok" added'){
    alert('class "submission ok" has been added');
});

Câu trả lời:


171

Không có sự kiện nào được nêu ra khi một lớp thay đổi. Giải pháp thay thế là tăng sự kiện theo cách thủ công khi bạn thay đổi lớp theo chương trình:

$someElement.on('event', function() {
    $('#myDiv').addClass('submission-ok').trigger('classChange');
});

// in another js file, far, far away
$('#myDiv').on('classChange', function() {
     // do stuff
});

CẬP NHẬT

Câu hỏi này dường như đang thu thập một số khách truy cập, vì vậy đây là bản cập nhật với một cách tiếp cận có thể được sử dụng mà không cần phải sửa đổi mã hiện có bằng cách sử dụng mới MutationObserver:

var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    if (mutation.attributeName === "class") {
      var attributeValue = $(mutation.target).prop(mutation.attributeName);
      console.log("Class attribute changed to:", attributeValue);
    }
  });
});
observer.observe($div[0], {
  attributes: true
});

$div.addClass('red');
.red { color: #C00; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo" class="bar">#foo.bar</div>

Lưu ý rằng tính năng MutationObservernày chỉ khả dụng cho các trình duyệt mới hơn, cụ thể là Chrome 26, FF 14, IE 11, Opera 15 và Safari 6. Xem MDN để biết thêm chi tiết. Nếu bạn cần hỗ trợ các trình duyệt cũ thì bạn sẽ cần sử dụng phương pháp mà tôi đã nêu trong ví dụ đầu tiên của mình.


Trong hoàn thành câu trả lời này, tôi thấy điều này: stackoverflow.com/a/1950052/1579667
Benj

1
@Benj Điều đó giống với câu trả lời ban đầu của tôi (tức là đang sử dụng trigger()) mặc dù lưu ý rằng nó rất lỗi thời do việc sử dụng bind(). Tuy nhiên, tôi không chắc nó 'hoàn thành' bất cứ điều gì
Rory McCrossan

Trong trường hợp của tôi, tôi cần thiết để bắn một sự kiện khi một nút dom có một lớp học cụ thể MutationObservercông trình đối với tôi
Mario

1
Đây là một dạng cải tiến của giải pháp này với bộ lọc stackoverflow.com/a/42121795/12074818
MVDeveloper1

20

Bạn có thể thay thế các hàm addClass và removeClass của jQuery ban đầu bằng hàm của riêng bạn sẽ gọi các hàm gốc và sau đó kích hoạt một sự kiện tùy chỉnh. (Sử dụng một hàm ẩn danh tự gọi để chứa tham chiếu hàm gốc)

(function( func ) {
    $.fn.addClass = function() { // replace the existing function on $.fn
        func.apply( this, arguments ); // invoke the original function
        this.trigger('classChanged'); // trigger the custom event
        return this; // retain jQuery chainability
    }
})($.fn.addClass); // pass the original function as an argument

(function( func ) {
    $.fn.removeClass = function() {
        func.apply( this, arguments );
        this.trigger('classChanged');
        return this;
    }
})($.fn.removeClass);

Sau đó, phần còn lại của mã của bạn sẽ đơn giản như bạn mong đợi.

$(selector).on('classChanged', function(){ /*...*/ });

Cập nhật:

Cách tiếp cận này đưa ra giả định rằng các lớp sẽ chỉ được thay đổi thông qua các phương thức addClass và removeClass của jQuery. Nếu các lớp được sửa đổi theo những cách khác (chẳng hạn như thao tác trực tiếp với thuộc tính lớp thông qua phần tử DOM) thì việc sử dụng một cái gì đó như MutationObservers như được giải thích trong câu trả lời được chấp nhận ở đây sẽ là cần thiết.

Cũng như một số cải tiến cho các phương pháp này:

  • Kích hoạt một sự kiện cho mỗi lớp được thêm ( classAdded) hoặc loại bỏ ( classRemoved) với lớp cụ thể được truyền làm đối số cho hàm gọi lại và chỉ được kích hoạt nếu lớp cụ thể thực sự được thêm vào (không có trước đây) hoặc bị xóa (đã có trước đó)
  • Chỉ kích hoạt classChangednếu bất kỳ lớp nào thực sự được thay đổi

    (function( func ) {
        $.fn.addClass = function(n) { // replace the existing function on $.fn
            this.each(function(i) { // for each element in the collection
                var $this = $(this); // 'this' is DOM element in this context
                var prevClasses = this.getAttribute('class'); // note its original classes
                var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString(); // retain function-type argument support
                $.each(classNames.split(/\s+/), function(index, className) { // allow for multiple classes being added
                    if( !$this.hasClass(className) ) { // only when the class is not already present
                        func.call( $this, className ); // invoke the original function to add the class
                        $this.trigger('classAdded', className); // trigger a classAdded event
                    }
                });
                prevClasses != this.getAttribute('class') && $this.trigger('classChanged'); // trigger the classChanged event
            });
            return this; // retain jQuery chainability
        }
    })($.fn.addClass); // pass the original function as an argument
    
    (function( func ) {
        $.fn.removeClass = function(n) {
            this.each(function(i) {
                var $this = $(this);
                var prevClasses = this.getAttribute('class');
                var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString();
                $.each(classNames.split(/\s+/), function(index, className) {
                    if( $this.hasClass(className) ) {
                        func.call( $this, className );
                        $this.trigger('classRemoved', className);
                    }
                });
                prevClasses != this.getAttribute('class') && $this.trigger('classChanged');
            });
            return this;
        }
    })($.fn.removeClass);
    

Với các hàm thay thế này, bạn có thể xử lý bất kỳ lớp nào đã thay đổi thông qua classChanged hoặc các lớp cụ thể được thêm vào hoặc xóa bằng cách kiểm tra đối số của hàm gọi lại:

$(document).on('classAdded', '#myElement', function(event, className) {
    if(className == "something") { /* do something */ }
});

1
Đây hoạt động tốt, nhưng trong "phần còn lại của mã" xử lý sự kiện nên được giao cho bộ chọn mục tiêu để cho phép liên kết với các yếu tố mới: $(parent_selector).on('classChanged', target_selector, function(){ /*...*/ });. Tôi đã mất một thời gian để xem tại sao các phần tử được tạo động của tôi không kích hoạt trình xử lý. Xem learning.jquery.com/events/event-delegation
Timm


2

bạn có thể sử dụng một cái gì đó như thế này:

$(this).addClass('someClass');

$(Selector).trigger('ClassChanged')

$(otherSelector).bind('ClassChanged', data, function(){//stuff });

nhưng nếu không, không, không có hàm được xác định trước để kích hoạt một sự kiện khi một lớp thay đổi.

Đọc thêm về trình kích hoạt tại đây


1
Trình xử lý sự kiện phải là cùng một mục kích hoạt sự kiện. $ (this) .addClass ('someClass'); $ (Selector) .trigger ('ClassChanged') // Nó phải giống cùng Selector $ (Selector) .bind ('ClassChanged', data, function () {// thứ});
Meko Perez Estevez

3
Có vẻ như bạn đã sao chép từ đây, nếu có thì tốt nếu bạn cung cấp liên kết quá stackoverflow.com/questions/1950038/…
Satinder singh 16/1013
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.