Javascript 在 Mobile Safari 下拉列表项选择框上使用“下一步”时,选择/下拉的 onchange() JS 事件的奇怪行为
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5960731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Strange behavior of select/dropdown's onchange() JS event when using 'Next' on Mobile Safari Dropdown list item select box
提问by Vaibhav Garg
This is a hard one to articulate and I am new to mobile web development so please bear with me:
这很难说清楚,我是移动 Web 开发的新手,所以请耐心等待:
On my webpage,I have 3 Nested dropdown lists (Area, Town, Street).
在我的网页上,我有 3 个嵌套下拉列表(区域、城镇、街道)。
Nested as in, each dropdown's items are modified when the selection in the dropdown above it changes. e.g selecting an Areachanges the Townand Streetlists and selecting a Townchanges the Streetlist.
嵌套在,当其上方下拉列表中的选择更改时,每个下拉列表的项目都会被修改。例如,选择一个区域会改变城镇和街道列表,选择一个城镇会改变街道列表。
I use XMLHTTPRequests in the onchange() javascript event of the dropdowns to fetch and populate the other downdowns. This works fine on Android and Desktop browsers.
我在下拉列表的 onchange() javascript 事件中使用 XMLHTTPRequests 来获取和填充其他下拉列表。这适用于 Android 和桌面浏览器。
On Mobile Safari, when a drowdown is touched, a list is shown where the user can select items. In addition the selection box has the "Previous/Next/Autofill/Done" buttons to navigate to other form elements.
在 Mobile Safari 上,当触摸下拉菜单时,会显示一个列表,用户可以在其中选择项目。此外,选择框具有“上一个/下一个/自动填充/完成”按钮以导航到其他表单元素。
So the user touches the first dropdown, selects a value and presses the Next button. This causes two problems:
所以用户触摸第一个下拉菜单,选择一个值并按下 Next 按钮。这会导致两个问题:
First, On this action the first dropdown's oncange() event is not triggered reliably! Sometimes it fires sometimes not.
首先,在这个动作中,第一个下拉菜单的 oncange() 事件没有被可靠地触发!有时会触发有时不会。
If after selecting an Area, the user touches somewhere else on the webpage or presses the "Done" button then the onchange() is fired normally and the Towns and Streets are populated normally.
如果在选择一个区域后,用户触摸网页上的其他地方或按下“完成”按钮,则 onchange() 正常触发,城镇和街道正常填充。
Second, the element that comes into focus when pressing then "Next" button is the dropdown whos elements need to be changed after being fetched. When the onchange() of the previous dropdown does get fired then, either the list is no updated or the items in the select box turn blue and all of them have a tick mark showing that they are all selected..
其次,按下“下一步”按钮时进入焦点的元素是下拉列表,其元素在获取后需要更改。当上一个下拉菜单的 onchange() 确实被触发时,要么列表没有更新,要么选择框中的项目变成蓝色,并且所有项目都有一个刻度线,表明它们都被选中了。
From what i can tell the problem would be solved if i can disable the Next/Previous buttons in the selection box or somehow fix how the onchange() is fired and the next in focus dropdown's list items are repopulated while it is in focus.
据我所知,如果我可以禁用选择框中的下一个/上一个按钮,或者以某种方式修复 onchange() 是如何触发的,并且下一个焦点下拉列表项在聚焦时重新填充,那么问题将得到解决。
Here is the code (simplified):
这是代码(简化):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no" />
<title></title>
</head>
<body onload="AppStart();">
<form action="#">
Area:
<select id="ddlArea">
<option value="">-- Select Area -- </option>
<option value="1">Area 1</option>
<option value="2">Area 2</option>
<option value="3">Area 3</option>
<option value="4">Area 4</option>
<option value="5">Area 5</option>
</select>
<br />
Town:
<select id="ddlTown">
<option value="">Please wait ...</option>
</select>
<br />
Street:
<select id="ddlStreet">
<option value="">-- Select Area or Town -- </option>
</select>
<br />
Unit:
<select id="ddlUnit">
<option value="">-- No Street Selected -- </option>
</select>
<script type="text/javascript">
var ddlArea, ddlTown, ddlStreet, ddlUnit;
function AppStart() {
ddlArea = document.getElementById("ddlArea");
ddlTown = document.getElementById("ddlTown");
ddlStreet = document.getElementById("ddlStreet");
ddlUnit = document.getElementById("ddlUnit");
ddlArea.onchange = areaChanged;
ddlTown.onchange = townChanged;
ddlStreet.onchange = streetChanged;
setTimeout(function() { updateTown(""); }, 250);
}
var areaId = "", townId = "", streetId = "", unitId = "";
function areaChanged(e) {
areaId = ddlArea.options[ddlArea.selectedIndex].value
ddlClear(ddlTown, createOption("Please Wait...", ""));
ddlClear(ddlStreet, createOption("Please Wait...", ""));
ddlClear(ddlUnit, createOption("-- No Street Selected --", ""));
setTimeout(function() { updateTown(areaId); }, 500);
setTimeout(function() { updateStreet(areaId, ""); }, 700);
}
function townChanged(e) {
townId = ddlTown.options[ddlTown.selectedIndex].value
ddlClear(ddlStreet, createOption("Please Wait...", ""));
ddlClear(ddlUnit, createOption("-- No Street Selected --", ""));
setTimeout(function() { updateStreet(areaId, townId); }, 400);
}
function streetChanged(e) {
streetId = ddlStreet.options[ddlStreet.selectedIndex].value
ddlClear(ddlUnit, createOption("Please Wait...", ""));
setTimeout(function() { updateUnit(streetId); }, 600);
}
function updateTown(areaID) {
ddlClear(ddlTown, createOption("-- Select Town --", ""));
var items = isNaN(parseInt(areaID)) ? 10 : parseInt(areaID);
if (areaID == "") areaID = "ALL";
for (var i = 0; i < items; i++) {
ddlTown.appendChild(createOption("Town " + (i+1) + ", Area " + areaID, i));
}
}
function updateStreet(areaID, townID) {
ddlClear(ddlStreet, createOption("-- Select Street --", ""));
var items1 = isNaN(parseInt(areaID)) ? 10 : parseInt(areaID);
var items2 = isNaN(parseInt(townID)) ? 10 : parseInt(townID);
var items = items1 + items2;
if (areaID == "") areaID = "ALL";
if (townID = "") townId = "ALL";
for (var i = 0; i < items; i++) {
ddlStreet.appendChild(createOption("Street " + (i + 1) + ", Area " + areaID + ", Town " + townID, i));
}
}
function updateUnit(streetID) {
ddlClear(ddlUnit, createOption("-- Select Unit --", ""));
var items = isNaN(parseInt(streetID)) ? 10 : parseInt(streetID);
if (streetID == "") streetID = "ALL";
for (var i = 0; i < items; i++) {
ddlUnit.appendChild(createOption("Unit " + (i + 1) + ", Street " + streetID, i));
}
}
function ddlClear(Dropdown, option) {
while (Dropdown.options.length > 0) {
try { Dropdown.options[0] = null; } catch (e) { };
}
if (option != null) {
Dropdown.appendChild(option);
}
}
function createOption(text, value) {
var oOption = document.createElement("OPTION");
oOption.innerHTML = text;
oOption.value = value;
return oOption;
}
</script>
</form>
</body>
</html>
Help. :/
帮助。:/
回答by InvisibleBacon
I had the same problem on my site. I was able to fix it by manually polling the selectedIndex
property on the select control. That way it fires as soon as you "check" the item in the list. Here's a jQuery plugin I wrote to do this:
我在我的网站上遇到了同样的问题。我能够通过手动轮询selectedIndex
选择控件上的属性来修复它。这样,只要您“检查”列表中的项目,它就会触发。这是我编写的一个 jQuery 插件:
$.fn.quickChange = function(handler) {
return this.each(function() {
var self = this;
self.qcindex = self.selectedIndex;
var interval;
function handleChange() {
if (self.selectedIndex != self.qcindex) {
self.qcindex = self.selectedIndex;
handler.apply(self);
}
}
$(self).focus(function() {
interval = setInterval(handleChange, 100);
}).blur(function() { window.clearInterval(interval); })
.change(handleChange); //also wire the change event in case the interval technique isn't supported (chrome on android)
});
};
You use it just like you would use the "change" event. For instance:
您可以像使用“change”事件一样使用它。例如:
$("#mySelect1").quickChange(function() {
var currVal = $(this).val();
//populate mySelect2
});
Edit: Android does not focus the select when you tap it to select a new value, but it also does not have the same problem that iphone does. So fix it by also wiring the old change
event.
编辑:当您点击它以选择新值时,Android 不会聚焦选择,但它也没有与 iphone 相同的问题。因此,通过连接旧change
事件来修复它。