jQuery UI 通过部件库(Widget Factory)扩展小部件

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 支持异步加载),告诉我,我可以提供完整代码示例!

文章已创建 3318

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部