teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

onend について追加

2021/01/11 07:42

投稿

A_kirisaki
A_kirisaki

スコア2853

answer CHANGED
@@ -33,4 +33,100 @@
33
33
  ```
34
34
  とすれば `speaking` が `false` になるまで待つことができるでしょう。
35
35
 
36
- あと `var` は使わないで `let` と `const` 使うようにして……。
36
+ あと `var` は使わないで `let` と `const` 使うようにして……。
37
+
38
+ 追記 2:
39
+ すみません、ドキュメントをよく読んだら onend イベントがありました……。なのでそれを使えば大丈夫です。
40
+ [SpeechSynthesisUtterance - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/SpeechSynthesisUtterance#event_handlers)
41
+ アロー関数にしてるのは `function` だと `this` が参照先で変わってしまうから。
42
+ ```HTML
43
+ <!DOCTYPE html>
44
+ <html>
45
+
46
+ <head>
47
+ <meta charset="UTF-8" />
48
+ <title>React</title>
49
+ <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
50
+ <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
51
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
52
+ </head>
53
+
54
+ <body>
55
+ <div id="root"></div>
56
+ <script type="text/babel">
57
+
58
+ (() => {
59
+
60
+ class App extends React.Component {
61
+ constructor() {
62
+ super();
63
+ this.state = {
64
+ answer: "abc",
65
+ blank: "a__",
66
+ location: 1,
67
+ speaking: undefined,
68
+ }
69
+ this.keydown = this.keydown.bind(this)
70
+ this.speak = this.speak.bind(this)
71
+ }
72
+ speak(word) {
73
+ var speech = new SpeechSynthesisUtterance(word)
74
+ speech.onend = () => {
75
+ this.setState({
76
+ ...this.state,
77
+ answer: "def",
78
+ blank: "d__",
79
+ location: 1,
80
+ });
81
+ }
82
+ speechSynthesis.speak(speech)
83
+ }
84
+ keydown(e) {
85
+ console.log(e.key)
86
+
87
+ if (this.state.answer[this.state.location] == e.key) {
88
+ this.setState((state, props) => ({
89
+ location: state.location + 1
90
+ }));
91
+ let blank = this.state.answer.substring(0, this.state.location) + '_'.repeat(this.state.blank.length - this.state.location);
92
+
93
+ this.setState({
94
+ blank: blank
95
+ })
96
+ console.log(blank)
97
+
98
+ if (this.state.answer.length == this.state.location) {
99
+ this.speak(this.state.answer)
100
+ }
101
+ }
102
+ }
103
+
104
+ componentDidMount() {
105
+ window.addEventListener('keydown', this.keydown)
106
+ }
107
+
108
+ render() {
109
+ return (
110
+ <div>
111
+ <div>
112
+ {this.state.answer}
113
+ </div>
114
+ <div>
115
+ {this.state.blank}
116
+ </div>
117
+ </div>
118
+ );
119
+ }
120
+ }
121
+
122
+ ReactDOM.render(
123
+ <App />,
124
+ document.getElementById('root')
125
+ );
126
+ })();
127
+
128
+ </script>
129
+ </body>
130
+
131
+ </html>
132
+ ```

1

speaking について追記

2021/01/11 07:42

投稿

A_kirisaki
A_kirisaki

スコア2853

answer CHANGED
@@ -14,4 +14,23 @@
14
14
  this.speak(this.state.answer)
15
15
  }
16
16
  ```
17
- ではどうでしょうか。
17
+ ではどうでしょうか。
18
+
19
+ 追記:
20
+ 音声が終わる前に次の回答がセットされるのを防ぐには `SpeechSynthesis.speaking` を使うのが良さそうです。
21
+ [SpeechSynthesis.speaking - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/speaking)
22
+ まず
23
+ ```JavaScript
24
+ speech = speechSynthesis.speak(utterance) // speak だと名前が紛らわしいので変えた
25
+ this.setState({...this.state,speech}) // スプレッド演算子でコピーを取らないと意図しない挙動をすることがあるので注意
26
+ ```
27
+ として適当に状態にオブジェクトを保存しておきます。次に正解したときの処理を
28
+ ```JavaScript
29
+ if (this.state.answer.length == this.state.location) {
30
+ this.speak(this.state.answer)
31
+ while(this.state.speech.speaking);
32
+ }
33
+ ```
34
+ とすれば `speaking` が `false` になるまで待つことができるでしょう。
35
+
36
+ あと `var` は使わないで `let` と `const` 使うようにして……。