Шаги по переопределению функциональности стандартного компонента Sencha ExtJS (Ext.дерево.Панель И Внутр.данные.TreeStore как два примера)
предположим, я расширяю стандартный виджет/компонент Sencha ExtJS 4, и я нашел кучу вещей, которые не работают так, как я хочу, или, возможно, они просто сломаны, и Sencha еще не удосужился исправить проблемы с компонентом. Я просто собираюсь использовать Sencha ExtJS Ext.дерево.Панель и внутр.дерево.Хранить как два примера компонентов. Каковы наиболее основные шаги для переопределения конструктора, конфигураций, свойств, методов и событий, чтобы я мог найти и исправить проблемы с этот компонент без изменения основного файла ExtJS 4 framework JS, который я сейчас использую?
Я понимаю, что иногда в фреймворке так много функциональности, что можно где-то упустить конфигурацию и не понять, что они могут исправить проблему со стандартной реализацией. И это то, что можно исправить с большим опытом работы с фреймворком. Отложив это в сторону, каковы будут эти самые основные шаги?
Предположим, мы начнем с этих двух реализации и начать с самых основ.
FYI: я получил основные функции этих двух компонентов, работающих без особых усилий, действительно используя Ext.Прямой стек на стороне сервера, и я мог бы объяснить все проблемы, совместимые с кросс-браузером, с Sencha ExtJS Ext.дерево.Компонент панели с IE, Mozilla Firefox и Google Chrome, но я, вероятно, потратил бы слишком много времени, задавая эти другие вопросы. И я не говорю, что IE сначала должен быть стереотипным, потому что все это браузеры имеют свои проблемы с внутр.дерево.Компонент панели. Я лучше научусь здесь рыбачить, чтобы ловить свою рыбу. Как только я лучше пойму эти классы, связанные с деревом, я задам более конкретные вопросы.
http://docs.sencha.com/extjs/4.2.1/#!/api / Ext.данные.Древостой
Пользовательские Ext.данные.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.дерево.Панель
Пользовательские Ext.дерево.Реализация панели:
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 ответов
обзор
существует три способа увеличения поведения классов акций в Ext JS 4.x без изменения источника фреймворка: подклассы, переопределение классов и конфигурация экземпляра.
наследование
подклассы-это то, что вы делаете, когда вам нужно создать пользовательский компонент, специально для вашего приложения. Это на самом деле то, что вы делаете в коде выше: вы берете компонент запаса, изменяя его поведение в соответствии с вашими потребностями, и используя его в качестве нового компонента. Важный момент заключается в том, что при подклассе вы не изменяете поведение компонента запаса, поэтому вы можете использовать как пользовательские, так и фондовые компоненты.
переопределение
переопределение-это еще один подход, который изменит поведение класса 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() {
...
}
});
таким образом, вы можете применить изменения, которые повлияют на все экземпляры TreePanel, как на складе, так и на заказ. Этот подход в основном используется для патчи и исправления; его можно использовать для добавления новых функций в компоненты запаса, но вам будет сложнее поддерживать его в будущем.
конфигурации экземпляра
тем не менее, самый популярный подход до сих пор заключается в создании экземпляров классов акций и изменении поведения экземпляров параметры config и переопределение методов:
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
}
});
этот способ делать вещи был популяризирован в более ранних версиях Ext JS и по-прежнему активно используется. Я не рекомендую этот подход для new 4.х приложений, потому что это не позволит вам распределить ваш код правильно и труднее поддерживать в долгосрочной перспективе.
декларативный классы
еще одно преимущество перехода к подклассу заключается в том, что он позволяет сохранить декларативный код вместо императивного:
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();
}
});
выше декларации класс совместно используется всеми экземплярами MyApp.view.Panel
, в том числе и store
опции config и initComponent
переопределение метода, но при создании экземпляра этого класса или его подклассов, initComponent
способ будет работать на любой конфигурации тока для конкретного класса.
поэтому при использовании такого класса, у вас будет выбор либо переопределение store
config для экземпляр:
var panel = new MyApp.view.Panel({
store: 'BarStore'
});
var items = panel.getItems(); // Return all items from BarStore
или просто вернуться к конфигурации по умолчанию, предоставляемой класс:
var panel = new MyApp.view.Panel();
var items = panel.getItems(); // Return all items from FooStore
вы также можете создать его подкласс, переопределяющий частью конфигурации или поведения, но не все:
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
декларативный vs императивный
сравните это с императивным подходом, в котором вам придется каждый раз указывать полную конфигурацию для экземпляра класса 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);
}
});
самым большим недостатком кода выше является то, что все происходит с экземпляр класса когда уже на полпути инициализирован (initComponent вызывается конструктор). Вы не можете обобщить этот подход, и вы не можете легко сделать экземпляры имеют поведения, но различаются в деталях: вам придется повторять код для каждого экземпляра.
подклассы подводные камни
это подводит нас к самой распространенной ошибке, которую люди делают с подклассами: идти только наполовину. Если вы посмотрите на свой код выше, вы можете заметить это точно ошибка:
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';
...
}
});
сравните свой код с декларативным примером выше. Разница в том, что в вашем классе конфигурация происходит во время создания экземпляра в то время как в примере это происходит во время объявления класса.
предположим, что в будущем вам нужно будет повторно использовать класс MainTree в другом месте приложения, но теперь с другим магазином или поведением. С кодом выше, вы не можете сделать это легко, и вы будете необходимо создать другой класс и переопределить initComponent
способ:
Ext.define('MyApp.view.AnotherMainTree', {
extend: 'MyApp.view.MainTree',
initComponent: function() {
this.store = 'AnotherTreeNodes';
...
}
});
сравните это с переопределением конфигурации экземпляра выше. Не только декларативный подход легче писать и поддерживать, но и бесконечно более проверяемым.
переопределите функции, которые, по вашему мнению, работают неправильно или так, как вы хотите, чтобы он работал
пример
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;
},
....
в приведенном выше примере я хочу, чтобы функция getTotalCount вычисляла количество по-разному, поэтому я расширил treestore и переопределил метод.