前の記事で、このようなトピックに触れました。コードの整理方法、ファサードとは何か、ビルド方法、コンポーネントとは何か。
この中で、3つのことに触れます。コンポーネントアーキテクチャについての議論を続け、プラグインとは何か、そしてそれらがアーキテクチャでどのように役立つかを調べ、その結果、いくつかのヒントを提供します。
モノリシックコンポーネント
フォーラムにアクセスするか、Extの使用例を見ると、ほとんどの場合、さまざまなオブジェクトがファイル全体に散らばって散らばり、最終的に1つのコンポーネントにアタッチされます。 例:
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
Copy Source | Copy HTML /** <br/> * somefile.js <br/> * @copyright (c) 2009, by someone <br/> * @date 20 November 2009 <br/> * <br/> */ function entityAdd(button, e){ /* */ } function entityRemove(button, e){ /* */ } function entityEdit(button, e){ /* */ } var somestore = new Ext.data.JsonStore({ /* */ }); var somewindow = new Ext.Window({ /* */ }) Ext. namespace ( "Application" ); Application.Grid = Ext.extend(Ext.grid.GridPanel, { initComponent: function () { Ext.apply( this , { store: somestore , bbar: new Ext.PagingToolbar({ pageSize: 50 , store: somestore , displayInfo: true , displayMsg: "Displaying accounts {0} - {1} of {2}" , emptyMsg: "No accounts to display" }) , tbar: new Ext.Toolbar({ , items: [{ , text: "Add" , handler: entityAdd },{ , text: "Edit" , handler: entityEdit },{ , text: "Remove" , handler: entityRemove }] }) }); Application.Grid.superclass.initComponent.apply( this , arguments); } }); Ext.reg( "applicationgrid" , Application.Grid);
コンポーネントクラスがリポジトリにアクセスし、そのコンテキスト外で機能することに注意してください。 このアプローチは、多くの問題につながるため、大規模なプロジェクトにはまったく適していません。
- クラスのインスタンスを複数持つことができ、それらはすべて同じリポジトリ/ウィンドウにアクセスします。
- ウィンドウの場合、ウィンドウから発信者に簡単にアクセスする機会はありません。
- ストレージの場合、あるグリッドインスタンスのデータが別のグリッドインスタンスに表示されるリスクがあります。
- どちらの場合も、オブジェクトのライフサイクルに対する制御は限られています。 したがって、グリッドからメモリを解放する場合、外部リソースを「アライブ」のままにする必要があります。
これらの問題を解決するために何を提供できますか? 「モノリシック」コンポーネントを作成することをお勧めします。 つまり すべての外部リソースがグリッドクラスのメンバーになるように設計します。 前の例を取り上げると、私が意味するコードは次のとおりです。
Copy Source | Copy HTML
- 内線 名前空間 ( "アプリケーション" );
- Application.Grid = Ext.extend(Ext.grid.GridPanel、{
- initComponent: function (){
- //ダイアログボックスを設定します
- Ext.apply( this 、{
- somewindow: 新しい Ext.Window({ / *ウィンドウ設定* / })
- });
- //リポジトリを設定します
- Ext.apply( this 、{
- store: 新しい Ext.data.JsonStore({ / *ストレージ設定* / }); // [1]
- });
- //ツールバーをカスタマイズします
- Ext.apply( this 、{
- bbar: 新しい Ext.PagingToolbar({
- pageSize:RESOURCES.SETTINGS.RECORDS_PER_PAGE // [2]
- 、ストア: this .store
- 、displayInfo: true
- 、displayMsg: 「{2}のアカウント{0}-{1}を表示しています」
- 、emptyMsg: 「表示するアカウントがありません」
- })
- 、tbar: 新しい Ext.Toolbar({
- 、アイテム:[{
- 、テキスト: 「追加」
- 、ハンドラー: this .entityAdd.createDelegate( this ) // [3]
- }、{
- 、テキスト: 「編集」
- 、ハンドラー: this .entityEdit.createDelegate( this )
- }、{
- 、テキスト: 「削除」
- 、ハンドラー: this .entityRemove.createDelegate( this )
- }]
- })
- });
- Application.Grid.superclass.initComponent.apply( this 、引数);
- }
- 、onDestroy: function (){
- this .somewindow.destroy();
- Application.Grid.superclass.onDestroy.call( this );
- }
- 、entityAdd: 関数 (ボタン、e){ / *エンティティを追加するためのコード* / }
- 、entityRemove: 関数 (ボタン、e){ / *エンティティ削除コード* / }
- 、entityEdit: function (button、e){ / *エンティティ編集コード* / }
- 、somewindow:未定義
- });
- Ext.reg( "applicationgrid" 、Application.Grid);
[1]少なくとも2つのExt.applyブロックが必要です。 1つ目はリポジトリを設定することであり、2つ目はページネータを設定することです。 理由:リポジトリとページネータの定義を1つのExt.applyブロックに入れると、ページネータはthis.storeによってリポジトリを参照できなくなります(this.storeブロックが実行されるまで、未定義を保存します)。
[2] 前の記事を参照
[3] createDelegateの説明については、 こちらをご覧ください 。 また、ExtJSのスコープを簡単に伝える価値があります(多くの場合、構成内の関数またはプロパティへの引数として表示されます)。 チュートリアルには、フレームワークでこの人気のある用語についてアクセス可能な説明があります。 ただし、単純な場合、スコープはコンテキストとして関数に渡されるオブジェクトです(つまり、関数内のthisはスコープの値と等しくなります)。
それで、コンポーネント設計に対するモノリシックなアプローチで何が得られるでしょう。 createDelegateと組み合わせて、予測可能な動作を持つコンポーネントを取得し、上記のすべての問題を取り除きます。 これまでのところ、この設計方法は私を決して失敗させたことがなく、経験が示すように、チュートリアルで説明するスカラーではなく、OOPのかなり良い実装を取得します。
コンポーネント設計の微妙な点をいくつか調べた後、次のトピックであるプラグインのトピックに進むことができます。
プラグイン
Ext.Componentクラスの各子孫にはpluginsプロパティがあります。 プラグインは通常の関数にすることができます(このオプションはテストしていません)が、ほとんどの場合、必要なinitメソッドのみを持つExt.util.Observableの子孫です。 それらの書き方をここに書いています 。 そして、プラグインとコンポーネントを使用した設計アプローチの違いを説明する簡単な記事があります。 記事を簡単に説明すると、次のようなものが出てきます。プラグインはコンポーネントの小さなアドオンに適しています。 これらは、コンポーネントから簡単に追加および削除できます。 コンポーネントはアプリケーションにより多く結び付けられ、クラスの一般的な外観の設計に適しています。
これらの記事を少し拡張したいと思います。 最初に、ページングを設計するとき、どのようなコンテキストで使用できるかを検討します。 たとえば、グリッドに機能を追加する場合は、ドロップダウンリストでプラグインのコレクションにプラグインを簡単に追加できることを考慮する必要があります。 このような操作を確認するのは非常に簡単です。
Copy Source | Copy HTML
- 内線 名前空間 ( "Ext.ux" );
- Ext.ux.Plugin = Ext.extend(Ext.util.Observable、{
- init: function (grid){
- if (grid instanceof Ext.grid.GridPanel){
- this .grid = grid;
- / *コードの残りの部分* /
- }
- }
- / *その他* /
- });
- Ext.preg( "ourplugin" 、Ext.ux.Plugin);
initメソッドは、親のインスタンスを取得します。 つまり プラグインコレクションにプラグインを持つオブジェクト。 あとは、目的のクラスに属していることを確認するだけです。
プラグインを設計するときは、親オブジェクトのライフサイクルも考慮する必要があります。 たとえば、まだレンダリングされていないコンポーネントにプラグインを追加できます。 そして、これは、子の遅延初期化では、それらにアクセスできないことを意味します。 取得できるのは、その子の構成だけです。 したがって、親コンポーネントをレンダリングした後にすべてのアクションを実行することが望ましいです。 これも非常に簡単です。 対応するイベントを購読します。
Copy Source | Copy HTML
- 内線 名前空間 ( "Ext.ux" );
- Ext.ux.Plugin = Ext.extend(Ext.util.Observable、{
- init: function (grid){
- if (grid instanceof Ext.grid.GridPanel){
- this .grid = grid;
- if (grid.rendered){
- //既にレンダリングされた親コンポーネント、つまり
- //コンポーネントのレンダリング後に追加されたプラグイン。
- this .onRender();
- } else {
- //それ以外の場合、レンダリングイベントにサブスクライブします
- //親コンポーネント
- grid.on({
- スコープ: これ
- 、シングル: true
- 、レンダリング: this .onRender
- 、再構成: this .onRender
- });
- }
- }
- }
- 、onRender: function (){
- / *親コンポーネントがレンダリングされます。 あなたは仕事を始めることができます* /
- }
- });
- Ext.preg( "ourplugin" 、Ext.ux.Plugin);
これで、プラグインをグリッドに自由に追加したり、グリッドから削除したりできます。 また、コンポーネントの場合と同様に、プラグインが削除されたときにメモリのクリアを慎重に処理する必要があります。
Paginsを使用すると、プロジェクトのコード量を半分に減らすことができました。なぜなら、それらの前に、継承による機能拡張を実装したからです。
プラグインとコンポーネントに加えて、/ js / resourcesからのファイルを介して機能を拡張する別の方法があります。 アプリケーションが既に成長しており、グリッドからさまざまな種類のコンポーネント継承を持っているとします。 ただし、ここでは、ロード時にすべてのグリッドが最初の行を選択するという要件があります。 行動を再定義する機会は救助に来ます。 / js / resourcesのファイルには、次のように簡単に記述できます。
Copy Source | Copy HTML
- 内線 オーバーライド (Ext.grid.GridView、{
- onLoad:Ext.grid.GridView.prototype.onLoad.createSequence( function (){
- if ( this .grid.store && this .grid.getSelectionModel()。selectFirstRow){
- this .grid.getSelectionModel()。selectFirstRow.defer( 1 、 this .grid.getSelectionModel());
- }
- })
- });
同様に、たとえば、行を削除するときに次/前の行を強調表示したり、追加したばかりの行を強調表示するなどの問題を解決できます。
これでプラグインのトピックを終了し、アプリケーションの機能を拡張します。 結論として、私はいくつかの提言をしたいと思います。
ヒントとコツ
私の例では、式の前にコンマを入れていることにすでに気付いています。 この習慣はExtに固有のものではありませんが、どこかにコンマを置くのを忘れたり、逆に最後の要素の後にコンマを置くことを忘れると(特にIEでは慎重です)、検出が難しいエラーが発生します。 コンマを付けるこの方法を使用すると、カンマに関連するエラーの数が大幅に削減されます。
大規模なアプリケーションを設計するときは、Extの1つのバージョンにバインドし、 変更しないでください 。 3番目のブランチでは、3.0.0のコードが3.0.1で機能しない、またはエラーが発生するという事実に関連する多くの不快な瞬間を見つけました。
API APIドキュメントで、Extはそのクラスのソースコードを表示することを可能にします。 そこをのぞくことを恐れないでください。 あなたは多くの新しいものを発見するでしょう。
この記事を書いている時点でのグラフのAPIは、ほとんどカバーされていません。 前のヒントを活用し、Extの例のグラフも調べてください。
これで、記事を終了します。 彼女が誰かを助けることを願っています。