UNPKG

easy-ring

Version:

A easy 、general and cool web component to ring/beep.(for js 、Vue、React)

155 lines (148 loc) 4.97 kB
const{ MusicBox, musicTexts } = require('./piano') let React let h let ReactComponent try { React = require('react') h = React.createElement ReactComponent = React.Component } catch(e) { console.log('🌟【EASY-RING LOG】:require React fail.(If you are not using React, please ignore this message.)') ReactComponent = class {} } class EasyRingReactComponent extends ReactComponent { // static defaultProps在class内部定义 需要react相关依赖进行解析。这里可以把defaultProps在class内部定义写在class外 // static defaultProps = { // 想设置props的默认值需要在这里设置 // open: false, // ring: false, // src: '', // loop: true, // log: true, // musicText: '', // defaultMusic: 'EZIOS_FAMILY', // ended: () => {} // } constructor(props) { super(props) // 必须直接把constructor的props直接传入,不能自己传入任意对象 this.state = { id: this._createAudioId(), active: false } this.musicbox = null this.audioObject = null // 与视图无关,实际上并不需要写在state里 } _createAudioId() { const id = parseInt(Math.random() * 1000000) return `easyRing${id}` } _openRing() { this._log(`open the ring(id=${this.state.id})`) this.setState({ active: true, }) this.audioObject.loop = false this.audioObject.pause() // 用于开启用户主动播放 this.musicbox = new MusicBox({ loop: this.props.loop, endedCallback: this.props.loop ? () => {} : () => { this.props.ended() } }) } _stopRing() { this._log(`close the ring(id=${this.state.id})`) this.setState({ active: false }) this.audioObject.pause() this.audioObject.currentTime = 0 } _play() { this._log(`play the ring(id=${this.state.id})`) if (!this.audioObject.loop && this.props.loop) { this.audioObject.loop = true } if (this.state.active) { if (this.props.src) { this.audioObject.currentTime = 0 this.audioObject.play() } else { if (this.props.musicText) { this.musicbox.playMusic(this.props.musicText) } else if(musicTexts[this.props.defaultMusic]) { this.musicbox.playMusic(musicTexts[this.props.defaultMusic]) } else { this._log(`💔invalid type of defaultMusicText in ths ring(id=${this.state.id}).`) } } } } _pause() { this._log(`pause the ring(id=${this.state.id})`) if (this.props.src) { this.audioObject.pause() } else { this.musicbox.stopMusic() } this.props.ended() } _log(info){ if (info && this.props.log) console.log(`🌟【EASY-RING LOG】:${info}`) } componentDidUpdate(prevProps) { // 触发时机是组件更新,还不是数据更新。但shouldComponentUpdate太快了 if (this.audioObject) { // componentDidUpdate貌似会立即执行,此时audioObject还未初始化。所以需要在这里加个判断 // 典型用法(不要忘记比较) if (prevProps.ring !== this.props.ring ) { if (this.props.ring) this._play() else this._pause() } if (prevProps.open !== this.props.open ) { if (this.props.open) this._openRing() else this._stopRing() } // “你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理, // 否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。” } } componentDidMount() { this._log('EasyRingReactComponent mounted') const audioObject = document.getElementById(this.state.id) // this.setState({ // audioObject // }) this.audioObject = audioObject this.audioObject.addEventListener('ended', () => { this.props.ended() }) } render() { // 用箭头就没法用this了 return h('div', { className: 'easy-ring-container' // 必须用className }, [ h('audio', { id: this.state.id, src: this.props.src, className: 'easy-ring', key: this.state.id // 必须给key }), h('div', { id: `${this.state.id}piano`, key: `${this.state.id}piano` // 必须给key }) ]) } } // static defaultProps在class内部定义,需要react相关依赖进行解析。这里可以把defaultProps在class内部定义写在class外 EasyRingReactComponent.defaultProps = { // 想设置props的默认值需要在这里设置 open: false, ring: false, src: '', loop: true, log: true, musicText: '', defaultMusic: 'EZIOS_FAMILY', ended: () => {} } module.exports = EasyRingReactComponent