最终,我正在尝试创建一个类似钢琴的应用程序,您可以通过单击或按下来控制它。我希望每个键盘键都可以控制某个音符。每个“钢琴”键都是具有键码属性和音符属性的组件。当event.keycode与keycode属性匹配时,我要播放关联的音符。最好的策略是什么?
我尝试使用refs并专注于componentDidMount。我似乎无法确定应该如何工作。
class Pad extends React.Component {
constructor(props) {
super(props)
this.state = {
clicked: false
}
this.clickedMouse = this.clickedMouse.bind(this)
this.unClickedMouse = this.unClickedMouse.bind(this)
this.handleDownKeyPress = this.handleDownKeyPress.bind(this)
this.handleUpKeyPress = this.handleUpKeyPress.bind(this)
}
clickedMouse(e) {
this.setState({ clicked: true })
this.props.onDown(this.props.note)
console.log(e)
}
unClickedMouse(e) {
this.setState({ clicked: false })
this.props.onUp(this.props.note)
}
handleDownKeyPress(e) {
if (e.keyCode === this.props.keyCode && this.state.clicked === false) {
this.setState({ clicked: true })
this.props.onDown(this.props.note)
}
}
handleUpKeyPress(e) {
this.setState({ clicked: false })
this.props.onUp(this.props.note)
}
render() {
return (
<div
className='pad'
onMouseUp={this.unClickedMouse}
onMouseDown={this.clickedMouse}
onKeyDown={this.handleDownKeyPress}
onKeyUp={this.handleUpKeyPress}
tabIndex='0'
/>
);
}
}
export default Pad
class Pads extends React.Component {
constructor(props) {
super(props);
// tone.js build
this.synth = new Tone.Synth().toMaster()
this.vol = new Tone.Volume(0)
this.synth.chain(this.vol, Tone.Master)
// bindings
this.onDownKey = this.onDownKey.bind(this);
this.onUpKey = this.onUpKey.bind(this);
}
onDownKey(note) {
console.log(`${note} played`);
this.synth.triggerAttack(note);
}
onUpKey(note) {
this.synth.triggerRelease();
}
render() {
const { octave } = this.props
return (
<div className="pad-grid">
<Pad
keyCode={65}
note={`C${octave}`}
onDown={this.onDownKey}
onUp={this.onUpKey}
/>
<Pad
keyCode={70}
note={`Db${octave}`}
onDown={this.onDownKey}
onUp={this.onUpKey}
/>
<Pad
keyCode={83}
note={`D${octave}`}
onDown={this.onDownKey}
onUp={this.onUpKey}
/>
<Pad
keyCode={68}
note={`Eb${octave}`}
onDown={this.onDownKey}
onUp={this.onUpKey}
/>
</div>
);
}
}
export default Pads
这里有一个Codepen,因此您可以在操作中https://codepen.io/P-FVNK/pen/XopBgW将其检出
答案 0 :(得分:0)
最终代码:https://codesandbox.io/s/5v89kw6w0n
因此,我进行了大量更改以启用所需的功能。
有没有办法遍历重复的组件及其属性以匹配event.keyCode来更正键码属性?
为此,我决定创建一个包含可能的键及其注释的对象数组。我将它们从现已弃用的KeyboardEvent.keyCode
更改为KeyboardEvent.key
。您也可以使用KeyboardEvent.code
。
this.padCodes = [
{
key: "a",
note: "C"
},
{
key: "f",
note: "Db"
},
{
key: "s",
note: "D"
},
{
key: "d",
note: "Eb"
}
];
我将keydown
事件侦听器从各个<Pad />
移到了父组件,并将侦听器附加到了文档上。
document.addEventListener("keydown", e => {
let index = this.state.pads.findIndex(item => item.key === e.key);
let { octave } = this.context;
if (this.state.pressed === false) {
this.onDownKey(`${this.state.pads[index].props.note}${octave}`);
this.setState({
activeNote: this.state.pads[index].note,
pressed: true
});
}
});
document.addEventListener("keyup", e => {
this.onUpKey(this.state.activeNote);
this.setState({
activeNote: "",
pressed: false
});
});
您可能还会注意到我决定使用Context
代替道具。那只是个人喜好,但我宁愿主要参考八度音阶,而不是将prop传递给每个子分量。
之后,只需确保这些函数调用相同的函数并传递音符和八度即可。
为了减少混乱,我制作了<Pad />
数组,后来我渲染了它们,而不是一一列出。
let newPadCodes = this.padCodes.map(x => (
<Pad
key={x.key.toString()}
note={`${x.note}`}
onDown={this.onDownKey}
onUp={this.onUpKey}
/>
));
this.setState({
pads: newPads
});
//And later
//Render if this.state.pads.length is > 0
{this.state.pads.length > 0 &&
this.state.pads}
这几乎涵盖了我所做的一切。这是带有修改后的代码的codeandbox:https://codesandbox.io/s/5v89kw6w0n