2010-01-28 38 views
151

Có thể tạo trình xử lý sự kiện trong jQuery có thể bị ràng buộc với bất kỳ thay đổi kiểu nào không? Ví dụ: nếu tôi muốn "làm" điều gì đó khi yếu tố thay đổi thứ nguyên hoặc bất kỳ thay đổi nào khác trong thuộc tính kiểu tôi có thể làm:Có thể nghe sự kiện "thay đổi kiểu" không?

$('div').bind('style', function() { 
    console.log($(this).css('height')); 
}); 

$('div').height(100); // yields '100' 

Nó thực sự hữu ích.

Bất kỳ ý tưởng nào?

CẬP NHẬT

Xin lỗi vì trả lời này bản thân mình, nhưng tôi đã viết một giải pháp gọn gàng mà có thể phù hợp với người khác:

(function() { 
    var ev = new $.Event('style'), 
     orig = $.fn.css; 
    $.fn.css = function() { 
     $(this).trigger(ev); 
     return orig.apply(this, arguments); 
    } 
})(); 

này sẽ tạm thời ghi đè phương pháp prototype.css nội bộ và xác định lại nó với một kích hoạt ở cuối. Vì vậy, nó hoạt động như thế này:

$('p').bind('style', function(e) { 
    console.log($(this).attr('style')); 
}); 

$('p').width(100); 
$('p').css('color','red'); 
+0

yup, giải pháp tốt đẹp, nhưng trong một ứng dụng thực tế, tôi nghi ngờ sức mạnh này mất rất nhiều tài nguyên và thậm chí làm cho trình duyệt có vẻ chậm để theo kịp tương tác của người dùng. Tôi rất muốn biết nếu đó là trường hợp hay không. – pixeline

+1

@pixeline: Tôi không thể thấy rằng nó sẽ chậm hơn nhiều. jQuery vẫn gọi các nguyên mẫu css anyway, tôi chỉ cần thêm một kích hoạt cho nó. Vì vậy, về cơ bản nó chỉ là một cuộc gọi phương thức bổ sung. – David

+0

Tôi hiểu rằng: có vẻ như trong luồng người dùng tương tác với một ứng dụng, css() được gọi là rất nhiều thời gian. Tùy thuộc vào những gì bạn làm với kích hoạt đó (nếu nó chỉ là một bảng điều khiển đăng nhập, tôi đoán bạn là an toàn tất nhiên), điều này có thể tạo ra các vấn đề. Tôi chỉ tự hỏi thôi. Nó cũng phụ thuộc vào ứng dụng. Cá nhân tôi có xu hướng thực hiện rất nhiều phản hồi trực quan trong nội dung của tôi. – pixeline

Trả lời

15

Vì jQuery là nguồn mở, tôi đoán bạn có thể tinh chỉnh hàm css để gọi hàm bạn chọn mỗi lần viện dẫn (truyền đối tượng jQuery). Tất nhiên, bạn sẽ muốn quét mã jQuery để đảm bảo không có gì khác mà nó sử dụng trong nội bộ để thiết lập các thuộc tính CSS. Lý tưởng nhất, bạn muốn viết một plugin riêng biệt cho jQuery để nó không can thiệp vào chính thư viện jQuery, nhưng bạn sẽ phải quyết định xem có khả thi cho dự án của bạn hay không.

+1

Nhưng trong trường hợp này điều gì sẽ xảy ra nếu tôi thiết lập thuộc tính kiểu dáng thẳng với các hàm DOM? –

+1

@jaime trong thuật ngữ của giáo dân: không có gì. – m93a

+0

Đây là ví dụ hoàn chỉnh về giải pháp này: https://gist.github.com/bbottema/426810c21ae6174148d4 –

1

Câu hỏi thú vị. Vấn đề là chiều cao() không chấp nhận một cuộc gọi lại, vì vậy bạn sẽ không thể kích hoạt một cuộc gọi lại. Sử dụng hoặc animate() hoặc css() để thiết lập chiều cao và sau đó kích hoạt sự kiện tùy chỉnh trong gọi lại. Dưới đây là một ví dụ sử dụng animate(), thử nghiệm và công trình (demo), như một bằng chứng của khái niệm:

$('#test').bind('style', function() { 
    alert($(this).css('height')); 
}); 

$('#test').animate({height: 100},function(){ 
$(this).trigger('style'); 
}); 
+6

Xin lỗi, nhưng điều này đã chứng minh điều gì? Bạn 'kích hoạt()' sự kiện theo cách thủ công. Tôi sẽ nghĩ rằng OP là sau khi một số sự kiện tự động kích hoạt khi một thuộc tính phong cách được sửa đổi. – JPot

+0

@JPot anh ta cho thấy rằng thuộc tính chiều cao không ném các sự kiện khi thay đổi. – AnthonyJClink

2

Không có hỗ trợ sẵn có cho sự kiện thay đổi phong cách trong jQuery hoặc trong kịch bản java. Nhưng jQuery hỗ trợ để tạo ra sự kiện tùy chỉnh và lắng nghe nó, nhưng mỗi lần có một sự thay đổi, bạn nên có một cách để kích hoạt nó trên chính mình. Vì vậy, nó sẽ không phải là một giải pháp hoàn chỉnh.

3

Như những người khác đã gợi ý, nếu bạn có thể kiểm soát những gì đang thay đổi phong cách của các yếu tố bạn có thể bắn một sự kiện tùy chỉnh khi bạn thay đổi chiều cao của phần tử:

$('#blah').bind('height-changed',function(){...}); 
... 
$('#blah').css({height:'100px'}); 
$('#blah').trigger('height-changed'); 

Nếu không, mặc dù khá nhiều tài nguyên , bạn có thể đặt hẹn giờ định kỳ kiểm tra các thay đổi đối với chiều cao của phần tử ...

+0

Đây thực sự là giải pháp rất gọn gàng nếu người dùng có quyền truy cập vào mã đang thay đổi kiểu. –

19

Việc khai báo đối tượng sự kiện của bạn phải nằm trong hàm css mới của bạn. Nếu không, sự kiện chỉ có thể được kích hoạt một lần.

(function() { 
    orig = $.fn.css; 
    $.fn.css = function() { 
     var ev = new $.Event('style'); 
     orig.apply(this, arguments); 
     $(this).trigger(ev); 
    } 
})(); 
+0

Tuyệt vời, cảm ơn bạn. Một số người cho biết thay đổi nguồn gốc nhưng tiện ích mở rộng của bạn là tốt nhất. Tôi đã có một số vấn đề nhưng cuối cùng nó hoạt động. – ccsakuweb

9

Tôi nghĩ câu trả lời hay nhất nếu từ Mike trong trường hợp bạn không thể khởi chạy sự kiện của mình vì không phải từ mã của bạn. Nhưng tôi nhận được một số lỗi khi tôi sử dụng nó. Vì vậy, tôi viết một câu trả lời mới cho bạn thấy mã mà tôi sử dụng.

mở rộng

// Extends functionality of ".css()" 
// This could be renamed if you'd like (i.e. "$.fn.cssWithListener = func ...") 
(function() { 
    orig = $.fn.css; 
    $.fn.css = function() { 
     var result = orig.apply(this, arguments); 
     $(this).trigger('stylechanged'); 
     return result; 
    } 
})(); 

Cách sử dụng

// Add listener 
$('element').on('stylechanged', function() { 
    console.log('css changed'); 
}); 

// Perform change 
$('element').css('background', 'red'); 

tôi đã nhận lỗi vì var ev = new $ .Event ('phong cách'); Một cái gì đó giống như phong cách đã không được xác định trong HtmlDiv .. Tôi gỡ bỏ nó, và tôi khởi động bây giờ $ (this) .trigger ("stylechanged"). Một vấn đề khác là Mike đã không trả về kết quả của $ (css, ..) sau đó nó có thể gây ra vấn đề trong một số trường hợp. Vì vậy, tôi nhận được kết quả và trả lại nó. Bây giờ làm việc^^ Trong mỗi thay đổi css bao gồm từ một số libs mà tôi không thể sửa đổi và kích hoạt một sự kiện.

1

Chỉ cần thêm và chính thức hóa @ David 's giải pháp với phần trên:

Lưu ý rằng chức năng jQuery là thể kết nối và trở lại 'này' để nhiều lời gọi có thể được gọi là một sau khi khác (ví dụ $container.css("overflow", "hidden").css("outline", 0);).

Vì vậy, các mã được cải tiến nên là:

(function() { 
    var ev = new $.Event('style'), 
     orig = $.fn.css; 
    $.fn.css = function() { 
     var ret = orig.apply(this, arguments); 
     $(this).trigger(ev); 
     return ret; // must include this 
    } 
})(); 
0

tôi đã cùng một vấn đề, vì vậy tôi đã viết này. Nó hoạt động khá tốt. Có vẻ tuyệt vời nếu bạn trộn nó với một số chuyển tiếp CSS.

function toggle_visibility(id) { 
    var e = document.getElementById("mjwelcome"); 
    if(e.style.height == '') 
     e.style.height = '0px'; 
    else 
     e.style.height = ''; 
} 
163

Mọi thứ đã chuyển một chút kể từ khi câu hỏi được hỏi - bây giờ có thể sử dụng một MutationObserver để phát hiện những thay đổi trong 'phong cách' thuộc tính của một phần tử, không có jQuery yêu cầu:

var observer = new MutationObserver(function(mutations) { 
    mutations.forEach(function(mutationRecord) { 
     console.log('style changed!'); 
    });  
}); 

var target = document.getElementById('myId'); 
observer.observe(target, { attributes : true, attributeFilter : ['style'] }); 

Đối số được chuyển đến hàm gọi lại là đối tượng MutationRecord cho phép bạn giữ các giá trị kiểu cũ và mới.

Hỗ trợ là good in modern browsers bao gồm IE 11+.

+6

Hãy nhớ rằng điều này chỉ hoạt động với kiểu nội tuyến, không phải khi kiểu thay đổi do hậu quả của thay đổi lớp hoặc thay đổi '@ media'. –

+0

@ bfred.it bạn có ý tưởng về cách đạt được điều đó không? Tôi muốn chạy một số js sau khi các quy tắc css của một lớp đã được áp dụng cho một phần tử. – Kragalon

+0

Bạn có thể sử dụng 'getComputedStyle' với' setInterval' nhưng điều đó sẽ làm chậm trang web của bạn rất nhiều. –

0

bạn có thể thử jquery plugin, nó kích hoạt sự kiện khi css là sự thay đổi và nó dễ dàng để sử dụng

http://meetselva.github.io/#gist-section-attrchangeExtension 
$([selector]).attrchange({ 
    trackValues: true, 
    callback: function (e) { 
    //console.log('<p>Attribute <b>' + e.attributeName +'</b> changed from <b>' + e.oldValue +'</b> to <b>' + e.newValue +'</b></p>'); 
    //event.attributeName - Attribute Name 
    //event.oldValue - Prev Value 
    //event.newValue - New Value 
    } 
}); 
Các vấn đề liên quan