|
1 | 1 | import React from 'react'; |
2 | 2 | import PropTypes from 'prop-types'; |
3 | 3 | import APlayer from 'aplayer'; |
| 4 | +import 'aplayer/dist/APlayer.min.css'; |
| 5 | +import events from './events'; |
4 | 6 |
|
5 | | -const events = ['play', 'pause', 'playing', 'canplay', 'ended', 'error']; |
6 | 7 | const capitalize = function(str) { |
7 | 8 | return str[0].toUpperCase() + str.slice(1); |
8 | 9 | }; |
9 | 10 |
|
10 | | -export default class ReactAplayer extends React.Component { |
11 | | - constructor(props) { |
12 | | - super(props); |
13 | | - this.state = { |
14 | | - control: null, |
15 | | - }; |
16 | | - } |
| 11 | +const eventsPropTypes = events.reduce((acc, event) => { |
| 12 | + acc[`on${capitalize(event)}`] = PropTypes.func; |
| 13 | + return acc; |
| 14 | +}, {}); |
17 | 15 |
|
18 | | - render() { |
19 | | - return ( |
20 | | - <div |
21 | | - className="aplayer" |
22 | | - ref={el => { |
23 | | - this.el = el; |
24 | | - }} |
25 | | - /> |
26 | | - ); |
27 | | - } |
| 16 | +const audioItemShape = PropTypes.shape({ |
| 17 | + name: PropTypes.string, |
| 18 | + artist: PropTypes.string, |
| 19 | + url: PropTypes.string, |
| 20 | + cover: PropTypes.string, |
| 21 | + lrc: PropTypes.string, |
| 22 | + theme: PropTypes.string, |
| 23 | + type: PropTypes.string |
| 24 | +}); |
| 25 | + |
| 26 | +class ReactAplayer extends React.Component { |
| 27 | + static propTypes = { |
| 28 | + onInit: PropTypes.func, |
| 29 | + // belows are the same props with aplayer |
| 30 | + fixed: PropTypes.bool, |
| 31 | + mini: PropTypes.bool, |
| 32 | + autoplay: PropTypes.bool, |
| 33 | + theme: PropTypes.string, |
| 34 | + loop: PropTypes.oneOf(['all', 'one', 'none']), |
| 35 | + order: PropTypes.oneOf(['list', 'random']), |
| 36 | + preload: PropTypes.oneOf(['auto', 'metadata', 'none']), |
| 37 | + volume: PropTypes.number, |
| 38 | + audio: PropTypes.oneOfType([ |
| 39 | + audioItemShape, |
| 40 | + PropTypes.arrayOf(audioItemShape) |
| 41 | + ]), |
| 42 | + customAudioType: PropTypes.object, |
| 43 | + mutex: PropTypes.bool, |
| 44 | + lrcType: PropTypes.number, |
| 45 | + listFolded: PropTypes.bool, |
| 46 | + listMaxHeight: PropTypes.string, |
| 47 | + storageName: PropTypes.string, |
| 48 | + // belows are bind event listener |
| 49 | + ...eventsPropTypes |
| 50 | + }; |
| 51 | + |
| 52 | + static defaultProps = { |
| 53 | + onInit() {}, |
| 54 | + fixed: false, |
| 55 | + mini: false, |
| 56 | + autoplay: false, |
| 57 | + theme: '#b7daff', |
| 58 | + loop: 'all', |
| 59 | + order: 'list', |
| 60 | + preload: 'auto', |
| 61 | + volume: 0.7, |
| 62 | + mutex: true, |
| 63 | + lrcType: 0, |
| 64 | + listFolded: false, |
| 65 | + storageName: 'react-aplayer-setting' |
| 66 | + }; |
28 | 67 |
|
29 | 68 | componentDidMount() { |
30 | | - let ap = (this.state.control = new APlayer({ |
31 | | - element: this.el, |
32 | | - narrow: this.props.narrow, |
33 | | - autoplay: this.props.autoplay, |
34 | | - showlrc: this.props.showlrc, |
35 | | - mutex: this.props.mutex, |
36 | | - theme: this.props.theme, |
37 | | - preload: this.props.preload, |
38 | | - mode: this.props.mode, |
39 | | - listmaxheight: this.props.listmaxheight, |
40 | | - music: this.props.music, |
41 | | - })); |
| 69 | + const { onInit, ...restProps } = this.props; |
| 70 | + |
| 71 | + const control = new APlayer({ |
| 72 | + ...restProps, |
| 73 | + container: this.container |
| 74 | + }); |
42 | 75 |
|
43 | 76 | events.forEach(event => { |
44 | | - let funcName = 'on' + capitalize(event); |
45 | | - let callback = this.props[funcName]; |
| 77 | + const funcName = 'on' + capitalize(event); |
| 78 | + const callback = this.props[funcName]; |
46 | 79 | if (callback) { |
47 | | - ap.on(event, callback); |
| 80 | + control.on(event, callback); |
48 | 81 | } |
49 | 82 | }); |
50 | | - } |
51 | | -} |
52 | 83 |
|
53 | | -ReactAplayer.propTypes = { |
54 | | - autoplay: PropTypes.bool, |
55 | | - listmaxheight: PropTypes.string, |
56 | | - mode: PropTypes.oneOf(['circulation', 'order', 'random', 'single']), |
57 | | - mutex: PropTypes.bool, |
58 | | - narrow: PropTypes.bool, |
59 | | - preload: PropTypes.oneOf(['auto', 'metadata', 'none']), |
60 | | - showlrc: PropTypes.number, |
61 | | - theme: PropTypes.string, |
62 | | - music(props, propName) { |
63 | | - const prop = props[propName]; |
64 | | - let audios; |
65 | | - if (!prop) return new Error(propName + ' is required'); |
66 | | - |
67 | | - if (Object.prototype.toString.call(prop) === '[object Object]') { |
68 | | - audios = [prop]; |
69 | | - } else if (Array.isArray(prop)) { |
70 | | - audios = prop; |
71 | | - } else { |
72 | | - return new Error(propName + ' should be Object / Array'); |
73 | | - } |
| 84 | + this.control = control; |
| 85 | + onInit(control); |
| 86 | + } |
74 | 87 |
|
75 | | - for (let i = 0; i < audios.length; i++) { |
76 | | - let item = audios[i]; |
77 | | - if (!item.url) { |
78 | | - return new Error(`${propName} should have 'url' property`); |
79 | | - } |
80 | | - } |
81 | | - }, |
82 | | - onCanplay: PropTypes.func, |
83 | | - onPlay: PropTypes.func, |
84 | | - onPause: PropTypes.func, |
85 | | - onPlaying: PropTypes.func, |
86 | | - onEnded: PropTypes.func, |
87 | | - onError: PropTypes.func, |
88 | | -}; |
| 88 | + render() { |
| 89 | + return <div ref={el => (this.container = el)} />; |
| 90 | + } |
| 91 | +} |
89 | 92 |
|
90 | | -ReactAplayer.defaultProps = { |
91 | | - autoplay: false, |
92 | | - mode: 'circulation', |
93 | | - mutex: false, |
94 | | - narrow: false, |
95 | | - preload: 'auto', |
96 | | - showlrc: 0, |
97 | | - theme: '#b7daff', |
98 | | -}; |
| 93 | +export default ReactAplayer; |
0 commit comments