19

Ext.app.Controller control()メソッドを使用する方法はありますが、DOMクエリを渡しますか?標準リンクを含むページがあり、それらが拡張ボタンとして作成されていない場合でも、クリックハンドラーを追加したいと思います。

私はもう試した

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

    init: function() {
        console.log("init");
        this.control({
            'a': {
                click: this.changeTab
            }   
        });
    },

    changeTab: function() {
        alert("new tab!");
    }   
});

ただし、リンクをクリックしてもアラートは発生しません。

this.controlでCSSセレクターを指定する方法はありますか?それとも、コンポーネントでのみ機能しますか?

4

5 に答える 5

39

今年の SenchaCon でこの質問をしたところ、Sencha の開発者は、DOM リスナーをビュー内にアタッチし、ビューがそれらをより意味のあるコンポーネント イベントに抽象化し、再起動することを意図していると述べました。

たとえば、人の顔のグリッドを表示する UserGallery というビューを作成しているとします。UserGallery ビュー クラス内で、<img>タグの DOM クリック イベントをリッスンしてイベントとターゲットを受け取ります。ビューは「userselected」というコンポーネント イベントを起動し、DOM ターゲットの代わりにクリックされたユーザーのモデル インスタンスを渡します。 .

最終的な目標は、ビューだけがインターフェイス イベントや DOM 要素などに関与し、アプリケーション レベルのコントローラーが意味のあるユーザー インテントのみを処理するようにすることです。アプリケーションとコントローラーのコードは、マークアップ構造またはインターフェイスの実装にまったく結合しないでください。

サンプルビュー

Ext.define('MyApp.view.UserGallery', {
    extend: 'Ext.Component'
    ,xtype: 'usergallery'

    ,tpl: '<tpl for="users"><img src="{avatar_src}" data-ID="{id}"></tpl>'

    ,initComponent: function() {
        this.addEvents('userselected');

        this.callParent(arguments);
    }

    ,afterRender: function() {
        this.mon(this.el, 'click', this.onUserClick, this, {delegate: 'img'});

        this.callParent(arguments);
    }

    ,onUserClick: function(ev, t) {
        ev.stopEvent();

        var userId = Ext.fly(t).getAttribute('data-ID');

        this.fireEvent('userselected', this, userId, ev);
    }
});

ビューに関する注意事項

  • 管理されたものだけが必要な場合は「Ext.Component」を拡張します<div>.Ext.Panelは、タイトルバー、ツールバー、折りたたみなどをサポートするために非常に重いです.
  • コンポーネントから DOM 要素にリスナーをアタッチする場合は、「マネージド」リスナーを使用します (Component.mon を参照)。コンポーネントによって管理されるリスナーは、そのコンポーネントが破棄されると自動的に解放されます
  • 複数の DOM 要素から同じイベントをリッスンする場合は、"delegate" イベント オプションを使用して、個々の要素ではなく共通の親にリスナーをアタッチします。これによりパフォーマンスが向上し、イベントリスナーを各子に継続的にアタッチ/削除することを心配することなく、子要素を任意に作成/破棄できます。のようなものを使用しないでください.select('img').on('click', handler)
  • ビューからイベントを発生させる場合、Sencha の規則では、イベントへの最初のパラメーターは、イベントscopeを発生させたビューへの参照です。これは、イベント ハンドラーの実際のスコープがコントローラーである必要があるコントローラーからイベントが処理されている場合に便利です。

サンプルコントローラー

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

    ,init: function() {
        this.control({
            'usergallery': {
                userselected: function(galleryView, userId, ev) {
                    this.openUserProfile(userID);
                }
            }   
        });
    }

    ,openUserProfile: function(userId) {
        alert('load another view here');
    }
});
于 2012-01-04T20:11:18.257 に答える
3

この問題の回避策を見つけました。期待するほど直接的ではありませんが、すべての「アクション」コードをコントローラーに残します。

要件: ページの html セクションを実際の でラップしますExt.Component。これは、いずれにしてもそうでしょう。たとえば、次のような HTML を含む単純なビューがあるとします。

Ext.define('app.view.myView', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.myView',
    title: 'My Cool Panel',
    html: '<div><a href="#">This link will open a window</a></div><br /> <label for="myInput">Type here: </label><input name="myInput" type="text" value="" />',
    initComponent: function(){
        var me = this;
        me.callParent(arguments);
    }
});

次に、コントローラーでafterrenderイベントを使用してリスナーを DOM 要素に適用します。以下の例では、リンク (要素) と入力要素の両方を示しています。

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

    init: function() {
        this.control({
            'myView': {
               afterrender: function(cmp){
                    var me = this; //the controller
                    var inputs = cmp.getEl().select('input'); // will grab all DOM inputs
                    inputs.on('keyup', function(evt, el, o){
                        me.testFunction(el); //you can call a function here
                    });

                    var links = cmp.getEl().select('a'); //will grab all DOM a elements (links)
                    links.on('click', function(evt, el, o){ 
                        //or you can write your code inline here
                        Ext.Msg.show({
                            title: 'OMG!',
                            msg: 'The controller handled the "a" element! OMG!'
                        });
                    });
                }
            }   
        });
    },
    testFunction: function(el) {
        var str = 'You typed ' + el.value;
        Ext.Msg.show({
            title: 'WOW!',
            msg: str
        });
    }   
});

これで、コントローラー内で処理され、MVC アーキテクチャに準拠した DOM 要素が完成しました。

于 2011-09-23T21:36:02.083 に答える
1

いいえ、これは不可能のようです。Ext.EventBus は、ExtJS コンポーネントによって発生したイベントをリッスンします。標準の DOM 要素は、これらのイベントを発生させません。さらに、クエリは ExtJS コンポーネントの is( String selector ) メソッドでチェックされますが、これは DOM 要素によって呼び出すことはできません。私が間違っていれば誰かが私を訂正するかもしれませんが、残念ながらそれは不可能だと確信しています.

于 2011-05-20T10:45:23.973 に答える
0

この問題を回避する解決策もあります。他にも利点があるので、この手法を使用します。アプリケーション全体のメッセージングバスを作成しました。Observableを拡張し、いくつかのイベントを定義する、私のアプリケーションのオブジェクトです。次に、HTMLリンクを含め、アプリ内の任意の場所からこれらのイベントをトリガーできます。これらのイベントをリッスンしたいコンポーネントは、それらを中継でき、そのコンポーネントから起動されたかのように起動します。

Ext.define('Lib.MessageBus', {
    extend: 'Ext.util.Observable',

    constructor: function() {
        this.addEvents( 
                  "event1",
                  "event2"
                 );
        this.callParent(arguments);
    }
});

次に、他の各コンポーネントは、初期化後にこれを追加できます。

this.relayEvents('Lib.MessageBus', ['event1','event2']);

そして、それらのイベントを聞いてください。次の手順を実行することで、何からでもイベントをトリガーできます。

Lib.MessageBus.fireEvent('event1', 'param a', 'param b')

そしてあなたはhtmlリンクを含む何からでもそれをすることができます。

アプリのある部分から別の部分にイベントを発生させるのに非常に便利です。

于 2013-03-18T14:46:01.450 に答える