我想创建一个带有下拉列表的文本字段,让用户选择一些预定义的值。用户还应该能够键入新值或从下拉列表中选择预定义的值。我知道我可以为此使用两个小部件,但在我的应用程序中,如果它统一在一个小部件中会更符合人体工程学。
是否有标准小部件或者我必须使用第三方 javascript?
浏览器的便携性如何?
我想创建一个带有下拉列表的文本字段,让用户选择一些预定义的值。用户还应该能够键入新值或从下拉列表中选择预定义的值。我知道我可以为此使用两个小部件,但在我的应用程序中,如果它统一在一个小部件中会更符合人体工程学。
是否有标准小部件或者我必须使用第三方 javascript?
浏览器的便携性如何?
您可以通过使用<datalist>
HTML5 中的标记来完成此操作。
<input type="text" name="product" list="productName"/>
<datalist id="productName">
<option value="Pen">Pen</option>
<option value="Pencil">Pencil</option>
<option value="Paper">Paper</option>
</datalist>
如果您在浏览器中双击输入文本,则会出现一个包含已定义选项的列表。
这可以在纯 HTML、CSS 和 JQuery 的帮助下实现。我创建了一个示例页面:
$(document).ready(function(){
$(".editableBox").change(function(){
$(".timeTextBox").val($(".editableBox option:selected").html());
});
});
.editableBox {
width: 75px;
height: 30px;
}
.timeTextBox {
width: 54px;
margin-left: -78px;
height: 25px;
border: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<select class="editableBox">
<option value="1">01:00</option>
<option value="2">02:00</option>
<option value="3">03:00</option>
<option value="4">04:00</option>
<option value="5">05:00</option>
<option value="6">06:00</option>
<option value="7">07:00</option>
<option value="8">08:00</option>
<option value="9">09:00</option>
<option value="10">10:00</option>
<option value="11">11:00</option>
<option value="12">12:00</option>
<option value="13">13:00</option>
<option value="14">14:00</option>
<option value="15">15:00</option>
<option value="16">16:00</option>
<option value="17">17:00</option>
<option value="18">18:00</option>
<option value="19">19:00</option>
<option value="20">20:00</option>
<option value="21">21:00</option>
<option value="22">22:00</option>
<option value="23">23:00</option>
<option value="24">24:00</option>
</select>
<input class="timeTextBox" name="timebox" maxlength="5"/>
</div>
最好的方法可能是使用第三方库。
在jQuery UI jQuery UI和dojo dojo中有一个您正在寻找的实现。jQuery 更受欢迎,但 dojo 允许您在 HTML 中以声明方式定义小部件,这听起来更像您正在寻找的东西。
您使用哪一个取决于您的风格,但两者都是为跨浏览器工作而开发的,并且两者都将比复制和粘贴代码更频繁地更新。
基于 CSS 和一行 JavaScript 代码的非常简单的实现(只有基本功能)。
.dropdown {
position: relative;
width: 200px;
}
.dropdown select {
width: 100%;
}
.dropdown > * {
box-sizing: border-box;
height: 1.5em;
}
.dropdown input {
position: absolute;
width: calc(100% - 20px);
}
<div class="dropdown">
<input type="text" />
<select onchange="this.previousElementSibling.value=this.value; this.previousElementSibling.focus()">
<option>This is option 1</option>
<option>Option 2</option>
</select>
</div>
请注意:它使用previousElementSibling()
的是旧浏览器(低于 IE9)不支持的
该<select>
标签只允许使用预定义的条目。您的问题的典型解决方案是使用一个标记为“其他”的条目和一个禁用的编辑字段 ( <input type="text"
)。添加一些 JavaScript 以仅在选择“其他”时启用编辑字段。
可能以某种方式创建一个允许直接编辑的下拉菜单,但 IMO 不值得付出努力。如果是这样,亚马逊、谷歌或微软就会这样做;-) 只需用最简单的解决方案完成工作。它更快(你的老板可能喜欢那样)并且通常更容易维护(你可能喜欢那样)。
带有文本框的组合框(用于预定义值和用户定义值。)
我不确定有没有办法在没有 javascript 的情况下自动完成。
您需要的是在浏览器端运行的东西,以便在用户进行选择时将您的表单提交回服务器 - 因此是 javascript。
此外,请确保您为那些关闭了 javascript 的人提供了替代方法(即提交按钮)。
一个很好的例子:组合框查看器
昨天我甚至有一个更复杂的组合框,使用这个dhtmlxCombo,使用 ajax 在大量数据中检索相关值。
一点CSS,你就完成了 小提琴
<div style="position: absolute;top: 32px; left: 430px;" id="outerFilterDiv">
<input name="filterTextField" type="text" id="filterTextField" tabindex="2" style="width: 140px;
position: absolute; top: 1px; left: 1px; z-index: 2;border:none;" />
<div style="position: absolute;" id="filterDropdownDiv">
<select name="filterDropDown" id="filterDropDown" tabindex="1000"
onchange="DropDownTextToBox(this,'filterTextField');" style="position: absolute;
top: 0px; left: 0px; z-index: 1; width: 165px;">
<option value="-1" selected="selected" disabled="disabled">-- Select Column Name --</option>
</select>
HTML 没有内置的可编辑下拉列表或组合框,但我在一篇文章中实现了一个主要是 CSS 的解决方案。
您可以在此处查看完整的演示,但总而言之,编写 HTML 如下:
<span class="combobox withtextlist">
<input value="Fruit">
<span tabindex="-1" class="downarrow"></span>
<select size="10" class="sticky">
<option>Apple</option>
<option>Banana</option>
<option>Cherry</option>
<option>Dewberry</option>
</select>
</span>
并使用这样的 CSS 来设置它的样式(这是为两个组合框设计的,组合框有一个向下箭头 ▾ 按钮,以及单击时打开的下拉菜单,并且可能有不同的样式):
/* ------------------------------------------ */
/* ----- combobox / dropdown list styling */
/* ------------------------------------------ */
.combobox {
/* Border slightly darker than Chrome's <select>, slightly lighter than FireFox's */
border: 1px solid #999;
padding-right: 1.25em; /* leave room for ▾ */
}
.dropdown, .combobox {
/* "relative" and "inline-block" (or just "block") are needed
here so that "absolute" works correctly in children */
position: relative;
display: inline-block;
}
.combobox > .downarrow, .dropdown > .downarrow {
/* ▾ Outside normal flow, relative to container */
display: inline-block;
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 1.25em;
cursor: default;
nav-index: -1; /* nonfunctional in most browsers */
border-width: 0px; /* disable by default */
border-style: inherit; /* copy parent border */
border-color: inherit; /* copy parent border */
}
/* Add a divider before the ▾ down arrow in non-dropdown comboboxes */
.combobox:not(.dropdown) > .downarrow {
border-left-width: 1px;
}
/* Auto-down-arrow if one is not provided */
.downarrow:empty::before {
content: '▾';
}
.downarrow::before, .downarrow > *:only-child {
text-align: center;
/* vertical centering trick */
position: relative;
top: 50%;
display: block; /* transform requires block/inline-block */
transform: translateY(-50%);
}
.combobox > input {
border: 0
}
.dropdown > *:last-child,
.combobox > *:last-child {
/* Using `display:block` here has two desirable effects:
(1) Accessibility: it lets input widgets in the dropdown to
be selected with the tab key when the dropdown is closed.
(2) It lets the opacity transition work.
But it also makes the contents visible, which is undesirable
before the list drops down. To compensate, use `opacity: 0`
and disable mouse pointer events. Another side effect is that
the user can select and copy the contents of the hidden list,
but don't worry, the selected content is invisible. */
display: block;
opacity: 0;
pointer-events: none;
transition: 0.4s; /* fade out */
position: absolute;
left: 0;
top: 100%;
border: 1px solid #888;
background-color: #fff;
box-shadow: 1px 2px 4px 1px #666;
box-shadow: 1px 2px 4px 1px #4448;
z-index: 9999;
min-width: 100%;
box-sizing: border-box;
}
/* List of situations in which to show the dropdown list.
- Focus dropdown or non-last child of it => show last-child
- Focus .downarrow of combobox => show last-child
- Stay open for focus in last child, unless .less-sticky
- .sticky last child stays open on hover
- .less-sticky stays open on hover, ignores focus in last-child */
.dropdown:focus > *:last-child,
.dropdown > *:focus ~ *:last-child,
.combobox > .downarrow:focus ~ *:last-child,
.combobox > .sticky:last-child:hover,
.dropdown > .sticky:last-child:hover,
.combobox > .less-sticky:last-child:hover,
.dropdown > .less-sticky:last-child:hover,
.combobox > *:last-child:focus:not(.less-sticky),
.dropdown > *:last-child:focus:not(.less-sticky) {
display: block;
opacity: 1;
transition: 0.15s;
pointer-events: auto;
}
/* focus-within not supported by Edge/IE. Unsupported selectors cause
the entire block to be ignored, so we must repeat all styles for
focus-within separately. */
.combobox > *:last-child:focus-within:not(.less-sticky),
.dropdown > *:last-child:focus-within:not(.less-sticky) {
display: block;
opacity: 1;
transition: 0.15s;
pointer-events: auto;
}
/* detect Edge/IE and behave if though less-sticky is on for all
dropdowns (otherwise links won't be clickable) */
@supports (-ms-ime-align:auto) {
.dropdown > *:last-child:hover {
display: block;
opacity: 1;
pointer-events: auto;
}
}
/* detect IE and do the same thing. */
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.dropdown > *:last-child:hover {
display: block;
opacity: 1;
pointer-events: auto;
}
}
.dropdown:not(.sticky) > *:not(:last-child):focus,
.downarrow:focus, .dropdown:focus {
pointer-events: none; /* Causes second click to close */
}
.downarrow:focus {
outline: 2px solid #8BF; /* Edge/IE can't do outline transparency */
outline: 2px solid #48F8;
}
/* ---------------------------------------------- */
/* Optional extra styling for combobox / dropdown */
/* ---------------------------------------------- */
*, *:before, *:after {
/* See https://css-tricks.com/international-box-sizing-awareness-day/ */
box-sizing: border-box;
}
.combobox > *:first-child {
display: inline-block;
width: 100%;
box-sizing: border-box; /* so 100% includes border & padding */
}
/* `.combobox:focus-within { outline:...}` doesn't work properly
in Firefox because the focus box is expanded to include the
(possibly hidden) drop list. As a workaround, put focus box on
the focused child. It is barely-visible so that it doesn't look
TOO ugly if the child isn't the same size as the parent. It
may be uglier if the first child is not styled as width:100% */
.combobox > *:not(:last-child):focus {
outline: 2px solid #48F8;
}
.combobox {
margin: 5px;
}
您还需要一些 JavaScript 来将列表与文本框同步:
function parentComboBox(el) {
for (el = el.parentNode; el != null && Array.prototype.indexOf.call(el.classList, "combobox") <= -1;)
el = el.parentNode;
return el;
}
// Uses jQuery
$(".combobox.withtextlist > select").change(function() {
var textbox = parentComboBox(this).firstElementChild;
textbox.value = this[this.selectedIndex].text;
});
$(".combobox.withtextlist > select").keypress(function(e) {
if (e.keyCode == 13) // Enter pressed
parentComboBox(this).firstElementChild.focus(); // Closes the popup
});
没有 CSS 的简单 HTML + Javascript 方法
function editDropBox() {
var cSelect = document.getElementById('changingList');
var optionsSavehouse = [];
if(cSelect != null) {
var optionsArray = Array.from(cSelect.options);
var arrayLength = optionsArray.length;
for (var o = 0; o < arrayLength; o++) {
var option = optionsArray[o];
var oVal = option.value;
if(oVal > 0) {
var localParams = [];
localParams.push(option.text);
localParams.push(option.value);
//localParams.push(option.selected); // if needed
optionsSavehouse.push(localParams);
}
}
}
var hidden = ("<input id='hidden_select_options' type='hidden' value='" + JSON.stringify(optionsSavehouse) + "' />");
var cSpan = document.getElementById('changingSpan');
if(cSpan != null) {
cSpan.innerHTML = (hidden + "<input size='2' type='text' id='tempInput' name='fname' onchange='restoreDropBox()'>");
}
}
function restoreDropBox() {
var cSpan = document.getElementById('changingSpan');
var cInput = document.getElementById('tempInput');
var hOptions = document.getElementById('hidden_select_options');
if(cSpan != null) {
var optionsArray = [];
if(hOptions != null) {
optionsArray = JSON.parse(hOptions.value);
}
var selectList = "<select id='changingList'>\n";
var arrayLength = optionsArray.length;
for (var o = 0; o < arrayLength; o++) {
var option = optionsArray[o];
selectList += ("<option value='" + option[1] + "'>" + option[0] + "</option>\n");
}
if(cInput != null) {
selectList += ("<option value='-1' selected>" + cInput.value + "</option>\n");
}
selectList += ("<option value='-2' onclick='editDropBox()'>- Edit -</option>\n</select>");
cSpan.innerHTML = selectList;
}
}
<span id="changingSpan">
<select id="changingList">
<option value="1">Apple</option>
<option value="2">Banana</option>
<option value="3">Cherry</option>
<option value="4">Dewberry</option>
<option onclick="editDropBox()" value="-2">- Edit -</option>
</select>
</span>