6

私がオンラインで見つけたSenchaTouchの例の多くは、適切なビューのカプセル化に焦点を当てていません。そのため、ボタンがビュー内に深くネストされている場合でも、コントローラーはすべてのボタンのイベントをリッスンします。言い換えれば、ビューの内部がリークし、それは決して良いことではありません。

地元のイベントに耳を傾け、意味のあるビジネスイベントなどを提起する意味のあるビューを作成することを奨励する1つの優れたチュートリアルを見つけました。

http://miamicoder.com/2012/how-to-create-a-sencha-touch-2-app-part-2/

ただし、これまで実際に理解できなかったことの1つは、ネストされたコンポーネントインスタンスを最適にキャッシュする方法です。この例を考えてみましょう。

Ext.define("NotesApp.view.NotesListContainer", {
    extend: "Ext.Container",
    alias: "widget.noteslistcontainer",

    initialize: function () {

        this.callParent(arguments);

        var newButton = {
            xtype: "button",
            text: 'New',
            ui: 'action',
            handler: this.onNewButtonTap,
            scope: this
        };

        var topToolbar = {
            xtype: "toolbar",
            title: 'My Notes',
            docked: "top",
            items: [
                { xtype: 'spacer' },
                newButton
            ]
        };

        this.add([topToolbar]);
    },
    onNewButtonTap: function () {
        console.log("newNoteCommand");
        this.fireEvent("newNoteCommand", this);
    },
    config: {
        layout: {
            type: 'fit'
        }
    }
});

にメソッドを追加したいとsetSpecialUIStateしますNotesListContainer。それが呼び出されたとき、私たちは何かをしたいですnewButton(例えばそれを隠す)。newButton悪用せずにインスタンスにアクセスするにはどうすればよいExt.getComp()ですか?インスタンス変数として設定できますか?正規の方法はどうですか?

アップデート

Nikolaj Borisikが提案したように、私はこれを試しました。

    this._newButton = this.add([{
            xtype: "button",
            text: 'New',
            ui: 'action',
            handler: this.onNewButtonTap,
            scope: this
        }];

それは魅力のように機能します。そうするのが慣用的であるかどうか、または私が見逃しているかもしれない欠点があるかどうかはわかりません。それ以外の場合は、これを行うことを強くお勧めします。Senchaはさておき、一貫性のあるUIパーツを抽象化する意味のあるビューを作成する方がはるかに優れています。これは、すべてのボタンをコントローラーにリークして直接いじるよりもはるかに優れています。

それで、このアプローチの欠点はあるのだろうか?

4

3 に答える 3

3

getComponent()を使用する以外に、2つのオプションがあります。

1インスタンスコンポーネントにExt.create(...)を使用する

initialize: function () {        
   this.callParent(arguments);
   this.newButton = Ext.create('Ext.Button',{
      xtype: "button",
      text: 'New',
      ui: 'action',
      handler: this.onNewButtonTap,
      scope: this
   });
   //....
},

setSpecialUIState : function(){
   this.newButton.hide()
}

2このロジックをコントローラーに移動し、refsセクションを使用します

Ext.define('NotesApp.controller.Home',{
        extend : 'Ext.app.Controller',

        config : {
            refs :{
                newButton : '#noteList [itemId=newButton]'
            },

            control :{
                newButton : {
                    tap : 'onNewButtonTap'
                }
            }

        },

        onNewButtonTap : function(){
            console.log('on new Button tap');
        },

        setSpecialUIState : function(){
           this.getNewButton.hide()
        }

    });



Ext.define("NotesApp.view.NotesListContainer", {
    extend :"Ext.Container",
    alias  :"widget.noteslistcontainer",
    id     :'noteList',
    config:{
        items:[
            {
                xtype  :"toolbar",
                title  :'My Notes',
                docked :"top",
                items:[
                    { xtype:'spacer' },
                    {
                        xtype   :"button",
                        text    :'New',
                        ui      :'action',
                        itemId  :'newButton'
                    }
                ]
            }
        ]

    }
});

私は2番目のオプションを好みます

私は両方のオプションを使用しますが、ケースが異なります。最初のオプションは、アプリケーションの他の部分や他のプロジェクトでさえ再利用できるコンポーネントに適していると思います。ただし、1回だけ使用できるビューを作成する場合、ビューからカスタムイベントを発生させる必要はないと思います。さらにコードを記述し、それを複製します。はい、「newNoteCommand」は「tap」よりも明確ですが、{control:'#noteList [itemId='newButton']は必要なすべての情報を提供します。次に、コンポーネントが深くネストされている場合に、2番目のオプションを選択する理由。この場合、コントローラーが処理する機会が得られるまで、親からのイベントの発生などではなく、最初のコンポーネントでイベントを発生させる必要があります。

于 2012-09-17T18:50:00.630 に答える
1

MVVMアーキテクチャはあなたの考え方に近いと思います。「VM」には、ビューとデータ/アクションを橋渡しするコンポーネントのようなコントローラーがあります。KnockoutJSはこのパラダイムに従い、データ処理をビューに埋め込みます。

サーバー側のMVCパターンから来て、JSPにコードを埋め込むことは大したことではありませんでした。データをレンダリングするために最小限のロジックを実行できるタグのみを使用しました。そして、コードの保守性を大幅に向上させるために一貫した方法でこれを行うことについては、言わなければならないことがあります。

しかし、あなたのように、私はすべてのボタンハンドラーのコントローラーを参照するのは少し圧倒的であることに気づきました。私の行動の論理がどこに行くのかを理解する上で、あなたは判断力を行使できると思います。アクションが再利用可能な場合は、必ずDRYプリンシパルを使用してください。ロジックが制限された単純なビュー固有の操作を実行している場合は、コントローラーをスキップする可能性があります。

あなたの見解をよく知っているコントローラーに対処するために...私はそれがリファクタリングの問題を引き起こすことに同意します。これを回避するには、ボタンハンドラーを作成して、親ビューからカスタムイベントを発行します。このように、コントローラーは、既に認識しているビューコンポーネントからのイベントをリッスンする必要があります。欠点は、senchaがイベントで行うように、カスタムイベントのより多くの配列が必要であり、それらを非常にうまく文書化することです。そうしないと、保守性も低下します。

于 2012-09-19T17:22:07.250 に答える
1

煎茶ともっと時間を過ごした後、私はについて間違った仮定をしていることに気づきましたExt.getCmp()。これは、最初にDOMにクエリを実行して一致するIDを見つけ、次にそれにバインドされているコンポーネントインスタンスを取得しようとすると思いました。しかし、それはそれがすることではありません。実際、DOMにはまったくクエリを実行しません。使用されているすべてのコンポーネントへの参照を保持するComponentManagerと呼ばれる機能を照会するだけです。

だから、それを使うのはそれほど汚いことではありません。しかし、それでももっとうまくやることができます。

すべてのコンテナは、メソッドchild(selector)をサポートし、down(selector)サブコンポーネントを照会します。一見すると、これはDOMにクエリを実行しているように見えますが、これもComponentManagerにのみクエリを実行します。開始点でコンテナを使用し、その内部アイテムを照会します。両方の違いは、child(selector)最初のサブレベルのみをクエリするのに対し、down(selector)すべてのサブレベルをクエリすることです。

それらを使用して、これらのサブコンポーネントを処理することは問題ないと思います。ただし、これらのメソッドを繰り返し呼び出すためにパフォーマンスの問題がまだある場合は、最初の取得後にそれらをキャッシュすることをお勧めします。

于 2012-10-08T11:56:31.150 に答える