使用“Next”时 select/dropdown 的 onchange() JS 事件的奇怪行为在 Mobile Safari 下拉列表项选择框中
这是一个很难说清楚的问题,而且我是移动 Web 开发的新手,所以请耐心等待:
在我的网页上,我有 3 个嵌套下拉列表(区域、城镇、街道)。
嵌套如下,当其上方的下拉列表中的选择发生更改时,每个下拉列表的项目都会被修改。例如,选择区域会更改城镇和街道列表,选择城镇会更改街道 em> 列表。
我在下拉菜单的 onchange() javascript 事件中使用 XMLHTTPRequests 来获取并填充其他下拉菜单。这在 Android 和桌面浏览器上运行良好。
在 Mobile Safari 上,当触摸下拉菜单时,会显示一个列表,用户可以在其中选择项目。此外,选择框还具有“上一个/下一个/自动填充/完成”按钮,用于导航到其他表单元素。
因此,用户触摸第一个下拉列表,选择一个值并按“下一步”按钮。这会导致两个问题:
首先,在此操作中,第一个下拉列表的 oncange() 事件未可靠触发!有时会火有时不火。
如果选择区域后,用户触摸网页上的其他位置或按下“完成”按钮,则 onchange() 会正常触发,城镇和街道也会正常填充。
第二,按下“下一步”按钮时进入焦点的元素是下拉列表,其元素在获取后需要更改。当上一个下拉列表的 onchange() 确实被触发时,要么列表没有更新,要么选择框中的项目变成蓝色,并且所有项目都有一个勾号,显示它们都已被选中。
据我所知如果我可以禁用选择框中的“下一个/上一个”按钮,或者以某种方式修复 onchange() 的触发方式,并且在焦点处于焦点时重新填充下一个焦点下拉列表项,则问题将得到解决。
这是代码(简化):
<!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>
帮助。 :/
This is a hard one to articulate and I am new to mobile web development so please bear with me:
On my webpage, I have 3 Nested dropdown lists (Area, Town, Street).
Nested as in, each dropdown's items are modified when the selection in the dropdown above it changes. e.g selecting an Area changes the Town and Street lists and selecting a Town changes the Street list.
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.
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.
So the user touches the first dropdown, selects a value and presses the Next button. This causes two problems:
First, On this action the first dropdown's oncange() event is not triggered reliably! Sometimes it fires sometimes not.
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.
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..
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.
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. :/
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的网站上也遇到了同样的问题。我可以通过手动轮询选择控件上的
selectedIndex
属性来修复它。这样,当您“检查”列表中的项目时,它就会立即触发。这是我为此编写的一个 jQuery 插件:您可以像使用“change”事件一样使用它。例如:
编辑:当您点击选择新值时,Android 不会聚焦选择,但它也不会出现与 iphone 相同的问题。因此,还可以通过连接旧的
change
事件来修复它。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:You use it just like you would use the "change" event. For instance:
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.