可编辑的“选择”元素

71

我希望在表单中有一个选择元素,除了下拉菜单中的选项外,能够编辑并添加新的选项,但不是使用另一个文本输入框,我需要一次性完成。这是否可能?


23
可编辑下拉菜单也称为“组合框”。现在你多了一个谷歌搜索关键词 :) - BalusC
https://www.jqwidgets.com/jquery-widgets-documentation/documentation/jqxcombobox/jquery-combobox-getting-started.htm - Mohammad Adnan
可能是HTML组合框带有输入选项的重复问题 - The Guy with The Hat
6个回答

145

没有什么是不可能的。以下是一个解决方案,只需在 <select> 的值更改时设置文本输入框的值(已在 Firefox 和 Google Chrome 上进行了测试):

没什么不可能的。以下是一个解决方案,只需在 <select> 的值更改时设置文本输入框的值(已在 Firefox 和 Google Chrome 上进行了测试):

.select-editable {position:relative; background-color:white; border:solid grey 1px;  width:120px; height:18px;}
.select-editable select {position:absolute; top:0px; left:0px; font-size:14px; border:none; width:120px; margin:0;}
.select-editable input {position:absolute; top:0px; left:0px; width:100px; padding:1px; font-size:12px; border:none;}
.select-editable select:focus, .select-editable input:focus {outline:none;}
<div class="select-editable">
  <select onchange="this.nextElementSibling.value=this.value">
    <option value=""></option>
    <option value="115x175 mm">115x175 mm</option>
    <option value="120x160 mm">120x160 mm</option>
    <option value="120x287 mm">120x287 mm</option>
  </select>
  <input type="text" name="format" value=""/>
</div>
jsfiddle: https://jsfiddle.net/nwH8A/

下一个示例将用户输入添加到<select>的空选项槽中(感谢@TomerPeled)。它还具有更灵活/可变的CSS:
下一个示例将用户输入添加到<select>的空选项槽中(感谢@TomerPeled)。它还具有更灵活/可变的CSS:

.select-editable {position:relative; width:120px;}
.select-editable > * {position:absolute; top:0; left:0; box-sizing:border-box; outline:none;}
.select-editable select {width:100%;}
.select-editable input {width:calc(100% - 20px); margin:1px; border:none; text-overflow:ellipsis;}
<div class="select-editable">
  <select onchange="this.nextElementSibling.value=this.value">
    <option value=""></option>
    <option value="115x175 mm">115x175 mm</option>
    <option value="120x160 mm">120x160 mm</option>
    <option value="120x287 mm">120x287 mm</option>
  </select>
  <input type="text" oninput="this.previousElementSibling.options[0].value=this.value; this.previousElementSibling.options[0].innerHTML=this.value" onchange="this.previousElementSibling.selectedIndex=0" value="" />
</div>
jsfiddle: https://jsfiddle.net/pu7cndLv/1/


DataList

在HTML5中,您还可以使用 <input>list属性<datalist> 元素 来实现此功能:

<input list="browsers" name="browser">
<datalist id="browsers">
  <option value="Internet Explorer">
  <option value="Firefox">
  <option value="Chrome">
  <option value="Opera">
  <option value="Safari">
</datalist>
(click once to focus and edit, click again to see option dropdown)
jsfiddle: https://jsfiddle.net/hrkxebtw/

但这更像是自动完成列表;一旦开始输入,只有包含键入字符串的选项才会留作建议。根据您想要使用它做什么,这可能或可能不实用。

我可以使用datalists吗?


1
那个输入元素不应该有一个闭合标签吗? - user3083619
3
输入是一个空元素,因此根据文档类型,它不应该有结束标签(因为它不能包含内容)。http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements - Patrick
6
你的实现存在一个错误:如果你从列表中选择了115x175毫米大小,然后手动插入一些文本-12222-,然后再次尝试选择115x175毫米大小-什么也不会发生-这是因为列表没有被更新,尽管输入已经改变。 - Tomer Peled
5
在输入元素中添加 onchange="this.previousElementSibling.selectedIndex = -1" 可以解决我上面提到的错误。 - Tomer Peled
2
<datalist>存在问题。如果您有一个非常长的列表,它会溢出浏览器并占据屏幕从上到下的区域。缩小宽度和高度的样式不起作用。在Chrome 52.x上测试了这种行为。Firefox也存在问题。总之,<datalist>还不稳定。因此,仅在选项数量少且有限的情况下使用<datalist>。不要将其用于长或动态列表。 - domino_katrino
显示剩余4条评论

12

与上面的答案类似,但不使用绝对定位:

<select style="width: 200px; float: left;" onchange="this.nextElementSibling.value=this.value">
    <option></option>
    <option>1</option>
    <option>2</option>
    <option>3</option> 
</select>
<input style="width: 185px; margin-left: -199px; margin-top: 1px; border: none; float: left;"/>

因此,创建一个输入框并将其放在组合框的上方


可能会因为浮点数而出现问题 - 下面做了一些微调的版本。 - Tom

7

A bit more universal <select name="env" style="width: 200px; position:absolute;" onchange="this.nextElementSibling.value=this.value">
    <option></option>
    <option>1</option>
    <option>2</option>
    <option>3</option> 
</select>
<input style="width: 178px; margin-top: 1px; border: none; position:relative; left:1px; margin-right: 25px;" value="123456789012345678901234"/>layout ...


澄清一下 - 标签周围的文本是为了演示,周围的布局几乎与它们的原始对应物相同。 - Tom
select 标签是操作系统创建的一个独立窗口,是否始终置顶? - Dee

1
基于其他答案,这里是一个与knockout一起使用的初稿: 用法
      <div data-bind="editableSelect: {options: optionsObservable, value: nameObservable}"></div>

敲门数据绑定。
composition.addBindingHandler('editableSelect',
  {
    init: function(hostElement, valueAccessor) {

      var optionsObservable = getOptionsObservable();
      var valueObservable = getValueObservable();

      var $editableSelect = $(hostElement);
      $editableSelect.addClass('select-editable');

      var editableSelect = $editableSelect[0];

      var viewModel = new editableSelectViewModel(optionsObservable, valueObservable);
      ko.applyBindingsToNode(editableSelect, { compose: viewModel });

      //tell knockout to not apply bindings twice
      return { controlsDescendantBindings: true };

      function getOptionsObservable() {
        var accessor = valueAccessor();
        return getAttribute(accessor, 'options');
      }

      function getValueObservable() {
        var accessor = valueAccessor();
        return getAttribute(accessor, 'value');
      }
    }
  });

查看

<select
  data-bind="options: options, event:{ focus: resetComboBoxValue, change: setTextFieldValue} "
  id="comboBox"
  ></select>
<input
  data-bind="value: value, , event:{ focus: textFieldGotFocus, focusout: textFieldLostFocus}"
  id="textField"
  type="text"/>

视图模型
define([
  'lodash',
  'services/errorHandler'
], function(
  _,
  errorhandler
) {

  var viewModel = function(optionsObservable, valueObservable) {

    var self = this;
    self.options = optionsObservable();
    self.value = valueObservable;
    self.resetComboBoxValue = resetComboBoxValue;
    self.setTextFieldValue = setTextFieldValue;
    self.textFieldGotFocus = textFieldGotFocus;
    self.textFieldLostFocus = textFieldLostFocus;

    function resetComboBoxValue() {
      $('#comboBox').val(null);
    }

    function setTextFieldValue() {
      var selection = $('#comboBox').val();
      self.value(selection);
    }

    function textFieldGotFocus() {
      $('#comboBox').addClass('select-editable-input-focus');

    }

    function textFieldLostFocus() {
      $('#comboBox').removeClass('select-editable-input-focus');
    }

  };
  errorhandler.includeIn(viewModel);

  return viewModel;
});

CSS
.select-editable {

  display: block;
  width: 100%;
  height: 31px;
  padding: 6px 12px;
  font-size: 12px;
  line-height: 1.42857143;
  color: #555555;
  background-color: #ffffff;
  background-image: none;
  border: 1px solid #cccccc;
  border-radius: 0px;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;padding: 0;
}


.select-editable select {
  outline:0;
  padding-left: 10px;
  border:none;
  width:100%;
  height: 29px;
}


.select-editable input {
  outline:0;
  position: relative;
  top: -27px;
  margin-left: 10px;
  width:90%;
  height: 25px;
  border:none;
}

.select-editable select:focus {
  outline:0;
  border: 1px solid #66afe9;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
}




.select-editable input:focus {
  outline:0;
}

.select-editable-input-focus {
outline:0;
  border: 1px solid #66afe9 !important;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
}

1
另一种解决方法可能是...
使用HTML标记:
<input type="text" id="myselect"/>
<datalist id="myselect">
<option>option 1</option>
<option>option 2</option>
<option>option 3</option>
<option>option 4</option>
</datalist>

至少在Firefox中,如果输入框为空,聚焦后跟随点击会下拉已知有效值列表,作为<datalist>元素的一部分。否则,必须清空字段才能在输入数据时看到有效选择。新值将被接受为键入。必须使用JS或其他方法处理新值以使其持久化。这不是完美的,但对于我的极简需求足够了,所以我想分享一下。

0
感谢@Arraxas的回答,我定制了箭头并使input元素自适应于select元素,并且在我的Android手机的Chrome、Firefox上看起来很好(为select设置color:transparent和一些颜色的option以隐藏select的文本显示,因为input.combobox div:after不能完全覆盖select)。

/* https://dev59.com/zmYr5IYBdhLWcg3waJj7#41941056
select option:first-child, */
.combobox select, .combobox select option { color: #000000; }
.combobox select:invalid, .combobox select option[value=""] { color:grey; }

.combobox {position:absolute; left:80px; top:6px;}
.combobox>div { position:relative; font-size:1em; }
.combobox select {
    font-size:inherit; color:transparent;
    padding:0; -moz-appearance:none; -webkit-appearance:none; appearance:none;
    border:1px solid blueviolet;
}
.combobox input {
    position:absolute;top:1px;left:0px; text-overflow:ellipsis;
    box-sizing:border-box; padding:0px; margin:0px; height:calc(100% - 1px); width:calc(100% - 20px);
    border:1px solid blueviolet; border-right:none; border-top:none;
}
.combobox>div:after{
    position:absolute; top:0px; right:0px; height:100%; width:20px;
    box-sizing:border-box; content:"▼"; border:1px solid blueviolet; pointer-events:none;
    display:flex; flex-direction:row; align-items:center; justify-content:center;
}
.combobox select:focus, .combobox input:focus {outline:none;}
<!-- mandatory benefits/social security/welfare -->
<div class="combobox"><div>
    <select id=MandatoryBenefits onchange="this.nextElementSibling.value=this.value" required>
        <option value="" selected>Select ...</option>
        <option value="Pension">Pension %</option>
        <option value="Medical">Medical %</option>
        <option value="Unemployment">Unemployment %</option>
        <option value="Injury">Injury %</option>
        <option value="Maternity">Maternity %</option>
        <option value="Serious Illness">Serious Illness %</option>
        <option value="Housing Fund">Housing Fund %</option>
    </select>
    <input type="text" value="" onchange="this.previousElementSibling.selectedIndex=0"
        oninput="this.previousElementSibling.options[0].value=this.value; this.previousElementSibling.options[0].innerHTML=this.value" />
</div></div>

在线演示 (@jsbin)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接