Kroki w celu nadpisania funkcji standardowego komponentu Sencha ExtJS (Ext.drzewo.Panel & Ext.data.TreeStore jako dwa przykłady)
Załóżmy, że rozszerzam standardowy widżet/komponent Sencha ExtJS 4 i znalazłem kilka rzeczy, które nie działają tak, jak chcę, a może są po prostu zepsute i Sencha jeszcze nie naprawił problemów z komponentem. Użyję tylko Sencha ExtJS Ext.drzewo.Panel i wew.drzewo.Przechowuj jako dwa przykładowe komponenty. Jakie są najbardziej podstawowe kroki, aby nadpisać konstruktor, configs, właściwości, metody i zdarzenia, abym mógł znaleźć i naprawić problemy z ten komponent bez modyfikowania pliku JS rdzenia ExtJS 4 framework, którego obecnie używam?
Zdaję sobie sprawę, że czasami jest tak dużo funkcjonalności w frameworku, że można przeoczyć gdzieś konfigurację i nie zdawać sobie sprawy, że mogą rozwiązać problem ze standardową implementacją. I to jest coś, co można poprawić przy większym doświadczeniu z frameworkiem. Odkładając to na bok, jakie byłyby te najbardziej podstawowe kroki?
Załóżmy, że zaczniemy od tych dwóch implementacji i zacznij od samych podstaw.
FYI: mam podstawowe cechy tych dwóch komponentów, które działają bez zbytniego wysiłku, naprawdę używając Ext.Bezpośredni stos po stronie serwera i mógłbym wyjaśnić wszystkie problemy z kompatybilnością między przeglądarkami z Sencha ExtJS Ext.drzewo.Komponent panelu z IE, Mozilla Firefox i Google Chrome, ale pewnie za dużo czasu poświęciłbym na zadawanie tych innych pytań. I nie mówię, że IE jako pierwszy jest stereotypowy, bo wszystkie te przeglądarki mają swoje problemy z Ext.drzewo.Komponent panelu. Wolałbym nauczyć się tu łowić ryby, żebym mógł łowić własną rybę. Kiedy lepiej zrozumiem te klasy związane z drzewem, zadam bardziej szczegółowe pytania.
Http://docs.sencha.com/extjs/4.2.1/#! / api / Ext. data. TreeStore
Custom Ext.data.Implementacja TreeStore:
Ext.define('MyApp.store.TreeNodes', {
extend: 'Ext.data.TreeStore',
xtype: 'store-tree-nodes',
model : 'MyApp.model.TreeNode',
proxy: {
type: 'direct',
directFn: Tree_Node_CRUD.read,
reader: {
root: 'data'
}
},
nodeParam: 'node',
parentField: 'parentId',
root: {
text: 'root',
id: '0',
expanded: true
},
autoLoad: false,
single: true,
listeners: {
beforeload: function(store, operation, options) {
},
append: function( thisNode, newChildNode, index, eOpts ) {
}
}
});
Http://docs.sencha.com/extjs/4.2.1/#! / api / ext. tree. Panel
Custom Ext.drzewo.Wykonanie panelu:
Ext.define('MyApp.view.MainTree', {
extend: 'Ext.tree.TreePanel',
xtype: 'view-main-tree',
requires: [
'MyApp.store.TreeNodes'
],
initComponent: function()
{
this.store = 'TreeNodes';
this.superclass.initComponent.call(this);
},
animate: false,
title: 'Tree',
rootVisible: true,
collapsible: true,
dockedItems: [{
xtype: 'toolbar',
items: [{
text: 'Open Node'
}, {
text: 'Create Node'
}, {
text: 'Delete Node'
}, {
text: 'Expand All'
}, {
text: 'Collapse All'
}]
}],
listeners: {
afterrender: function() {
},
itemclick: function(view, node, item, index, e) {
},
afteritemexpand: function() { //node, index, item, eOpts) {
},
afteritemcollapse: function() { //node, index, item, eOpts) {
}
}
});
2 answers
Przegląd
Istnieją trzy sposoby zwiększenia zachowania klas stock w Ext JS 4.x bez zmiany źródła frameworka: podklasowanie, nadpisywanie klas i konfiguracja instancji.
Podkategoria
Podklasowanie jest tym, co robisz, gdy musisz utworzyć niestandardowy komponent dostosowany do Twojej aplikacji. To właśnie robisz w powyższym kodzie: bierzesz komponent magazynowy, zmieniasz jego zachowanie zgodnie z Twoimi potrzebami i używasz go jako nowego komponent. Ważne jest to, że poprzez podklasowanie nie zmieniasz zachowania komponentu stock, dzięki czemu możesz używać zarówno komponentów niestandardowych, jak i stock.
Overriding
Nadpisywanie jest kolejnym podejściem, które zmieni zachowanie klasy stock:
Ext.define('MyApp.tree.TreePanel', {
override: 'Ext.tree.Panel',
// Stock fooMethod has a bug, so we are
// replacing it with a fixed method
fooMethod: function() {
...
}
});
W ten sposób możesz zastosować zmiany, które będą miały wpływ na wszystkie instancje panelu drzewa, zarówno stock, jak i custom. To podejście jest najczęściej używane do łatek i poprawek; może być używane do dodawania nowe funkcje komponentów magazynowych, ale trudniej będzie utrzymać je na drodze.
Konfiguracja instancji
To powiedziawszy, najpopularniejszym do tej pory podejściem jest tworzenie instancji klas stock i zmiana zachowania instancji poprzez ustawienie opcji konfiguracyjnych i nadrzędnych metod:
var tree = new Ext.tree.Panel({
fooConfig: 'bar', // override the default config option
fooMethod: function() {
// Nothing wrong with this method in the stock class,
// we just want it to behave differently
}
});
Ten sposób robienia rzeczy został spopularyzowany we wcześniejszych wersjach Ext JS i jest nadal mocno używany. Nie polecam tego podejścia do nowych 4.aplikacje x, ponieważ nie pozwala to na poprawną modularyzację kodu i jest trudniejsze do utrzymania na dłuższą metę.
Klasy deklaratywne
Inną korzyścią płynącą z podklasowania jest to, że pozwala zachować kod deklaratywny zamiast imperatywnego:]}Ext.define('MyApp.view.Panel', {
extend: 'Ext.panel.Panel',
store: 'FooStore',
// Note the difference with your code:
// the actual function reference
// will be resolved from the *object instance*
// at the object instantiation time
// and may as well be overridden in subclasses
// without changing it here
listeners: {
itemclick: 'onItemClick'
},
initComponent: function() {
var store = this.store;
if (!Ext.isObject(store) || !store.isStore) {
// The store is not initialized yet
this.store = Ext.StoreManager.lookup(store);
}
// You don't need to address the superclass directly here.
// In the class method scope, callParent will resolve
// the superclass method and call it.
this.callParent();
},
// Return all items in the store
getItems: function() {
return this.store.getRange();
},
onItemClick: function() {
this.doSomething();
}
});
Powyższa deklaracja klasy jest współdzielona przez wszystkie instancje MyApp.view.Panel
, w tym zarówno opcję konfiguracji store
, jak i nadpisanie metody initComponent
, ale gdy tworzysz instancję tej klasy lub jej podklasy, initComponent
metoda będzie działać na dowolnej konfiguracji bieżącej dla danej klasy .
Więc gdy używasz takiej klasy, będziesz miał do wyboru albo nadpisanie store
config dla instancji :
var panel = new MyApp.view.Panel({
store: 'BarStore'
});
var items = panel.getItems(); // Return all items from BarStore
Lub po prostu wraca do domyślnej konfiguracji podanej przez klasę:
var panel = new MyApp.view.Panel();
var items = panel.getItems(); // Return all items from FooStore
Można również podklasować, nadpisując część konfiguracji lub zachowania, ale nie wszystko:
Ext.define('MyApp.view.NewPanel', {
extend: 'MyApp.view.Panel',
// For this Panel, we only want to return first 10 items
getItems: function() {
return this.store.getRange(0, 9);
},
onItemClick: function() {
this.doSomethingElse();
}
});
var panel = new MyApp.view.NewPanel();
var items = panel.getItems(); // Return first 10 items from FooStore
Deklaratywny vs Imperatyw
Porównaj to z imperatywnym podejściem, w którym będziesz musiał każdorazowo określać pełną konfigurację dla instancji klasy stock:
var panelFoo = new Ext.panel.Panel({
initComponent: function() {
this.store = Ext.StoreManager.lookup('FooStore');
// Note that we can't use this.callParent() here
this.superclass.initComponent.call(this);
}
});
var panelBar = new Ext.panel.Panel({
initComponent: function() {
this.store = Ext.StoreManager.lookup('BarStore');
this.superclass.initComponent.call(this);
}
});
Największą wadą powyższego kodu jest to, że wszystko dzieje się z instancją klasy, gdy jest już W połowie zainicjalizowaną (initcomponent jest wywoływany przez konstruktor). Nie można uogólnić tego podejścia i nie można łatwo sprawić, by instancje dzieliły większość zachowań, ale różniły się szczegóły-będziesz musiał powtórzyć kod dla każdej instancji.
Podklasyczne pułapki
To prowadzi nas do najczęstszego błędu, który ludzie popełniają również z podklasowaniem: pójście tylko w połowie drogi. Jeśli spojrzysz na powyższy kod, możesz zauważyć ten dokładny błąd:
Ext.define('MyApp.view.MainTree', {
extend: 'Ext.tree.TreePanel', // You're using subclassing
initComponent: function() {
// But here you are assigning the config options
// to the the *class instance* that has been
// instantiated and half way initialized already
this.store = 'TreeNodes';
...
}
});
Porównaj swój kod z powyższym przykładem deklaratywnym. Różnica polega na tym, że w twojej klasie konfiguracja dzieje się w czasie tworzenia instancji, podczas gdy w przykładzie dzieje się w czas deklaracji klas .
Załóżmy, że w przyszłości będziesz musiał ponownie użyć swojej klasy MainTree gdzie indziej w aplikacji, ale teraz z innym sklepem lub zachowaniem. Z powyższym kodem nie możesz tego zrobić łatwo i będziesz musiał utworzyć inną klasę i nadpisać metodę initComponent
:
Ext.define('MyApp.view.AnotherMainTree', {
extend: 'MyApp.view.MainTree',
initComponent: function() {
this.store = 'AnotherTreeNodes';
...
}
});
Porównaj to z nadpisaniem konfiguracji instancji powyżej. Nie tylko deklaratywne podejście jest łatwiejsze do napisania i utrzymania, ale jest nieskończenie bardziej testowalne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 20:53:15
Nadpisuj funkcje, które Twoim zdaniem nie działają poprawnie lub w sposób, w jaki chcesz, aby działały
Przykład
Ext.define('MyApp.store.TreeGridStore', {
extend: 'Ext.data.TreeStore',
getTotalCount : function() {
if(!this.proxy.reader.rawData) return 0;
this.totalCount = this.proxy.reader.rawData.recordCount;
return this.totalCount;
},
....
W powyższym przykładzie chcę, aby funkcja getTotalCount różnie obliczała liczbę, więc rozszerzyłem treestore i nadpisałem metodę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-15 17:35:14