在React app中使用<audio>标签,在onClick上播放所选文件

时间:2017-06-06 01:03:43

标签: javascript reactjs audio onclick state

我可以通过数组映射并渲染一些图像(在generateWord函数的底部附近)。我希望能够点击图像,然后播放相关的音频文件。它播放阵列中的第二个(或最后一个)音频文件。我想我应该将某种键或索引附加到音频文件中,以便它知道要播放哪一个,但我不确定如何准确。下面的代码是组件。部分状态在它下面注释,因此您可以看到映射数组的来源。

const debug = require("debug")("components:Displayletter")
const React = require("react")
const { connect } = require("react-redux")
const request = require("superagent")
const { Link } = require("react-router")

class Displayletter extends React.Component {

  constructor() {
    super()
    this.playSound = this.playSound.bind(this)
  }

  playSound() {
    this.playWord.play()
  }

  handleClick(e) {
    e.preventDefault()
    this.props.router.push("/")
  }

  render() {
    debug(this.props)
    const { dispatch, letters, letter } = this.props
    const wordsArr = letter.wordImage

    return (
      <div className="row letter-container">
        <div className="col-sm-12">
          {this.generateWord(wordsArr)}
        </div>
      </div>
    )
  }

  generateWord(wordsArr) {
    return wordsArr.map((word) => {
      return (
        <div>
          <audio
          key={word.sound}
          ref={(x) => { this.playWord = x; }}>
            <source src={word.sound} preload='auto'/>
          </audio>
          <img src={word.image} onClick={this.playSound} />
        </div>
      )
    })
  }
}

module.exports = connect(state => state)(Displayletter)

//STATE
  // letters: [
  //   {
  //     id: 1,
  //     capital: "A",
  //     lowercase: "a",
  //     capitalSound: "/sounds/capitalSounds/A.mp3",
  //     lowerSound: "/sounds/lowerSounds/a.mp3",
  //     wordImage: [
  //       {id:1, image:"images/words/aniwaniwa.png", sound: "sounds/ua.mp3"},
  //       {id:2, image:"images/words/anuhe.png", sound: "sounds/anuhe.mp3"},
  //     ],
  //     multimedia: "/multimedia/aniwaniwa.webm",
  //     mediaName: "Aniwaniwa Song",
  //   },

第二次迭代 - 在构造函数中添加了一个空对象,并通过onClick和playSound传递了一个'word'参数。

generateWord(wordsArr) {
return wordsArr.map((word) => {
  return (
    <div>
    <audio
      key={word}
      ref={(x) => { this.playWords[word] = x; }}>
          <source src={word.sound} preload='auto'/>
    </audio>
      <img src={word.image} onClick={this.playSound.bind(this, word)} />
    </div>
  )
})

  playSound(word) {
    this.playWords[word].play()
  }

  constructor() {
    super()
    this.playCapital = this.playCapital.bind(this)
    this.playLower = this.playLower.bind(this)
    this.playSound = this.playSound.bind(this)
    this.playWords = {}
  }

***************第三轮*******************

const debug = require("debug")("components:Displayletter")
const React = require("react")
const { connect } = require("react-redux")
const request = require("superagent")
const { Link } = require("react-router")

class Displayletter extends React.Component {

  constructor() {
    super()
    this.playCapital = this.playCapital.bind(this)
    this.playLower = this.playLower.bind(this)
    this.playWords = {}
  }

  playCapital() {
    this.playCap.play()
  }

  playLower() {
    this.playLow.play()
  }

  playSound(word) {
    this.playWords[word].play()
  }

  handleClick(e) {
    e.preventDefault()
    this.props.router.push("/")
  }



  render() {
debug(this.props)
const { dispatch, letters, letter } = this.props
const wordsArr = letter.wordImage

    return (
  <div className="row letter-container">
    <div className="col-sm-12">

      <audio
      key={letter.capitalSound}
      ref={(cap) => { this.playCap = cap; }}>
        <source
          src={letter.capitalSound}
          preload="auto" />
        <track
          kind="captions"
          src=""
          srcLang="en" />
      </audio>

      <audio
      key={letter.lowerSound}
      ref={(low) => { this.playLow = low; }}>
        <source
          src={letter.lowerSound}
          preload="auto" />
        <track
          kind="captions"
          src=""
          srcLang="en" />
      </audio>

      <button
        type="button"
        className="btn btn-xl display"
        onClick={this.playCapital}>
        {letter.capital}
      </button>

      <button
        type="button"
        className="btn btn-xl display"
        onClick={this.playLower}>
        {letter.lowercase}
      </button>

    </div>

      <div className="col-sm-12">
    {this.generateWord(wordsArr)}
  </div>

        <div className="col-sm-12">
      <Link key={letter.id} to={`/media/${letter.capital}`}>
        <button
          type="button"
          className="btn"
          onClick={() =>
              dispatch({
                type: "RENDER_LETTER",
                payload: letter,
              })
          }>
          Watch: {letter.mediaName}
        </button>
      </Link>

    </div>
  </div>
)
  }

  generateWord(wordsArr) {
    return wordsArr.map((word) => {
      return (
    <div>
          <audio
        key={word}
        ref={(x) => { this.playWords[word] = x; }}>
          <source src={word.sound} preload='auto'/>
          </audio>
          <img src={word.image} onClick={this.playSound.bind(this, word)} />
        </div>
      )
    })
  }
}

module.exports = connect(state => state)(Displayletter)

  // letters: [
  //   {
  //     id: 1,
  //     capital: "A",
  //     lowercase: "a",
  //     capitalSound: "/sounds/capitalSounds/A.mp3",
  //     lowerSound: "/sounds/lowerSounds/a.mp3",
  //     wordImage: [
  //       {id:1, image:"images/words/aniwaniwa.png", sound: "sounds/ua.mp3"},
  //       {id:2, image:"images/words/anuhe.png", sound: "sounds/anuhe.mp3"},
  //     ],
  //     multimedia: "/multimedia/aniwaniwa.webm",
  //     mediaName: "Aniwaniwa Song",
  //   },

1 个答案:

答案 0 :(得分:2)

你真的很亲密!问题在于如何保存对音频元素的引用:ref={(x) => { this.playWord = x; }}。请注意,因为它位于map内,每个元素都会一个接一个地保存,this.playWord,因此当您单击时只会播放最后一个文件

您要做的是将所有单词保存到对象或数组,然后在您的单击处理程序中引用您想要播放的单词。

首先,在构造函数中执行类似this.playWords = {}的操作,然后在ref={(x) => { this.playWords[word] = x; }}中执行render。这将为您提供一个对象playWords,用于存储对按字键控的所有音频元素的引用。

然后,给playSound一个单词参数,并确保onClick通过绑定它来传递该参数,如onClick={this.playSound.bind(this, word)}

我汇总了一个简单的例子来证明基本结构;您应该能够轻松地将这些原则应用于您的组件。

class Example extends React.Component {
  constructor() {
    super();
    this.words = {};
  }

  logClick(i) {
    console.log("user clicked on", this.words[i]);
  }

  render() {
    const wordsArr = "this is an example sentence".split(" ");
    return (
      <div className="row letter-container">
        <div className="col-sm-12">
          {this.generateWord(wordsArr)}
        </div>
      </div>
    )
  }

  generateWord(wordsArr) {
    return wordsArr.map((word) => {
      return (
        <div>
          <span
            key={word}
            ref={x => { this.words[word] = x; }}
            onClick={this.logClick.bind(this, word)}
          >
            {word}
          </span>
        </div>
      );
    })
  }
}

ReactDOM.render(<Example />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="container"/>