HTML表单只读SELECT标签/输入

757
根据HTML规范,HTML中的标签的"readonly"属性,并仍然获取POST数据?

5
不要依赖这个来处理服务器端。任何人都可以创建自己的HTML页面并将其变为可读写。 - SineSwiper
11
这不是一个特定于PHP的问题。 - Kaleb Brasee
6
在这种情况下,我建议完全不使用选择元素。你是否有任何理由不能只将值显示为纯文本? - Big McLargeHuge
2
@ppumkin,你的评论毫无意义。我并不是说选择或隐藏表单字段从来没有好的使用情况。OP在页面上显示一些文本时遇到了问题,我只是想知道在这种情况下使用选择元素的目的是什么。 - Big McLargeHuge
3
我可能看错问题了。他说他想禁用选择框以防止用户更改它。也许他需要使用jQuery呈现带有选择框的页面并防止更改。但是当他提交回来时,没有相关的数据。我做过同样的事情。我需要显示由其他选择框过滤的选择框,并通过ajax将最后一个下拉菜单保存到数据库中,因此之前的所有选择框都必须被锁定。当我重新呈现页面时,可以显示标签而不是选择框,但这不是问题的关键 :) - Piotr Kula
显示剩余6条评论
48个回答

550

你应该保持 select 元素的 disabled 属性,同时添加另一个隐藏的 input,并设置相同的名称和值。

如果重新启用 SELECT 元素,在 onchange 事件中将其值复制到隐藏的输入框中,然后禁用(或删除)该隐藏的输入框。

这是一个演示:

$('#mainform').submit(function() {
    $('#formdata_container').show();
    $('#formdata').html($(this).serialize());
    return false;
});

$('#enableselect').click(function() {
    $('#mainform input[name=animal]')
        .attr("disabled", true);
    
    $('#animal-select')
        .attr('disabled', false)
     .attr('name', 'animal');
    
    $('#enableselect').hide();
    return false;
});
#formdata_container {
    padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
    <form id="mainform">
        <select id="animal-select" disabled="true">
            <option value="cat" selected>Cat</option>
            <option value="dog">Dog</option>
            <option value="hamster">Hamster</option>
        </select>
        <input type="hidden" name="animal" value="cat"/>
        <button id="enableselect">Enable</button>
        
        <select name="color">
            <option value="blue" selected>Blue</option>
            <option value="green">Green</option>
            <option value="red">Red</option>
        </select>

        <input type="submit"/>
    </form>
</div>

<div id="formdata_container" style="display:none">
    <div>Submitted data:</div>
    <div id="formdata">
    </div>
</div>


7
如果您重新启用选择,则必须同时禁用或删除隐藏输入框(按照描述复制其值),否则将会提交两次值。 - Adam
2
如果我正在使用多选功能,该怎么办? - Anyul Rivas
3
如果有两个元素具有相同的名称,只会提交最后一个启用的输入或选择,不会重复提交。而且,只有“selected”值会被提交,而不是整个列表。因此,您的“hidden”应该放在“select”之前,并保存所选值。如果选择因“readonly”而被禁用,则提交只包含隐藏输入的值。如果选择被启用,可见的所选选项将“覆盖/替换”隐藏值,并将其提交回来。 - Piotr Kula
63
虽然这是显而易见的解决方案,但它并不是一个好的解决方案,因为你需要增加另一个输入字段。 - Donato
1
@Yeen选择字段不需要名称,因此不应提交。如果您需要启用它并发送它的值-可以将onChange事件添加到它上面以将值复制到隐藏字段中,或者将名称从隐藏字段移动到选择字段中。 - bezmax
显示剩余14条评论

286

我们也可以禁用除所选选项外的所有选项。

这样,下拉列表仍然能够工作(并提交其值),但用户无法选择其他值。

演示

<select>
    <option disabled>1</option>
    <option selected>2</option>
    <option disabled>3</option>
</select>


6
感谢您选择动态选项。 - Diego Favero
13
适用于单一数值的SELECT标签!但对于<select multiple>无效,用户仍然可以取消选择某些选项,从而改变数值。 - Mikhail Bunkin
2
option 标签的 disabled 属性在浏览器中的支持情况。 - Jo.
9
这是一个很好的解决方案。我将其翻译成中文:你可以使用 jQuery 轻松实现它,代码如下: $("#yourSelectId option:not(:selected)).attr("disabled", "disabled") - Onkel-j
2
$('#yourSelectId option:not(:selected)').attr('disabled', 'disabled') $('#yourSelectId option:not(:selected)').attr('disabled', 'disabled') - Herman Zun
显示剩余3条评论

131
您可以在提交表单时重新启用选择对象。 编辑: 即通常使用禁用属性(disabled)禁用选择标记,然后在提交表单之前自动重新启用它:
使用jQuery的示例:
- 要禁用它:
$('#yourSelect').prop('disabled', true);
重新启用它以便在提交之前包括 GET / POST 数据:
$('#yourForm').on('submit', function() {
    $('#yourSelect').prop('disabled', false);
});
此外,你可以重新启用每个已禁用的输入或选择:

另外,您可以重新启用每个已被禁用的输入或选择:

$('#yourForm').on('submit', function() {
    $('input, select').prop('disabled', false);
});

4
使用.prop('disabled', true/false)来设置禁用属性。该属性不会改变实际状态。 - Paris Char
1
我认为这个解决方案比@bezmax的解决方案更聪明。 因为如果我们添加隐藏输入,我们必须考虑在任何时候只有一个相同名称的输入是启用的。 换句话说,如果两个输入都启用了,在服务器端,程序将获取可能导致异常的输入数组(例如,如果我们没有处理这种情况,并且我们期望一个字符串并使用'Request.Form[FieldName]'命令)。 - M.i.T
@Kevin,适用于90%的情况。此外,您必须掌握jQuery... 嗯。 - sitilge
3
这个解答比被接受的答案更加简洁。如果你不再想禁用该元素,解除其禁用状态的逻辑更容易实现,并且不需要额外的输入标签。 - Haohmaru
1
你救了我的一天!我一直在寻找类似的解决方案。在我的Spring Boot应用程序中,我总是遇到NullPointerException。非常感谢你! :) - madaimartin
我认为这个答案是最好的解决方案,而不是添加新的隐藏输入类型。 - Yohanim

85

使用CSS也可以为


14
不错的解决方案,但是你仍然可以通过键盘更改数值。 - Mario Werner
2
是的,这非常棒。如果您想使用键盘更改值,则必须将焦点移至该元素并选择它。如果您将背景颜色变为灰色或禁用,还可以在视觉上通知用户此选项已“禁用”,即使实际上并未禁用。现在没有人再支持IE了,所以谁在乎呢。如果您想要防止按键事件的默认行为,也可以使用keydown prevent default。 - Piotr Kula
相当不正统!!如果需要阻止选择器在页面渲染时被显示,可以使用 ... .on('mouseover', function(){ ... }); - Fr0zenFyr
5
pointer-events: none可以防止鼠标光标聚焦。为了同时防止键盘聚焦,您可以通过在所有聚焦事件上立即模糊补充它:$('select').css('pointer-events', 'none').on('focus', function () {$(this).blur();}); - Quinn Comendant
3
йҳІжӯўйҖҡиҝҮй”®зӣҳеҜјиҲӘйӣҶдёӯе…ғзҙ зҡ„ж–№жі•жҳҜдҪҝз”ЁtabIndexеұһжҖ§/еұһжҖ§пјҢеҖјдёә-1гҖӮ - Armen Michaeli
对于同时实现“鼠标锁定”和“键盘锁定”的解决方案,请参见此答案 - Jakub Holan

46

我知道现在已经太晚了,但使用简单的CSS可以完成:

select[readonly] option, select[readonly] optgroup {
    display: none;
}

不需要使用JavaScript技巧。


好的和简单的。我喜欢它。 - Jonathan Parent Lévesque
这是一个非常好的解决方案。谢谢! - OderWat
3
2020年,无法向下拉菜单添加只读属性...太棒了解决方法! - jbra95
它像魔法一样运行。优秀而优雅!谢谢 - ivo.tisljar

44

简单的jQuery解决方案

如果您的选择框具有 readonly 类,则使用此方法

jQuery('select.readonly option:not(:selected)').attr('disabled',true);

如果您的选择框具有readonly="readonly"属性,则可以使用此方法。

$('select[readonly="readonly"] option:not(:selected)').attr('disabled',true);

7
请解释一下你的代码。我们需要给选择元素添加'readonly'类吗?何时需要调用此代码:只在文档准备就绪时还是每次启用/禁用选择时都需要?你的代码是否支持无脚本环境? 请解释一下您的代码。我们需要在选择元素中添加“readonly”类吗?何时需要调用此代码:仅在文档就绪时还是每次启用/禁用选择器时都需要?你的代码是否支持无脚本环境? - anar khalilov
不理解这些。 - Piotr Kula
黑砖软件 - 您需要一个点赞,这是在选择列表上快速/清洁地模拟只读状态的方法。 - monkeylumps
2
我喜欢这个解决方案。我会将选择器更改为 select[readonly],这样您只需向元素添加 readonly 属性 - 这样您就不必将选择与任何其他类型区别对待。然后,JavaScript 逐步增强效果。请记住,此解决方案(以及大多数其他解决方案)仅帮助用户代理提供最佳用户体验 - 它实际上并没有强制执行任何内容(如果需要,必须在服务器端执行)。 - jgivoni
这对我不起作用。元素没有被修改。 - toddmo
显示剩余5条评论

42
<select id="countries" onfocus="this.defaultIndex=this.selectedIndex;" onchange="this.selectedIndex=this.defaultIndex;">
<option value="1">Country1</option>
<option value="2">Country2</option>
<option value="3">Country3</option>
<option value="4">Country4</option>
<option value="5">Country5</option>
<option value="6">Country6</option>
<option value="7" selected="selected">Country7</option>
<option value="8">Country8</option>
<option value="9">Country9</option>
</select>

在IE 6、7和8b2,Firefox 2和3,Opera 9.62,Windows的Safari 3.2.1以及Google Chrome中测试并且工作正常。


17
问题在于下拉框的呈现方式好像不是只读的。用户会认为它无法使用... - Lukas Eder
9
用户感到困惑,因为他们仍然可以选择一个选项,但是当他们选择它时,列表会返回到先前选择的值。禁用列表以防止用户选择任何内容会更加直观。 - dana
11
我有过类似的问题,解决方法是只显示已选择的选项。无需使用JS,对用户来说更清晰易懂...<select id="countries"> <option value="7" selected="selected">Country7</option> </select> - Potherca
1
@ppumkin @dana @LukasEder 不行,如果你能解决这个用户体验问题就好了。例如,你可以像这样做:onchange = 'this.selectedIndex=this.defaultIndex; alert("您不应该更改此项..");'而不是悄悄地更改所选的索引。 - Fr0zenFyr
1
@LukasEder 对于那些对响应体验感到疑虑的人,他们可以添加一些CSS来强调下拉框不应该被更改。将光标设置为“not-allowed”,将背景颜色设置为“#CCC”。 - Alexander Dixon
显示剩余5条评论

28

简单的 CSS 解决方案:

select[readonly]{
    background: #eee;
    cursor:no-drop;
}

select[readonly] option{
    display:none;
}
这会导致选择框变为灰色,在悬停时出现漂亮的“禁用”光标,而在选择后,选项列表则变为空,因此您无法更改其值。

1
如果你有CSRF验证(像Symfony和许多其他框架一样),它将无法工作。 - ThEBiShOp
3
一个小的改进:select[readonly] option:not([selected]) {display:none;}这样它只会禁用未选中的选项,并仍然提交表单中选定的值。但这仍然是一个很棒的答案! - Auspex
1
select[readonly]{ cursor:no-drop; user-select: none; pointer-events: none; opacity: 0.7; }select[readonly] option:not([selected]) { display:none; } - undefined

17

[最简单的解决方案]

由于原帖明确要求不禁用选择元素,这是我用来使选择只读的方法。

在html中:

<select style="pointer-events: none;" onclick="return false;" onkeydown="return false;" ></select>

这就是解决方法

解释

  • 将pointer-events设置为none可以禁用鼠标/光标事件编辑“select-element”
  • 将onclick和onkeydown函数设置为返回false可以禁用键盘编辑“select-element”

这样,您无需创建任何额外的元素,也不需要使用JavaScript禁用/重新启用元素或搞乱表单提交逻辑,也不需要使用任何第三方库。

另外,您可以轻松地添加CSS样式,例如将背景颜色设置为灰色或将文本颜色设置为灰色,以表示该元素为只读。我未将其添加到代码中,因为它非常特定于您的站点主题。

或者,如果您想通过JavaScript来实现:

let isReadOnly = true ;

selectElement.onclick = function () {
    return !isReadOnly ;
};
selectElement.onkeydown =function(){
    return !isReadOnly ;
} ;
selectElement.style.pointerEvents = isReadOnly ? "none" : "all" ;


2
非常感谢!在所有有效的解决方案中,这个(对我来说)是最简单的! - Ale DC

16
更简单的方法是:在您的

这对我来说是有效的,但指针事件会使跨浏览器支持吗? - Abhijit Jagtap
8
不行。用户可以使用键盘更改输入。 - Sandhu

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