在做項目的過程中,遇到場景是客戶要求播放語音的場景,這裡需要js來實作文字轉語音播放的功能。在不使用第三方API接口(這種方式需要外網),能想到的也就是利用html5的個API:SpeechSynthesis。
SpeechSynthesis用于将指定文字合成為對應的語音.也包含一些配置項,指定如何去閱讀(語言,音量,音調)等等。
執行個體對象屬性
- lang 擷取并設定話語的語言
- pitch 擷取并設定話語的音調(值越大越尖銳,越低越低沉)
- rate 擷取并設定說話的速度(值越大語速越快,越小語速越慢)
- text 擷取并設定說話時的文本
- voice 擷取并設定說話的聲音
- volume 擷取并設定說話的音量
SpeechSynthesis方法
- speak() 将對應的執行個體添加到語音隊列中
- cancel() 删除隊列中所有的語音.如果正在播放,則直接停止
- pause() 暫停語音
- resume() 恢複暫停的語音
- getVoices 擷取支援的語言數組. 注意:必須添加在voiceschanged事件中才能生效
執行個體對象方法
onstart – 語音合成開始時候的回調。
onpause – 語音合成暫停時候的回調。
onresume – 語音合成重新開始時候的回調。
onend – 語音合成結束時候的回調。
簡單實作
先從最簡單的例子說起,如果想讓浏覽器讀出“你好,世界!”的聲音,可以下面的js代碼:
let utterThis = new SpeechSynthesisUtterance('你好,世界!');
speechSynthesis.speak(utterThis);
隻需要這麼一點代碼就足夠了,大家可以在自己浏覽器的控制台裡面運作上面兩行代碼,看看有沒有讀出聲音。
除了使用speak方法,我們還可以執行個體對象屬性text,是以上面的代碼也可以寫成:
let utterThis = new SpeechSynthesisUtterance();
utterThis.text = '你好,世界!';
utterThis.lang = 'zh';//漢語
utterThis.rate = 0.7;//語速
speechSynthesis.speak(utterThis);
項目實戰
html:
<div class="voiceinator">
<h1>聽說 5000</h1>
<select name="voice" id="voices">
<option value="">Select A Voice</option>
</select>
<label for="rate">Rate:</label>
<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
<label for="pitch">Pitch:</label>
<input name="pitch" type="range" min="0" max="2" step="0.1">
<textarea name="text">你好 給你點?</textarea>
<button id="stop">Stop!</button>
<button id="speak">Speak</button>
</div>
JavaScript:
const synth = window.speechSynthesis
const msg = new SpeechSynthesisUtterance()
let voices = []
const voicesDropdown = document.querySelector('[name="voice"]')
const options = document.querySelectorAll('[type="range"], [name="text"]')
const speakButton = document.querySelector('#speak')
const stopButton = document.querySelector('#stop')
msg.text = '你好 給你點?'
msg.lang = 'zh-CN'
synth.addEventListener('voiceschanged',getSupportVoices)
speakButton.addEventListener('click',throttle(handleSpeak,1000))
stopButton.addEventListener('click',handleStop)
options.forEach(e => e.addEventListener('change',handleChange))
function getSupportVoices() {
voices = synth.getVoices()
voices.forEach(e => {
const option = document.createElement('option')
option.value = e.lang
option.text = e.name
voicesDropdown.appendChild(option)
})
}
function handleSpeak(e) {
msg.lang = voicesDropdown.selectedOptions[0].value
synth.speak(msg)
}
function handleStop(e) {
synth.cancel(msg)
}
function handleChange(e) {
msg[this.name] = this.value
}
function throttle(fn,delay) {
let last = 0
return function() {
const now = new Date()
if(now - last > delay) {
fn.apply(this,arguments)
last = now
}
}
}
代碼解讀
html部分:
頁面布局方面就是通過select下拉菜單選擇需要轉換為什麼語言,具體包括什麼語言是通過js動态加載的。
其次分别用兩個input的滑動來選擇語音播報的速度和音調。
通過修改textarea來設定需要播報的文字内容。
最後通過按鈕來控制語音的播報和停止。
JS部分:
首先通過const synth = window.speechSynthesis來建立語音,用const msg = new SpeechSynthesisUtterance()來建立文本執行個體設定預設播報的文本和語言:msg.text和msg.lang。
通過voiceschanged事件來動态擷取支援的語言種類,并生成options添加到html中.其中最主要的方法就是synth.getVoices()擷取.各位可以通過自行列印擷取到的數組檢視具體包含的屬性。
建立按鈕點選事件,分别通過synth.speak(msg)和synth.cancel(msg)來播放和取消播放。
在播放前通過voicesDropdown.selectedOptions[0].value來設定文本的語言(這裡如果文本的内容語言和播報選擇的語言不一緻的話會出現亂讀的情況)。
最後添加了一個節流函數,防止多次點選按鈕不斷播放(最好是能擷取播放的時長,或監聽播報完畢事件,這裡就是簡單的2秒識别一次,有興趣的小夥伴可以自行編寫)。
遇到問題
1、google chrome播放語音可能會卡住,是以無聲音。
解決方法:在播放語音之前先 調用一下cancel方法:
window.speechSynthesis.cancel()
2、出現警告:speechSynthesis.speak() without user activation is no longer allowed since M71, around December 2018.
解決方法:進去必須有一個事件動作,如點選事件click,或者你直接滑鼠點選頁面某處就可以播放了。
3、SpeechSynthesisUtterance在浏覽器會存在相容性問題(如IE不支援),目前主流浏覽器如Chrome,Edge,Safari等等都是支援的。
解決方案,提示使用者更換其他浏覽器通路,代碼:
if(!!window.SpeechSynthesisUtterance){
console.log("請使用其他浏覽器!")
}