「スタイルチェンジ」イベントを聞くことは可能ですか?


206

スタイルの変更にバインドできるjQueryでイベントリスナーを作成することは可能ですか?たとえば、要素が寸法を変更したときに何かを「実行」したい場合、またはスタイル属性のその他の変更を実行したい場合、

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

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

それは本当に便利でしょう。

何か案は?

更新

私自身これに答えて申し訳ありませんが、私は他の誰かに合うかもしれないきちんとしたソリューションを書きました:

(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 2010年

1
@pixeline:かなり遅くなるはずです。とにかくjQueryはcssプロトタイプを呼び出しますが、それにトリガーを追加しているだけです。したがって、これは基本的に1つの追加のメソッド呼び出しです。
David Hellsing、2010年

私はそれを理解しています:アプリケーションと対話するユーザーの流れの中で、css()は多くの時間呼び出されているようです。そのトリガーをどのように処理するかによって(それが単なるコンソールログであれば、もちろん安全だと思います)、これにより問題が発生する可能性があります。ちょっと思ったんです。アプリケーションにも依存します。私は個人的に自分の作品に多くの視覚的フィードバックをする傾向があります。
pixeline

既存のjqueryのcss呼び出しで機能させるには、さらに2つのことを行う必要があります。1)新しいcss関数から要素を返す必要があります。そうしないと、流暢なスタイルのcss呼び出しが中断されます。例えば。$( 'p')。css( 'display'、 'block')。css( 'color'、 'black'); など2)プロパティ値の呼び出し(たとえば、 'obj.css(' height ');')の場合は、元の関数の戻り値を返します。これは、引数リストかどうかを確認することで行います。関数の引数は1つだけです。
theringostarrs

1
このアプローチのより堅牢なバージョンを作成しました。これは、スタイル属性自体が削除されているときにも機能します。この方法で削除されるスタイルごとに 'style'イベントをスローします。 gist.github.com/bbottema/426810c21ae6174148d4
ベニーボッテマ

回答:


19

jQueryはオープンソースなので、css呼び出されるたびに(jQueryオブジェクトを渡して)選択した関数を呼び出すように関数を微調整できると思います。もちろん、jQueryコードを精査して、CSSプロパティを設定するために内部で使用するコードが他にないことを確認する必要があります。理想的には、jQueryライブラリ自体に干渉しないようにjQueryのプラグインを個別に作成する必要がありますが、それがプロジェクトに適しているかどうかを判断する必要があります。


1
しかし、この場合、DOM関数でスタイルプロパティを直接設定するとどうなりますか?
Jaime Hablutzel、2011

このソリューションの完全な例を次に示します。gist.github.com
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 2016年

2
@ bfred.itそれを実現する方法についてのアイデアはありますか?クラスのcssルールが要素に適用された後、いくつかのjsを実行したいのですが。
Kragalon

で使用getComputedStyleすることはできますsetIntervalが、ウェブサイトの速度が大幅に低下します。
fregante

注:MutiObserverは実際には、Android 4.4のすべてのバージョンで機能するわけではありません。
ジェームズグールド

textareaの幅が300pxを超えて拡大されたときにtextareaの背景色を青に変更する例については、このひねりを参照してください。jsfiddle.net/RyanNerd/y2q8wuf0 (残念ながら、FFにスクリプトがハングするバグがあるようですHTMLElement.style.prop = "value"
RyanNerd 2017

18

イベントオブジェクトの宣言は、新しいcss関数内にある必要があります。それ以外の場合、イベントは一度だけ発生できます。

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

よかった。ありがとう。元のソースを変更すると言う人もいますが、あなたの拡張機能が最適です。私はいくつかの問題を抱えていましたが、最終的には動作します。
ccsakuweb

このコードを実行した後、継続的に発火し、必要な結果さえ達成しません。
smkrn110

13

コードからではなく、イベントを起動できない場合は、マイクからの回答が最適です。しかし、それを使用するとエラーが発生します。そこで、私が使用するコードを紹介するための新しい回答を書きます。

拡張

// 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")を起動します。もう1つの問題は、Mikeが$(css、..)の結果を返さなかったことです。この場合、問題が発生する可能性があります。結果を取得して返します。動作します^^すべてのcss変更に、変更およびイベントのトリガーができない一部のライブラリからのインクルードがあります。


非常に親切で賢い
dgo '19年

5

他の人が示唆しているように、要素のスタイルを変更するコードを制御できる場合は、要素の高さを変更するときにカスタムイベントを発生させることができます。

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

それ以外の場合は、かなりのリソースを消費しますが、タイマーを設定して、要素の高さの変更を定期的にチェックできます...


スタイルを変更するコードにアクセスできる場合、これは確かに非常に優れたソリューションです。
Umair Hafeez 2014

2

jQueryまたはJavaScriptのスタイル変更イベントの組み込みサポートはありません。ただし、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

興味深い質問です。問題は、height()がコールバックを受け入れないため、コールバックを起動できないことです。animate()またはcss()を使用して高さを設定し、コールバックでカスタムイベントをトリガーします。以下は、コンセプトの証明として、テストおよび動作するanimate()を使用した例です(demo)。

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

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

8
申し訳ありませんが、これは何を証明しましたか?あなたtrigger()のイベントを手動。OPは、スタイル属性が変更されたときに自動トリガーされるイベントの後であると思います。
JPot 2010年

@JPot彼は、height属性が変更されてもイベントをスローしないことを示しています。
AnthonyJClink 2016

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はどうですか?

多分私は質問を理解していませんが、あなたが探しているものはcssHookscss()機能を変更することなく、で簡単に行うことができます。

ドキュメントからコピー:

(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.