文档帮助

术语、图标和标签

许多类在使用配置对象创建(实例化)类时都有快捷名称。快捷名称被称为 alias(或如果类继承自 Ext.Component,则称为 xtype)。别名/xtype 列在适用类的类名旁边,以便快速参考。

访问级别

框架类或其成员可以指定为 privateprotected。否则,类/成员为 publicPublicprotectedprivate 是访问描述符,用于说明类或类成员应如何以及何时使用。

成员类型

成员语法

下面是一个类成员示例,我们可以剖析它以展示类成员的语法(在本例中为从 Ext.button.Button 类查看的 lookupComponent 方法)。

lookupComponent ( item ) : Ext.Component
protected

当原始配置对象添加到此容器时调用,无论是在 items 配置的初始化期间,还是在 添加新项目或 {@link #insert 插入} 新项目时。

此方法将传递的对象转换为实例化的子组件。

当需要对子组件创建应用特殊处理时,可以在子类中重写此方法。

参数

item :  Object

正在添加的配置对象。

返回值
Ext.Component

要添加的组件。

让我们看一下成员行的每个部分

成员标志

API 文档使用许多标志来进一步说明类成员的功能和意图。标签可以用文本标签、缩写或图标表示。

类图标

- 表示框架类

- 单例框架类。*有关更多信息,请参阅单例标志

- 组件类型框架类(Ext JS 框架中任何继承自 Ext.Component 的类)

- 表示类、成员或指南在当前查看的版本中是新的

成员图标

- 表示类型为 config 的类成员

- 表示类型为 property 的类成员

- 表示类型为 method 的类成员

- 表示类型为 event 的类成员

- 表示类型为 theme variable 的类成员

- 表示类型为 theme mixin 的类成员

- 表示类、成员或指南在当前查看的版本中是新的

类成员快速导航菜单

在 API 文档页面的类名正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮显示按类型划分的成员计数(此计数会随着应用过滤器而更新)。单击按钮会将您导航到该成员部分。将鼠标悬停在成员类型按钮上将显示该类型的所有成员的弹出菜单,以便快速导航。

Getter 和 Setter 方法

与类配置选项相关的 getter 和 setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,紧挨着它们所操作的配置下方。getter 和 setter 方法文档将在配置行中找到,以便于参考。

历史记录栏

您的页面历史记录保存在本地存储中,并显示在顶部标题栏正下方(使用可用的实际空间)。默认情况下,显示的唯一搜索结果是与您当前查看的产品/版本匹配的页面。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选选项来展开显示的内容。这将显示所有产品/版本在历史记录栏中的所有最近页面。

在历史记录配置菜单中,您还将看到最近访问页面的列表。结果按“当前产品/版本”和“全部”单选选项进行过滤。单击 按钮将清除历史记录栏以及本地存储中保存的历史记录。

如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史页面的产品/版本将与页面名称一起显示在历史记录栏中。将光标悬停在历史记录栏中的页面名称上也会将产品/版本显示为工具提示。

搜索和过滤器

可以使用页面顶部的搜索字段搜索 API 文档和指南。

在 API 文档页面上,还有一个过滤器输入字段,用于使用过滤器字符串过滤成员行。除了按字符串过滤外,您还可以按访问级别、继承和只读过滤类成员。这可以通过使用页面顶部的复选框来完成。

API 类导航树底部的复选框过滤类列表,以包含或排除私有类。

单击空的搜索字段将显示您最近 10 次的搜索,以便快速导航。

API 文档类元数据

每个 API 文档页面(JavaScript 原始类型页面除外)都有一个与该类相关的元数据菜单视图。此元数据视图将具有以下一个或多个

展开和折叠示例及类成员

可运行的示例 (Fiddles) 默认在页面上展开。您可以使用代码块左上角的箭头单独折叠和展开示例代码块。您还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。

类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标展开和折叠成员,或者使用右上角的展开/折叠全部切换按钮全局展开和折叠成员。

桌面 -vs- 移动视图

在较窄的屏幕或浏览器上查看文档将导致针对较小外形尺寸优化的视图。桌面视图和“移动”视图之间的主要区别是

查看类源代码

可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“view source”链接来查看类成员的源代码。

Ext JS 7.8.0 - Classic Toolkit


顶部
指南适用于: classic

Tree Panel 组件是 ExtJS 中功能最全面的组件之一,是用于在 应用程序 中显示分层数据的出色工具。Tree Panel 继承自与 Grid Panel 相同的类,因此,Grid Panel 的大多数优点(功能、扩展和插件)也可以在 Tree Panel 上使用。诸如列、列大小调整、拖放、渲染器、排序和过滤等功能预计在这两个组件上的工作方式类似。

让我们从创建一个非常简单的树开始。

此 Tree Panel 将自身渲染到文档主体。我们定义了一个默认展开的根 节点 。根节点有三个子节点,前两个是叶节点,这意味着它们不能有任何子节点。第三个节点不是叶节点,并且有一个子叶节点。text 属性用作节点的文本标签。

在内部,Tree Panel 将其数据存储在 TreeStore 中。上面的示例使用 root 配置作为配置 Store 的快捷方式。如果我们分别配置 Store,代码将如下所示

var store = Ext.create('Ext.data.TreeStore', {
    root: {
        text: 'Root',
        expanded: true,
        children: [
            {
                text: 'Child 1',
                leaf: true
            },
            {
                text: 'Child 2',
                leaf: true
            },
            ...
        ]
    }
});

Ext.create('Ext.tree.Panel', {
    title: 'Simple Tree',
    store: store,
    ...
});

从 Store 继承

重要的是要注意,TreeStore 的 Store 角色根据基于 根节点 的链接节点结构管理其自身的内容。

只有可见节点才在 store 中表示。当父节点展开时,其子节点会紧随其后立即插入到 store 中。当该节点折叠时,这些节点将从 store 中移除。

被认为在任何方面都不可见的节点,无论是由于祖先折叠还是由于过滤,都会出现在 Store 的记录集合中。

所有节点仍然可以通过树层次结构访问

store 纯粹用于驱动用户界面。节点以一对一的方式映射到视图中。

要操作 store 的内容,您必须始终通过 Ext.data.TreeModel 提供的接口来 插入 、 追加 或 移除 节点到其他节点或从其他节点移除。

某些方法(例如 each 和 collect )在 TreeStore 级别重新实现,以提供对结构中所有节点的访问,而不是仅对平面 Store 角色中的可见节点进行访问。

Node 接口

在上面的示例中,我们在 Tree 节点上设置了几个不同的属性。但节点到底是什么?如前所述,Tree Panel 绑定到 TreeStore 。ExtJS 中的 Store 管理 Model 实例的集合。

在没有配置 Model 类型的情况下,Store 将使用 Ext.data.TreeModel 类来封装数据。这是一个 Model 子类,它已使用在 Tree 中使用所需的字段、方法和属性进行修饰。以下是显示开发者工具中节点结构的屏幕截图。

A TreeModel instance illustrating the
TreeModel

为了查看节点上可用的完整字段、方法和属性集,请参阅 NodeInterface 类的 API 文档。

您为在树中使用而定义的 Model 应扩展 Ext.data.TreeModel 类。

更改您的树

让我们尝试一些简单的操作。当您将 useArrows 配置设置为 true 时,Tree Panel 会隐藏线条并使用箭头作为展开和折叠图标。

Arrows

rootVisible 属性设置为 false 会在视觉上移除根节点。通过这样做,根节点将自动展开。下图显示了相同的树,其中 rootVisible 设置为 falselines 设置为 false。

Root not visible and no lines

多列

由于 Tree Panel 继承自与 Grid Panel 相同的基类,因此添加更多列非常容易。

`columns` 配置期望 Ext.grid.column.Column 配置的数组,就像 Grid Panel 会有的那样。唯一的区别是 Tree Panel 至少需要一个 xtype 为 'treecolumn' 的列。这种类型的列具有特定于树的可视效果,例如深度、线条以及展开和折叠图标。典型的 Tree Panel 只有一个 'treecolumn'。

`fields` 配置传递给内部创建的 Store 使用的 Ext.data.Model 。请注意列上的 `dataIndex` 配置如何映射到我们指定的字段 - `name` 和 `description`。

还值得注意的是,当未定义列时,Tree 将自动创建一个 `dataIndex` 设置为 `'text'` 的 `treecolumn`。

如果未定义列配置了 header text ,则不会显示标题容器。

添加节点

Tree Panel 的根节点不必在初始配置中指定。我们总是可以在以后添加它

var tree = Ext.create('Ext.tree.Panel');
tree.setRootNode({
    text: 'Root',
    expanded: true,
    children: [{
        text: 'Child 1',
        leaf: true
    }, {
        text: 'Child 2',
        leaf: true
    }]
});

虽然这对于只有少量静态节点的非常小的树很有用,但大多数 Tree Panel 将包含更多节点。因此,让我们看一下如何以编程方式向 Tree 添加新节点。

var root = tree.getRootNode();

var parent = root.appendChild({
    text: 'Parent 1'
});

parent.appendChild({
    text: 'Child 3',
    leaf: true
});

parent.expand();

每个不是叶节点的节点都有一个 `appendChild` 方法,该方法接受 Node 或 Node 的配置对象作为其第一个参数,并返回附加的 Node。上面的示例还调用了 `expand` 方法来展开新创建的父节点。

Appending to the tree

在创建新的父节点时内联定义子节点的能力也很有用。以下代码为我们提供了相同的结果。

var parent = root.appendChild({
    text: 'Parent 1',
    expanded: true,
    children: [{
        text: 'Child 3',
        leaf: true
    }]
});

有时我们希望将节点插入到树中的特定位置,而不是附加它。除了 `appendChild` 方法,`Ext.data.NodeInterface` 还提供了 `insertBefore` 和 `insertChild` 方法。

var child = parent.insertChild(0, {
    text: 'Child 2.5',
    leaf: true
});

parent.insertBefore({
    text: 'Child 2.75',
    leaf: true
}, child.nextSibling);

`insertChild` 方法期望子节点将被插入的索引。`insertBefore` 方法期望一个参考节点。新节点将插入在参考节点之前。

Inserting children into the tree

TreeModel 还提供了节点上的几个更多属性,这些属性可用于引用其他节点。

通过 Proxy 加载和保存

由于表示树的层次结构需要所有字段,因此加载和保存树数据比处理平面数据稍微复杂一些。本节将解释使用树数据的复杂性。

TreeModel 字段

使用树数据时,首先也是最重要的事情是了解 TreeModel 类的字段如何工作。树中的每个节点都只是一个使用 TreeModel 的字段和方法修饰的 Model 实例。假设一个应用程序有一个名为 “Person” 的 Model。Person 只有两个字段 - `id` 和 `name`。

为了在 TreeStore 中使用它,请扩展 `TreeModel` 类

Ext.define('Person', {
    extend: 'Ext.data.TreeModel',
    fields: ['id', {
        name: 'name',
        type: 'string'
    }]
});

生成的模型有许多额外的字段,这些字段用于管理节点在树结构中的上下文

console.log(store.getRoot().getFields().length); // outputs '27'

Person 模型的原型仅通过扩展 `TreeModel` 就添加了 25 个额外的字段。

那么这 25 个额外的字段究竟是什么,它们有什么作用?快速查看 TreeModel 源代码可以发现,它使用以下字段修饰 Model。这些字段在内部用于存储与树的结构和状态相关的信息

{
    name: 'parentId',
    type: idType,
    defaultValue: null,
    useNull: idField.useNull
}, {
    name: 'index',
    type: 'int',
    defaultValue: -1,
    persist: false,
    convert: null
}, {
    name: 'depth',
    type: 'int',
    defaultValue: 0,
    persist: false,
    convert: null
}, {
    name: 'expanded',
    type: 'bool',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'expandable',
    type: 'bool',
    defaultValue: true,
    persist: false,
    convert: null
}, {
    name: 'checked',
    type: 'auto',
    defaultValue: null,
    persist: false,
    convert: null
}, {
    name: 'leaf',
    type: 'bool',
    defaultValue: false
}, {
    name: 'cls',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'iconCls',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'icon',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'root',
    type: 'boolean',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'isLast',
    type: 'boolean',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'isFirst',
    type: 'boolean',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'allowDrop',
    type: 'boolean',
    defaultValue: true,
    persist: false,
    convert: null
}, {
    name: 'allowDrag',
    type: 'boolean',
    defaultValue: true,
    persist: false,
    convert: null
}, {
    name: 'loaded',
    type: 'boolean',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'loading',
    type: 'boolean',
    defaultValue: false,
    persist: false,
    convert: null
}, {
    name: 'href',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'hrefTarget',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'qtip',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'qtitle',
    type: 'string',
    defaultValue: '',
    persist: false,
    convert: null
}, {
    name: 'qshowDelay',
    type: 'int',
    defaultValue: 0,
    persist: false,
    convert: null
}, {
    name: 'children',
    type: 'auto',
    defaultValue: null,
    persist: false,
    convert: null
}, {
    name: 'visible',
    type: 'boolean',
    defaultValue: true,
    persist: false,
}, {
    name: 'text',
    type: 'string',
    persist: 'false
}

TreeModel 字段是保留名称

重要的是要注意,以上所有字段名称都应被视为“保留”名称。例如,如果 Model 旨在在树中使用,则不允许在 Model 中使用名为“parentId”的字段,因为 Model 的字段将覆盖 TreeModel 字段。此规则的例外情况是当确实需要覆盖字段的持久性时。

持久字段与非持久字段

TreeModel 的大多数字段默认设置为 persist: false。这意味着它们默认是非持久字段。当调用 TreeStore 的 sync 方法或在 Model 上调用 save() 时,非持久字段不会通过 Proxy 保存。在大多数情况下,这些字段的大部分可以保留其默认持久性设置,但在某些情况下,有必要覆盖某些字段的持久性。
以下示例演示如何覆盖 TreeModel 字段的 persistence。覆盖 TreeModel 字段时,重要的是仅更改 persist 属性。nametypedefaultValue 属性永远不应更改。

    // overriding the persistence of TreeModel fields in a Model definition
    Ext.define('Person', {
        extend: 'Ext.data.TreeModel',
        fields: [
            // Person fields
            { name: 'id', type: 'int' },
            { name: 'name', type: 'string' }

            // override a non-persistent TreeModel field to make it persistent
            { name: 'iconCls', type: 'string',  defaultValue: null, persist: true }
        ]
    });

让我们更深入地了解每个 TreeModel 字段以及可能需要覆盖其 persist 属性的场景。在下面的每个示例中,除非另有说明,否则假定正在使用 服务器代理

默认持久化

  • parentId - 用于存储节点父节点的 ID。此字段应始终持久化,不应被覆盖。
  • leaf - 用于指示节点是叶节点,因此不能向其追加子节点。此字段通常不需要被覆盖。

默认非持久化

  • index - 用于存储节点在其父节点中的顺序。当一个节点被 插入移除 时,插入点或移除点之后的所有兄弟节点都将更新其索引。如果需要,应用程序可以使用此字段来持久化节点的顺序。

    但是,如果服务器使用不同的方法来存储顺序,则将 index 字段保留为非持久化可能更合适。当使用 WebStorage 代理 且需要存储顺序时,必须覆盖此字段使其持久化。

    此外,如果正在使用客户端 排序,建议将 index 字段保留为非持久化,因为排序会更新所有已排序节点的索引,如果 persist 属性为 true,则会导致它们在下次同步或保存时被持久化。

  • depth - 用于存储节点在树层次结构中的深度。如果服务器需要存储深度字段,请覆盖此字段以启用持久化。当使用 WebStorage 代理 时,建议不要覆盖 depth 字段的持久性,因为它不是正确存储树结构所必需的,并且只会占用额外的空间。

  • checked - 如果树正在使用 复选框功能,则应覆盖此字段使其持久化
  • expanded - 用于存储节点的展开/折叠状态。此字段通常不需要被覆盖。
  • expandable - 内部用于指示此节点是否可展开。不要覆盖此字段的持久性。
  • cls - 用于在 TreePanel 中渲染节点时向其应用 CSS 类。如果需要,请覆盖此字段使其持久化。
  • iconCls - 用于在 TreePanel 中渲染节点时向其图标应用 CSS 类。如果需要,请覆盖此字段使其持久化。
  • icon - 用于在 TreePanel 中渲染节点时向其应用自定义图标。如果需要,请覆盖此字段使其持久化。
  • root - 用于指示此节点是根节点。此字段不应被覆盖。
  • isLast - 用于指示此节点是其兄弟节点中的最后一个。此字段通常不需要被覆盖。
  • isFirst - 用于指示此节点是其兄弟节点中的第一个。此字段通常不需要被覆盖。
  • allowDrop - 内部用于拒绝在该节点上进行拖放操作。不要覆盖此字段的持久性。
  • allowDrag - 内部用于拒绝拖动该节点。不要覆盖此字段的持久性。
  • loaded - 内部用于指示节点的子节点已加载。
    不要覆盖此字段的持久性。
  • loading - 内部用于指示代理正在加载节点的子节点。不要覆盖此字段的持久性。
  • href - 用于指定节点应链接到的 URL。如果需要,请覆盖使其持久化。
  • hrefTarget - 用于指定 href 的目标。如果需要,请覆盖使其持久化。
  • qtip - 用于向节点添加 工具提示 文本。如果需要,请覆盖使其持久化。
  • qtitle - 用于指定 tooltip 的标题。如果需要,请覆盖使其持久化。
  • children - 在一次请求中加载节点及其子节点时在内部使用。不要覆盖此字段的持久性。

加载数据

加载树数据有两种方法。第一种是让代理一次性获取整个树。对于较大的树,一次性加载所有内容可能不太理想,最好使用第二种方法 - 在每个节点展开时动态加载其子节点。

加载整个树

在内部,树仅在节点展开时才加载数据。但是,如果代理检索包含整个树结构的嵌套对象,则可以加载整个层次结构。为了实现这一点,将 TreeStore 的根节点初始化为 expanded

Ext.define('Person', {
    extend: 'Ext.data.Model',
    fields: [
        { name: 'id', type: 'int' },
        { name: 'name', type: 'string' }
    ],
    proxy: {
        type: 'ajax',
        api: {
            create: 'createPersons',
            read: 'readPersons',
            update: 'updatePersons',
            destroy: 'destroyPersons'
        }
    }

});

var store = Ext.create('Ext.data.TreeStore', {
    model: 'Person',
    root: {
        name: 'People',
        expanded: true
    }
});

Ext.create('Ext.tree.Panel', {
    renderTo: document.body,
    width: 300,
    height: 200,
    title: 'People',
    store: store,
    columns: [{
        xtype: 'treecolumn', 
        header: 'Name', 
        dataIndex: 'name', 
        flex: 1
    }]
});

假设 readPersons URL 返回以下 JSON 对象

{
    "success": true,
    "children": [
        { "id": 1, "name": "Phil", "leaf": true },
        { "id": 2, "name": "Nico", "expanded": true, "children": [
            { "id": 3, "name": "Mitchell", "leaf": true }
        ]},
        { "id": 4, "name": "Sue", "loaded": true }
    ]
}

这就是加载整个树所需的全部内容。

Tree with Bulk Loaded Data

需要注意的重要事项

  • 对于所有没有子节点的非叶节点(例如,上面名为 Sue 的 Person),服务器响应必须将 loaded 属性设置为 true。否则,代理将在这些节点展开时尝试加载其子节点。
  • 然后出现一个问题 - 如果允许服务器在 JSON 响应中设置节点的 loaded 属性,它是否可以设置任何其他非持久化字段?答案是肯定的 - 有时可以。在上面的示例中,名为 "Nico" 的节点的 expanded 字段设置为 true,以便它最初在 Tree Panel 中显示为展开状态。应谨慎使用,因为在某些情况下这不合适,并且可能导致严重问题,例如在不是根节点的节点上设置 root 属性。一般来说,loadedexpanded 是建议服务器在 JSON 响应中设置非持久化字段的唯一情况。

动态加载子节点

对于较大的树,可能需要仅加载树的部分内容,即仅在其父节点展开时才加载子节点。假设在上面的示例中,服务器响应未将名为 "Sue" 的节点的 loaded 字段设置为 true。树将在节点旁边显示一个展开器图标。当节点展开时,代理将向 readPersons URL 发出另一个请求,如下所示

/readPersons?node=4

这告诉服务器检索 id 为 4 的节点的子节点。返回的数据应与用于加载根节点的数据格式相同

{
    "success": true,
    "children": [
        { "id": 5, "name": "Evan", "leaf": true }
    ]
}

现在树看起来像这样

Tree with Dynamically Loaded Node

保存数据

创建、更新和删除节点由代理自动无缝处理。

创建新节点

// Create a new node and append it to the tree:
var newPerson = Ext.create('Person', { name: 'Nige', leaf: true });
store.getNodeById(2).appendChild(newPerson);

由于代理直接在模型上定义,因此可以使用模型的 save() 方法来持久化数据

newPerson.save();

更新现有节点

store.getNodeById(1).set('name', 'Philip');

移除节点

store.getRootNode().lastChild.remove();

批量操作

在创建、更新和移除多个节点后,可以通过调用 TreeStore 的 sync() 方法在一个操作中持久化所有这些节点

store.sync();

过滤树数据

远程过滤的工作方式与其他任何 store 类型相同。过滤器被编码并传递到服务器,服务器必须仅使用所需的数据进行响应。

树的本地过滤与过滤网格等平面数据集不同。

过滤器条件可能包括低于父节点的节点,而父节点被过滤器条件排除。

默认情况下,通过过滤器条件的节点,但其父节点未通过过滤器条件的节点不包含在 store 中。这是自上而下的过滤,可以使用 filterer 配置进行重新配置。

要强制包含通过过滤器的节点的祖先节点,请将 filterer 配置为 bottomup

有关此类过滤的说明,请参阅 过滤树 示例。

这种过滤需要遍历树结构,以确定所有节点的可见性状态,然后再更新视图。

对于应用程序代码对单个记录进行细粒度或程序化过滤,您可以设置 TreeModelvisible 字段,视图将遵循该设置,并根据该值显示或隐藏节点。

Ext JS 7.8.0 - Classic Toolkit