1. ホーム
  2. javascript

[解決済み] "AngularJSで考える "って、jQueryのバックグラウンドがあれば?[終了しました]

2022-03-15 16:26:24

質問

でクライアントサイドのアプリケーションを開発することに精通しているとします。 jQuery を使い始めたいのですが。 アンギュラーJS . 必要なパラダイムシフトを説明できますか?以下は、答えを導き出すのに役立つかもしれないいくつかの質問です。

  • クライアントサイドのWebアプリケーションのアーキテクチャーと設計はどのように違うのでしょうか?最大の違いは何ですか?
  • 何をやめ、何を始めるべきか?
  • サーバー側で考慮すべきこと、制限事項はありますか?

との詳細な比較を求めているわけではありません。 jQueryAngularJS .

解決方法は?

1. ページをデザインした後、そのページを DOM 操作

jQueryでは、ページをデザインして、それを動的にする。これは、jQueryが拡張のために設計され、その単純な前提から信じられないほど成長したためです。

しかし、AngularJSでは、アーキテクチャを一から考えなければなりません。DOMのこの部分を持っていて、これをX"させたい」と考えるのではなく、「何を達成したいか」から始めて、アプリケーションを設計し、最後にビューを設計する必要があります。

2. AngularJSでjQueryを補強してはいけない

同様に、jQueryでX、Y、Zができるから、その上にモデルやコントローラ用にAngularJSを追加しようという発想で始めるのはやめましょう。これは 本当に 少なくともAngularJSのやり方に慣れるまでは、jQueryを使わないことをお勧めします。

私は、ここやメーリングリストで多くの開発者が、150行から200行のコードからなるjQueryプラグインで精巧なソリューションを作り、それをコールバックの集合体と $apply しかし、彼らは最終的にそれを動作させることができます。問題は 最も jQueryプラグインをAngularJSで書き直せば、わずかなコードで、突然、すべてが理解でき、簡単になります。

解決策を考えるときは、まずAngularJSで考え、解決策が思いつかないときはコミュニティに質問し、それでも簡単には解決できないときは、その場で解決する。 では jQueryに手を伸ばすのは自由です。しかし、jQueryが松葉杖にならないように、さもなければ、AngularJSをマスターすることはできません。

3. 常にアーキテクチャの観点で考える

まず知っておきたいこと シングルページ・アプリケーション アプリケーション . それらは ではない ウェブページになります。だからサーバーサイドの開発者のように考える必要があるのです さらに クライアントサイドの開発者のように考えるだけでなく アプリケーションを個々の拡張可能でテスト可能なコンポーネントに分割する方法について考えなければなりません。

それでは どのように をするのですか?AngularJSでどのように考えるのでしょうか?ここでは、jQueryと対比して、いくつかの一般的な原則を紹介します。

ビューは公式記録です。

jQueryでは、プログラムによってビューを変更します。ドロップダウン・メニューを ul というように

<ul class="main-menu">
    <li class="active">
        <a href="#/home">Home</a>
    </li>
    <li>
        <a href="#/menu1">Menu 1</a>
        <ul>
            <li><a href="#/sm1">Submenu 1</a></li>
            <li><a href="#/sm2">Submenu 2</a></li>
            <li><a href="#/sm3">Submenu 3</a></li>
        </ul>
    </li>
    <li>
        <a href="#/home">Menu 2</a>
    </li>
</ul>

jQueryでは、アプリケーションのロジックで、以下のような感じで有効化することになります。

$('.main-menu').dropdownMenu();

ビューを見ただけでは、ここに何か機能があることはすぐにわかりません。小さなアプリケーションであれば、それでも構いません。しかし、そうでないアプリケーションでは、すぐに混乱し、メンテナンスが難しくなります。

しかし、AngularJSでは、ビューはビューベースの機能を公式に記録するものです。私たちの ul の宣言は、代わりに次のようになります。

<ul class="main-menu" dropdown-menu>
    ...
</ul>

この2つは同じことをするのですが、AngularJS版では、テンプレートを見れば、何が起こるのかがわかります。開発チームの新しいメンバーが参加するときはいつでも、このテンプレートを見て、それから 知っている というディレクティブがあること dropdownMenu 正しい答えを直感したり、コードを吟味したりする必要はないのです。ビューは、何が起こるべきかを教えてくれるのです。ずっとすっきりしています。

AngularJSを初めて使う開発者はよく、「特定の種類のリンクをすべて見つけて、その上にディレクティブを追加するにはどうすればいいか」というような質問をします。私たちが「できない」と答えると、開発者はいつもあきれ顔です。しかし、そうしない理由は、これは半分jQuery、半分AngularJSのようなもので、良いことはないからです。この問題は、開発者がAngularJSのコンテキストでjQueryを使おうとしていることです。これは決してうまくいくものではありません。ビュー が公式記録となります。指令以外では(詳細は後述します)、絶対に 決して は DOM を変更します。そして、ディレクティブは適用される ビューで というように、意図が明確です。

覚えておいてほしいのは、デザインしてからマークアップしてはいけないということです。設計してからマークアップするのではなく、アーキテクトしてから設計するのです。

データバインディング

これはAngularJSの最も素晴らしい機能の1つで、前のセクションで述べたようなDOM操作の必要性を大幅に削減することができます。AngularJSは自動的にビューを更新するので、あなたはその必要がありません。jQueryでは、イベントに応答して、コンテンツを更新します。みたいな感じですね。

$.ajax({
  url: '/myEndpoint.json',
  success: function ( data, status ) {
    $('ul#log').append('<li>Data Received!</li>');
  }
});

このようなビューの場合。

<ul class="messages" id="log">
</ul>

懸念の混在とは別に、先ほどのインテントの意味付けの問題もあります。しかしもっと重要なのは、DOMノードを手動で参照し更新しなければならないということです。また、ログ・エントリーを削除したい場合は、そのためのコードもDOMに対して書かなければなりません。DOM とは別に、どのようにロジックをテストすればいいのでしょうか?また、プレゼンテーションを変更したい場合はどうすればよいのでしょうか?

これはちょっと面倒で、ひ弱な感じですね。しかし、AngularJSでは、これができるのです。

$http( '/myEndpoint.json' ).then( function ( response ) {
    $scope.log.push( { msg: 'Data Received!' } );
});

そして、ビューは次のようになります。

<ul class="messages">
    <li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>

しかし、それよりも、私たちのビューは、次のように見えるかもしれません。

<div class="messages">
    <div class="alert" ng-repeat="entry in log">
        {{ entry.msg }}
    </div>
</div>

そして今、順番なしリストの代わりに、Bootstrap のアラートボックスを使用しています。しかも、コントローラのコードを変更する必要はありません。しかし、もっと重要なのは どこ または どのように ログが更新されると、ビューも変更されます。自動的に。すてきですね。

ここでは紹介しませんでしたが、データバインディングは双方向です。ですから、このようにすることで、ログメッセージもビューで編集できるようになります。 <input ng-model="entry.msg" /> . そして、多くの喜びの声が上がりました。

識別可能なモデル層

jQueryでは、DOMがモデルのようなものです。しかしAngularJSでは、ビューから完全に独立して、好きなように管理できる独立したモデル層があります。これは、上記のデータバインディングのために役立ちます。 懸念の分離 そして、より高いテスト容易性を実現します。この点については、他の回答でも触れられているので、この辺にしておきます。

懸念事項の分離

そして、上記のすべてが、この包括的なテーマと結びついています。ビューは、何が起こるのかを公式に記録し、モデルはデータを表し、再利用可能なタスクを実行するサービスレイヤーを持ち、DOM操作を行い、ディレクティブでビューを拡張し、コントローラですべてをつなぎ合わせます。これは他の回答でも言及されていますが、私が唯一付け加えたいのは、以下の別のセクションで説明するテスト容易性に関することです。

依存性注入

懸念の分離を支援するために 依存性注入 (DI)といいます。サーバーサイドの言語から来た場合( Java から PHP しかし、あなたがjQueryから来たクライアントサイドの人であれば、このコンセプトは馬鹿げていたり、余計なことをしていたり、ヒップスターに見えたりすることでしょう。しかし、そんなことはありません :-)

DIとは、広い意味で、コンポーネントを非常に自由に宣言でき、他のコンポーネントから、そのインスタンスを要求すれば、それが与えられるということです。読み込み順とか、ファイルの場所とか、そういうことは知らなくていいんです。その威力はすぐに目に見えるものではないかもしれませんが、ここでは一つの例として、テストについて説明します。

例えば、私たちのアプリケーションで、サーバーサイドのストレージを REST また、アプリケーションの状態によっては、ローカルストレージも使用できます。コントローラのテストを行う際に、サーバと通信する必要がないようにしたいものです。 コントローラ ということです。元のコンポーネントと同じ名前のモックサービスを追加すれば、 インジェクタが自動的に偽物のサービスを取得するようになります。

テストといえば...。

4. テスト駆動開発 - 常に

これは本当は第3章「アーキテクチャ」の一部なのですが、非常に重要なので、独立したトップレベルのセクションとして置いています。

あなたがこれまでに見たり、使ったり、書いたりした多くのjQueryプラグインの中で、テストスイートが付属していたものはいくつありましたか?jQueryはテストにあまり従順ではないので、あまり多くはありません。しかし、AngularJSはそうです。

jQueryでは、多くの場合、テストがDOM操作を実行できるサンプル/デモページとコンポーネントを独立して作成することしかできません。そのため、コンポーネントを個別に開発する必要があります。 では アプリケーションに組み込むことができます。なんて不便なんでしょう。このように、jQueryを使った開発では、テスト駆動開発ではなく、反復開発を選択することが多いのです。そして、誰が私たちを責めることができるでしょうか?

しかし、AngularJSでは懸念事項の分離が可能なため、テスト駆動開発を繰り返し行うことができるのです 例えば、現在のルートが何であるかをメニューに表示する超簡単なディレクティブが必要だとします。アプリケーションのビューで、欲しいものを宣言することができます。

<a href="/hello" when-active>Hello</a>

さて、これで存在しない when-active ディレクティブを使用します。

it( 'should add "active" when the route changes', inject(function() {
    var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );

    $location.path('/not-matching');
    expect( elm.hasClass('active') ).toBeFalsey();

    $location.path( '/hello' );
    expect( elm.hasClass('active') ).toBeTruthy();
}));

そして、テストを実行すると、失敗することが確認できます。ここで初めて、ディレクティブを作成する必要があります。

.directive( 'whenActive', function ( $location ) {
    return {
        scope: true,
        link: function ( scope, element, attrs ) {
            scope.$on( '$routeChangeSuccess', function () {
                if ( $location.path() == element.attr( 'href' ) ) {
                    element.addClass( 'active' );
                }
                else {
                    element.removeClass( 'active' );
                }
            });
        }
    };
});

これでテストは成功です のメニューは要求通りに動作します。私たちの開発は どちらも 反復的 テストドリブン。とてもクールです。

5. 概念的には、ディレクティブは ではなく パッケージされたjQuery

よく、「DOM操作はディレクティブの中だけで行いましょう"」と言われます。 これは必需品です。 ぞんざいに扱ってはいけません

でも、もう少し深く掘り下げてみると...。

ディレクティブの中には、すでにビューにあるものを装飾するだけのものもあります (たとえば ngClass そのため、すぐに DOM 操作を行い、基本的に終了することもあります。しかし、もしディレクティブがウィジェットのようなもので、テンプレートがあるならば、それは また は関心事の分離を尊重します。つまり、テンプレート は、リンクやコントローラ関数での実装から大きく独立している必要があります。

AngularJSには、これを非常に簡単にするためのツール一式が付属しています。 ngClass を使用すると、クラスを動的に更新することができます。 ngModel は双方向のデータバインディングを可能にします。 ngShowngHide プログラムによる要素の表示/非表示、その他多数 - 自分たちで書いたものも含む。言い換えれば、私たちはあらゆる種類の素晴らしいことをすることができるのです。 を使わずに DOM操作。DOM操作が少なければ少ないほど、ディレクティブのテストが容易になり、スタイル付けが容易になり、将来的な変更が容易になり、再利用や配布が可能になるのです。

AngularJSを初めて使う開発者の多くが、ディレクティブをjQueryの束を放り込む場所として使っているのを見かけます。言い換えれば、彼らは「コントローラでDOM操作ができないから、そのコードをディレクティブに入れよう」と考えているのです" 。確かにその方がずっといいのですが、多くの場合、それは まだ間違っている .

3節でプログラミングしたロガーを考えてみてください。それをディレクティブの中に入れたとしても、私たちは それでも は、quot;Angular Way"で行いたいものです。それは 今も は、DOM操作を一切必要としません! DOM操作が必要な場合もたくさんありますが、それは ロット あなたが思っているよりも稀なことなのです。DOM操作の前に どこでも は、本当に必要なのか、自問自答してください。もっと良い方法があるかもしれません。

私が最も頻繁に目にするパターンを示す簡単な例を挙げます。トグル可能なボタンが欲しい。(注:この例は、全く同じ方法で解決されるより複雑なケースを表現するために、少し工夫して冗長にしています)。

.directive( 'myDirective', function () {
    return {
        template: '<a class="btn">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            var on = false;

            $(element).click( function () {
                on = !on;
                $(element).toggleClass('active', on);
            });
        }
    };
});

これにはいくつか間違いがあります。

  1. まず、jQueryは決して必要ではありませんでした。ここでやったことで、jQueryが必要だったことはまったくありません。
  2. 第二に、たとえページにすでにjQueryがあったとしても、ここでそれを使う理由はありません。 angular.element このコンポーネントは、jQueryを搭載していないプロジェクトにドロップしても動作します。
  3. 第三に、jQuery を前提とした場合でも でした。 は、このディレクティブが動作するために必要なもので、jqLite ( angular.element ) は 常に jQueryがロードされていれば、それを使用します。そのため $ - を使用すればよいのです。 angular.element .
  4. 4つ目は、3つ目と密接に関連するが、jqLiteの要素は、ラップする必要がないことである。 $ - その element に渡される link 関数は すでに jQueryの要素です。
  5. そして5つ目は、これまでのセクションでも触れてきたことですが、なぜテンプレートのものをロジックに混ぜているのでしょうか?

このディレクティブは、(非常に複雑なケースでも!)もっとシンプルに、次のように書き換えることができます。

.directive( 'myDirective', function () {
    return {
        scope: true,
        template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            scope.on = false;

            scope.toggle = function () {
                scope.on = !scope.on;
            };
        }
    };
});

繰り返しになりますが、テンプレートのものはテンプレート内にあるので、あなた(またはあなたのユーザー)は必要なスタイルに合ったものに簡単に交換することができます。 ロジック は触る必要がありませんでした。再利用性 - ドーン!

さらに、テストが容易であるなど、他の利点もあります。テンプレートに何が書かれていても、ディレクティブの内部APIには一切触れないので、リファクタリングが簡単です。ディレクティブに触れることなく、好きなだけテンプレートを変更することができます。そして、何を変更しても、テストはパスします。

w00t!

では、ディレクティブが単なるjQueryのような関数の集まりでないとしたら、それは何なのでしょうか?ディレクティブは実際には HTMLの拡張 . HTMLがやってくれないことを、代わりにやってくれるディレクティブを書き、それをあたかもHTMLの一部であるかのように使うのです。

別の言い方をすれば、もしAngularJSがいきなり何かをしないなら、チームがどのようにそれを成し遂げるか考えてください。 ngClick , ngClass などがあります。

概要

jQueryも使わないでください。入れるのもやめましょう。足かせになります。そして、jQueryで解決する方法をすでに知っていると思うような問題にぶつかったとき、jQueryを使う前に $ AngularJSの中でどうやったらできるかを考えてみてください。わからなければ聞いてみてください。20回中19回は、jQueryを必要としない最善の方法であり、jQueryで解決しようとすることは、結果的にあなたの仕事を増やすことになるのです。