Skip to content

Commit b08d1a5

Browse files
committed
add readme file for challenge 23
1 parent 93925bd commit b08d1a5

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

23 - Speech Synthesis/README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
> 在Github上看到了[wesbos](https://twitter.com/wesbos)的一个Javascript30天挑战的[repo](https://github.com/wesbos/JavaScript30),旨在使用纯Js来进行练习,不允许使用任何其他的库和框架,该挑战共30天,我会在这里记录下自己练习的过程和遇到的问题。
3+
4+
5+
第23天要做一个语音的记事本类似的场景,输入一段内容,选择不同的语言可以进行朗读。还可以选择不同的语速和语调。
6+
7+
![Demo](/images/0722-demo.gif)
8+
9+
线上DEMO请[点击这里](http://htmlpreview.github.io/?https://github.com/winar-jin/JavaScript30-Challenge/blob/master/23%20-%20Speech%20Synthesis/index.html)
10+
11+
## 源代码
12+
```Javascript
13+
// 实例化一个语音对象,并获得页面上的各DOM元素
14+
const msg = new SpeechSynthesisUtterance();
15+
let voices = [];
16+
const voicesDropdown = document.querySelector('[name="voice"]');
17+
const options = document.querySelectorAll('[type="range"], [name="text"]');
18+
const speakButton = document.querySelector('#speak');
19+
const stopButton = document.querySelector('#stop');
20+
msg.text = document.querySelector('[name="text"]').value;
21+
22+
// 设置各种语言的下拉选择框
23+
function populateVoices() {
24+
voices = this.getVoices();
25+
voicesDropdown.innerHTML = voices
26+
.filter(voice => voice.lang.includes('en'))
27+
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
28+
.join('');
29+
}
30+
31+
// 设置当前语音的语言
32+
function setVoice() {
33+
msg.voice = voices.find(voice => voice.name === this.value);
34+
toggle();
35+
}
36+
37+
// 切换语音的播放和暂停
38+
function toggle(startOver = true) {
39+
speechSynthesis.cancel();
40+
if (startOver) {
41+
speechSynthesis.speak(msg);
42+
}
43+
}
44+
45+
// 设置语音的语速和语调
46+
function setOption() {
47+
console.log(this.name, this.value);
48+
msg[this.name] = this.value;
49+
toggle();
50+
}
51+
52+
// 监听语音对象的语言改变的事件
53+
speechSynthesis.addEventListener('voiceschanged', populateVoices);
54+
// 当切换语言选择下拉菜单时被调用
55+
voicesDropdown.addEventListener('change', setVoice);
56+
// 为语速和语调设置改变的事件监听
57+
options.forEach(option => option.addEventListener('change', setOption));
58+
// 分别监听播放和暂停事件
59+
speakButton.addEventListener('click', toggle);
60+
stopButton.addEventListener('click', () => toggle(false));
61+
}
62+
```
63+
64+
## 思路
65+
首先要明确实现这样的效果要怎么做。
66+
* 设置语言选择下拉框,并将所选择的语言设置为语音的语言;
67+
* 监听语调和语速的滑动条,将语调和语速的值设置为语音的语调和语速;
68+
* 提供一个可以输入语音的内容的输入框;
69+
* 监听开始和暂停按钮,切换语音的播放状态;
70+
71+
## 技术点
72+
* `SpeechSynthesis.getVoices()`:获取所有的语言列表,代表在当前语音对象上所有可用的语言;
73+
* `SpeechSynthesis.cancel()`:结束,结束当前的语音状态,并将当前语音内容清空;
74+
* `SpeechSynthesis.pause()`:暂停,暂停当前的语音状态,当不清空语音内容,可以继续播放;
75+
* `SpeechSynthesis.speak()`:播放,将文字内容加入到播放序列中并开始播放语音;
76+
* `SpeechSynthesis.resume()`:继续,当语音处于暂停状态的时候,继续播放该语音;
77+
* 当我们为事件监听绑定函数**需要参数**的时候的几种做法:
78+
1.
79+
```
80+
node.onclick = function(){
81+
callback(args);
82+
}
83+
```
84+
2. `node.onclick = callback.bind(null,args);`
85+
3. `node.onclick = () => callback(args);`
86+
> 通常我们会想到会创建匿名函数,执行带参的回调函数(法一),但其实这样代码即冗长也不美观;其次用ES6箭头函数也可以创造匿名函数,执行带参的回调函数(法三);我认为最优雅的方法是法二,通过为回调函数绑定参数的方式实现。
87+
* `toggle(startOver)`函数中,之所以要带上参数,是因为我们可以通过这个参数控制语音播放的两种状态,播放和暂停,只要传入不同的布尔标记即可;并且在播放新的语音前一定要将上一次的语音清除,因为假入我们切换了语言类型或者语素语调,一定要先停止再以新的设置开始播放语音。
88+
89+
90+
END! 💯

0 commit comments

Comments
 (0)