UNPKG

react-youtube-lazy

Version:

After seeing many similar packages none of the had exactly what was needed for my development. Most didn't have a lazyload features, and tryin to implement broke the component, and other simply plugged the videoID you provided into youtube embed iframe. S

274 lines (252 loc) 9.06 kB
import React, { Component } from "react"; class ReactYoutube extends Component { constructor(props) { super(); this.state = { ...this._handleInit(props), UUID: "ReactYoutube" + Math.floor(Math.random() * 10000000), playPress: false}; } _handleInit(props){ let allObjects = {}; let handleVideoObject = this._handleVideoV2(props); allObjects = {...allObjects, ...handleVideoObject, ...this._handleThumbnailV2(props, handleVideoObject.videoID), ...this._handleOtherV2(props)}; return allObjects; } _handleOtherV2(props){ let { height, width, lazyload, lazyloadSize, transition, duration } = props; let css = ""; if (!height) height = 450; height += "px"; if (!width) width = 800; width += "px"; if (lazyload === "false") { lazyload = false; } else if (lazyload === "true") { lazyload = true; } else { lazyload = false; } if (lazyload) { if (!lazyloadSize) { lazyloadSize = 300; } switch (transition) { case "ease-out": transition = "ease-out"; break; case "ease-in-out": transition = "ease-in-out"; break; case "none": transition = "none;" break; default: transition = "ease-in"; } if (transition !== "none") { if (!duration) { duration = 300; } duration = (duration / 1000) + "s"; css = `.ReactYoutube-initFade{ opacity: 0; } .ReactYoutube-startFade{ opacity: 0; } .ReactYoutube-fadeDone{ opacity: 1; transition: opacity ${duration} ${transition}; }`; } } else { lazyloadSize = null; transition = null; } return{ height: height, width: width, lazyload: lazyload, lazyloadSize: lazyloadSize, transition: transition, transCSS: css, duration: duration }; } _handleThumbnailV2(props, videoID){ let urlEnding = ""; switch (props.thumbnailRes) { case "hq": urlEnding += "hq"; break; case "mq": urlEnding += "mq"; break; case "sd": urlEnding += "sd"; break; default: urlEnding += "maxres"; } switch (props.thumbnailId) { case "0": urlEnding += "0"; break; case "1": urlEnding += "1"; break; case "2": urlEnding += "2"; break; case "3": urlEnding += "3"; break; default: urlEnding += "default"; } return { thumbnail: `https://img.youtube.com/vi/${videoID}/${urlEnding}.jpg` }; } _handleVideoV2(props){ let query = ""; for (let key in props.youtubeOptions) { if (query.length === 0) { query += `${key}=${props.youtubeOptions[key]}` } else { query += `&${key}=${props.youtubeOptions[key]}` } } if (props.videoID) { return {videoID: props.videoID, URL: `https://www.youtube.com/embed/${props.videoID}?${query}`}; } else if (props.URL) { let videoID = props.URL.substr(props.URL.indexOf("v=") + 2, props.URL.length); let endOf = videoID.indexOf("&"); if (endOf === -1) endOf = videoID.length; videoID = videoID.substr(0, endOf); return { videoID: videoID, URL: `https://www.youtube.com/embed/${videoID}?${query}` }; } else { return {videoID: null, URL: null} } } componentWillReceiveProps(props){ let allObjects = {}; let handleVideoObject = this._handleVideoV2(props); allObjects = { ...allObjects, ...handleVideoObject, ...this._handleThumbnailV2(props, handleVideoObject.videoID), ...this._handleOtherV2(props) }; this.setState({...allObjects}); } componentDidMount(){ window.addEventListener("scroll", this._scrollHandler); this._scrollHandler("init"); } componentDidUpdate(){ if(!this.state.startLazy) this._scrollHandler("init") } _elementShouldShow(element, distance){ let topOff = window.innerHeight - element.y; let botOff = element.top - element.height; if((topOff > -(distance) && botOff > -(element.height * 2)) || (botOff + element.height * 2 > -(distance) && topOff > 0)){ return true; } return false; } _scrollHandler = (y) => { if(this.state.videoID == null){ if (y === "init"){ return; } } let element = this.refs[this.state.UUID].getBoundingClientRect(); let x = this._elementShouldShow(element, this.state.lazyloadSize); if(x){ this.setState({startLazy: true}); window.removeEventListener("scroll", this._scrollHandler); this._startFade(); } } _startFade = () => { this.setState({fadePostFix: " ReactYoutube-initFade"}); this.forceUpdate(); this.setState({fadePostFix: " ReactYoutube-startFade"}); let x = setInterval(() => { this.setState({fadePostFix: " ReactYoutube-fadeDone"}); clearInterval(x); }, this.state.duration || 0) } _playHandler = (props) => { if(!this.state.playPress){ let stylePlayAwait = { height: this.state.height, width: this.state.width, position: "relative", backgroundColor: "black" }, styleBG = { maxWidth: "100%", maxHeight: "100%", cursor: "pointer", position: "absolute", transform: "translateY(-50%) translateX(-50%)", top: "50%", left: "50%" }, stylePlayButton = { position: "absolute", height: "20%", maxHeight: "50px", width: "100%", transform: "translateY(-50%)", top: "50%" } return ( <div className={`ReactYoutube-PlayAwait${this.state.fadePostFix}`} style={stylePlayAwait} onMouseUp={() => this.setState({playPress: true})}> <img src={this.state.thumbnail} alt="Youtube Thumbnail" style={styleBG}/> <svg style={stylePlayButton} version="1.1" viewBox="0 0 68 48"><path d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill={this.color} fillOpacity="0.8"></path><path d="M 45,24 27,14 27,34" fill="#fff"></path></svg> <style> {`.ReactYoutube-PlayAwait:hover{ fill: red; }`} </style> </div> ) }else{ return ( <iframe title="Youtube Video" id="ytplayer" type="text/html" width={this.state.width} height={this.state.height} src={this.state.URL} frameBorder="0"> </iframe> ) } } _lazyWait = () => { if(this.state.lazyload && this.state.startLazy !== true){ let style = { width: this.state.width, height: this.state.height } return <div className="ReactYoutube-LazyLoad" style={style}></div> }else{ return <this._playHandler/>; } } render(){ console.log(this.state); if(this.state.videoID == null) return <div className="ReactYoutube-NoID"></div> return ( <div ref={this.state.UUID} className="ReactYoutube"> <style> {this.state.transCSS} </style> <this._lazyWait/> </div> ) } } export default ReactYoutube;