web-dev-qa-db-ja.com

onclick = "" vsイベントハンドラ

関数を実行したい場合は、インラインjsを実行します。

<p id="element" onclick="doSomething();">Click me</p>

デバッグが簡単だからです。

ただし、インラインjsを使用しないように言われる人々の声を聞いて、次のようにします。

document.getElementById('element').onclick = doSomething;

Jsイベントリスナーが推奨されるのはなぜですか?

34
Johan

基本的にそれは全体と関係があり、私が信じているすべてのものを別々に保ちます。したがって、HTML/CSS/JSはすべて分離してください。これにより、HTMLが整然となり、ナビゲートしなくてもナビゲートしやすくなります。

次に、大きな変更が必要な場合/必要な場合は、インラインJSを外部ファイルにシフトする必要があるため、十分なスペースがありますOR複数のボタンに同じ機能を適用する場合、それからそれはより少ないコードですそしてより少ないコードはより幸せな場所です

JSファイルが適切にあり、完全に文書化されている場合、外部の人がそれらをナビゲートするのが簡単になります

13
LeeR

インラインイベントハンドラーに対する1つの大きな引数、およびここで他の回答によって対処される引数は プレゼンテーションとロジックの分離 です。

ただし、実際にはもっと大きな問題IMOがあります。インラインイベントハンドラーが評価される方法がどういうわけかわかりにくい方法です。

ご存知かもしれませんが、_on*_属性の内容は、イベントハンドラー関数のbodyとして使用されます。しかし、この関数にはどのような特徴がありますか?

驚くべきものの1つは、一部の祖先要素のプロパティおよび要素自体のプロパティが、インラインイベントハンドラのscopeにあることです。

_<form>
    <input name="foo" />
    <button type="button" onclick="console.log(foo); console.log(window.foo);">
        Click me
    </button>
    <div onclick="console.log(foo);">Click me as well!</div>
</form>_

buttonログをクリックする

_<input name="foo"></input>
undefined
_

コンソールで。 _window.foo_がundefinedであるという事実は、グローバル変数fooがないことを示しています。では、変数fooはどこから来るのでしょうか。なぜconsole.log(foo)は入力要素をログに記録し、参照エラーをスローしないのですか?
form要素のプロパティはイベントハンドラーのスコープ内にあり、form要素には、それに含まれる名前付きフォームコントロール要素ごとにプロパティがあるためです。これはconsole.log(document.querySelector('form').foo)で簡単にテストできます。

ここで、div要素をクリックすると、実際に参照エラーがスローされます。

_ReferenceError: foo is not defined_

つまり、form要素はフォームコントロール要素のスコープ内にのみあり、子孫はありません。それはどのように混乱していますか?

同様に、 document オブジェクトのプロパティもインラインイベントハンドラーのスコープ内にあります。これは いくつかの驚くべきバグにつながる可能性がありますdocumentにはプロパティplugins?)があります。

インラインイベントハンドラーの正確な評価方法は HTML5仕様 で形式化されています。特にスコープチェーンの作成が説明されているステップ10でループを作成します。


結論

要素とインラインイベントハンドラーの間のこのimplicit接続のため、バグの追跡は本当に難しい場合があります。もちろん、何かをテストするだけの場合は、インラインイベントハンドラーを使用することもできます。ただし、量産コードでそれらを使用すると、メンテナンスコストが高くなります。

quirksmode.orgの記事 イベントハンドラーをバインドするさまざまな方法とそれらの(欠点)の利点を非常によく説明しています。

40
Felix Kling

インラインJavaScriptを回避する理由はたくさんあり、おそらく最も重要なものの1つはコードの保守性です。

簡単な例(単にデモンストレーションの目的でjQueryを使用しています)。

<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>

突然、すべての段落を変更して別の関数を実行するように要求された場合はどうなりますか?あなたの例では、HTMLコードのすべてを手動で変更する必要があります。ただし、JavaScriptからHTMLを分離することを選択した場合は、次のようにすることができます。

<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>

$('.element').bind('click', doSomethingElse);

HTMLコードもよりクリーンで、デザイナーが他の人も関与するプロジェクトで作業しているときに実際に何かが壊れるのではないかと心配することなく、設計に専念できます。

編集:以下のコメントの例を示します。

Project = {
    // All the variables/constants/objects that need to be globally accessible inside the Project object.

    init : function(){
        // Main entry point...
        this.MainMenu.init();

        // Rest of the code which should execute the moment Project is initiated.
    }
}

Project.MainMenu = {
    // All the variables/constants/objects that need to be accessible only to MainMenu.

    init : function(){ // Is run immediatelly by Project.init()
        // Event handlers relevant to the main menu are bound here

        // Rest of the initialization code
    }
}

Project.SlideShow = {
    // All the variables/constants/objects that need to be accessible only to SlideShow.

    init : function(){ // Is run only on pages that really require it.
        // Event handlers for the slideshow.
    }
}
4
brezanac

他の人が何を考えているかにかかわらず、マークアップでリスナーをインライン化することには価値があると思います。具体的には、DOMノードを変更する自由度が大幅に向上します。 JavaScriptを介してリスナーを追加する場合、親ノードのinnerHTMLを置き換えると、リスナーは失われます。リスナーをマークアップでインライン化する場合は、ノードを複製し、ノードに変更を加えてから、元のノードを複製して変更したノードで置き換えることができます。

おそらく、特定のユースケースで説明する方が良いでしょう。リフローを何度もトリガーせずに、ドキュメントの複数の部分に変更を加えたいです。したがって、この場合、ノードのクローンを作成し、ノードに変更を加え(デタッチされているためリフローなし)、前のノードを変更されたノードに置き換える(リフローをトリガーする)ことができます。インライン化されたリスナーを使用すると、置換中にリスナーが失われるのを防ぎます。

3
ming_codes

プレゼンテーションとビジネスロジックに関する懸念を分離する必要があると言う人もいます。

彼の例のOPは確かにこの分離を示しています!インラインイベントハンドラーにはロジックはありませんが、「クリック」イベントで実行される関数参照/呼び出しのみです。ロジック自体は、他の場所で個別に維持できます。

論理的なフローの発見可能性のため、私は個人的にこのアプローチを好みます。これまでにアプリケーションを見たことがない場合...コードトラバーサルを開始する最初の場所はDOMであり、そこにどのイベントハンドラーが機能していて、どの関数がロジックを提供しているのかが明確になります。ハンドラ。使用して、「JQuery.On」イベンティングアプローチを言うと、htmlをざっと見ただけでは、どのハンドラーが実際に接続されて機能を提供しているかがわかりません。

関数へのポインタを提供するだけのインラインイベントハンドラは、イベントを単純に関連付けて、ロジックをプレゼンテーションにリークしません。

2
ProxyTech

コーディング標準の観点から離れて

属性の使用:

<p id="element" onclick="doSomething();">Click me</p>

同じ属性を再度追加した場合(以下を参照)-最新の属性が考慮されます。

<p id="element" onclick="doSomethingMore();">Click me</p>

イベントハンドラの使用:

document.getElementById('element').onclick = doSomething;

以下の行を追加したとしましょう

document.getElementById('element').onclick = doSomethingMore;両方のハンドラーが呼び出されます。

0
Shekhar Reddy

CSSとインラインスタイルを含めることについても同じことが言えます。現在のクラス/ ID、または作業中の親/子要素を見つけるために、CSSファイルをたどる必要がないのは簡単です。

クリックをバインドしてインラインで10の異なるアイテムを言う方が本当に良いですか?または、クラスをターゲットとする1つのイベントハンドラだけですか? 10個のクリックハンドラーが必要ない場合でも、保守性を確保するためにコードを設定し、将来的にアップグレードすることをお勧めします。

0
Loktar

インラインハンドラーを使用することと、後でハンドラーをアタッチすることの違いを私は知りません。私の経験では、動的要素を処理する必要がある場合、たとえば、各画像にハンドラーを追加したい場合や、画像の数が他のデータに応じて変化する場合(例:dbの画像)、インラインメソッドを使用することを好みます。この場合、インラインを使用して、各画像にハンドラーを追加できます。それ以外の場合、JavaScriptファイル内の画像の数を再計算して、各画像に添付してハンドラーを作成する必要があります。

もちろん、要素のリストをインラインで簡単に取得できるjQueryのようなライブラリを使用できる場合は、役に立ちません

0
wezzy