优秀的编程知识分享平台

网站首页 > 技术文章 正文

语音版计算器:开源代码分享

nanyue 2024-12-31 13:38:32 技术文章 4 ℃

使用计算器可以保存下面二维码在微信还是浏览器都可以打开,也可以输入这个计算器应用的网址用谷歌浏览器可以添加到自己的手机桌面。

语音版计算器开源代码分享

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>漂亮的计算器</title>
  <style>
    /* 重置样式 */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: #f5f5f5;
      font-family: 'Roboto', sans-serif;
    }

    .calculator {
      width: 320px;
      background-color: #2e2e2e;
      border-radius: 15px;
      box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
      overflow: hidden;
    }

    .display {
      width: 100%;
      height: 80px;
      background-color: #1c1c1c;
      color: #ffffff;
      font-size: 2.5em;
      text-align: right;
      padding: 20px;
      border-bottom: 1px solid #444;
      overflow-x: auto;
    }

    .history {
      width: 100%;
      height: 30px;
      background-color: #1c1c1c;
      color: #888;
      font-size: 1em;
      text-align: right;
      padding: 5px 20px;
      border-bottom: 1px solid #444;
      overflow-x: auto;
    }

    .buttons {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 10px;
      padding: 20px;
    }

    .btn {
      background-color: #f0f0f0;
      border: none;
      border-radius: 10px;
      padding: 20px;
      font-size: 1.5em;
      color: #000000;
      cursor: pointer;
      transition: background-color 0.2s, transform 0.1s;
      position: relative;
      overflow: hidden;
    }

    .btn:hover {
      background-color: #d0d0d0;
    }

    .btn:active {
      transform: scale(0.95);
    }

    .operator {
      background-color: #ff9500;
      color: #ffffff;
    }

    .operator:hover {
      background-color: #e08900;
    }

    .zero {
      grid-column: span 2;
    }

    .equals {
      background-color: #34c759;
      color: #ffffff;
    }

    .equals:hover {
      background-color: #2da94f;
    }
  </style>
</head>
<body>
  <div class="calculator">
    <div class="history" id="history"></div>
    <div class="display" id="display">0</div>
    <div class="buttons">
      <button class="btn operator" data-value="AC">AC</button>
      <button class="btn operator" data-value="C">C</button>
      <button class="btn operator" data-value="%">%</button>
      <button class="btn operator" data-value="/">÷</button>
      <button class="btn" data-value="7">7</button>
      <button class="btn" data-value="8">8</button>
      <button class="btn" data-value="9">9</button>
      <button class="btn operator" data-value="*">×</button>
      <button class="btn" data-value="4">4</button>
      <button class="btn" data-value="5">5</button>
      <button class="btn" data-value="6">6</button>
      <button class="btn operator" data-value="-">?</button>
      <button class="btn" data-value="1">1</button>
      <button class="btn" data-value="2">2</button>
      <button class="btn" data-value="3">3</button>
      <button class="btn operator" data-value="+">+</button>
      <button class="btn zero" data-value="0">0</button>
      <button class="btn" data-value=".">.</button>
      <button class="btn operator equals" data-value="=">=</button>
    </div>
  </div>

  <script>
    // 获取元素
    const display = document.getElementById('display');
    const history = document.getElementById('history');
    const buttons = document.querySelectorAll('.btn');

    let currentInput = '';
    let operator = null;
    let previousInput = '';
    let historyRecord = '';

    // 初始化语音合成
    const synth = window.speechSynthesis;
    let voices = [];
    let selectedVoice = null;

    function populateVoices() {
      voices = synth.getVoices();
      // 选择一个支持中文的语音
      selectedVoice = voices.find(voice => voice.lang.startsWith('zh')) || voices[0];
    }

    populateVoices();
    if (synth.onvoiceschanged !== undefined) {
      synth.onvoiceschanged = populateVoices;
    }

    // 播放语音函数
    function speak(text) {
      if (synth.speaking) {
        console.error('语音合成正在进行中...');
        synth.cancel(); // 中止之前的语音
      }
      if (text !== '') {
        const utterThis = new SpeechSynthesisUtterance(text);
        utterThis.onend = function (event) {
          console.log('语音合成结束');
        };
        utterThis.onerror = function (event) {
          console.error('语音合成出错:', event.error);
        };
        utterThis.voice = selectedVoice;
        utterThis.pitch = 1; // 音调
        utterThis.rate = 1;  // 语速
        utterThis.volume = 1; // 音量设置为最大(0到1之间)
        synth.speak(utterThis);
      }
    }

    // 更新显示内容
    function updateDisplay() {
      display.textContent = currentInput || '0';
      history.textContent = historyRecord;
    }

    // 获取操作符符号显示
    function getOperatorSymbol(op) {
      switch(op) {
        case '+': return '+';
        case '-': return '?';
        case '*': return '×';
        case '/': return '÷';
        default: return op;
      }
    }

    // 计算结果
    function calculate() {
      const num1 = parseFloat(previousInput);
      const num2 = parseFloat(currentInput);
      let result = 0;

      switch (operator) {
        case '+':
          result = num1 + num2;
          break;
        case '-':
          result = num1 - num2;
          break;
        case '*':
          result = num1 * num2;
          break;
        case '/':
          result = num2 !== 0 ? num1 / num2 : '错误';
          break;
        default:
          return;
      }

      historyRecord += `${num2} = `;
      currentInput = String(result);
    }

    // 处理按钮点击事件
    buttons.forEach(button => {
      button.addEventListener('click', () => {
        const value = button.getAttribute('data-value');

        // 启动音频上下文(某些浏览器需要用户交互后才能播放语音)
        if (synth.speaking === false && synth.paused === false) {
          // 已经处于运行状态,无需操作
        } else if (synth.speaking === false && synth.paused === true) {
          // 被暂停,尝试恢复
          synth.resume();
        }

        // 播放对应的语音
        if (value !== '' && value !== 'AC' && value !== 'C') {
          let speakText = '';
          if (!isNaN(value)) {
            speakText = value;
          } else if (value === '.') {
            speakText = '点';
          } else if (value === '=') {
            speakText = '结果';
          } else if (value === 'AC') {
            speakText = '清除所有';
          } else if (value === 'C') {
            speakText = '删除';
          } else {
            switch(value) {
              case '+':
                speakText = '加';
                break;
              case '-':
                speakText = '减';
                break;
              case '*':
                speakText = '乘';
                break;
              case '/':
                speakText = '除';
                break;
              case '%':
                speakText = '百分比';
                break;
              default:
                speakText = value;
            }
          }
          speak(speakText);
        }

        // 处理计算逻辑
        if (value === 'AC') {
          currentInput = '';
          previousInput = '';
          operator = null;
          historyRecord = '';
        } else if (value === 'C') {
          currentInput = currentInput.slice(0, -1);
          speak('删除');
        } else if (value === '%') {
          if (currentInput !== '') {
            currentInput = String(parseFloat(currentInput) / 100);
            speak(currentInput); // 朗读转换后的百分比结果
          }
        } else if (['+', '-', '*', '/'].includes(value)) {
          if (currentInput !== '') {
            if (previousInput !== '') {
              calculate();
            }
            operator = value;
            previousInput = currentInput;
            historyRecord += `${currentInput} ${getOperatorSymbol(operator)} `;
            currentInput = '';
          }
        } else if (value === '=') {
          if (operator && currentInput !== '' && previousInput !== '') {
            calculate();
            operator = null;
            previousInput = '';
            // 播放结果语音
            if (currentInput !== '错误') {
              speak(`结果是 ${currentInput}`);
            } else {
              speak('计算错误');
            }
          }
        } else {
          if (value === '.' && currentInput.includes('.')) return;
          currentInput += value;
        }

        updateDisplay();
      });
    });

    // 初始化显示
    updateDisplay();
  </script>
</body>
</html>

Tags:

最近发表
标签列表