You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript动态生成的PayPal费率选项在iOS端不显示问题求助

PayPal费用计算器iOS兼容性及DOCTYPE依赖问题

我开发了一个基于HTML和JavaScript的PayPal费用计算器,在Android和Windows平台运行正常,但**iOS系统(即使使用Chrome浏览器)**中,选择货币后动态生成的费率选项无法显示。

iOS端异常截图:
iOS端选项情况

另外,移除<DOCTYPE html>标签后,Android和PC端的费率选项也会消失,求解决方法。


现有代码

HTML部分

<label for="amount">Amount:</label>
<input type="number" placeholder="0.00" id="amount" name="amount"><br><br>

<label for="currency">Country or Region (Currency):</label>
<select id="currency" name="currency" onchange="updateFeeOptions()">
  <option value="">Select</option>
  <option value="INR">India (INR)</option>
  <option value="USD">United States (USD)</option>
  <option value="GBP">United Kingdom (GBP)</option>
</select><br><br>

<label for="fee-option">Fee Rate:</label>

<br/>
<br/>
<select id="fee-option" name="fee-option">
  <option value="">Automatic Selection</option>
  <!-- Fee options will be dynamically generated based on currency selection -->
</select><br><br>

<button onclick="calculateFees()">Calculate Fees</button><br><br>

<label for="total-fees">Total Fees:</label>
<input type="text" id="total-fees" name="total-fees" readonly><br><br>

<label for="you-will-receive">You Will Receive:</label>
<input type="text" id="you-will-receive" name="you-will-receive" readonly><br><br>

<label for="you-should-ask-for">You Should Ask For:</label>
<input type="text" id="you-should-ask-for" name="you-should-ask-for" readonly><br><br>

JavaScript部分

// Define fee options based on currency
const feeOptions = {
  USD: [{
      label: "Domestic",
      options: [{
          value: "2.9-0.30",
          label: "2.9% + $0.30 (online transaction)"
        },
        {
          value: "2.7-0.30",
          label: "2.7% + $0.30 (store location)"
        },
        {
          value: "2.2-0.30",
          label: "2.2% + $0.30 (non-profit)"
        },
        {
          value: "5-0.05",
          label: "5% + $0.05 (micropayment)"
        }
      ]
    },
    {
      label: "International",
      options: [{
          value: "4.4-0.30",
          label: "4.4% + $0.30 (online transaction)"
        },
        {
          value: "4.2-0.30",
          label: "4.2% + $0.30 (store location)"
        },
        {
          value: "3.7-0.30",
          label: "3.7% + $0.30 (non-profit)"
        },
        {
          value: "6.5-0.05",
          label: "6.5% + $0.05 (micropayment)"
        }
      ]
    },
    {
      label: "Mobile Card Reader",
      options: [{
          value: "2.7",
          label: "2.7% (swiped & check-in transactions)"
        },
        {
          value: "3.5-0.15",
          label: "3.5% + $0.15 (keyed & scanned transactions)"
        },
        {
          value: "4.2",
          label: "4.2% (international + 1.5% cross-border fee)"
        }
      ]
    },
    {
      label: "Virtual Terminal",
      options: [{
          value: "3.1-0.30",
          label: "3.1% + $0.30 (domestic)"
        },
        {
          value: "4.6-0.30",
          label: "4.6% + $0.30 (cross-border)"
        }
      ]
    }
  ],
  GBP: [{
      label: "Domestic",
      options: [{
        value: "2.9-0.30",
        label: "2.9% + £0.30"
      }, ]
    },
    {
      label: "International - from Europe I, Northern Europe",
      options: [{
        value: "3.4-0.30",
        label: "3.4% + £0.30"
      }, ]
    },
    {
      label: "International - from CANADA, USA, Europe II, rest of the world",
      options: [{
        value: "4.9-0.30",
        label: "4.9% + £.30"
      }, ]
    },
    {
      label: "Charity",
      options: [{
        value: "1.4-0.20",
        label: "1.4% + £.20"
      }, ]
    },
    {
      label: "Micropayment",
      options: [{
        value: "5-0.05",
        label: "5% + £0.05 (domestic)"
      }, ]
    }
  ],

  INR: [{
      label: "Domestic",
      options: [{
        value: "2.5-3",
        label: "2.5% + ₹3"
      }]
    },
    {
      label: "International",
      options: [{
          value: "4.4-3",
          label: "4.4% + ₹3 (up to $3000 monthly sales)"
        },
        {
          value: "3.9-3",
          label: "3.9% + ₹3 (up to $3000 to $10000 monthly sales)"
        },
        {
          value: "3.7-3",
          label: "3.7% + ₹3 (up to ₹10000 to $100000 monthly sales)"
        },
        {
          value: "3.4-3",
          label: "3.4% + ₹3 ($100000+ monthly sales)"
        }
      ]
    }
  ]
};

function updateFeeOptions() {
  const currencySelect = document.getElementById("currency");
  const feeOptionSelect = document.getElementById("fee-option");

  // Clear existing options
  feeOptionSelect.innerHTML = "";

  // Add new options based on selected currency
  const selectedCurrency = currencySelect.value;
  const options = feeOptions[selectedCurrency];
  for (let i = 0; i < options.length; i++) {
    const optgroup = document.createElement("optgroup");
    optgroup.label = options[i].label;
    for (let j = 0; j < options[i].options.length; j++) {
      const option = document.createElement("option");
      option.value = options[i].options[j].value;
      option.label = options[i].options[j].label;
      optgroup.appendChild(option);
    }
    feeOptionSelect.appendChild(optgroup);
  }
}

function calculateFees() {
  const amountInput = document.getElementById("amount");
  const feeOptionSelect = document.getElementById("fee-option");
  const totalFeesInput = document.getElementById("total-fees");
  const youWillReceiveInput = document.getElementById("you-will-receive");
  const youShouldAskForInput = document.getElementById("you-should-ask-for");

  const amount = amountInput.value.trim(); // remove any leading/trailing spaces
  if (!amount) {
    alert("Please enter an amount.");
    return; // stop the function
  }

  const feeOption = feeOptionSelect.value.split("-");
  const feePercent = parseFloat(feeOption[0]) / 100;
  const feeFixed = parseFloat(feeOption[1]);

  const totalFees = (amount * feePercent) + feeFixed;
  const youWillReceive = amount - totalFees;
  const youShouldAskFor = amount / (1 - feePercent) + feeFixed;

  totalFeesInput.value = totalFees.toFixed(2);
  youWillReceiveInput.value = youWillReceive.toFixed(2);
  youShouldAskForInput.value = youShouldAskFor.toFixed(2);
}

解决方案

1. 修复iOS动态生成选项的兼容性问题

iOS的Safari内核(包括Chrome for iOS)对动态创建<optgroup>的DOM操作存在兼容性问题,修改updateFeeOptions函数:

function updateFeeOptions() {
  const currencySelect = document.getElementById("currency");
  const feeOptionSelect = document.getElementById("fee-option");

  // 安全清空子元素(替代innerHTML="",避免iOS渲染异常)
  while (feeOptionSelect.firstChild) {
    feeOptionSelect.removeChild(feeOptionSelect.firstChild);
  }

  const selectedCurrency = currencySelect.value;
  if (!selectedCurrency) {
    // 添加默认选项
    const defaultOption = document.createElement("option");
    defaultOption.value = "";
    defaultOption.text = "Automatic Selection";
    feeOptionSelect.appendChild(defaultOption);
    return;
  }

  const options = feeOptions[selectedCurrency];
  for (let i = 0; i < options.length; i++) {
    const optgroup = document.createElement("optgroup");
    optgroup.label = options[i].label;
    for (let j = 0; j < options[i].options.length; j++) {
      const option = document.createElement("option");
      option.value = options[i].options[j].value;
      // 优先设置text属性而非label,适配iOS内核
      option.text = options[i].options[j].label;
      optgroup.appendChild(option);
    }
    feeOptionSelect.appendChild(optgroup);
  }

  // 手动触发重绘,解决iOS下拉菜单不更新的问题
  feeOptionSelect.style.display = 'none';
  feeOptionSelect.offsetHeight; // 触发浏览器重排
  feeOptionSelect.style.display = '';
}

2. 保留标准DOCTYPE声明

移除<DOCTYPE html>后浏览器会进入怪异模式,导致DOM操作行为不一致。必须在HTML文档最开头保留标准声明,同时添加移动端适配标签:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PayPal Fee Calculator</title>
</head>
<body>
    <!-- 你的HTML内容 -->
</body>
</html>

3. 修复计算函数的边界问题

处理无固定费用的选项(比如USD的"2.7"),避免feeFixed变成NaN:

function calculateFees() {
  // ... 原有代码 ...

  const feeOption = feeOptionSelect.value.split("-");
  const feePercent = parseFloat(feeOption[0]) / 100;
  // 处理无固定费用的情况
  const feeFixed = feeOption.length > 1 ? parseFloat(feeOption[1]) : 0;

  // ... 原有计算代码 ...
}

内容的提问来源于stack exchange,提问作者Chanakya Sahu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:37:19