回答編集履歴

2

onend について追加

2021/01/11 07:42

投稿

A_kirisaki
A_kirisaki

スコア2853

test CHANGED
@@ -69,3 +69,195 @@
69
69
 
70
70
 
71
71
  あと `var` は使わないで `let` と `const` 使うようにして……。
72
+
73
+
74
+
75
+ 追記 2:
76
+
77
+ すみません、ドキュメントをよく読んだら onend イベントがありました……。なのでそれを使えば大丈夫です。
78
+
79
+ [SpeechSynthesisUtterance - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/SpeechSynthesisUtterance#event_handlers)
80
+
81
+ アロー関数にしてるのは `function` だと `this` が参照先で変わってしまうから。
82
+
83
+ ```HTML
84
+
85
+ <!DOCTYPE html>
86
+
87
+ <html>
88
+
89
+
90
+
91
+ <head>
92
+
93
+ <meta charset="UTF-8" />
94
+
95
+ <title>React</title>
96
+
97
+ <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
98
+
99
+ <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
100
+
101
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
102
+
103
+ </head>
104
+
105
+
106
+
107
+ <body>
108
+
109
+ <div id="root"></div>
110
+
111
+ <script type="text/babel">
112
+
113
+
114
+
115
+ (() => {
116
+
117
+
118
+
119
+ class App extends React.Component {
120
+
121
+ constructor() {
122
+
123
+ super();
124
+
125
+ this.state = {
126
+
127
+ answer: "abc",
128
+
129
+ blank: "a__",
130
+
131
+ location: 1,
132
+
133
+ speaking: undefined,
134
+
135
+ }
136
+
137
+ this.keydown = this.keydown.bind(this)
138
+
139
+ this.speak = this.speak.bind(this)
140
+
141
+ }
142
+
143
+ speak(word) {
144
+
145
+ var speech = new SpeechSynthesisUtterance(word)
146
+
147
+ speech.onend = () => {
148
+
149
+ this.setState({
150
+
151
+ ...this.state,
152
+
153
+ answer: "def",
154
+
155
+ blank: "d__",
156
+
157
+ location: 1,
158
+
159
+ });
160
+
161
+ }
162
+
163
+ speechSynthesis.speak(speech)
164
+
165
+ }
166
+
167
+ keydown(e) {
168
+
169
+ console.log(e.key)
170
+
171
+
172
+
173
+ if (this.state.answer[this.state.location] == e.key) {
174
+
175
+ this.setState((state, props) => ({
176
+
177
+ location: state.location + 1
178
+
179
+ }));
180
+
181
+ let blank = this.state.answer.substring(0, this.state.location) + '_'.repeat(this.state.blank.length - this.state.location);
182
+
183
+
184
+
185
+ this.setState({
186
+
187
+ blank: blank
188
+
189
+ })
190
+
191
+ console.log(blank)
192
+
193
+
194
+
195
+ if (this.state.answer.length == this.state.location) {
196
+
197
+ this.speak(this.state.answer)
198
+
199
+ }
200
+
201
+ }
202
+
203
+ }
204
+
205
+
206
+
207
+ componentDidMount() {
208
+
209
+ window.addEventListener('keydown', this.keydown)
210
+
211
+ }
212
+
213
+
214
+
215
+ render() {
216
+
217
+ return (
218
+
219
+ <div>
220
+
221
+ <div>
222
+
223
+ {this.state.answer}
224
+
225
+ </div>
226
+
227
+ <div>
228
+
229
+ {this.state.blank}
230
+
231
+ </div>
232
+
233
+ </div>
234
+
235
+ );
236
+
237
+ }
238
+
239
+ }
240
+
241
+
242
+
243
+ ReactDOM.render(
244
+
245
+ <App />,
246
+
247
+ document.getElementById('root')
248
+
249
+ );
250
+
251
+ })();
252
+
253
+
254
+
255
+ </script>
256
+
257
+ </body>
258
+
259
+
260
+
261
+ </html>
262
+
263
+ ```

1

speaking について追記

2021/01/11 07:42

投稿

A_kirisaki
A_kirisaki

スコア2853

test CHANGED
@@ -31,3 +31,41 @@
31
31
  ```
32
32
 
33
33
  ではどうでしょうか。
34
+
35
+
36
+
37
+ 追記:
38
+
39
+ 音声が終わる前に次の回答がセットされるのを防ぐには `SpeechSynthesis.speaking` を使うのが良さそうです。
40
+
41
+ [SpeechSynthesis.speaking - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/speaking)
42
+
43
+ まず
44
+
45
+ ```JavaScript
46
+
47
+ speech = speechSynthesis.speak(utterance) // speak だと名前が紛らわしいので変えた
48
+
49
+ this.setState({...this.state,speech}) // スプレッド演算子でコピーを取らないと意図しない挙動をすることがあるので注意
50
+
51
+ ```
52
+
53
+ として適当に状態にオブジェクトを保存しておきます。次に正解したときの処理を
54
+
55
+ ```JavaScript
56
+
57
+ if (this.state.answer.length == this.state.location) {
58
+
59
+ this.speak(this.state.answer)
60
+
61
+ while(this.state.speech.speaking);
62
+
63
+ }
64
+
65
+ ```
66
+
67
+ とすれば `speaking` が `false` になるまで待つことができるでしょう。
68
+
69
+
70
+
71
+ あと `var` は使わないで `let` と `const` 使うようにして……。