我当时正在开发一个HTML,并意识到在iOS Safari上,select字段的行为与其他浏览器(包括几个基于安卓的浏览器)非常不同。
Safari忽略了我的hidden
元素的option
属性,允许用户选择占位符值。虽然可以设置disabled
属性来阻止用户在iOS上选择这些字段,但这仍然会将这些字段显示给用户,并且必须使用媒体查询来处理,因为选项元素在其他浏览器中根本不会显示(甚至是占位符)。
我想要一个无缝的通用解决方案。一些阅读和实验表明,Safari实际上是在剥离隐藏属性,并从option
s中生成一个弹出。
当然,如果选项标签不存在,它就不能生成包含它们的弹出器.
发布于 2022-06-04 05:50:47
我的解决方案是将事件侦听器添加到:
touchstart
& touchend
暂时删除应该隐藏的选项(请注意,如果您滑动元素,而tapping)change input
侦听器阻止代码多次运行,而blur focusout touchcancel
侦听器确保如果用户取消选择选项,则可以触发不触发触摸结束的点击。)
这段代码看起来相对较长,但为了可读性,我是这样写的。它可以被显著压缩,性能命中可以忽略不计。
我已经使用jQuery实现了它,但是我认为没有理由不能用原生JS和querySelector()
来实现它。
这种方法对于其他触摸输入(滑动、滚动等)意外触发非常健壮,并且能够在click
事件发生之前很久就做出响应(这似乎是在产生弹出之后发生的)。
它并不完美,但它确实使Safari的行为在这个小方面与所有其他浏览器保持一致。
希望这能帮到别人!
$(document).ready(function() {
//Workaround - Safari/Ios - does not respect the <option hidden> attribute
//Momentarily remove the hidden option element when the user clicks a select element.
//Re-Add it after iOS has generated its selection popover
var hiddenOption; //Holds the option element we want to be non-selectable extra option)
var timers = []; //Collect setTimout timers
function returnOptionToSelect(element) {
if ($(element).children('[data-ioshidden]').length > 0) {
//It's already there. Do nothing.
} else {
$(element).prepend(hiddenOption); //Put it back
}
}
$('#jQueryWorkaroundForm select').on('touchstart touchend', function(e) {
if ($(e.target).data('has-been-changed')) {
//don't do anything
} else {
if($(e.target).children('[data-ioshidden]').length > 0){
hiddenOption = $(e.target).children('[data-ioshidden]');
$(hiddenOption).remove();
}
timers.push(setTimeout(returnOptionToSelect, 35, $(e.target))); //Nice short interval that's largely imperceptible, but long enough for the popover to generate
}
});
$('#jQueryWorkaroundForm select').on('input', function(e) {
if ($(e.target).data('has-been-changed')) {
//do nothing
} else {
$(e.target).data('has-been-changed', true);
if (navigator.maxTouchPoints && navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')){
$(e.target).prop('selectedIndex', (e.target.selectedIndex+1)); //Need to bump the index +1 on ios
}
//make sure the option is gone
for (var x in timers) {
clearTimeout(x);
}
timers = [];
if ($(e.target).children('[data-ioshidden]').length > 0) {
$(e.target).children('[data-ioshidden]').remove();
}
hiddenOption = undefined; //throw away the option so it can't get put back
}
});
$('#jQueryWorkaroundForm select').on('blur focusout touchcancel', function(e) {
if ($(e.target).data('has-been-changed')) {
//The user selected an option. Don't put the element back.
} else {
//The user did not select an option.
if ($(e.target).children('[data-ioshidden]').length > 0) {
//It's already there. Do nothing.
} else {
$(e.target).prepend(hiddenOption); //Put it back
}
}
});
});
select{
width:300px;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<p>jQuery Workaround</p>
<form id="jQueryWorkaroundForm">
<select>
<option hidden data-ioshidden value="">This option not selectable in any browser</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</form>
<p>Standard HTML</p>
<form id="standardHTMLForm">
<select>
<option value="" hidden>This option selectable in iOS Safari</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</form>
</body>
</html>
这里是JS小提琴:https://jsfiddle.net/wjcprbyg/97/
https://stackoverflow.com/questions/72497423
复制相似问题