许多类在通过配置对象创建(实例化)类时都有快捷名称。快捷名称称为 alias
(别名)(如果类扩展了 Ext.Component,则称为 xtype
)。别名/xtype 列在适用类的类名旁边,以便快速参考。
框架类或其成员可以指定为 private
(私有)或 protected
(受保护)。否则,类/成员为 public
(公共)。Public
、protected
和 private
是访问描述符,用于传达类或类成员应如何以及何时使用。
公共类和类成员可供任何其他类或应用程序代码使用,并且在主要产品版本中可以作为稳定且持久的内容依赖。公共类和成员可以通过子类安全地扩展。
受保护的类成员是稳定的 public
成员,旨在由拥有类或其子类使用。受保护的成员可以通过子类安全地扩展。
私有的类和类成员在框架内部使用,不供应用程序开发人员使用。私有类和成员可能会随时更改或从框架中省略,恕不另行通知,并且不应在应用程序逻辑中依赖。
static
标签。*请参阅下面的静态。下面是一个示例类成员,我们可以对其进行剖析以显示类成员的语法(在本例中是从 Ext.button.Button 类查看的 lookupComponent 方法)。
让我们看一下成员行的每个部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回除 undefined
之外的任何内容的方法,可以省略此项,或者可以显示为由正斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(即,如果 get 方法调用成功,则方法可能返回 Component,如果失败则返回 false
,这将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参阅下面的标志部分)Ext.container.Container
)。如果成员源自当前类,则源类将显示为蓝色链接;如果成员从祖先类或混入类继承,则显示为灰色链接。view source
)item : Object
)。undefined
之外的值,“返回值”部分将注明返回的类或对象类型以及描述(示例中为 Ext.Component
)Available since 3.4.0
- 示例中未显示),紧接在成员描述之后Defaults to: false
)API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可阻止的事件将不会触发- 表示框架类
- 单例框架类。*有关更多信息,请参阅单例标志
- 组件类型框架类(Ext JS 框架中扩展 Ext.Component 的任何类)
- 表示类、成员或指南在当前查看的版本中是新的
- 表示 config
类型的类成员
- 表示 property
类型的类成员
- 表示 method
类型的类成员
- 表示 event
类型的类成员
- 表示 theme variable
类型的类成员
- 表示 theme mixin
类型的类成员
- 表示类、成员或指南在当前查看的版本中是新的
在 API 文档页面的类名正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮显示按类型划分的成员计数(此计数在应用过滤器后更新)。单击按钮将导航到该成员部分。悬停在成员类型按钮上将显示该类型的所有成员的弹出菜单,以便快速导航。
与类配置选项相关的 Getter 和 setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,紧靠它们所作用的配置下方。Getter 和 setter 方法文档将在配置行中找到,以便于参考。
您的页面历史记录保存在本地存储中,并在顶部标题栏正下方显示(使用可用的实际空间)。默认情况下,仅显示的搜索结果是与您当前查看的产品/版本匹配的页面。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选按钮来扩展显示的内容。这将显示所有产品/版本历史记录栏中的所有最近页面。
在历史记录配置菜单中,您还将看到最近访问页面的列表。结果按“当前产品/版本”和“全部”单选按钮过滤。单击 按钮将清除历史记录栏以及本地存储中保存的历史记录。
如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史页面的产品/版本将在历史记录栏中与页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也会将产品/版本显示为工具提示。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个过滤器输入字段,用于使用过滤器字符串过滤成员行。除了按字符串过滤外,您还可以按访问级别、继承和只读过滤类成员。这可以通过使用页面顶部的复选框来完成。
API 类导航树底部的复选框过滤类列表,以包含或排除私有类。
单击空的搜索字段将显示您最近 10 次搜索,以便快速导航。
每个 API 文档页面(JavaScript 原始类型页面除外)都有一个与该类相关的元数据菜单视图。此元数据视图将具有以下一项或多项
Ext.button.Button
类具有 Ext.Button
的备用类名)。备用类名通常为了向后兼容性而维护。可运行示例 (Fiddles) 默认在页面上展开。您可以使用代码块左上角的箭头单独折叠和展开示例代码块。您还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。
类成员默认在页面上折叠。您可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠所有切换按钮来展开和折叠成员。
在较窄的屏幕或浏览器上查看文档将导致针对较小外形尺寸优化的视图。桌面视图和“移动”视图之间的主要区别在于
可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“view source”链接来查看类成员的源代码。
开发人员可用的最强大的交互设计模式之一是“拖放”。我们使用拖放而没有真正考虑太多 - 尤其是在做得正确的情况下。以下是确保优雅实现的 5 个简单步骤。
拖动操作本质上是在鼠标按钮按住且鼠标移动时单击某些 UI 元素的手势。放置操作发生在拖动操作后鼠标按钮释放时。从高层次来看,拖放决策可以通过以下流程图来概括。
为了加快我们的开发速度,Ext JS 为我们提供了 Ext.dd 类来管理基本决策。在本指南中,我们将介绍放置邀请的外观和移除、无效放置修复以及成功放置发生时的编码。
乍一看 Ext.dd 文档中的类可能有点吓人。但是,如果我们花一点时间查看这些类,我们会发现它们都源于 DragDrop 类,并且大多数可以分为 Drag 或 Drop 组。稍微花更多的时间和挖掘,我们可以看到这些类可以进一步分为单节点和多节点拖放交互。
为了学习拖放的基础知识,我们将专注于将单次拖放交互应用于 DOM 节点。为此,我们将使用 DD 和 DDTarget 类,它们为各自的拖放行为提供基本实现。但是,在开始实现拖放之前,我们需要讨论我们的目标是什么。
假设我们被要求开发一个应用程序,该应用程序将为汽车租赁公司提供将其汽车和卡车放置在三种状态之一的能力:可用、已出租或维修状态。汽车和卡车只能放置在其各自的“可用”容器中。
首先,我们必须使汽车和卡车“可拖动”。为此,我们将使用 DD。我们需要使已出租、维修和车辆容器成为“放置目标”。为此,我们将使用 DDTarget。最后,我们将使用不同的拖放组来帮助强制执行汽车和卡车只能放置在其各自的“可用”容器中的要求。现在我们可以开始编码,将拖动操作添加到汽车和卡车。
要将车辆 DIV 元素配置为可拖动,我们需要获取列表并循环遍历它以实例化 DD 的新实例。以下是我们执行此操作的方式。
Ext.onReady(function() {
// Create an object that we'll use to implement and override drag behaviors a little later
var overrides = {};
// Configure the cars to be draggable
var carElements = Ext.get('cars').select('div');
Ext.each(carElements.elements, function(el) {
var dd = Ext.create('Ext.dd.DD', el, 'carsDDGroup', {
isTarget : false
});
//Apply the overrides object to the newly created instance of DD
Ext.apply(dd, overrides);
});
var truckElements = Ext.get('trucks').select('div');
Ext.each(truckElements.elements, function(el) {
var dd = Ext.create('Ext.dd.DD', el, 'trucksDDGroup', {
isTarget : false
});
Ext.apply(dd, overrides);
});
});
所有拖放类都设计为通过重写其方法来实现。这就是为什么在上面的代码段中,我们创建了一个名为 overrides 的空对象,稍后将使用特定于我们需要操作的重写来填充该对象。我们通过利用 DomQuery select 方法查询汽车容器中的所有子 div 元素来获取汽车和卡车元素的列表。为了使汽车和卡车元素可拖动,我们创建了 DD 的新实例,传入要拖动的汽车或卡车元素以及它要参与的拖放组。请注意,车辆类型有其各自的拖放组。这对于稍后将已出租和维修容器设置为放置目标时非常重要。另请注意,我们正在使用 Ext.apply 将 overrides 对象应用于新创建的 DD 实例。,这是一种将属性或方法添加到现有对象的便捷方法。在我们继续实施之前,我们需要花一点时间分析一下在屏幕上拖动元素时会发生什么。有了这种理解,其余的实现将水到渠成。
拖动汽车或卡车元素时,您首先会注意到它们将停留在放置的任何位置。这现在没问题,因为我们才刚刚开始实施。重要的是要了解拖动节点如何受到影响。这将有助于我们为返回到其原始位置进行编码,当它们被放置在任何不是有效放置目标的位置时,这被称为“无效放置”。下面的插图使用了 FireBug 的 HTML 检查面板,并突出显示了当拖动操作应用于 Camaro 元素时所做的更改。
在拖动操作期间检查拖动元素时,我们可以看到一个 style 属性添加到元素中,其中填充了三个 CSS 值:position、top 和 left。进一步检查显示 position 属性设置为 relative,而 top 和 left 属性在节点被拖动时更新。在拖动手势完成后,style 属性以及其中包含的样式仍然存在。这就是我们在为无效放置的修复进行编码时必须清理的内容。在我们设置正确的放置目标之前,所有放置操作都被认为是无效的。
阻力最小的路径是通过重置在拖动操作期间应用的 style 属性来修复无效的放置。这意味着拖动元素将从鼠标下方消失,并重新出现在其原始位置,并且会非常无聊。为了使其更平滑,我们将使用 Ext.Fx 来动画化此操作。请记住,拖放类设计为重写方法。要实现修复,我们需要重写 b4StartDrag、onInvalidDrop 和 endDrag 方法。让我们将以下方法添加到上面的 overrides 对象中,我们将讨论它们是什么以及做什么。
var overrides = {
// Called the instance the element is dragged.
b4StartDrag : function() {
// Cache the drag element
if (!this.el) {
this.el = Ext.get(this.getEl());
}
//Cache the original XY Coordinates of the element, we'll use this later.
this.originalXY = this.el.getXY();
},
// Called when element is dropped in a spot without a dropzone, or in a dropzone without matching a ddgroup.
onInvalidDrop : function() {
// Set a flag to invoke the animated repair
this.invalidDrop = true;
},
// Called when the drag operation completes
endDrag : function() {
// Invoke the animation if the invalidDrop flag is set to true
if (this.invalidDrop === true) {
// Remove the drop invitation
this.el.removeCls('dropOK');
// Create the animation configuration object
var animCfgObj = {
easing : 'elasticOut',
duration : 1,
scope : this,
callback : function() {
// Remove the position attribute
this.el.dom.style.position = '';
}
};
// Apply the repair animation
this.el.setXY(this.originalXY, animCfgObj);
delete this.invalidDrop;
}
},
在上面的代码中,我们首先重写 b4StartDrag 方法,该方法在拖动元素开始在屏幕上拖动时立即调用,并使其成为缓存拖动元素和原始 XY 坐标的理想位置 - 我们稍后将在本过程中使用它们。接下来,我们重写 onInvalidDrop,当拖动节点放置在任何不是参与同一拖放组的放置目标时,将调用该方法。此重写只是将本地 invalidDrop 属性设置为 true,这将在下一个方法中使用。我们重写的最后一个方法是 endDrag,当拖动元素不再在屏幕上拖动并且拖动元素不再受鼠标移动控制时,将调用该方法。此重写将使用动画将拖动元素移回其原始 X 和 Y 位置。我们配置动画使用 elasticOut easing,以便在动画结束时提供酷炫有趣的弹性效果。
好的,现在我们已经完成了修复操作。为了使其在放置邀请和有效放置操作上起作用,我们需要设置放置目标。
我们的要求规定,我们将允许汽车和卡车放置在已出租和维修容器以及它们各自的原始容器中。为此,我们需要实例化 DDTarget 类的实例。以下是如何完成的。
// Instantiate instances of Ext.dd.DDTarget for the cars and trucks container
var carsDDTarget = Ext.create('Ext.dd.DDTarget', 'cars','carsDDGroup');
var trucksDDTarget = Ext.create('Ext.dd.DDTarget', 'trucks', 'trucksDDGroup');
// Instantiate instances of DDTarget for the rented and repair drop target elements
var rentedDDTarget = Ext.create('Ext.dd.DDTarget', 'rented', 'carsDDGroup');
var repairDDTarget = Ext.create('Ext.dd.DDTarget', 'repair', 'carsDDGroup');
// Ensure that the rented and repair DDTargets will participate in the trucksDDGroup
rentedDDTarget.addToGroup('trucksDDGroup');
repairDDTarget.addToGroup('trucksDDGroup');
在上面的代码片段中,我们为汽车、卡车、已出租和维修元素设置了放置目标。请注意,汽车容器元素仅参与“carsDDGroup”,而卡车容器元素参与“trucksDDGroup”。这有助于强制执行汽车和卡车只能放置在其原始容器中的要求。接下来,我们为已出租和维修元素实例化 DDTarget 实例。最初,它们被配置为仅参与“carsDDGroup”。为了允许它们参与“trucksDDGroup”,我们必须通过 addToGroup 添加它。好的,现在我们已经配置了我们的放置目标。让我们看看当我们将汽车或卡车放置在有效的放置元素上时会发生什么。
在练习放置目标时,我们看到拖动元素完全停留在其放置的位置。也就是说,图像可以放置在放置目标上的任何位置并停留在那里。这意味着我们的放置实现尚不完整。为了完成它,我们需要通过对我们之前创建的 DD 实例的另一个重写来实际为“完成放置”操作编码。
要完成放置,我们将需要使用 DOM 工具实际将元素从其父元素拖动到放置目标元素。这是通过重写 DD 的 onDragDrop 方法来实现的。将以下方法添加到 overrides 对象。
var overrides = {
...
// Called upon successful drop of an element on a DDTarget with the same
onDragDrop : function(evtObj, targetElId) {
// Wrap the drop target element with Ext.Element
var dropEl = Ext.get(targetElId);
// Perform the node move only if the drag element's
// parent is not the same as the drop target
if (this.el.dom.parentNode.id != targetElId) {
// Move the element
dropEl.appendChild(this.el);
// Remove the drag invitation
this.onDragOut(evtObj, targetElId);
// Clear the styles
this.el.dom.style.position ='';
this.el.dom.style.top = '';
this.el.dom.style.left = '';
}
else {
// This was an invalid drop, initiate a repair
this.onInvalidDrop();
}
},
在上面的重写中,拖动元素被移动到放置目标元素,但前提是它与拖动元素的父节点不同。在移动拖动元素后,将清除其样式。如果放置元素与拖动元素的父元素相同,我们通过调用 this.onInvalidDrop 来确保发生修复操作。
成功放置后,拖动元素现在将从其父元素移动到放置目标。用户如何知道他们是否悬停在有效的放置目标上方?我们将通过配置放置邀请为用户提供一些视觉反馈。
为了使拖放更有用,我们需要向用户提供有关放置操作是否可以成功发生的反馈。这意味着我们将不得不重写 onDragEnter 和 onDragOut 方法。将最后两个方法添加到 overrides 对象。
var overrides = {
...
// Only called when the drag element is dragged over the a drop target with the
same ddgroup
onDragEnter : function(evtObj, targetElId) {
// Colorize the drag target if the drag node's parent is not the same as the
drop target
if (targetElId != this.el.dom.parentNode.id) {
this.el.addCls('dropOK');
}
else {
// Remove the invitation
this.onDragOut();
}
},
// Only called when element is dragged out of a dropzone with the same ddgroup
onDragOut : function(evtObj, targetElId) {
this.el.removeCls('dropOK');
}
};
在上面的代码中,我们重写了 onDragEnter 和 onDragOut 方法,这两个方法仅在拖动元素与参与同一拖放组的放置目标交互时才使用。仅当鼠标光标首次与放置目标的边界相交时(当拖动项目处于拖动模式时),才调用 onDragEnter 方法。同样,当鼠标光标在拖动模式下首次拖动到放置目标的边界之外时,将调用 onDragOut。
通过向 onDragEnter 和 onDragOut 方法添加重写,我们可以看到当鼠标光标首次与有效放置目标相交时,拖动元素的背景将变为绿色,并在离开放置目标或被放置时失去其绿色背景。这完成了我们使用 DOM 元素实现的拖放。
今天,我们学习了如何使用第一级拖放实现类来实现 DOM 节点的端到端拖放。从高层次来看,我们定义并讨论了什么是拖放,以及如何在框架方面考虑它。我们还了解到,拖放类可以按拖动或放置行为以及它们是否支持单次或多次拖放操作进行分组。在实现此行为时,我们说明了 dd 类有助于做出一些行为决策,而我们负责编码最终行为。我们希望您喜欢对 DOM 节点的一些基本拖放操作进行的全面了解。我们期待在未来为您带来更多关于此主题的文章。
由 Jay Garcia 撰写
加西亚先生是《Ext JS in Action》和《Sencha Touch in Action》的作者。自 2006 年以来,他一直是基于 Sencha 的 JavaScript 框架的倡导者。Jay 还是 Modus Create 的联合创始人兼首席技术官,Modus Create 是一家数字机构,专注于利用顶尖人才开发高质量的基于 Sencha 的应用程序。Modus Create 是 Sencha 的高级合作伙伴。