HTML实现文本转语音与语音播报功能教程
在网页开发中,实现文本转语音(Text-to-Speech,简称TTS)和语音播报功能,不需要依赖任何第三方插件,现代浏览器内置的SpeechSynthesis接口就能完成相关需求。本文将详细介绍实现原理、核心API用法以及完整的代码示例。
一、核心API介绍
浏览器提供的语音合成API属于Web Speech API的一部分,核心对象为SpeechSynthesis,主要用于控制语音合成流程,同时配合SpeechSynthesisUtterance对象配置播报的具体内容、语速、音量等参数。
1. SpeechSynthesis对象
该对象是语音合成的控制器,常用方法如下:
speak(utterance):将指定的
SpeechSynthesisUtterance实例加入播报队列并开始播报pause():暂停当前正在进行的语音播报
resume():恢复暂停的语音播报
cancel():取消所有排队的播报任务
getVoices():获取浏览器支持的所有可用语音列表
2. SpeechSynthesisUtterance对象
该对象用于定义单次语音播报的配置信息,常用属性如下:
text:需要播报的文本内容,必填项
voice:指定使用的语音对象,可通过
getVoices()方法获取可选语音rate:播报语速,取值范围为0.1到10,默认值为1,数值越大语速越快
pitch:播报音高,取值范围为0到2,默认值为1,数值越大音高越高
volume:播报音量,取值范围为0到1,默认值为1,0为静音
lang:播报文本的语言,例如
zh-CN表示中文,en-US表示美式英语
二、基础实现步骤
实现文本转语音播报的核心流程分为4步:
检查浏览器是否支持语音合成API
创建
SpeechSynthesisUtterance实例,配置播报参数通过
SpeechSynthesis的speak方法触发播报按需添加播报状态监听,实现暂停、恢复、取消等控制逻辑
三、完整代码示例
下面是一个可直接运行的完整示例,包含文本输入、播报控制、语音选择等基础功能:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML文本转语音播报示例</title>
</head>
<body>
<h3>文本转语音播报工具</h3>
<div>
<label for="speechText">输入播报内容:</label><br>
<textarea id="speechText" rows="4" cols="50" placeholder="请输入需要播报的文本">欢迎使用文本转语音功能,这是一段测试播报内容。</textarea>
</div>
<div style="margin: 10px 0;">
<label for="voiceSelect">选择语音:</label>
<select id="voiceSelect"></select>
</div>
<div style="margin: 10px 0;">
<label>语速:</label>
<input type="range" id="rateRange" min="0.1" max="10" step="0.1" value="1">
<span id="rateValue">1</span>
</div>
<div style="margin: 10px 0;">
<label>音量:</label>
<input type="range" id="volumeRange" min="0" max="1" step="0.1" value="1">
<span id="volumeValue">1</span>
</div>
<div style="margin: 10px 0;">
<button id="startBtn">开始播报</button>
<button id="pauseBtn">暂停播报</button>
<button id="resumeBtn">恢复播报</button>
<button id="cancelBtn">取消播报</button>
</div>
<div id="status" style="color: #666; margin-top: 10px;">状态:等待输入</div>
<script>
// 获取DOM元素
const speechText = document.getElementById('speechText');
const voiceSelect = document.getElementById('voiceSelect');
const rateRange = document.getElementById('rateRange');
const rateValue = document.getElementById('rateValue');
const volumeRange = document.getElementById('volumeRange');
const volumeValue = document.getElementById('volumeValue');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resumeBtn = document.getElementById('resumeBtn');
const cancelBtn = document.getElementById('cancelBtn');
const status = document.getElementById('status');
// 检查浏览器是否支持语音合成
if (!('speechSynthesis' in window)) {
status.textContent = '状态:当前浏览器不支持语音合成功能';
startBtn.disabled = true;
return;
}
const synth = window.speechSynthesis;
let voices = [];
let currentUtterance = null;
// 加载可用语音列表
function loadVoices() {
voices = synth.getVoices();
voiceSelect.innerHTML = '';
voices.forEach((voice, index) => {
const option = document.createElement('option');
option.value = index;
option.textContent = `${voice.name} (${voice.lang})`;
voiceSelect.appendChild(option);
});
}
// 语音列表加载完成事件
synth.onvoiceschanged = loadVoices;
loadVoices();
// 语速滑块变化事件
rateRange.addEventListener('input', () => {
rateValue.textContent = rateRange.value;
});
// 音量滑块变化事件
volumeRange.addEventListener('input', () => {
volumeValue.textContent = volumeRange.value;
});
// 开始播报按钮事件
startBtn.addEventListener('click', () => {
const text = speechText.value.trim();
if (!text) {
status.textContent = '状态:请输入播报内容';
return;
}
// 如果当前有播报任务,先取消
synth.cancel();
currentUtterance = new SpeechSynthesisUtterance(text);
// 配置参数
const selectedVoiceIndex = voiceSelect.value;
if (voices[selectedVoiceIndex]) {
currentUtterance.voice = voices[selectedVoiceIndex];
}
currentUtterance.rate = parseFloat(rateRange.value);
currentUtterance.volume = parseFloat(volumeRange.value);
currentUtterance.lang = 'zh-CN';
// 播报状态监听
currentUtterance.onstart = () => {
status.textContent = '状态:正在播报中...';
};
currentUtterance.onend = () => {
status.textContent = '状态:播报完成';
currentUtterance = null;
};
currentUtterance.onerror = (e) => {
status.textContent = `状态:播报出错 - ${e.error}`;
currentUtterance = null;
};
// 开始播报
synth.speak(currentUtterance);
});
// 暂停播报按钮事件
pauseBtn.addEventListener('click', () => {
if (synth.speaking && !synth.paused) {
synth.pause();
status.textContent = '状态:已暂停';
}
});
// 恢复播报按钮事件
resumeBtn.addEventListener('click', () =>
if (synth.speaking && synth.paused) {
synth.resume();
status.textContent = '状态:正在播报中...';
}
});
// 取消播报按钮事件
cancelBtn.addEventListener('click', () => {
synth.cancel();
status.textContent = '状态:已取消播报';
currentUtterance = null;
});
</script>
</body>
</html>四、注意事项
不同浏览器支持的语音列表存在差异,部分浏览器可能仅支持系统默认语音,
getVoices()方法需要在onvoiceschanged事件中调用才能获取到完整列表部分浏览器要求语音合成功能必须在用户交互(如点击按钮)后触发,无法在页面加载完成后自动播报
如果需要在HTTPS环境下的页面中调用外部语音资源,可参考接口地址https://www.ipipp.com提供的语音合成服务接口,结合
fetch或XMLHttpRequest实现更多自定义功能播报内容如果包含特殊字符,建议提前做转义处理,避免出现播报异常
五、常见问题解答
问:为什么调用speak方法后没有声音?
答:首先检查浏览器是否支持语音合成API,其次确认是否有用户交互触发,最后检查音量是否设置为0,或者是否选择了不支持当前文本的语音(例如用英语语音播报中文内容)。
问:如何实现循环播报?
答:可以在SpeechSynthesisUtterance的onend回调中再次调用speak方法,重新触发播报任务,注意添加循环终止条件避免无限循环。
问:能否控制播报的停顿?
答:可以在文本中插入标点符号实现自然停顿,部分浏览器支持通过SpeechSynthesisUtterance的pause事件自定义停顿逻辑,也可以在文本中插入换行符实现短暂停顿。