JS30 Day 23 筆記


Posted by GL on 2023-05-23

功能

將文字轉換成語音,並透過控制條調整語音的速率以及音調。

Demo

step 1 : 建立 SpeechSynthesisUtterance 物件,并且取得 HTML 頁面中的元素


// 設置 SpeechSynthesisUtterance
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
// 選取器同時選取 type 為 range,以及 name 為 text 
const options = document.querySelectorAll('[type="range"],[name="text"]');
const speakButton = document.querySelector("#speak");
const stopButton = document.querySelector("#stop");

// 語音說出的内容為文字欄位中的内容
msg.text = document.querySelector('[name="text"]').value;

step 2 : 拿到當前使用裝置的語音語系,並放入下拉選單中

SpeechSynthesis.getVoices():回傳當前裝置可用的所有聲音清單(包含lang, name等屬性)

function populateVoices() {
  //  取得當前裝置的語音語系,並放入變數 voices
  voices = this.getVoices();

  // 將所有語系選項放入下拉選單中
  voicesDropdown.innerHTML = voices
    // filter 篩選出包含 en 的語系
    .filter(voice => voice.lang.includes('en'))
    // 用 map 將篩選後資料組一個個 option 選項
    .map(voice => `<option value=${voice.name}>${voice.name} (${voice.lang})</option>`)
    // 用 join 去除 map 後回傳的陣列中的逗號
    .join('');
}

// 監聽語系選單,選單改變時,觸發該事件並更新語系清單
speechSynthesis.addEventListener('voiceschanged', populateVoices);

step 3 : 設定播放相關功能

function toggle(starOver = true) {
  // 先停止播放
  speechSynthesis.cancel();
  // 如果 startOver 為 true
  if (starOver) {
     // 開始播放
    speechSynthesis.speak(msg);
  }
}

function setVoice() {
  // 設定發音的語系設爲下拉選單中切換的語系
  msg.voice = voices.find(voice => voice.name === this.value);
  // 播放
  toggle();
}


function setOption() {
// options 這個 Nodelist,
// 剛好裡面每個值的 name 取名的與 SpeechSynthesisUtterance 的物件屬性相同
// 所有可以通過下列方式,改變其 value
  msg[this.name] = this.value;
// 播放
  toggle();
}

// 監聽語系的下拉選單,可以切換發音的語系
voicesDropdown.addEventListener('change', setVoice);

// 監聽速率跟音調控制條以及文字欄位,有變動時觸發 setOption function
options.forEach(option => option.addEventListener('change', setOption));

// 監聽播放按鈕,如果被點擊,觸發 toggle function
speakButton.addEventListener('click', toggle);

// 監聽停止按鈕,如果被點擊,觸發 toggle function,並帶入參數 false
stopButton.addEventListener('click', () => toggle(false));

完整程式碼

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 = document.querySelector('[name="text"]').value;

function populateVoices() {
  voices = this.getVoices();
  voicesDropdown.innerHTML = voices
    .filter((voice) => voice.lang.includes("en"))
    .map(
      (voice) =>
        `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`
    )
    .join("");
}

function setVoice() {
  msg.voice = voices.find((voice) => voice.name === this.value);
  toggle();
}


// function play() {
//   stop();
//   speechSynthesis.speak(utterance);
// }
// function stop() {
//   speechSynthesis.cancel();
// }


function toggle(startOver = true) {
  speechSynthesis.cancel();
  if (startOver) {
    speechSynthesis.speak(msg);
  }
}

function setOption() {
  console.log(this.name, this.value);
  msg[this.name] = this.value;
  // play();
  toggle();
}

speechSynthesis.addEventListener("voiceschanged", populateVoices);
voicesDropdown.addEventListener("change", setVoice);
options.forEach((option) => option.addEventListener("change", setOption));
speakButton.addEventListener("click", toggle);
stopButton.addEventListener("click", () => toggle(false));
// speakButton.addEventListener("click", play);
// stopButton.addEventListener("click", stop);

參考資料:


#JS 30







Related Posts

Fetch、Promise 介紹與應用

Fetch、Promise 介紹與應用

JS30 days

JS30 days

What Type of Laser Engraving Machine Should be Used for Stainless Steel Engraving?

What Type of Laser Engraving Machine Should be Used for Stainless Steel Engraving?


Comments