jQuery UI 通过 Widget Factory 扩展小部件
Widget Factory($.widget)提供了强大的继承机制,让开发者可以轻松扩展现有 jQuery UI 小部件,或基于一个部件创建全新的变体。这正是 jQuery UI 官方许多小部件(如 Menu 是 Button 的扩展,Autocomplete 是 Menu 的扩展)实现方式的核心。
扩展基本语法
$.widget("custom.newWidgetName", $.existingNamespace.existingWidget, {
// 新选项、方法、重写父类方法
});
custom.newWidgetName:新部件的全名(命名空间 + 部件名)。$.existingNamespace.existingWidget:要继承的父部件(例如$.ui.dialog)。- 第三个对象:定义新选项、重写父类方法、添加新方法。
关键方法:
this._super():调用父类同名方法。this._superApply(arguments):带参数调用父类方法。
示例 1:简单扩展 Dialog(添加标题图标和自定义按钮)
$.widget("custom.iconDialog", $.ui.dialog, {
// 新增默认选项
options: {
iconClass: "ui-icon-info", // 默认信息图标
extraButton: null // 额外按钮配置 { text: "帮助", click: function }
},
// 重写 _create 方法,在标题栏添加图标
_create: function() {
// 先调用父类的 _create
this._super();
// 在标题栏前添加图标
if (this.options.iconClass) {
var icon = $("<span>")
.addClass("ui-dialog-title-icon " + this.options.iconClass)
.prependTo(this.uiDialogTitlebar);
}
// 添加额外按钮
if (this.options.extraButton) {
var buttons = this.options.buttons || {};
buttons[this.options.extraButton.text] = this.options.extraButton.click;
this.options.buttons = buttons;
this._setOption("buttons", buttons); // 触发按钮更新
}
},
// 可选:重写 open 方法,打开时添加动画效果
open: function() {
this._super(); // 调用父类 open
this.element.effect("bounce", { times: 3 }, 300); // 额外弹跳效果
}
});
使用方式:
<div id="myDialog" title="重要提示">这是一个带图标的对话框。</div>
<script>
$(function() {
$("#myDialog").customIconDialog({
iconClass: "ui-icon-alert",
modal: true,
extraButton: {
text: "帮助",
click: function() { alert("帮助内容"); }
}
});
// 打开对话框
$("#myDialog").customIconDialog("open");
});
</script>
示例 2:扩展 Tabs(添加“关闭”按钮到每个标签)
$.widget("custom.closableTabs", $.ui.tabs, {
options: {
closable: true
},
_create: function() {
this._super();
if (this.options.closable) {
this._addCloseButtons();
}
},
// 在每个标签后添加关闭图标
_addCloseButtons: function() {
this.tablist.find("li").each(function() {
var $tab = $(this);
if (!$tab.find(".ui-tabs-close").length) {
$("<span>")
.addClass("ui-tabs-close ui-icon ui-icon-close")
.appendTo($tab)
.on("click", function(e) {
e.stopPropagation();
var panelId = $tab.find("a").attr("href");
var index = $("li", $tab.parent()).index($tab);
$tab.closest(".ui-tabs").customClosableTabs("remove", index);
});
}
});
},
// 重写 refresh 方法,确保新添加的标签也有关闭按钮
refresh: function() {
this._super();
this._addCloseButtons();
},
// 可选:自定义 remove 方法,触发关闭事件
remove: function(index) {
var panelId = this.tabs.eq(index).attr("aria-controls");
var eventData = { panel: this.panels.eq(index) };
if (this._trigger("beforeClose", null, eventData) === false) {
return;
}
this._super(index);
this._trigger("close", null, eventData);
}
});
使用方式:
<div id="tabs">
<ul>
<li><a href="#tab1">标签1</a></li>
<li><a href="#tab2">标签2</a></li>
</ul>
<div id="tab1">内容1</div>
<div id="tab2">内容2</div>
</div>
<script>
$("#tabs").customClosableTabs({
closable: true,
beforeClose: function(event, ui) {
return confirm("确定关闭此标签页?");
}
});
</script>
示例 3:基于 Button 创建带加载状态的按钮
$.widget("custom.loadingButton", $.ui.button, {
options: {
loadingText: "加载中..."
},
// 添加 loading 方法
loading: function(state) {
if (state) {
this.originalText = this.element.text();
this.element.text(this.options.loadingText);
this.options.disabled = true;
this._super("option", "disabled", true);
} else {
if (this.originalText) {
this.element.text(this.originalText);
}
this.options.disabled = false;
this._super("option", "disabled", false);
}
}
});
总结优势
- 代码复用:继承父部件的大部分功能,只修改需要的部分。
- 保持兼容:新部件仍支持所有父部件的选项、方法、事件。
- 一致性:自动继承 CSS 类、主题支持、状态管理等。
- 链式继承:可以多层继承(如 A → B → C)。
通过 Widget Factory 的继承机制,你可以轻松创建功能更丰富、符合项目需求的自定义小部件,同时保持 jQuery UI 的统一风格和行为。
如果您有具体需求(如扩展 Datepicker 添加节假日高亮,或扩展 Autocomplete 支持异步加载),告诉我,我可以提供完整代码示例!