เป็นไปได้ไหมที่จะฟังเหตุการณ์ "เปลี่ยนสไตล์"?


206

เป็นไปได้ไหมที่จะสร้างตัวฟังเหตุการณ์ใน jQuery ที่สามารถผูกกับการเปลี่ยนแปลงสไตล์ได้? ตัวอย่างเช่นถ้าฉันต้องการที่จะ "ทำ" บางสิ่งบางอย่างเมื่อองค์ประกอบเปลี่ยนมิติหรือการเปลี่ยนแปลงอื่น ๆ ในแอตทริบิวต์สไตล์ที่ฉันสามารถทำได้:

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

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

มันจะมีประโยชน์จริงๆ

ความคิดใด ๆ

UPDATE

ขออภัยที่ตอบคำถามนี้ด้วยตัวเอง แต่ฉันได้เขียนวิธีแก้ไขที่เรียบร้อยซึ่งอาจเหมาะกับคนอื่น:

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

นี่จะเป็นการชั่วคราวแทนที่เมธอด prototype.css ภายในและกำหนดใหม่ด้วยทริกเกอร์ที่ท้าย ดังนั้นจึงทำงานเช่นนี้:

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

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

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

1
@pixeline: ฉันไม่เห็นว่ามันน่าจะช้ากว่านี้มาก jQuery ยังคงเรียกต้นแบบ css อยู่ดีฉันแค่เพิ่มทริกเกอร์ ดังนั้นจึงเป็นเพียงวิธีการโทรพิเศษหนึ่ง
David Hellsing

ฉันเข้าใจว่า: ดูเหมือนว่าในการไหลของผู้ใช้ที่มีปฏิสัมพันธ์กับแอปพลิเคชัน css () เรียกว่าเวลามาก ขึ้นอยู่กับสิ่งที่คุณทำกับทริกเกอร์นั้น (ถ้าเป็นเพียงบันทึกคอนโซลฉันคิดว่าคุณปลอดภัยแน่นอน) นี่อาจสร้างปัญหาได้ ฉันแค่สงสัย ขึ้นอยู่กับแอพพลิเคชั่นด้วย ฉันมักจะทำข้อเสนอแนะภาพมากในสิ่งที่ฉัน
pixeline

มีสองสามสิ่งที่ต้องทำเพื่อให้ทำงานกับ jQuery css call ที่มีอยู่: 1) คุณต้องการคืนองค์ประกอบออกจากฟังก์ชัน css ใหม่ของคุณ เช่น. $ ('p'). css ('display', 'block'). css ('color', 'black'); เป็นต้น 2) ถ้าเป็นการเรียกค่าคุณสมบัติ (เช่น 'obj.css (' height ');') คุณต้องการคืนค่าส่งคืนของฟังก์ชันดั้งเดิม - ฉันทำสิ่งนี้โดยตรวจสอบว่ารายการอาร์กิวเมนต์ สำหรับฟังก์ชั่นนี้มีเพียงหนึ่งอาร์กิวเมนต์
theringostarrs

1
ฉันสร้างเวอร์ชันที่แข็งแกร่งยิ่งขึ้นของวิธีการนี้ซึ่งใช้งานได้เมื่อลบแอตทริบิวต์ของตัวเองออกไป มันจะโยนเหตุการณ์ 'สไตล์' สำหรับแต่ละสไตล์ที่จะถูกลบด้วยวิธีนี้ gist.github.com/bbottema/426810c21ae6174148d4
Benny Bottema

คำตอบ:


19

เนื่องจาก jQuery เป็นโอเพ่นซอร์สฉันจึงเดาว่าคุณสามารถปรับแต่งcssฟังก์ชันเพื่อเรียกใช้ฟังก์ชันที่คุณเลือกทุกครั้งที่เรียกใช้ (ผ่านวัตถุ jQuery) แน่นอนคุณจะต้อง scour โค้ด jQuery เพื่อให้แน่ใจว่าไม่มีสิ่งอื่นใดที่จะใช้ภายในเพื่อตั้งค่าคุณสมบัติ CSS ตามหลักการแล้วคุณต้องการเขียนปลั๊กอินแยกต่างหากสำหรับ jQuery เพื่อไม่ให้รบกวนไลบรารี jQuery แต่คุณต้องตัดสินใจว่าจะเป็นไปได้หรือไม่สำหรับโครงการของคุณ


1
แต่ในกรณีนี้จะเกิดอะไรขึ้นถ้าฉันตั้งค่าคุณสมบัติรูปแบบตรงกับฟังก์ชัน DOM ??
Jaime Hablutzel

ต่อไปนี้เป็นตัวอย่างที่สมบูรณ์ของโซลูชันนี้: gist.github.com/bbottema/426810c21ae6174148d4
Benny Bottema

272

สิ่งต่าง ๆ ย้ายไปเล็กน้อยตั้งแต่คำถามถูกถาม - ตอนนี้เป็นไปได้ที่จะใช้MutationObserverเพื่อตรวจจับการเปลี่ยนแปลงในแอตทริบิวต์ 'style' ขององค์ประกอบไม่จำเป็นต้อง jQuery:

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

อาร์กิวเมนต์ที่ถูกส่งผ่านไปยังฟังก์ชันการเรียกกลับเป็นวัตถุMutationRecordที่ให้คุณได้รับค่าสไตล์เก่าและใหม่

การสนับสนุนเป็นสิ่งที่ดีในเบราว์เซอร์ที่ทันสมัยรวมถึง IE 11+


19
เก็บไว้ในใจที่ว่านี้จะทำงานเฉพาะกับรูปแบบอินไลน์ไม่ได้เมื่อมีการเปลี่ยนแปลงรูปแบบที่เป็นผลมาจากการเปลี่ยนแปลงของระดับหรือ@mediaการเปลี่ยนแปลง
Fregante

2
@ bfred.it คุณมีความคิดว่าจะทำอย่างไรให้สำเร็จ ฉันต้องการเรียกใช้ js หลังจากกฎ css ของชั้นเรียนถูกนำไปใช้กับองค์ประกอบ
Kragalon

คุณสามารถใช้getComputedStyleกับsetIntervalแต่นั่นจะทำให้เว็บไซต์ของคุณช้าลงมาก
fregante

หมายเหตุ: MutationObserver ไม่สามารถใช้งานได้กับ Android 4.4 ทุกเวอร์ชันแม้จะมีสิ่งที่ชาวแคนาดาพูด
James Gould

ดู twiddle นี้เพื่อเป็นตัวอย่างของการเปลี่ยนสีพื้นหลังของ textarea เป็นสีน้ำเงินเมื่อความกว้างของ textarea ยืดผ่าน 300px jsfiddle.net/RyanNerd/y2q8wuf0 (น่าเสียดายที่มีข้อผิดพลาดใน FF ที่แฮงค์สคริปต์ที่HTMLElement.style.prop = "value"
RyanNerd

18

การประกาศของวัตถุเหตุการณ์ของคุณจะต้องอยู่ในฟังก์ชั่น css ใหม่ของคุณ ไม่เช่นนั้นจะสามารถเริ่มต้นเหตุการณ์ได้เพียงครั้งเดียว

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

เยี่ยมมากขอบคุณ บางคนบอกว่าเปลี่ยนแหล่งต้นฉบับ แต่ส่วนขยายของคุณดีที่สุด ฉันมีปัญหา แต่ในที่สุดก็ใช้งานได้
ccsakuweb

มันเริ่มทำงานอย่างต่อเนื่องหลังจากรันโค้ดนี้และไม่ได้ผลตามที่ต้องการ
smkrn110

13

ฉันคิดว่าคำตอบที่ดีที่สุดหากจาก Mike ในกรณีที่คุณไม่สามารถเริ่มกิจกรรมของคุณได้เพราะไม่ใช่จากรหัสของคุณ แต่ฉันได้รับข้อผิดพลาดบางอย่างเมื่อฉันใช้มัน ดังนั้นฉันจึงเขียนคำตอบใหม่เพื่อแสดงรหัสที่ฉันใช้

ส่วนขยาย

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

การใช้

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

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

ฉันพบข้อผิดพลาดเนื่องจาก var ev = new $ .Event ('style'); สิ่งที่ชอบสไตล์ไม่ได้กำหนดไว้ใน HtmlDiv .. ฉันลบออกและตอนนี้ฉันเริ่มใช้ $ (this) .trigger ("stylechanged") ปัญหาอีกประการหนึ่งคือไมค์ไม่ส่งคืนผลลัพธ์ของ $ (css, .. ) จากนั้นอาจทำให้เกิดปัญหาในบางกรณี ดังนั้นฉันได้รับผลลัพธ์และส่งคืน ตอนนี้ใช้งานได้ ^^ ในทุกการเปลี่ยนแปลง CSS รวมถึงจาก libs บางอย่างที่ฉันไม่สามารถแก้ไขและเรียกใช้เหตุการณ์ได้


มีประโยชน์และฉลาดมาก
dgo

5

ตามที่คนอื่น ๆ แนะนำถ้าคุณสามารถควบคุมรหัสใด ๆ ที่เปลี่ยนสไตล์ขององค์ประกอบที่คุณสามารถดำเนินการเหตุการณ์ที่กำหนดเองเมื่อคุณเปลี่ยนความสูงขององค์ประกอบ:

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

ไม่เช่นนั้นคุณจะสามารถตั้งเวลาเพื่อตรวจสอบการเปลี่ยนแปลงความสูงขององค์ประกอบ ...


นี่เป็นทางออกที่เรียบร้อยมากหากมีการเข้าถึงโค้ดที่เปลี่ยนสไตล์
Umair Hafeez

2

ไม่มีการสนับสนุน inbuilt สำหรับเหตุการณ์การเปลี่ยนสไตล์ใน jQuery หรือในจาวาสคริปต์ แต่ jQuery สนับสนุนการสร้างเหตุการณ์ที่กำหนดเองและฟังมัน แต่ทุกครั้งที่มีการเปลี่ยนแปลงคุณควรมีวิธีที่จะทำให้มันเกิดขึ้นเอง ดังนั้นมันจะไม่เป็นทางออกที่สมบูรณ์


2

คุณสามารถลองปลั๊กอิน Jquery มันจะทริกเกอร์เหตุการณ์เมื่อมีการเปลี่ยนแปลง CSS และใช้งานง่าย

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

1

คำถามที่น่าสนใจ ปัญหาคือความสูง () ไม่ยอมรับการติดต่อกลับดังนั้นคุณจะไม่สามารถโทรกลับได้ ใช้ animate () หรือ css () เพื่อกำหนดความสูงจากนั้นทริกเกอร์เหตุการณ์ที่กำหนดเองในการติดต่อกลับ นี่คือตัวอย่างการใช้ภาพเคลื่อนไหว (), การทดสอบและการทำงาน ( ตัวอย่าง ) เพื่อเป็นหลักฐานของแนวคิด:

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

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

8
ขออภัยสิ่งนี้พิสูจน์ได้อย่างไร ให้คุณtrigger()จัดกิจกรรมด้วยตนเอง ฉันคิดว่า OP จะเกิดขึ้นหลังจากเหตุการณ์ที่ถูกเรียกอัตโนมัติเมื่อมีการปรับเปลี่ยนแอตทริบิวต์ของสไตล์
JPot

@JPot เขาแสดงให้เห็นว่าคุณลักษณะความสูงไม่ได้โยนเหตุการณ์เมื่อมีการเปลี่ยนแปลง
AnthonyJClink

1

เพียงแค่เพิ่มและทำให้เป็นทางออกของ @David จากด้านบน:

โปรดทราบว่าฟังก์ชั่น jQuery นั้นสามารถเชื่อมโยงได้และส่งคืน 'this' เพื่อให้สามารถเรียกใช้การเรียกใช้หลายรายการได้หนึ่งรายการภายหลัง (เช่น$container.css("overflow", "hidden").css("outline", 0);)

ดังนั้นรหัสที่ได้รับการปรับปรุงควรเป็น:

(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

jQuery เป็นอย่างไร cssHooks?

บางทีฉันอาจไม่เข้าใจคำถาม แต่สิ่งที่คุณค้นหาทำได้ง่ายด้วยcssHooksโดยไม่ต้องเปลี่ยนcss()ฟังก์ชั่น

คัดลอกจากเอกสาร:

(function( $ ) {

// First, check to see if cssHooks are supported
if ( !$.cssHooks ) {
  // If not, output an error message
  throw( new Error( "jQuery 1.4.3 or above is required for this plugin to work" ) );
}

// Wrap in a document ready call, because jQuery writes
// cssHooks at this time and will blow away your functions
// if they exist.
$(function () {
  $.cssHooks[ "someCSSProp" ] = {
    get: function( elem, computed, extra ) {
      // Handle getting the CSS property
    },
    set: function( elem, value ) {
      // Handle setting the CSS value
    }
  };
});

})( jQuery ); 

https://api.jquery.com/jQuery.cssHooks/


-1

ฉันมีปัญหาเดียวกันดังนั้นฉันจึงเขียนสิ่งนี้ มันใช้งานได้ค่อนข้างดี ดูดีถ้าคุณผสมกับการเปลี่ยน CSS บางอย่าง

function toggle_visibility(id) {
   var e = document.getElementById("mjwelcome");
   if(e.style.height == '')
      e.style.height = '0px';
   else
      e.style.height = '';
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.