Skip to content

Commit 9455aae

Browse files
committed
完成了day23的任务,更新了readme
1 parent f204f30 commit 9455aae

File tree

6 files changed

+315
-2
lines changed

6 files changed

+315
-2
lines changed

23 - Speech Synthesis/README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# 23 Speech Synthesis 中文指南
2+
3+
> 本篇作者:©[大史快跑Dashrun](https://github.com/dashrun)——Chinasoft Frontend Developer
4+
5+
> 简介:[JavaScript30](https://javascript30.com)[Wes Bos](https://github.com/wesbos) 推出的一个 30 天挑战。项目免费提供了 30 个视频教程、30 个挑战的起始文档和 30 个挑战解决方案源代码。目的是帮助人们用纯 JavaScript 来写东西,不借助框架和库,也不使用编译器和引用。现在你看到的是这系列指南的第 23 篇。完整指南在 [GitHub](https://github.com/soyaine/JavaScript30),喜欢请 Star 哦♪(^∇^*)
6+
7+
> 创建时间:2017-09-20
8+
最后更新:2017-09-22
9+
10+
## 挑战任务
11+
初始文档`index-start.html`提供了一个阅读器,你需要完成如下编程任务:
12+
1.使用相应的WebAPI接口获得浏览器支持的语言种类列表,并填充至页面的下拉菜单中,选择中文;
13+
2.在文本域中输入对应语言的文字,点击`speak`按钮后浏览器会阅读输入的文字;
14+
3.在浏览器阅读时,点击`stop`按钮,浏览器会停止阅读;
15+
4.拖动`rate``pitch`滑块可改变阅读速度和音高。
16+
17+
## 实现效果
18+
![结果展示](https://github.com/dashrun/vanilla-javascript-30/blob/master/23%20-%20Speech%20Synthesis/effects.png)
19+
20+
## 相关知识
21+
1.`SpeechSynthesisUtterance`接口
22+
本接口用于设置阅读器阅读的配置参数,包括语言,阅读速度,语调等,实例化`SpeechSynthesisUtterance`后,可以通过为其属性赋值来完成参数配置,详细信息请直接参考MDN中的[SpeechSynthesisUtterance接口说明](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance)
23+
2.`SpeechSynthesis`接口
24+
本接口用于控制阅读器行为,包括获取浏览器支持的朗读语言,文本朗读,暂停,停止等,接口属性中定义有paused,speaking等只读属性来表明当前的状态,详细使用方式请参考MDN中的[SpeechSynthesis接口说明](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis)
25+
26+
## 编程思路
27+
本次编程任务使用相应接口的最基本功能即可实现,编程中根据挑战任务中的说明逐步实现即可。
28+
29+
## 过程指南
30+
1.取得`speechSynthesis`对象,并取得浏览器支持的朗读语言,将所有支持的选项动态添加至下拉列表
31+
```js
32+
const synth = window.speechSynthesis;
33+
34+
//将获取支持语言并添加至下拉列表的代码段封装在一个函数中
35+
function getSupportVoice() {
36+
voices = synth.getVoices();//获取支持的语言
37+
for(i = 0; i < voices.length ; i++) {
38+
var option = document.createElement('option');
39+
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
40+
41+
if(voices[i].default) {
42+
option.textContent += ' -- DEFAULT';
43+
}
44+
45+
option.setAttribute('data-lang', voices[i].lang);
46+
option.setAttribute('data-name', voices[i].name);
47+
voicesDropdown.appendChild(option);
48+
}
49+
}
50+
51+
//经测试直接执行getSupportVoice()时无法获得预期效果,须由事件触发该函数。
52+
synth.addEventListener('voiceschanged', getSupportVoice);
53+
```
54+
2.点击`speak`按钮后朗读(为方便说明,以下代码段与所提供的完成代码顺序不完全一致)
55+
```js
56+
//实例化配置对象
57+
const msg = new SpeechSynthesisUtterance();
58+
59+
//定义一段默认朗读内容
60+
msg.text = '你能说中文吗';
61+
62+
//点击speak按钮时阅读文字
63+
function speak() {
64+
console.log(voicesDropdown.value);
65+
synth.speak(msg);
66+
}
67+
68+
//将阅读函数绑定至`speak`按钮的点击事件上
69+
speakButton.addEventListener('click', speak);
70+
```
71+
3.点击`stop`按钮停止朗读
72+
```js
73+
//停止朗读
74+
function stopSpeak(){
75+
synth.cancel();
76+
}
77+
//将停止朗读函数绑定至`stop`按钮的点击事件上
78+
stopButton.addEventListener('click', stopSpeak);
79+
```
80+
4.参数配置可更改
81+
```js
82+
//index-start.html中提供的选择器将返回rate值,pitch值以及阅读内容对应的DOM元素
83+
const options = document.querySelectorAll('[type="range"], [name="text"]');
84+
//将阅读参数赋值至msg的同名实例属性
85+
function paramChange(){
86+
msg[this.name] = this.value;
87+
}
88+
options.forEach(opt => opt.addEventListener('change', paramChange));
89+
```
90+
91+
92+
93+

23 - Speech Synthesis/effects.png

73.1 KB
Loading
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Speech Synthesis</title>
6+
<link rel="stylesheet" href="style.css">
7+
</head>
8+
<body>
9+
10+
<div class="voiceinator">
11+
12+
<h1>听说 5000</h1>
13+
14+
<select name="voice" id="voices">
15+
<option value="">Select A Voice</option>
16+
</select>
17+
18+
<label for="rate">Rate:</label>
19+
<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
20+
21+
<label for="pitch">Pitch:</label>
22+
23+
<input name="pitch" type="range" min="0" max="2" step="0.1">
24+
<textarea name="text">Hello! I love JavaScript 👍</textarea>
25+
<button id="stop">Stop!</button>
26+
<button id="speak">Speak</button>
27+
28+
</div>
29+
30+
<script>
31+
const synth = window.speechSynthesis;
32+
let voices = [];
33+
const msg = new SpeechSynthesisUtterance();
34+
const voicesDropdown = document.querySelector('[name="voice"]');
35+
const options = document.querySelectorAll('[type="range"], [name="text"]');
36+
const speakButton = document.querySelector('#speak');
37+
const stopButton = document.querySelector('#stop');
38+
msg.text = '你能说中文吗';
39+
40+
//获得浏览器支持的阅读语言并填充至下拉列表
41+
function getSupportVoice() {
42+
voices = synth.getVoices();
43+
for(i = 0; i < voices.length ; i++) {
44+
var option = document.createElement('option');
45+
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
46+
47+
if(voices[i].default) {
48+
option.textContent += ' -- DEFAULT';
49+
}
50+
51+
option.setAttribute('data-lang', voices[i].lang);
52+
option.setAttribute('data-name', voices[i].name);
53+
voicesDropdown.appendChild(option);
54+
}
55+
}
56+
57+
//点击speak按钮时阅读文字
58+
function speak() {
59+
console.log(voicesDropdown.value);
60+
synth.speak(msg);
61+
}
62+
63+
//阅读参数发生变化
64+
function paramChange(){
65+
msg[this.name] = this.value;
66+
console.log(this.name,this.value);
67+
}
68+
69+
//停止阅读
70+
function stopSpeak(){
71+
synth.cancel();
72+
}
73+
74+
// 事件绑定
75+
options.forEach(opt => opt.addEventListener('change', paramChange));
76+
synth.addEventListener('voiceschanged', getSupportVoice);//经测试直接执行无效,须由事件触发
77+
speakButton.addEventListener('click', speak);
78+
stopButton.addEventListener('click', stopSpeak);
79+
</script>
80+
81+
</body>
82+
</html>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Speech Synthesis</title>
6+
<link rel="stylesheet" href="style.css">
7+
</head>
8+
<body>
9+
10+
<div class="voiceinator">
11+
12+
<h1>The Voiceinator 5000</h1>
13+
14+
<select name="voice" id="voices">
15+
<option value="">Select A Voice</option>
16+
</select>
17+
18+
<label for="rate">Rate:</label>
19+
<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
20+
21+
<label for="pitch">Pitch:</label>
22+
23+
<input name="pitch" type="range" min="0" max="2" step="0.1">
24+
<textarea name="text">Hello! I love JavaScript 👍</textarea>
25+
<button id="stop">Stop!</button>
26+
<button id="speak">Speak</button>
27+
28+
</div>
29+
30+
<script>
31+
const msg = new SpeechSynthesisUtterance();
32+
let voices = [];
33+
const voicesDropdown = document.querySelector('[name="voice"]');
34+
const options = document.querySelectorAll('[type="range"], [name="text"]');
35+
const speakButton = document.querySelector('#speak');
36+
const stopButton = document.querySelector('#stop');
37+
</script>
38+
39+
</body>
40+
</html>

23 - Speech Synthesis/style.css

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
html {
2+
font-size: 10px;
3+
box-sizing: border-box;
4+
}
5+
6+
*, *:before, *:after {
7+
box-sizing: inherit;
8+
}
9+
10+
body {
11+
margin: 0;
12+
padding: 0;
13+
font-family: sans-serif;
14+
background-color:#3BC1AC;
15+
display:flex;
16+
min-height: 100vh;
17+
align-items: center;
18+
19+
background-image:
20+
radial-gradient(circle at 100% 150%, #3BC1AC 24%, #42D2BB 25%, #42D2BB 28%, #3BC1AC 29%, #3BC1AC 36%, #42D2BB 36%, #42D2BB 40%, transparent 40%, transparent),
21+
radial-gradient(circle at 0 150%, #3BC1AC 24%, #42D2BB 25%, #42D2BB 28%, #3BC1AC 29%, #3BC1AC 36%, #42D2BB 36%, #42D2BB 40%, transparent 40%, transparent),
22+
radial-gradient(circle at 50% 100%, #42D2BB 10%, #3BC1AC 11%, #3BC1AC 23%, #42D2BB 24%, #42D2BB 30%, #3BC1AC 31%, #3BC1AC 43%, #42D2BB 44%, #42D2BB 50%, #3BC1AC 51%, #3BC1AC 63%, #42D2BB 64%, #42D2BB 71%, transparent 71%, transparent),
23+
radial-gradient(circle at 100% 50%, #42D2BB 5%, #3BC1AC 6%, #3BC1AC 15%, #42D2BB 16%, #42D2BB 20%, #3BC1AC 21%, #3BC1AC 30%, #42D2BB 31%, #42D2BB 35%, #3BC1AC 36%, #3BC1AC 45%, #42D2BB 46%, #42D2BB 49%, transparent 50%, transparent),
24+
radial-gradient(circle at 0 50%, #42D2BB 5%, #3BC1AC 6%, #3BC1AC 15%, #42D2BB 16%, #42D2BB 20%, #3BC1AC 21%, #3BC1AC 30%, #42D2BB 31%, #42D2BB 35%, #3BC1AC 36%, #3BC1AC 45%, #42D2BB 46%, #42D2BB 49%, transparent 50%, transparent);
25+
background-size:100px 50px;
26+
}
27+
28+
29+
.voiceinator {
30+
padding:2rem;
31+
width:50rem;
32+
margin:0 auto;
33+
border-radius:1rem;
34+
position: relative;
35+
background:white;
36+
overflow: hidden;
37+
z-index: 1;
38+
box-shadow:0 0 5px 5px rgba(0,0,0,0.1);
39+
}
40+
41+
h1 {
42+
width:calc(100% + 4rem);
43+
margin: -2rem 0 2rem -2rem;
44+
padding:.5rem;
45+
background: #ffc600;
46+
border-bottom: 5px solid #F3C010;
47+
text-align: center;
48+
font-size: 5rem;
49+
font-weight: 100;
50+
font-family: 'Pacifico', cursive;
51+
text-shadow:3px 3px 0 #F3C010;
52+
53+
}
54+
55+
.voiceinator input,
56+
.voiceinator button,
57+
.voiceinator select,
58+
.voiceinator textarea {
59+
width: 100%;
60+
display: block;
61+
margin:10px 0;
62+
padding:10px;
63+
border:0;
64+
font-size: 2rem;
65+
background:#353535;
66+
color:white;
67+
outline:0;
68+
}
69+
70+
textarea {
71+
height: 20rem;
72+
}
73+
74+
input[type="select"] {
75+
76+
}
77+
78+
.voiceinator button {
79+
background:#ffc600;
80+
border:0;
81+
width: 49%;
82+
float:left;
83+
font-family: 'Pacifico', cursive;
84+
margin-bottom: 0;
85+
font-size: 2rem;
86+
border-bottom: 5px solid #F3C010;
87+
cursor:pointer;
88+
position: relative;
89+
}
90+
91+
.voiceinator button:active {
92+
top:2px;
93+
}
94+
95+
.voiceinator button:nth-of-type(1) {
96+
margin-right: 2%;
97+
}
98+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ No | Guide | Demo
6161
19 | [Webcam Fun 指南](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun/README.md) | [网络摄像头及图片处理在线效果](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun/index-finished-Dashrun.html)
6262
20 | [Speech Detection指南](https://github.com/soyaine/JavaScript30/blob/master/20%20-%20Speech%20Detection/README.md) | [Speech Detection效果](https://github.com/soyaine/JavaScript30/blob/master/20%20-%20Speech%20Detection/index-finished-Dashrun.html)
6363
21 | [Geolocation指南](https://github.com/soyaine/JavaScript30/blob/master/21%20-%20Geolocation/README.md) | [Geolocation效果](https://github.com/soyaine/JavaScript30/blob/master/21%20-%20Geolocation/index-finished-Dashrun.html)
64-
22 | Follow Along Link Highlighter | -
64+
22 | [Follow Along Link Highlighter指南](https://github.com/soyaine/JavaScript30/blob/master/22%20-%20Follow%20Along%20Link%20Highlighter/README.md) | [Follow Along Link Highlighter效果](https://github.com/soyaine/JavaScript30/blob/master/22%20-%20Follow%20Along%20Link%20Highlighter/index-finished-Dashrun.html)
6565
23 | Speech Synthesis | -
6666
24 | Sticky Nav | -
6767
25 | Event Capture, Propagation, Bubbling, and Once | -
@@ -80,7 +80,7 @@ Name | Contribution
8080
[@DrakeXiang](https://github.com/DrakeXiang) | No.[11](https://github.com/soyaine/JavaScript30/tree/master/11%20-%20Custom%20Video%20Player)
8181
[@zzh466](http://github.com/zzh466) | Review
8282
[@Xing Liu](https://github.com/S1ngS1ng) | Review
83-
[@大史快跑Dashrun](https://github.com/dashrun) | No.[16](https://github.com/soyaine/JavaScript30/tree/master/16%20-%20Mouse%20Move%20Shadow).[17](https://github.com/soyaine/JavaScript30/tree/master/17%20-%20Sort%20Without%20Articles).[18](https://github.com/soyaine/JavaScript30/tree/master/18%20-%20AddingUpTimesWithReduce).[19](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun).[20](https://github.com/soyaine/JavaScript30/tree/master/20%20-%20Speech%20Detection).[21](https://github.com/soyaine/JavaScript30/tree/master/21%20-%20Geolocation)
83+
[@大史快跑Dashrun](https://github.com/dashrun) | No.[16](https://github.com/soyaine/JavaScript30/tree/master/16%20-%20Mouse%20Move%20Shadow).[17](https://github.com/soyaine/JavaScript30/tree/master/17%20-%20Sort%20Without%20Articles).[18](https://github.com/soyaine/JavaScript30/tree/master/18%20-%20AddingUpTimesWithReduce).[19](https://github.com/soyaine/JavaScript30/blob/master/19%20-%20Webcam%20Fun).[20](https://github.com/soyaine/JavaScript30/tree/master/20%20-%20Speech%20Detection).[21](https://github.com/soyaine/JavaScript30/tree/master/21%20-%20Geolocation).[22](https://github.com/soyaine/JavaScript30/tree/master/22%20-%20Follow%20Along%20Link%20Highlighter)
8484
[@缉熙Soyaine](https://github.com/soyaine) | No.[1](https://github.com/soyaine/JavaScript30/tree/master/01%20-%20JavaScript%20Drum%20Kit).[2](https://github.com/soyaine/JavaScript30/tree/master/02%20-%20JS%20%2B%20CSS%20Clock).[3](https://github.com/soyaine/JavaScript30/tree/master/03%20-%20CSS%20%Variables).[4](https://github.com/soyaine/JavaScript30/tree/master/04%20-%20Array%20Cardio%20Day%201).[5](https://github.com/soyaine/JavaScript30/blob/master/05%20-%20Flex%20Panel%20Gallery).[6](https://github.com/soyaine/JavaScript30/blob/master/06%20-%20Type%20Ahead).[7](https://github.com/soyaine/JavaScript30/tree/master/07%20-%20Array%20Cardio%20Day%202).[8](https://github.com/soyaine/JavaScript30/tree/master/08%20-%20Fun%20with%20HTML5%20Canvas).[9](https://github.com/soyaine/JavaScript30/blob/master/09%20-%20Dev%20Tools%20Domination).[10](https://github.com/soyaine/JavaScript30/blob/master/10%20-%20Hold%20Shift%20and%20Check%20Checkboxes/README.md).[12](https://github.com/soyaine/JavaScript30/tree/master/12%20-%20Key%20Sequence%20Detection/README.md).[13](https://github.com/soyaine/JavaScript30/blob/master/13%20-%20Slide%20in%20on%20Scroll/README.md).[14](https://github.com/soyaine/JavaScript30/tree/master/14%20-%20JavaScript%20References%20VS%20Copying)
8585

8686
## JOIN US

0 commit comments

Comments
 (0)