在 Mobile Safari 下拉列表项选择框上使用“下一步”时,选择/下拉的 onchange() JS 事件的奇怪行为

IT技术 javascript iphone web-applications mobile-safari mobile-website
2021-02-23 07:37:52

这很难说清楚,我是移动 Web 开发的新手,所以请耐心等待:

在我的网页上,我有 3 个嵌套下拉列表(区域、城镇、街道)。

嵌套在,当其上方下拉列表中的选择更改时,每个下拉列表的项目都会被修改。例如,选择一个区域会改变城镇街道列表,选择一个城镇会改变街道列表。

我在下拉列表的 onchange() javascript 事件中使用 XMLHTTPRequests 来获取和填充其他下拉列表。这适用于 Android 和桌面浏览器。

在 Mobile Safari 上,当触摸下拉菜单时,会显示一个列表,用户可以在其中选择项目。此外,选择框具有“上一个/下一个/自动填充/完成”按钮以导航到其他表单元素。

所以用户触摸第一个下拉菜单,选择一个值并按下 Next 按钮。这会导致两个问题:

首先,在这个动作中,第一个下拉菜单的 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>

帮助。:/

1个回答

我在我的网站上遇到了同样的问题。我能够通过手动轮询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)
    });
};

您可以像使用“更改”事件一样使用它。例如:

$("#mySelect1").quickChange(function() { 
    var currVal = $(this).val();
    //populate mySelect2
});

编辑:当您点击它以选择新值时,Android 不会聚焦选择,但它也没有与 iphone 相同的问题。因此,通过连接旧change事件来修复它

啊,是的,这是我的下一步!不错的演出!我将使用 JSFiddle 重新创建。喜欢那个移动调试解决方案......
2021-04-17 07:37:52
我发布这个后发现了android问题。有关修复,请参阅我的编辑和上面的新代码。你能为第一个问题创建一个 jsfiddle 吗?
2021-04-23 07:37:52
这是一个很好的解决方案,它确实解决了 Safari 移动 Web 浏览器(iOS 5 上仍然存在)的一阶故障。但这似乎留下了另一个次要影响。现在“微调器”正在填充,但是在点击“下一步”或“完成”时,实际的下拉菜单似乎没有随选择更新,也没有注册。任何见解?此外,该修复程序似乎暂时破坏了 Android 版本的界面。但后来它奏效了。
2021-04-29 07:37:52
感谢您提供此示例。它为我节省了很多时间。尽管现在随着 iOS 7 更新,此解决方案不再有效。我正在尝试调试您的代码,但到目前为止还没有运气让它在更新的 iOS 上运行。有人有运气吗?
2021-05-01 07:37:52
谢谢你..我已经通过在下一个下拉列表中调用 blur() 解决了这个问题,当第一个选择被更改并返回 XMLHttpRequest 数据时,选择框消失,用户必须触摸第二个下拉列表才能访问它,这会导致列表中的项目被刷新.. 这是一个我不太喜欢的黑客..
2021-05-14 07:37:52