我必须扩展一个使用1.10.4版本的现有项目,并且此jQuery-UI版本的构建没有任何小部件。 现在,我要使用“ Spinner”和“ Selectmenu”小部件。
对于“ Spinner”小部件:jQuery 1.10.4版可用。 可从versoin 1.11.4中获得“ Selectmenu”小工具。
不幸的是,我无法更新jQuery-UI的当前版本,所以我想知道如何/是否有可能使用这两个小部件来增强当前版本。
答案 0 :(得分:0)
使用$.widget()
可以扩展或创建自己的自定义窗口小部件。我从https://code.jquery.com/ui/1.11.4/jquery-ui.js收集了这段代码,由于$.ui.menu
存在于1.10.4中,因此大多数情况下都有效。必须进行一些调整。
我从https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
收集了样式
$(function() {
$.widget("custom.selectmenu", {
version: "1.11.4",
defaultElement: "<select>",
options: {
appendTo: null,
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
},
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
width: null,
// callbacks
change: null,
close: null,
focus: null,
open: null,
select: null
},
_create: function() {
var selectmenuId = this.element.uniqueId().attr("id");
this.ids = {
element: selectmenuId,
button: selectmenuId + "-button",
menu: selectmenuId + "-menu"
};
this._drawButton();
this._drawMenu();
if (this.options.disabled) {
this.disable();
}
},
_drawButton: function() {
var that = this;
// Associate existing label with the new button
this.label = $("label[for='" + this.ids.element + "']").attr("for", this.ids.button);
this._on(this.label, {
click: function(event) {
this.button.focus();
event.preventDefault();
}
});
// Hide original select element
this.element.hide();
// Create button
this.button = $("<span>", {
"class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
tabindex: this.options.disabled ? -1 : 0,
id: this.ids.button,
role: "combobox",
"aria-expanded": "false",
"aria-autocomplete": "list",
"aria-owns": this.ids.menu,
"aria-haspopup": "true"
})
.insertAfter(this.element);
$("<span>", {
"class": "ui-icon " + this.options.icons.button
})
.prependTo(this.button);
this.buttonText = $("<span>", {
"class": "ui-selectmenu-text"
})
.appendTo(this.button);
this._setText(this.buttonText, this.element.find("option:selected").text());
this._resizeButton();
this._on(this.button, this._buttonEvents);
this.button.one("focusin", function() {
// Delay rendering the menu items until the button receives focus.
// The menu may have already been rendered via a programmatic open.
if (!that.menuItems) {
that._refreshMenu();
}
});
this._hoverable(this.button);
this._focusable(this.button);
},
_drawMenu: function() {
var that = this;
// Create menu
this.menu = $("<ul>", {
"aria-hidden": "true",
"aria-labelledby": this.ids.button,
id: this.ids.menu
});
// Wrap menu
this.menuWrap = $("<div>", {
"class": "ui-selectmenu-menu ui-front"
})
.append(this.menu)
.appendTo(this._appendTo());
// Initialize menu widget
this.menuInstance = this.menu
.menu({
role: "listbox",
select: function(event, ui) {
event.preventDefault();
// support: IE8
// If the item was selected via a click, the text selection
// will be destroyed in IE
that._setSelection();
that._select(ui.item.data("ui-selectmenu-item"), event);
},
focus: function(event, ui) {
var item = ui.item.data("ui-selectmenu-item");
// Prevent inital focus from firing and check if its a newly focused item
if (that.focusIndex != null && item.index !== that.focusIndex) {
that._trigger("focus", event, {
item: item
});
if (!that.isOpen) {
that._select(item, event);
}
}
that.focusIndex = item.index;
that.button.attr("aria-activedescendant",
that.menuItems.eq(item.index).attr("id"));
}
})
.data("ui-menu");
// Adjust menu styles to dropdown
this.menu
.addClass("ui-corner-bottom")
.removeClass("ui-corner-all");
// Don't close the menu on mouseleave
this.menuInstance._off(this.menu, "mouseleave");
// Cancel the menu's collapseAll on document click
this.menuInstance._closeOnDocumentClick = function() {
return false;
};
// Selects often contain empty items, but never contain dividers
this.menuInstance._isDivider = function() {
return false;
};
},
refresh: function() {
this._refreshMenu();
this._setText(this.buttonText, this._getSelectedItem().text());
if (!this.options.width) {
this._resizeButton();
}
},
_refreshMenu: function() {
this.menu.empty();
var item,
options = this.element.find("option");
if (!options.length) {
return;
}
this._parseOptions(options);
this._renderMenu(this.menu, this.items);
this.menuInstance.refresh();
this.menuItems = this.menu.find("li").not(".ui-selectmenu-optgroup");
item = this._getSelectedItem();
// Update the menu to have the correct item focused
this.menuInstance.focus(null, item);
this._setAria(item.data("ui-selectmenu-item"));
// Set disabled state
this._setOption("disabled", this.element.prop("disabled"));
},
open: function(event) {
if (this.options.disabled) {
return;
}
// If this is the first time the menu is being opened, render the items
if (!this.menuItems) {
this._refreshMenu();
} else {
// Menu clears focus on close, reset focus to selected item
this.menu.find(".ui-state-focus").removeClass("ui-state-focus");
this.menuInstance.focus(null, this._getSelectedItem());
}
this.isOpen = true;
this._toggleAttr();
this._resizeMenu();
this._position();
this._on(this.document, this._documentClick);
this._trigger("open", event);
},
_position: function() {
this.menuWrap.position($.extend({ of: this.button
}, this.options.position));
},
close: function(event) {
if (!this.isOpen) {
return;
}
this.isOpen = false;
this._toggleAttr();
this.range = null;
this._off(this.document);
this._trigger("close", event);
},
widget: function() {
return this.button;
},
menuWidget: function() {
return this.menu;
},
_renderMenu: function(ul, items) {
var that = this,
currentOptgroup = "";
$.each(items, function(index, item) {
if (item.optgroup !== currentOptgroup) {
$("<li>", {
"class": "ui-selectmenu-optgroup ui-menu-divider" +
(item.element.parent("optgroup").prop("disabled") ?
" ui-state-disabled" :
""),
text: item.optgroup
})
.appendTo(ul);
currentOptgroup = item.optgroup;
}
that._renderItemData(ul, item);
});
},
_renderItemData: function(ul, item) {
return this._renderItem(ul, item).data("ui-selectmenu-item", item);
},
_renderItem: function(ul, item) {
var li = $("<li>");
if (item.disabled) {
li.addClass("ui-state-disabled");
}
this._setText(li, item.label);
return li.appendTo(ul);
},
_setText: function(element, value) {
if (value) {
element.text(value);
} else {
element.html(" ");
}
},
_move: function(direction, event) {
var item, next,
filter = ".ui-menu-item";
if (this.isOpen) {
item = this.menuItems.eq(this.focusIndex);
} else {
item = this.menuItems.eq(this.element[0].selectedIndex);
filter += ":not(.ui-state-disabled)";
}
if (direction === "first" || direction === "last") {
next = item[direction === "first" ? "prevAll" : "nextAll"](filter).eq(-1);
} else {
next = item[direction + "All"](filter).eq(0);
}
if (next.length) {
this.menuInstance.focus(event, next);
}
},
_getSelectedItem: function() {
return this.menuItems.eq(this.element[0].selectedIndex);
},
_toggle: function(event) {
this[this.isOpen ? "close" : "open"](event);
},
_setSelection: function() {
var selection;
if (!this.range) {
return;
}
if (window.getSelection) {
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(this.range);
// support: IE8
} else {
this.range.select();
}
// support: IE
// Setting the text selection kills the button focus in IE, but
// restoring the focus doesn't kill the selection.
this.button.focus();
},
_documentClick: {
mousedown: function(event) {
if (!this.isOpen) {
return;
}
if (!$(event.target).closest(".ui-selectmenu-menu, #" + this.ids.button).length) {
this.close(event);
}
}
},
_buttonEvents: {
// Prevent text selection from being reset when interacting with the selectmenu (#10144)
mousedown: function() {
var selection;
if (window.getSelection) {
selection = window.getSelection();
if (selection.rangeCount) {
this.range = selection.getRangeAt(0);
}
// support: IE8
} else {
this.range = document.selection.createRange();
}
},
click: function(event) {
this._setSelection();
this._toggle(event);
},
keydown: function(event) {
var preventDefault = true;
switch (event.keyCode) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ESCAPE:
this.close(event);
preventDefault = false;
break;
case $.ui.keyCode.ENTER:
if (this.isOpen) {
this._selectFocusedItem(event);
}
break;
case $.ui.keyCode.UP:
if (event.altKey) {
this._toggle(event);
} else {
this._move("prev", event);
}
break;
case $.ui.keyCode.DOWN:
if (event.altKey) {
this._toggle(event);
} else {
this._move("next", event);
}
break;
case $.ui.keyCode.SPACE:
if (this.isOpen) {
this._selectFocusedItem(event);
} else {
this._toggle(event);
}
break;
case $.ui.keyCode.LEFT:
this._move("prev", event);
break;
case $.ui.keyCode.RIGHT:
this._move("next", event);
break;
case $.ui.keyCode.HOME:
case $.ui.keyCode.PAGE_UP:
this._move("first", event);
break;
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_DOWN:
this._move("last", event);
break;
default:
this.menu.trigger(event);
preventDefault = false;
}
if (preventDefault) {
event.preventDefault();
}
}
},
_selectFocusedItem: function(event) {
var item = this.menuItems.eq(this.focusIndex);
if (!item.hasClass("ui-state-disabled")) {
this._select(item.data("ui-selectmenu-item"), event);
}
},
_select: function(item, event) {
var oldIndex = this.element[0].selectedIndex;
// Change native select element
this.element[0].selectedIndex = item.index;
this._setText(this.buttonText, item.label);
this._setAria(item);
this._trigger("select", event, {
item: item
});
if (item.index !== oldIndex) {
this._trigger("change", event, {
item: item
});
}
this.close(event);
},
_setAria: function(item) {
var id = this.menuItems.eq(item.index).attr("id");
this.button.attr({
"aria-labelledby": id,
"aria-activedescendant": id
});
this.menu.attr("aria-activedescendant", id);
},
_setOption: function(key, value) {
if (key === "icons") {
this.button.find("span.ui-icon")
.removeClass(this.options.icons.button)
.addClass(value.button);
}
this._super(key, value);
if (key === "appendTo") {
this.menuWrap.appendTo(this._appendTo());
}
if (key === "disabled") {
this.menuInstance.option("disabled", value);
this.button
.toggleClass("ui-state-disabled", value)
.attr("aria-disabled", value);
this.element.prop("disabled", value);
if (value) {
this.button.attr("tabindex", -1);
this.close();
} else {
this.button.attr("tabindex", 0);
}
}
if (key === "width") {
this._resizeButton();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if (element) {
element = element.jquery || element.nodeType ?
$(element) :
this.document.find(element).eq(0);
}
if (!element || !element[0]) {
element = this.element.closest(".ui-front");
}
if (!element.length) {
element = this.document[0].body;
}
return element;
},
_toggleAttr: function() {
this.button
.toggleClass("ui-corner-top", this.isOpen)
.toggleClass("ui-corner-all", !this.isOpen)
.attr("aria-expanded", this.isOpen);
this.menuWrap.toggleClass("ui-selectmenu-open", this.isOpen);
this.menu.attr("aria-hidden", !this.isOpen);
},
_resizeButton: function() {
var width = this.options.width;
if (!width) {
width = this.element.show().outerWidth();
this.element.hide();
}
this.button.outerWidth(width);
},
_resizeMenu: function() {
this.menu.outerWidth(Math.max(
this.button.outerWidth(),
// support: IE10
// IE10 wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping
this.menu.width("").outerWidth() + 1
));
},
_getCreateOptions: function() {
return {
disabled: this.element.prop("disabled")
};
},
_parseOptions: function(options) {
var data = [];
options.each(function(index, item) {
var option = $(item),
optgroup = option.parent("optgroup");
data.push({
element: option,
index: index,
value: option.val(),
label: option.text(),
optgroup: optgroup.attr("label") || "",
disabled: optgroup.prop("disabled") || option.prop("disabled")
});
});
this.items = data;
},
_destroy: function() {
this.menuWrap.remove();
this.button.remove();
this.element.show();
this.element.removeUniqueId();
this.label.attr("for", this.ids.element);
}
});
$("#spinner").spinner();
$("#speed").selectmenu();
});
.ui-selectmenu-menu {
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
display: none;
}
.ui-selectmenu-menu .ui-menu {
overflow: auto;
/* Support: IE7 */
overflow-x: hidden;
padding-bottom: 1px;
}
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
font-size: 1em;
font-weight: bold;
line-height: 1.5;
padding: 2px 0.4em;
margin: 0.5em 0 0 0;
height: auto;
border: 0;
}
.ui-selectmenu-open {
display: block;
}
.ui-selectmenu-button {
display: inline-block;
overflow: hidden;
position: relative;
text-decoration: none;
cursor: pointer;
}
.ui-selectmenu-button span.ui-icon {
right: 0.5em;
left: auto;
margin-top: -8px;
position: absolute;
top: 50%;
}
.ui-selectmenu-button span.ui-selectmenu-text {
text-align: left;
padding: 0.4em 2.1em 0.4em 1em;
display: block;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js" integrity="sha256-tp8VZ4Y9dg702r7D6ynzSavKSwB9zjariSZ4Snurvmw=" crossorigin="anonymous"></script>
<p>
<label for="spinner">Select a value:</label>
<input id="spinner" name="value">
</p>
<label for="speed">Select a speed</label>
<select name="speed" id="speed">
<option>Slower</option>
<option>Slow</option>
<option selected="selected">Medium</option>
<option>Fast</option>
<option>Faster</option>
</select>
第一个问题1.11.4使用.menu('instance')
,而1.10.4对此不可用。在上面的代码中,该代码用在第145行上,可以恢复为.data("ui-menu");
进行补偿。
第二,选择项目时,由于未定义item
,因此触发了错误。这也与上述问题有关。需要做更多的工作。进行中。