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

React+TypeScript+Vite语音识别计算器npm run dev后空白页求助

带语音识别功能的计算器空白页问题修复与完整实现

核心问题分析

启动后页面空白及功能失效的原因包括:

  • main.tsx未实现React应用的DOM挂载逻辑,组件无法渲染到页面
  • 语音识别模块未读取转录结果,语音输入无法转化为计算表达式
  • calculate函数硬编码固定值,未使用用户输入内容进行计算

分步修复方案

1. 完善main.tsx的渲染入口

添加React应用挂载代码,将App组件渲染到页面根节点(需确保项目HTML文件中存在id为root的节点)。

2. 修复Calculator组件的语音识别与计算逻辑

  • 获取语音识别的transcript字段,将语音内容转换为可计算的表达式
  • 修正calculate函数,使用用户输入的表达式进行计算
  • 处理语音转录中的自然语言运算符(如将"plus"转为"+"、"minus"转为"-"等)

3. 确保样式路径正确

确认组件中样式文件的导入路径与实际文件结构匹配,避免样式加载失败导致组件不可见


完整代码实现

main.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import Calculator from "./Component/Calculator";
import "./styles/calculator.css";

function App() {
  return (
    <div className="App">
      <Calculator />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Calculator.tsx

import React, { useState } from "react";
import SpeechRecognition, { useSpeechRecognition } from "react-speech-recognition";
import "../styles/calculator.css";

function Calculator() {
  const [result, setResult] = useState("");
  const { transcript, resetTranscript } = useSpeechRecognition();

  // 将语音转录的自然语言转换为计算运算符
  const convertVoiceToExpression = (text: string): string => {
    return text
      .replace(/plus/gi, "+")
      .replace(/minus/gi, "-")
      .replace(/multiply by/gi, "*")
      .replace(/divided by/gi, "/")
      .replace(/equals/gi, "=")
      .replace(/\s+/g, "");
  };

  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    setResult(result.concat(e.currentTarget.name));
  };

  const clear = () => {
    setResult("");
  };

  const backspace = () => {
    setResult(result.slice(0, -1));
  };

  function evaluateExpression(expression: string): string {
    try {
      // 过滤非法字符,仅保留数字、运算符和小数点
      const sanitizedExpr = expression.replace(/[^0-9+\-*/.]/g, "");
      if (!sanitizedExpr) return "";
      // eslint-disable-next-line no-new-func
      const calcResult = Function(`"use strict"; return (${sanitizedExpr})`)();
      return calcResult.toString();
    } catch (error) {
      console.error(error);
      return "Error";
    }
  }

  const calculate = (inputExpr?: string) => {
    try {
      const expression = inputExpr || result;
      const calcResult = evaluateExpression(expression);
      setResult(calcResult);
    } catch (error) {
      console.error(error);
      setResult("Error");
    }
  };

  const handleVoiceRecognition = () => {
    if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
      alert("你的浏览器不支持语音识别功能");
      return;
    }
    resetTranscript();
    SpeechRecognition.startListening({
      continuous: true,
      language: "zh-CN", // 可根据需求切换为"en-US"
    });
  };

  const stopVoiceRecognition = () => {
    SpeechRecognition.stopListening();
    const voiceExpr = convertVoiceToExpression(transcript);
    setResult(voiceExpr);
    calculate(voiceExpr);
  };

  return (
    <div className="calculator">
      <input type="text" value={result} readOnly />
      <div className="keypad">
        <button className="operator" onClick={clear}>AC</button>
        <button className="operator" onClick={backspace}>C</button>
        <button className="operator" name="+" onClick={handleClick}>+</button>
        <button name="7" onClick={handleClick}>7</button>
        <button name="8" onClick={handleClick}>8</button>
        <button name="9" onClick={handleClick}>9</button>
        <button className="operator" name="-" onClick={handleClick}>-</button>
        <button name="4" onClick={handleClick}>4</button>
        <button name="5" onClick={handleClick}>5</button>
        <button name="6" onClick={handleClick}>6</button>
        <button className="operator" name="*" onClick={handleClick}>x</button>
        <button name="1" onClick={handleClick}>1</button>
        <button name="2" onClick={handleClick}>2</button>
        <button name="3" onClick={handleClick}>3</button>
        <button className="operator" name="/" onClick={handleClick}>÷</button>
        <button name="." onClick={handleClick}>.</button>
        <button name="0" onClick={handleClick}>0</button>
        <button className="operator" onClick={() => calculate()}>=</button>
        <button className="operator" onClick={handleVoiceRecognition}>🎤</button>
        <button className="operator" onClick={stopVoiceRecognition}>🛑</button>
      </div>
    </div>
  );
}

export default Calculator;

calculator.css

.calculator {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 20px auto;
  max-width: 300px;
  background-color: #f9f9f9;
  border-radius: 10px;
  padding: 20px;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
}

.calculator input[type="text"] {
  display: block;
  width: 100%;
  margin-bottom: 10px;
  padding: 10px;
  font-size: 24px;
  text-align: right;
  border: none;
  border-radius: 5px;
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}

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

button {
  background-color: #e0e0e0;
  color: #333;
  font-size: 20px;
  padding: 10px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}

button:hover {
  background-color: #333;
  color: #fff;
}

.operator {
  background-color: #ff8c00;
  color: #fff;
}

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

内容的提问来源于stack exchange,提问作者Kevin Paul Babu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:29:59