发布在:jQuery UI > 部件工厂

使用部件工厂扩展部件

jQuery UI 的部件工厂可以轻松构建部件,以扩展现有部件的功能。这样做可以让你在现有基础上构建强大的部件,以及对现有部件的功能进行微调。

注意:本文假设你对部件工厂是什么以及如何工作有一些基本了解。如果你不熟悉这些内容,请先阅读如何使用部件工厂

link 创建部件扩展

使用部件工厂创建部件的方法是将部件的名称和一个原型对象传递给 $.widget()。以下内容在“custom”命名空间中创建了一个“superDialog”部件。

1
$.widget( "custom.superDialog", {} );

为了允许扩展,$.widget() 可选择接受一个部件的构造函数,用作父级。指定父级部件时,将其作为第二个参数传递 - 在部件名称之后,在部件原型对象之前。

与上一个示例类似,以下内容也在“custom”命名空间中创建了一个“superDialog”部件。但是,这次传递了jQuery UI 的 dialog 部件 ($.ui.dialog) 的构造函数,表明 superDialog 部件应使用 jQuery UI 的 dialog 部件作为父级。

1
$.widget( "custom.superDialog", $.ui.dialog, {} );

此处 superDialog 和 dialog 本质上是具有不同名称和命名空间的等效部件。为了使我们的新部件更有趣,我们可以向其原型对象添加方法。

部件的原型对象是传递给 $.widget() 的最后一个参数。到目前为止,我们的示例一直使用空对象。让我们向此对象添加一个方法

1
2
3
4
5
6
7
8
9
10
$.widget( "custom.superDialog", $.ui.dialog, {
red: function() {
this.element.css( "color", "red" );
}
});
// Create a new <div>, convert it into a superDialog, and call the red() method.
$( "<div>I am red</div>" )
.superDialog()
.superDialog( "red" );

现在 superDialog 有一个 red() 方法,该方法会将文本颜色更改为红色。请注意,部件工厂如何自动将 this 设置为部件的实例对象。有关实例上可用的方法和属性的完整列表,请参阅部件工厂的 API 文档

link 扩展现有方法

有时,您需要调整或添加现有小部件方法的行为。为此,请指定一个方法,其名称与要在原型对象上覆盖的方法相同。以下示例覆盖了对话框的 open() 方法。由于对话框默认自动打开,因此当此代码运行时,将记录 "open"

1
2
3
4
5
6
7
8
$.widget( "custom.superDialog", $.ui.dialog, {
open: function() {
console.log( "open" );
}
});
// Create a new <div>, and convert it into a superDialog.
$( "<div>" ).superDialog();

在运行此代码时,会出现一个问题。由于我们覆盖了 open() 的默认行为,因此对话框不再显示在屏幕上。

当我们在原型对象上放置方法时,我们实际上并没有覆盖原始方法,而是将新方法放置在原型链中的更高级别。

为了使父级方法可用,小部件工厂提供了两种方法 - _super()_superApply()

link 使用 _super()_superApply() 访问父级

_super()_superApply() 调用父级小部件中同名的方法。请参阅以下示例。与前一个示例类似,此示例也覆盖了 open() 方法来记录 "open"。但是,这次运行 _super() 以调用对话框的 open() 并打开对话框。

1
2
3
4
5
6
7
8
9
10
$.widget( "custom.superDialog", $.ui.dialog, {
open: function() {
console.log( "open" );
// Invoke the parent widget's open().
return this._super();
}
});
$( "<div>" ).superDialog();

_super()_superApply() 的设计目的是像本机 Function.prototype.call()Function.prototype.apply() 方法一样。因此,_super() 接受一个参数列表,而 _superApply() 接受一个参数数组。此差异在下面的示例中显示。

1
2
3
4
5
6
7
8
9
$.widget( "custom.superDialog", $.ui.dialog, {
_setOption: function( key, value ) {
// Both invoke dialog's setOption() method. _super() requires the arguments
// be passed as an argument list, _superApply() as a single array.
this._super( key, value );
this._superApply( arguments );
}
});

link 重新定义小部件

jQuery UI 1.9 添加了小部件重新定义自身的功能。因此,我们可以向 $.widget() 传递现有小部件的名称和构造函数,而不是创建新小部件。以下示例在 open() 中添加了相同的日志记录,但不会创建新小部件来执行此操作。

1
2
3
4
5
6
7
8
$.widget( "ui.dialog", $.ui.dialog, {
open: function() {
console.log( "open" );
return this._super();
}
});
$( "<div>" ).dialog();

使用此方法,您可以扩展现有小部件的方法,并且仍然可以使用 _super() 访问原始方法 - 所有这些都不用创建新小部件。

link 小部件和多态性

在与小部件扩展及其插件交互时,需要特别注意一点。父级小部件的插件不能用于调用子级小部件元素上的方法。这在下面的示例中显示。

1
2
3
4
5
6
7
8
9
$.widget( "custom.superDialog", $.ui.dialog, {} );
var dialog = $( "<div>" ).superDialog();
// This works.
dialog.superDialog( "close" );
// This doesn't.
dialog.dialog( "close" );

在上面,父小部件的插件 dialog() 不能在超对话框元素上调用 close() 方法。有关调用小部件方法的更多信息,请参阅 小部件方法调用

链接 自定义单个实例

我们到目前为止看到的示例都扩展了小部件原型上的方法。在原型上重写的方法会影响小部件的所有实例。

要显示此内容,请参阅以下示例;对话框的两个实例都使用相同的 open() 方法。

1
2
3
4
5
6
7
8
9
10
$.widget( "ui.dialog", $.ui.dialog, {
open: function() {
console.log( "open" );
return this._super();
}
});
// Create two dialogs, both use the same open(), therefore "open" is logged twice.
$( "<div>" ).dialog();
$( "<div>" ).dialog();

虽然这很强大,但有时你只需要更改小部件单个实例的行为。为此,请获取对实例的引用并使用常规 JavaScript 属性赋值来重写方法。下面的示例对此进行了说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var dialogInstance = $( "<div>" )
.dialog()
// Retrieve the dialog's instance and store it.
.data( "ui-dialog" );
// Override the close() method for this dialog
dialogInstance.close = function() {
console.log( "close" );
};
// Create a second dialog
$( "<div>" ).dialog();
// Select both dialogs and call close() on each of them.
// "close" will only be logged once.
$( ":data(ui-dialog)" ).dialog( "close" );

这种为单个实例重写方法的技术非常适合一次性自定义。